-
Notifications
You must be signed in to change notification settings - Fork 454
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e608ecc
commit 037a2a5
Showing
18 changed files
with
1,967 additions
and
0 deletions.
There are no files selected for viewing
290 changes: 290 additions & 0 deletions
290
...m/contrib/drt/extension/preplanned/optimizer/offlineOptimization/InsertionCalculator.java
Large diffs are not rendered by default.
Oops, something went wrong.
402 changes: 402 additions & 0 deletions
402
.../drt/extension/preplanned/optimizer/offlineOptimization/OnlineAndOfflineDrtOptimizer.java
Large diffs are not rendered by default.
Oops, something went wrong.
83 changes: 83 additions & 0 deletions
83
...rt/extension/preplanned/optimizer/offlineOptimization/basicStructures/FleetSchedules.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package org.matsim.contrib.drt.extension.preplanned.optimizer.offlineOptimization.basicStructures; | ||
|
||
import org.matsim.api.core.v01.Id; | ||
import org.matsim.api.core.v01.network.Link; | ||
import org.matsim.api.core.v01.network.Network; | ||
import org.matsim.api.core.v01.population.Person; | ||
import org.matsim.contrib.dvrp.fleet.DvrpVehicle; | ||
|
||
import java.util.*; | ||
|
||
public record FleetSchedules( | ||
Map<Id<DvrpVehicle>, List<TimetableEntry>> vehicleToTimetableMap, | ||
Map<Id<Person>, Id<DvrpVehicle>> requestIdToVehicleMap, | ||
Map<Id<Person>, GeneralRequest> pendingRequests) { | ||
|
||
public static List<TimetableEntry> copyTimetable(List<TimetableEntry> timetable) { | ||
List<TimetableEntry> timetableCopy = new ArrayList<>(); | ||
for (TimetableEntry timetableEntry : timetable) { | ||
timetableCopy.add(new TimetableEntry(timetableEntry)); | ||
} | ||
return timetableCopy; | ||
} | ||
|
||
public static FleetSchedules initializeFleetSchedules(Map<Id<DvrpVehicle>, OnlineVehicleInfo> onlineVehicleInfoMap) { | ||
Map<Id<DvrpVehicle>, List<TimetableEntry>> vehicleToTimetableMap = new LinkedHashMap<>(); | ||
for (OnlineVehicleInfo vehicleInfo : onlineVehicleInfoMap.values()) { | ||
vehicleToTimetableMap.put(vehicleInfo.vehicle().getId(), new ArrayList<>()); | ||
} | ||
Map<Id<Person>, Id<DvrpVehicle>> requestIdToVehicleMap = new HashMap<>(); | ||
Map<Id<Person>, GeneralRequest> rejectedRequests = new LinkedHashMap<>(); | ||
return new FleetSchedules(vehicleToTimetableMap, requestIdToVehicleMap, rejectedRequests); | ||
} | ||
|
||
public FleetSchedules copySchedule() { | ||
Map<Id<DvrpVehicle>, List<TimetableEntry>> vehicleToTimetableMapCopy = new LinkedHashMap<>(); | ||
for (Id<DvrpVehicle> vehicleId : this.vehicleToTimetableMap().keySet()) { | ||
vehicleToTimetableMapCopy.put(vehicleId, copyTimetable(this.vehicleToTimetableMap.get(vehicleId))); | ||
} | ||
Map<Id<Person>, Id<DvrpVehicle>> requestIdToVehicleMapCopy = new HashMap<>(this.requestIdToVehicleMap); | ||
Map<Id<Person>, GeneralRequest> rejectedRequestsCopy = new LinkedHashMap<>(this.pendingRequests); | ||
|
||
return new FleetSchedules(vehicleToTimetableMapCopy, requestIdToVehicleMapCopy, rejectedRequestsCopy); | ||
} | ||
|
||
public void updateFleetSchedule(Network network, LinkToLinkTravelTimeMatrix linkToLinkTravelTimeMatrix, | ||
Map<Id<DvrpVehicle>, OnlineVehicleInfo> onlineVehicleInfoMap) { | ||
for (Id<DvrpVehicle> vehicleId : onlineVehicleInfoMap.keySet()) { | ||
// When new vehicle enters service, create a new entry for it | ||
this.vehicleToTimetableMap().computeIfAbsent(vehicleId, t -> new ArrayList<>()); | ||
if (!onlineVehicleInfoMap.containsKey(vehicleId)) { | ||
// When a vehicle ends service, remove it from the schedule | ||
this.vehicleToTimetableMap().remove(vehicleId); | ||
} | ||
} | ||
|
||
for (Id<DvrpVehicle> vehicleId : this.vehicleToTimetableMap().keySet()) { | ||
List<TimetableEntry> timetable = this.vehicleToTimetableMap().get(vehicleId); | ||
if (!timetable.isEmpty()) { | ||
Link currentLink = onlineVehicleInfoMap.get(vehicleId).currentLink(); | ||
double currentTime = onlineVehicleInfoMap.get(vehicleId).divertableTime(); | ||
for (TimetableEntry timetableEntry : timetable) { | ||
Id<Link> stopLinkId = timetableEntry.getStopType() == TimetableEntry.StopType.PICKUP ? | ||
timetableEntry.getRequest().getFromLinkId() : timetableEntry.getRequest().getToLinkId(); | ||
Link stopLink = network.getLinks().get(stopLinkId); | ||
double newArrivalTime = currentTime + linkToLinkTravelTimeMatrix.getTravelTime(currentLink, stopLink, currentTime); | ||
timetableEntry.updateArrivalTime(newArrivalTime); | ||
|
||
// Delay the latest arrival time of the stop when necessary (e.g., due to traffic uncertainty), in order to make sure assigned requests will remain feasible | ||
if (timetableEntry.getStopType() == TimetableEntry.StopType.PICKUP) { | ||
double originalLatestDepartureTime = timetableEntry.getRequest().getLatestDepartureTime(); | ||
timetableEntry.getRequest().setLatestDepartureTime(Math.max(originalLatestDepartureTime, newArrivalTime)); | ||
} else { | ||
double originalLatestArrivalTime = timetableEntry.getRequest().getLatestArrivalTime(); | ||
timetableEntry.getRequest().setLatestArrivalTime(Math.max(originalLatestArrivalTime, newArrivalTime)); | ||
} | ||
|
||
currentTime = timetableEntry.getDepartureTime(); | ||
currentLink = stopLink; | ||
} | ||
} | ||
} | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
...rt/extension/preplanned/optimizer/offlineOptimization/basicStructures/GeneralRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.matsim.contrib.drt.extension.preplanned.optimizer.offlineOptimization.basicStructures; | ||
|
||
import org.matsim.api.core.v01.Id; | ||
import org.matsim.api.core.v01.network.Link; | ||
import org.matsim.api.core.v01.population.Person; | ||
|
||
public class GeneralRequest { | ||
private final Id<Person> passengerId; | ||
private final Id<Link> fromLinkId; | ||
private final Id<Link> toLinkId; | ||
private final double earliestDepartureTime; | ||
|
||
// latest departure time (flexibility is needed to account for traffic uncertainty) | ||
private double latestDepartureTime; | ||
// latest arrival time (flexibility is needed to account for traffic uncertainty) | ||
private double latestArrivalTime; | ||
|
||
public GeneralRequest(Id<Person> passengerId, Id<Link> fromLinkId, Id<Link> toLinkId, double earliestDepartureTime, | ||
double latestStartTime, double latestArrivalTime) { | ||
this.passengerId = passengerId; | ||
this.fromLinkId = fromLinkId; | ||
this.toLinkId = toLinkId; | ||
this.earliestDepartureTime = earliestDepartureTime; | ||
this.latestDepartureTime = latestStartTime; | ||
this.latestArrivalTime = latestArrivalTime; | ||
} | ||
|
||
public Id<Person> getPassengerId() { | ||
return passengerId; | ||
} | ||
|
||
public double getEarliestDepartureTime() { | ||
return earliestDepartureTime; | ||
} | ||
|
||
public double getLatestArrivalTime() { | ||
return latestArrivalTime; | ||
} | ||
|
||
public double getLatestDepartureTime() { | ||
return latestDepartureTime; | ||
} | ||
|
||
public Id<Link> getFromLinkId() { | ||
return fromLinkId; | ||
} | ||
|
||
public Id<Link> getToLinkId() { | ||
return toLinkId; | ||
} | ||
|
||
public void setLatestArrivalTime(double latestArrivalTime) { | ||
this.latestArrivalTime = latestArrivalTime; | ||
} | ||
|
||
public void setLatestDepartureTime(double latestDepartureTime) { | ||
this.latestDepartureTime = latestDepartureTime; | ||
} | ||
} | ||
|
123 changes: 123 additions & 0 deletions
123
.../preplanned/optimizer/offlineOptimization/basicStructures/LinkToLinkTravelTimeMatrix.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package org.matsim.contrib.drt.extension.preplanned.optimizer.offlineOptimization.basicStructures; | ||
|
||
import one.util.streamex.EntryStream; | ||
import org.matsim.api.core.v01.Id; | ||
import org.matsim.api.core.v01.network.Link; | ||
import org.matsim.api.core.v01.network.Network; | ||
import org.matsim.api.core.v01.network.Node; | ||
import org.matsim.contrib.dvrp.fleet.DvrpVehicle; | ||
import org.matsim.contrib.dvrp.path.VrpPaths; | ||
import org.matsim.contrib.dvrp.router.TimeAsTravelDisutility; | ||
import org.matsim.contrib.zone.Zone; | ||
import org.matsim.contrib.zone.skims.Matrix; | ||
import org.matsim.contrib.zone.skims.TravelTimeMatrices; | ||
import org.matsim.contrib.zone.skims.TravelTimeMatrix; | ||
import org.matsim.core.router.util.TravelTime; | ||
|
||
import java.util.*; | ||
import java.util.stream.Stream; | ||
|
||
import static java.util.stream.Collectors.toMap; | ||
import static org.matsim.contrib.dvrp.path.VrpPaths.FIRST_LINK_TT; | ||
|
||
/** | ||
* Link to link travel time to be used by the offline solver * | ||
*/ | ||
public class LinkToLinkTravelTimeMatrix { | ||
private final TravelTimeMatrix nodeToNodeTravelTimeMatrix; | ||
private final TravelTime travelTime; | ||
private final Network network; | ||
|
||
LinkToLinkTravelTimeMatrix(Network network, TravelTime travelTime, Set<Id<Link>> relevantLinks, double time) { | ||
this.network = network; | ||
this.travelTime = travelTime; | ||
this.nodeToNodeTravelTimeMatrix = calculateTravelTimeMatrix(relevantLinks, time); | ||
} | ||
|
||
public static LinkToLinkTravelTimeMatrix prepareLinkToLinkTravelMatrix(Network network, TravelTime travelTime, FleetSchedules previousSchedules, | ||
Map<Id<DvrpVehicle>, OnlineVehicleInfo> onlineVehicleInfoMap, List<GeneralRequest> newRequests, | ||
double time) { | ||
Set<Id<Link>> relevantLinks = new HashSet<>(); | ||
|
||
// Vehicle locations | ||
for (OnlineVehicleInfo onlineVehicleInfo : onlineVehicleInfoMap.values()) { | ||
relevantLinks.add(onlineVehicleInfo.currentLink().getId()); | ||
} | ||
|
||
// Requests locations | ||
// requests on the timetable | ||
for (List<TimetableEntry> timetable : previousSchedules.vehicleToTimetableMap().values()) { | ||
for (TimetableEntry timetableEntry : timetable) { | ||
if (timetableEntry.getStopType() == TimetableEntry.StopType.PICKUP) { | ||
relevantLinks.add(timetableEntry.getRequest().getFromLinkId()); | ||
} else { | ||
relevantLinks.add(timetableEntry.getRequest().getToLinkId()); | ||
} | ||
} | ||
} | ||
|
||
// new requests | ||
for (GeneralRequest request : newRequests) { | ||
relevantLinks.add(request.getFromLinkId()); | ||
relevantLinks.add(request.getToLinkId()); | ||
} | ||
|
||
// Pending rejected requests (i.e., not yet properly inserted and not yet formally rejected) | ||
for (GeneralRequest request : previousSchedules.pendingRequests().values()) { | ||
relevantLinks.add(request.getFromLinkId()); | ||
relevantLinks.add(request.getToLinkId()); | ||
} | ||
|
||
return new LinkToLinkTravelTimeMatrix(network, travelTime, relevantLinks, time); | ||
} | ||
|
||
@Deprecated | ||
public void updateFleetSchedule(FleetSchedules previousSchedules, | ||
Map<Id<DvrpVehicle>, OnlineVehicleInfo> onlineVehicleInfoMap) { | ||
for (Id<DvrpVehicle> vehicleId : onlineVehicleInfoMap.keySet()) { | ||
previousSchedules.vehicleToTimetableMap().computeIfAbsent(vehicleId, t -> new ArrayList<>()); // When new vehicle enters service, create a new entry for it | ||
if (!onlineVehicleInfoMap.containsKey(vehicleId)) { | ||
previousSchedules.vehicleToTimetableMap().remove(vehicleId); // When a vehicle ends service, remove it from the schedule | ||
} | ||
} | ||
|
||
for (Id<DvrpVehicle> vehicleId : previousSchedules.vehicleToTimetableMap().keySet()) { | ||
List<TimetableEntry> timetable = previousSchedules.vehicleToTimetableMap().get(vehicleId); | ||
if (!timetable.isEmpty()) { | ||
Link currentLink = onlineVehicleInfoMap.get(vehicleId).currentLink(); | ||
double currentTime = onlineVehicleInfoMap.get(vehicleId).divertableTime(); | ||
for (TimetableEntry timetableEntry : timetable) { | ||
Id<Link> stopLinkId = timetableEntry.getStopType() == TimetableEntry.StopType.PICKUP ? | ||
timetableEntry.getRequest().getFromLinkId() : timetableEntry.getRequest().getToLinkId(); | ||
Link stopLink = network.getLinks().get(stopLinkId); | ||
double newArrivalTime = currentTime + this.getTravelTime(currentLink, stopLink, currentTime); | ||
timetableEntry.updateArrivalTime(newArrivalTime); | ||
currentTime = timetableEntry.getDepartureTime(); | ||
currentLink = stopLink; | ||
} | ||
} | ||
} | ||
} | ||
|
||
public double getTravelTime(Link fromLink, Link toLink, double departureTime) { | ||
if (fromLink.getId().toString().equals(toLink.getId().toString())) { | ||
return 0; | ||
} | ||
double travelTimeFromNodeToNode = nodeToNodeTravelTimeMatrix.getTravelTime(fromLink.getToNode(), toLink.getFromNode(), departureTime); | ||
return FIRST_LINK_TT + travelTimeFromNodeToNode | ||
+ VrpPaths.getLastLinkTT(travelTime, toLink, departureTime + travelTimeFromNodeToNode); | ||
} | ||
|
||
private TravelTimeMatrix calculateTravelTimeMatrix(Set<Id<Link>> relevantLinks, double time) { | ||
Map<Node, Zone> zoneByNode = relevantLinks | ||
.stream() | ||
.flatMap(linkId -> Stream.of(network.getLinks().get(linkId).getFromNode(), network.getLinks().get(linkId).getToNode())) | ||
.collect(toMap(n -> n, node -> new Zone(Id.create(node.getId(), Zone.class), "node", node.getCoord()), | ||
(zone1, zone2) -> zone1)); | ||
var nodeByZone = EntryStream.of(zoneByNode).invert().toMap(); | ||
Matrix nodeToNodeMatrix = TravelTimeMatrices.calculateTravelTimeMatrix(new TravelTimeMatrices.RoutingParams(network, travelTime, | ||
new TimeAsTravelDisutility(travelTime), Runtime.getRuntime().availableProcessors()), nodeByZone, time); | ||
|
||
return (fromNode, toNode, departureTime) -> nodeToNodeMatrix.get(zoneByNode.get(fromNode), zoneByNode.get(toNode)); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
...extension/preplanned/optimizer/offlineOptimization/basicStructures/OnlineVehicleInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.matsim.contrib.drt.extension.preplanned.optimizer.offlineOptimization.basicStructures; | ||
|
||
import org.matsim.api.core.v01.network.Link; | ||
import org.matsim.contrib.dvrp.fleet.DvrpVehicle; | ||
|
||
public record OnlineVehicleInfo(DvrpVehicle vehicle, Link currentLink, double divertableTime) { | ||
} |
Oops, something went wrong.