Skip to content

Commit c5002ce

Browse files
authored
Merge pull request #113 from moia-oss/prebooking-fix
Prebooking fix
2 parents 8b61506 + d16ca05 commit c5002ce

File tree

2 files changed

+68
-30
lines changed

2 files changed

+68
-30
lines changed

contribs/drt/src/main/java/org/matsim/contrib/drt/prebooking/PrebookingStopActivity.java

+67-29
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package org.matsim.contrib.drt.prebooking;
22

3-
import java.util.HashSet;
3+
import java.util.LinkedList;
44
import java.util.List;
55
import java.util.Map;
66
import java.util.PriorityQueue;
77
import java.util.Queue;
8-
import java.util.Set;
98
import java.util.function.Supplier;
109

1110
import org.matsim.api.core.v01.Id;
1211
import org.matsim.api.core.v01.IdMap;
12+
import org.matsim.api.core.v01.IdSet;
1313
import org.matsim.api.core.v01.Identifiable;
1414
import org.matsim.api.core.v01.population.Person;
1515
import org.matsim.contrib.drt.passenger.AcceptedDrtRequest;
@@ -39,9 +39,13 @@ public class PrebookingStopActivity extends FirstLastSimStepDynActivity implemen
3939
private final Map<Id<Request>, ? extends AcceptedDrtRequest> pickupRequests;
4040
private final Map<Id<Request>, ? extends AcceptedDrtRequest> dropoffRequests;
4141

42-
private final IdMap<Request, Double> enterTimes = new IdMap<>(Request.class);
42+
private final Queue<QueuedRequest> enterTimes = new PriorityQueue<>();
4343
private final Queue<QueuedRequest> leaveTimes = new PriorityQueue<>();
44-
private final Set<Id<Request>> enteredRequests = new HashSet<>();
44+
45+
private final IdSet<Request> enteredRequests = new IdSet<>(Request.class);
46+
47+
private final IdSet<Request> registeredPickups = new IdSet<>(Request.class);
48+
private final IdMap<Request, AcceptedDrtRequest> expectedPickups = new IdMap<>(Request.class);
4549

4650
private final PrebookingManager prebookingManager;
4751
private final PassengerHandler passengerHandler;
@@ -93,7 +97,6 @@ private void initDropoffRequests(double now) {
9397
}
9498

9599
private boolean updateDropoffRequests(double now) {
96-
97100
while (!leaveTimes.isEmpty() && leaveTimes.peek().time <= now) {
98101
Id<Request> requestId = leaveTimes.poll().id;
99102
passengerHandler.dropOffPassengers(driver, requestId, now);
@@ -105,60 +108,94 @@ private boolean updateDropoffRequests(double now) {
105108
}
106109

107110
private record QueuedRequest(Id<Request> id, double time) implements Comparable<QueuedRequest> {
108-
109111
@Override
110112
public int compareTo(QueuedRequest o) {
111113
return Double.compare(this.time, o.time);
112114
}
113115
}
114116

117+
private int cachedPickupRequestsHash = -1;
118+
115119
private boolean updatePickupRequests(double now, boolean isFirstStep) {
116-
var pickupIterator = pickupRequests.values().iterator();
117-
118-
while (pickupIterator.hasNext()) {
119-
var request = pickupIterator.next();
120-
121-
if (!enteredRequests.contains(request.getId()) && !enterTimes.containsKey(request.getId())) {
122-
// this is a new request that has been added after the activity has been created
123-
// or that had not arrived yet
124-
125-
if (passengerHandler.notifyWaitForPassengers(this, this.driver, request.getId())) {
126-
// agent starts to enter
127-
queuePickup(request, now);
128-
} else if (now > request.getEarliestStartTime() && !isFirstStep) {
129-
if (abandonVoter.abandonRequest(now, vehicle, request)) {
130-
prebookingManager.abandon(request.getId());
131-
}
120+
int pickupRequestsHash = pickupRequests.hashCode();
121+
122+
// part 1: check if the pickup list has been updated dynamically
123+
124+
if (isFirstStep || pickupRequestsHash != cachedPickupRequestsHash) {
125+
cachedPickupRequestsHash = pickupRequestsHash;
126+
127+
// added requests
128+
for (AcceptedDrtRequest request : pickupRequests.values()) {
129+
if (!registeredPickups.contains(request.getId())) {
130+
// in the first step, this is a standard pickup request, later this is a request that has been added after the activity has been created
131+
expectedPickups.put(request.getId(), request);
132+
registeredPickups.add(request.getId());
133+
}
134+
}
135+
136+
// removed requests (for instance via cancellation)
137+
var expectedIterator = expectedPickups.iterator();
138+
while (expectedIterator.hasNext()) {
139+
if (!pickupRequests.containsKey(expectedIterator.next().getId())) {
140+
// a request has been removed from the list of expected pickups
141+
expectedIterator.remove();
132142
}
133143
}
134144
}
145+
146+
// part 2: handle the requests that we expect but which have not arrived yet
147+
148+
var expectedIterator = expectedPickups.values().iterator();
149+
while (expectedIterator.hasNext()) {
150+
AcceptedDrtRequest request = expectedIterator.next();
151+
152+
if (passengerHandler.notifyWaitForPassengers(this, this.driver, request.getId())) {
153+
// agent starts to enter
154+
queuePickup(request, now);
155+
expectedIterator.remove();
156+
} else if (now > request.getEarliestStartTime() && !isFirstStep) {
157+
if (abandonVoter.abandonRequest(now, vehicle, request)) {
158+
// abandon the request, but not in the first time step for the sake of event timing
159+
prebookingManager.abandon(request.getId());
160+
expectedIterator.remove();
161+
}
162+
}
163+
}
164+
165+
// part 3: handle the requests that are currently entering the vehicle
166+
167+
var enterIterator = enterTimes.iterator();
135168

136-
var enterIterator = enterTimes.entrySet().iterator();
169+
// logic is as follows:
170+
// - let people enter in the order at which they arrived + their interaction time
171+
// - but in case there is no capacity (others still disembarking) they need to wait
137172

138173
while (enterIterator.hasNext()) {
139174
var entry = enterIterator.next();
140175
int availableCapacity = vehicle.getCapacity() - onboard;
141176

142-
if (entry.getValue() <= now) {
143-
int requiredCapacity = pickupRequests.get(entry.getKey()).getPassengerCount();
177+
if (entry.time <= now) {
178+
int requiredCapacity = pickupRequests.get(entry.id).getPassengerCount();
144179

145180
if (requiredCapacity <= availableCapacity) {
146181
// let agent enter now
147-
Verify.verify(passengerHandler.tryPickUpPassengers(this, driver, entry.getKey(), now));
148-
enteredRequests.add(entry.getKey());
182+
Verify.verify(passengerHandler.tryPickUpPassengers(this, driver, entry.id, now));
183+
enteredRequests.add(entry.id);
149184
onboard += requiredCapacity;
150185
enterIterator.remove();
151186
}
187+
} else {
188+
break;
152189
}
153190
}
154191

155-
return enterTimes.size() == 0 && pickupRequests.size() == enteredRequests.size();
192+
return expectedPickups.size() == 0 && pickupRequests.size() == enteredRequests.size();
156193
}
157194

158195
private void queuePickup(AcceptedDrtRequest request, double now) {
159196
prebookingManager.notifyPickup(now, request);
160197
double enterTime = now + stopDurationProvider.calcPickupDuration(vehicle, request.getRequest());
161-
enterTimes.put(request.getId(), enterTime);
198+
enterTimes.add(new QueuedRequest(request.getId(), enterTime));
162199
}
163200

164201
@Override
@@ -170,6 +207,7 @@ protected void simStep(double now) {
170207
public void notifyPassengersAreReadyForDeparture(List<MobsimPassengerAgent> passengers, double now) {
171208
var request = getRequestForPassengers(passengers.stream().map(Identifiable::getId).toList());
172209
queuePickup(request, now);
210+
expectedPickups.remove(request.getId());
173211
}
174212

175213
private AcceptedDrtRequest getRequestForPassengers(List<Id<Person>> passengerIds) {

contribs/vsp/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@
184184
<dependency>
185185
<groupId>org.openjfx</groupId>
186186
<artifactId>javafx-graphics</artifactId>
187-
<version>22.0.1</version>
187+
<version>22.0.2</version>
188188
</dependency>
189189
<dependency>
190190
<groupId>com.graphhopper</groupId>

0 commit comments

Comments
 (0)