Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nav 126 re improve performance of raptor #80

Merged
merged 41 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
17bcbc9
ENH: NAV-65 - Add trip ids to raptor lookup.
clukas1 Jul 5, 2024
ccb080e
ENH: NAV-65 - First throw at RaptorTripMaskProvider
clukas1 Jul 5, 2024
02e4e66
ENH: NAV-65 - Pass tripMaskProvider down to RaptorRouter.
clukas1 Jul 5, 2024
b70a103
ENH: NAV-65 - Build raptor with TripMaskProvider.
clukas1 Jul 5, 2024
67283f6
REFACTOR: NAV-65 - Remove unused import.
clukas1 Jul 5, 2024
8f59e06
REFACTOR: NAV-65 - Format project.
clukas1 Jul 5, 2024
6b50aa0
ENH: NAV-65 - Make raptor algorithm use trip masks.
clukas1 Jul 6, 2024
91b3bdb
Merge branch 'main' into NAV-65-Mask-Trips-in-Raptor
clukas1 Jul 6, 2024
8588db5
ENH: NAV-66 - Implement multi day logic for raptor router.
clukas1 Jul 6, 2024
5b9b94b
ENH: NAV-66 - Make public transit service map gtfs trips correctly to…
clukas1 Jul 6, 2024
6c292bb
TEST: NAV-66 - Move test helpers to different class file for reuse in…
clukas1 Jul 7, 2024
b45b4d5
ENH: NAV-66 - Make days to scan configurable.
clukas1 Jul 7, 2024
5bc4e4a
TEST: NAV-66 - Add first multi day raptor tests.
clukas1 Jul 7, 2024
3be15e8
TEST: NAV-66 - More tests.
clukas1 Jul 8, 2024
c97d1be
FIX: NAV-66 - Fix failing test due to wrong argument order in Service…
clukas1 Jul 8, 2024
da45b1b
ENH: NAV-126 - Make StopTimes use int arrays instead of object arrays.
clukas1 Jul 8, 2024
02185f4
ENH: NAV-126 - Implement raptor cache that stores stop time arrays fo…
clukas1 Jul 9, 2024
a06b42f
ENH: NAV-126 - Allow preparing stop times for dates in benchmark befo…
clukas1 Jul 9, 2024
546d3b6
ENH: NAV-126 - Only scan previous day if needed.
clukas1 Jul 9, 2024
a8f0614
DOC: NAV-126 - Add docstrings to new methods/classes.
clukas1 Jul 12, 2024
35af8ce
REFACTOR: NAV-126 - Rename RaptorCache to StopTimeProvider.
clukas1 Jul 12, 2024
630f636
REFACTOR: NAV-126 - Add RaptorTripMaskProvider directly to StopTimePr…
clukas1 Jul 12, 2024
81ab799
ENH: NAV-126 - Make stop time provider cache configurable.
clukas1 Jul 12, 2024
5412495
ENH: NAV-126 - Remove transfer generators from benchmark.
clukas1 Jul 12, 2024
921dfa5
REFACTOR: NAV-126 - Remove unused same stop transfer generator.
clukas1 Jul 12, 2024
d2c57e0
REFACTOR: NAV-126 - Format project.
clukas1 Jul 12, 2024
e296c90
ENH: NAV-126 - Make transfer generation optional in service.
clukas1 Jul 12, 2024
48432ad
ENH: NAV-126 - Reduce log levels for some messages to boost performance.
clukas1 Jul 12, 2024
cf1653f
ENH: NAV-126 - Introduce RaptorConfig class.
clukas1 Jul 16, 2024
d5946b2
ENH: NAV-126 - Calculate earliest and latest stop times for routes an…
clukas1 Jul 16, 2024
48bfb41
REFACTOR: NAV-126 - Align variable names in application propteries an…
clukas1 Jul 23, 2024
fce670a
REFACTOR: NAV-126 - Remove unnecessary @NotNull annotations.
clukas1 Jul 23, 2024
09f31a5
ENH: NAV-126 - Reduce the amount of caching for service days.
clukas1 Jul 23, 2024
5f93d47
REFACTOR: NAV-126 - Add DayMask and RouteMask to RaptorTripMaskProvid…
clukas1 Jul 23, 2024
f5a7a29
REFACTOR: NAV-126 - Link constants for more consistency.
clukas1 Jul 23, 2024
74fa3b7
FIX: NAV-126 - Fix failing tests.
clukas1 Jul 24, 2024
c16dd58
STYLE: NAV-126 - Format project
munterfi Jul 24, 2024
94c92e6
STYLE: NAV-126 - Unify case in log messages
munterfi Jul 24, 2024
2ef28d1
REFACTOR. NAV-126 - Rename trip masks.
clukas1 Jul 25, 2024
a3e62da
FIX: NAV-126 - Actually use generated transfers when creating convert…
clukas1 Jul 25, 2024
9bcf5f8
Merge branch 'NAV-126-Re-Improve-Performance-of-Raptor' of github.com…
clukas1 Jul 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public ServiceConfigParser(@Value("${gtfs.static.uri}") String gtfsStaticUri,
@Value("${walking.calculator.type}") String walkingCalculatorType,
@Value("${walking.speed}") double walkingSpeed,
@Value("${walking.duration.minimum}") int walkingDurationMinimum,
@Value("${cache.size}") int cacheSize,
@Value("${raptor.days.to.scan}") int raptorDaysToScan,
@Value("${cache.service.day.size}") int cacheServiceDaySize,
@Value("${cache.eviction.strategy}") String cacheEvictionStrategy) {

ServiceConfig.WalkCalculatorType walkCalculatorTypeEnum = ServiceConfig.WalkCalculatorType.valueOf(
Expand All @@ -30,7 +31,7 @@ public ServiceConfigParser(@Value("${gtfs.static.uri}") String gtfsStaticUri,

this.serviceConfig = new ServiceConfig(gtfsStaticUri, gtfsStaticUpdateCron, transferTimeSameStopDefault,
transferTimeBetweenStopsMinimum, transferTimeAccessEgress, walkingSearchRadius, walkCalculatorTypeEnum,
walkingSpeed, walkingDurationMinimum, cacheSize, cacheEvictionStrategyEnum);
walkingSpeed, walkingDurationMinimum, raptorDaysToScan, cacheServiceDaySize, cacheEvictionStrategyEnum);
}

}
9 changes: 7 additions & 2 deletions src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package ch.naviqore.raptor;

import ch.naviqore.raptor.router.RaptorConfig;
import ch.naviqore.raptor.router.RaptorRouterBuilder;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

public interface RaptorAlgorithm {

static RaptorRouterBuilder builder(int sameStopTransferTime) {
return new RaptorRouterBuilder(sameStopTransferTime);
static RaptorRouterBuilder builder(RaptorConfig config) {
return new RaptorRouterBuilder(config);
}

/**
Expand Down Expand Up @@ -48,4 +50,7 @@ List<Connection> routeLatestDeparture(Map<String, Integer> departureStops, Map<S
Map<String, Connection> routeIsolines(Map<String, LocalDateTime> sourceStops, TimeType timeType,
QueryConfig config);

// TODO: Discuss if this should be added to the interface (for now added for benchmark test)
void prepareStopTimesForDate(LocalDate date);
clukas1 marked this conversation as resolved.
Show resolved Hide resolved

}
14 changes: 3 additions & 11 deletions src/main/java/ch/naviqore/raptor/router/DateTimeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,13 @@

class DateTimeUtils {

static LocalDate getReferenceDate(Map<?, LocalDateTime> sourceStops, TimeType timeType) {
static LocalDateTime getReferenceDate(Map<?, LocalDateTime> sourceStops, TimeType timeType) {
if (timeType == TimeType.DEPARTURE) {
// get minimum departure time
return sourceStops.values()
.stream()
.min(Comparator.naturalOrder())
.map(LocalDateTime::toLocalDate)
.orElseThrow();
return sourceStops.values().stream().min(Comparator.naturalOrder()).orElseThrow();
} else {
// get maximum arrival time
return sourceStops.values()
.stream()
.max(Comparator.naturalOrder())
.map(LocalDateTime::toLocalDate)
.orElseThrow();
return sourceStops.values().stream().max(Comparator.naturalOrder()).orElseThrow();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
class LabelPostprocessor {

private final Stop[] stops;
private final StopTime[] stopTimes;
private final int[] stopTimes;
private final Route[] routes;
private final RouteStop[] routeStops;

Expand Down Expand Up @@ -375,7 +375,8 @@ private boolean canStopTimeBeTarget(StopTime stopTime, int routeSourceTime, Time
return null;
}

return stopTimes[firstStopTimeIdx + tripOffset * numberOfStops + stopOffset];
int stopTimeIndex = firstStopTimeIdx + 2 * (tripOffset * numberOfStops + stopOffset) + 2;
munterfi marked this conversation as resolved.
Show resolved Hide resolved
return new StopTime(stopTimes[stopTimeIndex], stopTimes[stopTimeIndex + 1]);
}

private @Nullable StopLabelsAndTimes.Label getBestLabelForStop(List<StopLabelsAndTimes.Label[]> bestLabelsPerRound,
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/ch/naviqore/raptor/router/Lookup.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

import java.util.Map;

record Lookup(Map<String, Integer> stops, Map<String, Integer> routes) {
record Lookup(Map<String, Integer> stops, Map<String, Integer> routes, Map<String, String[]> routeTripIds) {
}
15 changes: 12 additions & 3 deletions src/main/java/ch/naviqore/raptor/router/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ch.naviqore.raptor.TimeType;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -31,6 +32,9 @@ class Query {
private final int cutoffTime;
private final StopLabelsAndTimes stopLabelsAndTimes;

private final LocalDateTime referenceDate;
private final int maxDaysToScan;

/**
* @param raptorData the current raptor data structures.
* @param sourceStopIndices the indices of the source stops.
Expand All @@ -39,9 +43,12 @@ class Query {
* @param walkingDurationsToTarget the walking durations to the target stops.
* @param timeType the time type (arrival or departure) of the query.
* @param config the query configuration.
* @param referenceDate the reference date for the query.
* @param raptorConfig the raptor configuration.
*/
Query(RaptorData raptorData, int[] sourceStopIndices, int[] targetStopIndices, int[] sourceTimes,
int[] walkingDurationsToTarget, QueryConfig config, TimeType timeType) {
int[] walkingDurationsToTarget, QueryConfig config, TimeType timeType, LocalDateTime referenceDate,
RaptorConfig raptorConfig) {

if (sourceStopIndices.length != sourceTimes.length) {
throw new IllegalArgumentException("Source stops and departure/arrival times must have the same size.");
Expand All @@ -58,6 +65,8 @@ class Query {
this.walkingDurationsToTarget = walkingDurationsToTarget;
this.config = config;
this.timeType = timeType;
this.referenceDate = referenceDate;
this.maxDaysToScan = raptorConfig.getDaysToScan();

targetStops = new int[targetStopIndices.length * 2];
cutoffTime = determineCutoffTime();
Expand Down Expand Up @@ -85,7 +94,7 @@ List<StopLabelsAndTimes.Label[]> run() {
FootpathRelaxer footpathRelaxer = new FootpathRelaxer(stopLabelsAndTimes, raptorData,
config.getMinimumTransferDuration(), config.getMaximumWalkingDuration(), timeType);
RouteScanner routeScanner = new RouteScanner(stopLabelsAndTimes, raptorData,
config.getMinimumTransferDuration(), timeType);
config.getMinimumTransferDuration(), timeType, referenceDate, maxDaysToScan);

// initially relax all source stops and add the newly improved stops by relaxation to the marked stops
Set<Integer> markedStops = initialize();
Expand Down Expand Up @@ -118,7 +127,7 @@ List<StopLabelsAndTimes.Label[]> run() {
* @return the initially marked stops.
*/
Set<Integer> initialize() {
log.info("Initializing global best times per stop and best labels per round");
log.debug("Initializing global best times per stop and best labels per round");

// fill target stops
for (int i = 0; i < targetStops.length; i += 2) {
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/ch/naviqore/raptor/router/RaptorConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ch.naviqore.raptor.router;

import ch.naviqore.utils.cache.EvictionCache;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

@Getter
@NoArgsConstructor
@ToString
public class RaptorConfig {

@Setter
private RaptorTripMaskProvider maskProvider = new NoMaskProvider();

private int daysToScan = 1;
private int defaultSameStopTransferTime = 120;

private int stopTimeCacheSize = 5;
@Setter
private EvictionCache.Strategy stopTimeCacheStrategy = EvictionCache.Strategy.LRU;

public RaptorConfig(int daysToScan, int defaultSameStopTransferTime, int stopTimeCacheSize,
EvictionCache.Strategy stopTimeCacheStrategy, RaptorTripMaskProvider maskProvider) {
setDaysToScan(daysToScan);
setDefaultSameStopTransferTime(defaultSameStopTransferTime);
setStopTimeCacheSize(stopTimeCacheSize);
setStopTimeCacheStrategy(stopTimeCacheStrategy);
setMaskProvider(maskProvider);
}

public void setDaysToScan(int daysToScan) {
if (daysToScan <= 0) {
throw new IllegalArgumentException("Days to scan must be greater than 0.");
}
this.daysToScan = daysToScan;
}

public void setDefaultSameStopTransferTime(int defaultSameStopTransferTime) {
if (defaultSameStopTransferTime < 0) {
throw new IllegalArgumentException("Default same stop transfer time must be greater than or equal to 0.");
}
this.defaultSameStopTransferTime = defaultSameStopTransferTime;
}

public void setStopTimeCacheSize(int stopTimeCacheSize) {
if (stopTimeCacheSize <= 0) {
throw new IllegalArgumentException("Stop time cache size must be greater than 0.");
}
this.stopTimeCacheSize = stopTimeCacheSize;
}

/**
* No mask provider as default mask provider (no masking of trips).
*/
@Setter
@NoArgsConstructor
static class NoMaskProvider implements RaptorTripMaskProvider {

Map<String, String[]> tripIds = null;

@Override
public String getServiceIdForDate(LocalDate date) {
return "NoMask";
}

@Override
public DayTripMask getDayTripMask(LocalDate date) {
Map<String, RouteTripMask> tripMasks = new HashMap<>();
for (Map.Entry<String, String[]> entry : tripIds.entrySet()) {
String routeId = entry.getKey();
String[] tripIds = entry.getValue();
boolean[] tripMask = new boolean[tripIds.length];
for (int i = 0; i < tripIds.length; i++) {
tripMask[i] = true;
}
tripMasks.put(routeId, new RouteTripMask(tripMask));
}

return new DayTripMask(getServiceIdForDate(date), date, tripMasks);
}
}

}
2 changes: 2 additions & 0 deletions src/main/java/ch/naviqore/raptor/router/RaptorData.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ interface RaptorData {

RouteTraversal getRouteTraversal();

StopTimeProvider getStopTimeProvider();

}
28 changes: 22 additions & 6 deletions src/main/java/ch/naviqore/raptor/router/RaptorRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,29 @@ class RaptorRouter implements RaptorAlgorithm, RaptorData {
@Getter
private final RouteTraversal routeTraversal;

@Getter
private final StopTimeProvider stopTimeProvider;

private final RaptorConfig config;

private final InputValidator validator;

RaptorRouter(Lookup lookup, StopContext stopContext, RouteTraversal routeTraversal) {
RaptorRouter(Lookup lookup, StopContext stopContext, RouteTraversal routeTraversal, RaptorConfig config) {
this.lookup = lookup;
this.stopContext = stopContext;
this.routeTraversal = routeTraversal;
this.config = config;
config.getMaskProvider().setTripIds(lookup.routeTripIds());
this.stopTimeProvider = new StopTimeProvider(this, config.getMaskProvider(), config.getStopTimeCacheSize(),
config.getStopTimeCacheStrategy());
validator = new InputValidator(lookup.stops());
}

@Override
public void prepareStopTimesForDate(LocalDate date) {
stopTimeProvider.getStopTimesForDate(date);
}

@Override
public List<Connection> routeEarliestArrival(Map<String, LocalDateTime> departureStops,
Map<String, Integer> arrivalStops, QueryConfig config) {
Expand Down Expand Up @@ -68,14 +82,15 @@ public Map<String, Connection> routeIsolines(Map<String, LocalDateTime> sourceSt
InputValidator.validateSourceStopTimes(sourceStops);

log.info("Routing isolines from {} with {}", sourceStops.keySet(), timeType);
LocalDate referenceDate = DateTimeUtils.getReferenceDate(sourceStops, timeType);
LocalDateTime referenceDateTime = DateTimeUtils.getReferenceDate(sourceStops, timeType);
LocalDate referenceDate = referenceDateTime.toLocalDate();
Map<Integer, Integer> validatedSourceStopIdx = validator.validateStopsAndGetIndices(
DateTimeUtils.mapLocalDateTimeToTimestamp(sourceStops, referenceDate));

int[] sourceStopIndices = validatedSourceStopIdx.keySet().stream().mapToInt(Integer::intValue).toArray();
int[] refStopTimes = validatedSourceStopIdx.values().stream().mapToInt(Integer::intValue).toArray();
List<StopLabelsAndTimes.Label[]> bestLabelsPerRound = new Query(this, sourceStopIndices, new int[]{},
refStopTimes, new int[]{}, config, timeType).run();
refStopTimes, new int[]{}, config, timeType, referenceDateTime, this.config).run();

return new LabelPostprocessor(this, timeType).reconstructIsolines(bestLabelsPerRound, referenceDate);
}
Expand All @@ -98,7 +113,8 @@ public Map<String, Connection> routeIsolines(Map<String, LocalDateTime> sourceSt
private List<Connection> getConnections(Map<String, LocalDateTime> sourceStops, Map<String, Integer> targetStops,
TimeType timeType, QueryConfig config) {
InputValidator.validateSourceStopTimes(sourceStops);
LocalDate referenceDate = DateTimeUtils.getReferenceDate(sourceStops, timeType);
LocalDateTime referenceDateTime = DateTimeUtils.getReferenceDate(sourceStops, timeType);
LocalDate referenceDate = referenceDateTime.toLocalDate();
Map<String, Integer> sourceStopsSecondsOfDay = DateTimeUtils.mapLocalDateTimeToTimestamp(sourceStops,
referenceDate);
Map<Integer, Integer> validatedSourceStops = validator.validateStopsAndGetIndices(sourceStopsSecondsOfDay);
Expand All @@ -111,7 +127,7 @@ private List<Connection> getConnections(Map<String, LocalDateTime> sourceStops,
int[] walkingDurationsToTarget = validatedTargetStops.values().stream().mapToInt(Integer::intValue).toArray();

List<StopLabelsAndTimes.Label[]> bestLabelsPerRound = new Query(this, sourceStopIndices, targetStopIndices,
sourceTimes, walkingDurationsToTarget, config, timeType).run();
sourceTimes, walkingDurationsToTarget, config, timeType, referenceDateTime, this.config).run();

return new LabelPostprocessor(this, timeType).reconstructParetoOptimalSolutions(bestLabelsPerRound,
validatedTargetStops, referenceDate);
Expand Down Expand Up @@ -190,7 +206,7 @@ private Map<Integer, Integer> validateStopsAndGetIndices(Map<String, Integer> st
if (stopsToIdx.containsKey(stopId)) {
validStopIds.put(stopsToIdx.get(stopId), time);
} else {
log.warn("Stop ID {} not found in lookup removing from query.", entry.getKey());
log.debug("Stop ID {} not found in lookup removing from query.", entry.getKey());
}
}

Expand Down
Loading