Skip to content

Commit

Permalink
Merge pull request #3024 from matsim-org/support-turn-restrictions-in…
Browse files Browse the repository at this point in the history
…-SpeedyALT

Support turn restrictions in SpeedyALT
  • Loading branch information
tduberne authored May 6, 2024
2 parents 670fd95 + 33b85cd commit 25de0eb
Show file tree
Hide file tree
Showing 24 changed files with 1,088 additions and 103 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ matsimExamples
matsim/docs/doxygen/html
matsim/src/main/java/Doxyfile

# VS Code files
.vscode

# ignore output directories:
output/
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.matsim.core.mobsim.framework.events.MobsimBeforeCleanupEvent;
import org.matsim.core.mobsim.framework.listeners.MobsimBeforeCleanupListener;
import org.matsim.core.router.speedy.SpeedyGraph;
import org.matsim.core.router.speedy.SpeedyGraphBuilder;
import org.matsim.core.router.util.TravelDisutility;
import org.matsim.core.router.util.TravelTime;

Expand All @@ -63,7 +64,7 @@ class MultiInsertionDetourPathCalculator implements MobsimBeforeCleanupListener

MultiInsertionDetourPathCalculator(Network network, TravelTime travelTime, TravelDisutility travelDisutility,
DrtConfigGroup drtCfg) {
SpeedyGraph graph = new SpeedyGraph(network);
SpeedyGraph graph = SpeedyGraphBuilder.build(network);
IdMap<Node, Node> nodeMap = new IdMap<>(Node.class);
nodeMap.putAll(network.getNodes());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.matsim.contrib.zone.skims.SparseMatrix.SparseRow;
import org.matsim.core.router.speedy.LeastCostPathTree;
import org.matsim.core.router.speedy.SpeedyGraph;
import org.matsim.core.router.speedy.SpeedyGraphBuilder;
import org.matsim.core.router.util.TravelDisutility;
import org.matsim.core.router.util.TravelTime;
import org.matsim.core.utils.misc.Counter;
Expand Down Expand Up @@ -115,7 +116,7 @@ private interface Calculation<E> {

private static <E> void calculate(RoutingParams params, Collection<? extends E> elements, Calculation<E> calculation, String counterPrefix) {
var trees = IntStream.range(0, params.numberOfThreads)
.mapToObj(i -> new LeastCostPathTree(new SpeedyGraph(params.routingNetwork), params.travelTime, params.travelDisutility))
.mapToObj(i -> new LeastCostPathTree(SpeedyGraphBuilder.build(params.routingNetwork), params.travelTime, params.travelDisutility))
.toList();
var executorService = new ExecutorServiceWithResource<>(trees);
var counter = new Counter(counterPrefix, " / " + elements.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class SpeedyMultiSourceALTFactory {

public SpeedyMultiSourceALT createPathCalculator(Network network, TravelDisutility travelCosts,
TravelTime travelTimes) {
SpeedyGraph graph = this.graphs.computeIfAbsent(network, SpeedyGraph::new);
SpeedyGraph graph = this.graphs.computeIfAbsent(network, SpeedyGraphBuilder::build);

var graphTravelCostsPair = Pair.of(graph, travelCosts);
int landmarksCount = Math.min(16, graph.nodeCount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.IdMap;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.network.Node;
Expand All @@ -39,6 +40,7 @@
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.router.speedy.LeastCostPathTree;
import org.matsim.core.router.speedy.SpeedyGraph;
import org.matsim.core.router.speedy.SpeedyGraphBuilder;
import org.matsim.core.router.util.LeastCostPathCalculator.Path;
import org.matsim.core.router.util.TravelTime;
import org.matsim.core.trafficmonitoring.FreeSpeedTravelTime;
Expand All @@ -65,7 +67,7 @@ public class OneToManyPathCalculatorTest {
private final IdMap<Node, Node> nodeMap = new IdMap<>(Node.class);

private final TravelTime travelTime = new FreeSpeedTravelTime();
private final LeastCostPathTree dijkstraTree = new LeastCostPathTree(new SpeedyGraph(network), travelTime,
private final LeastCostPathTree dijkstraTree = new LeastCostPathTree(SpeedyGraphBuilder.build(network), travelTime,
new TimeAsTravelDisutility(travelTime));

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.junit.jupiter.api.Test;
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.network.Node;
Expand Down Expand Up @@ -74,7 +75,7 @@ public class SpeedyMultiSourceALTBackwardTest {

private final TravelTime travelTime = new FreeSpeedTravelTime();
private final TravelDisutility travelDisutility = new TimeAsTravelDisutility(travelTime);
private final SpeedyGraph speedyGraph = new SpeedyGraph(network);
private final SpeedyGraph speedyGraph = SpeedyGraphBuilder.build(network);
private final SpeedyALTData landmarks = new SpeedyALTData(speedyGraph, 3, travelDisutility);
private final SpeedyMultiSourceALT multiSourceALT = new SpeedyMultiSourceALT(landmarks, travelTime,
travelDisutility);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.junit.jupiter.api.Test;
import org.matsim.api.core.v01.Coord;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.network.Node;
Expand Down Expand Up @@ -72,7 +73,7 @@ public class SpeedyMultiSourceALTForwardTest {

private final TravelTime travelTime = new FreeSpeedTravelTime();
private final TravelDisutility travelDisutility = new TimeAsTravelDisutility(travelTime);
private final SpeedyGraph speedyGraph = new SpeedyGraph(network);
private final SpeedyGraph speedyGraph = SpeedyGraphBuilder.build(network);
private final SpeedyALTData landmarks = new SpeedyALTData(speedyGraph, 3, travelDisutility);
private final SpeedyMultiSourceALT multiSourceALT = new SpeedyMultiSourceALT(landmarks, travelTime,
travelDisutility);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.router.speedy.SpeedyGraphBuilder;
import org.matsim.core.router.util.TravelDisutility;
import org.matsim.core.router.util.TravelTime;
import org.matsim.core.utils.misc.Counter;
Expand All @@ -58,7 +59,7 @@ private NetworkSkimMatrices() {

public static <T> NetworkIndicators<T> calculateSkimMatrices(Network xy2lNetwork, Network routingNetwork, Map<T, Coord[]> coordsPerZone, double departureTime, TravelTime travelTime,
TravelDisutility travelDisutility, int numberOfThreads) {
SpeedyGraph routingGraph = new SpeedyGraph(routingNetwork);
SpeedyGraph routingGraph = SpeedyGraphBuilder.build(routingNetwork);
Map<T, Node[]> nodesPerZone = new HashMap<>();
for (Map.Entry<T, Coord[]> e : coordsPerZone.entrySet()) {
T zoneId = e.getKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.matsim.contrib.taxi.optimizer.VehicleData;
import org.matsim.contrib.taxi.optimizer.assignment.AssignmentDestinationData.DestEntry;
import org.matsim.core.router.speedy.SpeedyGraph;
import org.matsim.core.router.speedy.SpeedyGraphBuilder;
import org.matsim.core.router.util.LeastCostPathCalculator;
import org.matsim.core.router.util.TravelDisutility;
import org.matsim.core.router.util.TravelTime;
Expand Down Expand Up @@ -71,7 +72,7 @@ public VehicleAssignmentProblem(Network network, TravelTime travelTime, TravelDi

IdMap<Node, Node> nodeMap = new IdMap<>(Node.class);
nodeMap.putAll(network.getNodes());
pathSearch = OneToManyPathSearch.createSearch(new SpeedyGraph(network), nodeMap, travelTime, travelDisutility,
pathSearch = OneToManyPathSearch.createSearch(SpeedyGraphBuilder.build(network), nodeMap, travelTime, travelDisutility,
false);

// TODO this kNN is slow
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.matsim.core.network;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -34,10 +37,34 @@ public class DisallowedNextLinks {
// list in favor of a smaller memory footprint.
private final Map<String, List<List<Id<Link>>>> linkIdSequencesMap = new HashMap<>();

/**
* A builder to allow building a populated instance in one statement.
* Be aware that several calls to the build() method of a particular Builder instance will
* return the same DisallowedNextLinks instance!
*/
public static class Builder {
private final DisallowedNextLinks instance = new DisallowedNextLinks();

public Builder withDisallowedLinkSequence(String mode, List<Id<Link>> linkSequence) {
instance.addDisallowedLinkSequence(mode, linkSequence);
return this;
}

/**
* Be aware that several calls to the build() method of a particular Builder
* instance will return the same DisallowedNextLinks instance!
*
* @return an instance with the required disallowedNextLinks set
*/
public DisallowedNextLinks build() {
return instance;
}
}

public DisallowedNextLinks() { // ! remove constructor, if routing considers this
if (!warnedAboutNotConsideredInRouting) {
warnedAboutNotConsideredInRouting = true;
LOG.warn("Considering DisallowedNextLinks in routing is not yet implemented!");
LOG.warn("Considering DisallowedNextLinks in routing is only implemented by SpeedyDijkstra and SpeedyALT!");
}
}

Expand Down Expand Up @@ -75,6 +102,25 @@ public List<List<Id<Link>>> getDisallowedLinkSequences(String mode) {
return sequences != null ? Collections.unmodifiableList(sequences) : Collections.emptyList();
}

/**
* Returns an aggregation of all link restrictions, for all modes. This is meant to be used in monomodal networks.
*/
public Collection<List<Id<Link>>> getMergedDisallowedLinkSequences() {
// Implementation note: we do not want duplicates, so the logical choice is a set,
// as the argument for memory footprint does not hold here (short lived object).
// This makes the return types inconsistent, but one could argue that all methods should
// return Collections rather than Lists (ordering is not meaningful)
// We use a LinkedHashSet to preserve iteration order, to be consistent with other methods in this class
// td 04.24
final Set<List<Id<Link>>> sequences = new LinkedHashSet<>();

for (List<List<Id<Link>>> sequencesForMode : linkIdSequencesMap.values()) {
sequences.addAll(sequencesForMode);
}

return Collections.unmodifiableSet(sequences);
}

@Nullable
public List<List<Id<Link>>> removeDisallowedLinkSequences(String mode) {
return this.linkIdSequencesMap.remove(mode);
Expand All @@ -85,6 +131,18 @@ public Map<String, List<List<Id<Link>>>> getAsMap() {
.collect(Collectors.toMap(Entry::getKey, e -> Collections.unmodifiableList(e.getValue())));
}

public DisallowedNextLinks copyOnlyModes(final Collection<String> modes) {
final DisallowedNextLinks newInstance = new DisallowedNextLinks();

for (String mode : modes) {
for (List<Id<Link>> sequence : getDisallowedLinkSequences(mode)) {
newInstance.addDisallowedLinkSequence(mode, sequence);
}
}

return newInstance;
}

public void clear() {
this.linkIdSequencesMap.clear();
}
Expand Down Expand Up @@ -120,4 +178,9 @@ public int hashCode() {
return this.linkIdSequencesMap.hashCode();
}

@Override
public String toString() {
return "DisallowedNextLinks [linkIdSequencesMap=" + linkIdSequencesMap + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.network.NetworkFactory;
import org.matsim.api.core.v01.network.Node;
import org.matsim.core.network.DisallowedNextLinks;
import org.matsim.core.network.NetworkChangeEvent;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.network.TimeDependentNetwork;
Expand Down Expand Up @@ -102,6 +103,11 @@ public void filter(final Network subNetwork, final Set<String> extractModes) {
NetworkUtils.setType(link2, NetworkUtils.getType(link));
AttributesUtils.copyAttributesFromTo(link, link2);
subNetwork.addLink(link2);

DisallowedNextLinks disallowedNextLinks = NetworkUtils.getDisallowedNextLinks(link);
if (disallowedNextLinks != null) {
NetworkUtils.setDisallowedNextLinks(link2, disallowedNextLinks.copyOnlyModes(extractModes));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,7 @@ public RoutingModule get() {
+ routingMode + ";\tmode=" + mode) ;

// the network refers to the (transport)mode:
Network filteredNetwork = null;

// Ensure this is not performed concurrently by multiple threads!
synchronized (this.singleModeNetworksCache.getSingleModeNetworksCache()) {
filteredNetwork = this.singleModeNetworksCache.getSingleModeNetworksCache().get(mode);
if (filteredNetwork == null) {
TransportModeNetworkFilter filter = new TransportModeNetworkFilter(network);
Set<String> modes = new HashSet<>();
modes.add(mode);
filteredNetwork = NetworkUtils.createNetwork(networkConfigGroup);
filter.filter(filteredNetwork, modes);
this.singleModeNetworksCache.getSingleModeNetworksCache().put(mode, filteredNetwork);
}
}
Network filteredNetwork = singleModeNetworksCache.getOrCreateSingleModeNetwork(mode);

// the travel time & disutility refer to the routing mode:
TravelDisutilityFactory travelDisutilityFactory = this.travelDisutilityFactories.get(routingMode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,46 @@

package org.matsim.core.router;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.matsim.api.core.v01.network.Network;
import org.matsim.core.config.groups.NetworkConfigGroup;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.network.algorithms.TransportModeNetworkFilter;

import com.google.inject.Inject;

public class SingleModeNetworksCache {

private Map<String, Network> singleModeNetworksCache = new ConcurrentHashMap<>();
private final Map<String, Network> singleModeNetworksCache = new ConcurrentHashMap<>();
private final Network fullNetwork;
private final NetworkConfigGroup networkConfigGroup;

@Inject
public SingleModeNetworksCache(Network fullNetwork, NetworkConfigGroup networkConfigGroup) {
this.fullNetwork = fullNetwork;
this.networkConfigGroup = networkConfigGroup;
}

public Map<String, Network> getSingleModeNetworksCache() {
return singleModeNetworksCache;
}

public Network getOrCreateSingleModeNetwork(final String mode) {
return getSingleModeNetworksCache().computeIfAbsent(mode, this::filterNetwork);
}

private Network filterNetwork(final String mode) {
TransportModeNetworkFilter filter = new TransportModeNetworkFilter(fullNetwork);
Set<String> modes = new HashSet<>();
modes.add(mode);

final Network filteredNetwork = NetworkUtils.createNetwork(networkConfigGroup);
filter.filter(filteredNetwork, modes);

return filteredNetwork;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class SpeedyALTFactory implements LeastCostPathCalculatorFactory {
public LeastCostPathCalculator createPathCalculator(Network network, TravelDisutility travelCosts, TravelTime travelTimes) {
SpeedyGraph graph = this.graphs.get(network);
if (graph == null) {
graph = new SpeedyGraph(network);
graph = SpeedyGraphBuilder.build(network);
this.graphs.put(network, graph);
}
SpeedyALTData landmarks = this.landmarksData.get(graph);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class SpeedyDijkstraFactory implements LeastCostPathCalculatorFactory {
public LeastCostPathCalculator createPathCalculator(Network network, TravelDisutility travelCosts, TravelTime travelTimes) {
SpeedyGraph graph = graphs.get(network);
if (graph == null) {
graph = new SpeedyGraph(network);
graph = SpeedyGraphBuilder.build(network);
graphs.put(network, graph);
}
return new SpeedyDijkstra(graph, travelTimes, travelCosts);
Expand Down
Loading

0 comments on commit 25de0eb

Please sign in to comment.