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

Draft: DRT consolidate prebookings and group bookings #2991

Merged
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
package org.matsim.contrib.drt.prebooking;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.events.GenericEvent;
import org.matsim.api.core.v01.population.Person;
import org.matsim.contrib.dvrp.optimizer.Request;
import org.matsim.contrib.dvrp.passenger.AbstractPassengerRequestEvent;

import java.util.*;

/**
* @author Sebastian Hörl (sebhoerl), IRT SystemX
*/
public class PassengerRequestBookedEvent extends AbstractPassengerRequestEvent {
public static final String EVENT_TYPE = "PassengerRequest booked";

public PassengerRequestBookedEvent(double time, String mode, Id<Request> requestId, Id<Person> personId) {
super(time, mode, requestId, List.of(personId));
public PassengerRequestBookedEvent(double time, String mode, Id<Request> requestId, List<Id<Person>> personIds) {
super(time, mode, requestId, personIds);
}

@Override
Expand All @@ -30,7 +28,8 @@ public static PassengerRequestBookedEvent convert(GenericEvent event) {
double time = Double.parseDouble(attributes.get(ATTRIBUTE_TIME));
String mode = Objects.requireNonNull(attributes.get(ATTRIBUTE_MODE));
Id<Request> requestId = Id.create(attributes.get(ATTRIBUTE_REQUEST), Request.class);
Id<Person> personId = Id.createPersonId(attributes.get(ATTRIBUTE_PERSON));
return new PassengerRequestBookedEvent(time, mode, requestId, personId);
String[] personIdsAttribute = attributes.get(ATTRIBUTE_PERSON).split(",");
List<Id<Person>> personIds = Arrays.stream(personIdsAttribute).map(Id::createPersonId).toList();
return new PassengerRequestBookedEvent(time, mode, requestId, personIds);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
package org.matsim.contrib.drt.prebooking;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nullable;

import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.IdMap;
import org.matsim.api.core.v01.IdSet;
Expand All @@ -25,14 +17,7 @@
import org.matsim.contrib.dvrp.fleet.DvrpVehicle;
import org.matsim.contrib.dvrp.optimizer.Request;
import org.matsim.contrib.dvrp.optimizer.VrpOptimizer;
import org.matsim.contrib.dvrp.passenger.AdvanceRequestProvider;
import org.matsim.contrib.dvrp.passenger.PassengerRequest;
import org.matsim.contrib.dvrp.passenger.PassengerRequestCreator;
import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEvent;
import org.matsim.contrib.dvrp.passenger.PassengerRequestRejectedEventHandler;
import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent;
import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler;
import org.matsim.contrib.dvrp.passenger.PassengerRequestValidator;
import org.matsim.contrib.dvrp.passenger.*;
import org.matsim.core.api.experimental.events.EventsManager;
import org.matsim.core.mobsim.framework.MobsimAgent;
import org.matsim.core.mobsim.framework.MobsimAgent.State;
Expand All @@ -43,8 +28,10 @@
import org.matsim.core.mobsim.qsim.agents.WithinDayAgentUtils;
import org.matsim.core.mobsim.qsim.interfaces.MobsimEngine;

import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
* This class manages prebooked requests. One instance of PrebookingManager
Expand Down Expand Up @@ -140,6 +127,8 @@ public void handleEvent(PersonStuckEvent event) {
private record RejectionItem(Id<Request> requestId, List<Id<Person>> personIds, String cause) {
}

public record PersonLeg(MobsimAgent agent, Leg leg){}

private final ConcurrentLinkedQueue<RejectionItem> rejections = new ConcurrentLinkedQueue<>();

private void processRejection(PassengerRequest request, String cause) {
Expand All @@ -163,35 +152,47 @@ private void flushRejections(double now) {
// collects new bookings that need to be submitted
private final ConcurrentLinkedQueue<PassengerRequest> bookingQueue = new ConcurrentLinkedQueue<>();

public void prebook(MobsimAgent person, Leg leg, double earliestDepartureTime) {
Preconditions.checkArgument(leg.getMode().equals(mode), "Invalid mode for this prebooking manager");
Preconditions.checkState(!person.getState().equals(State.ABORT), "Cannot prebook aborted agent");
public void prebook(MobsimAgent agent, Leg leg, double earliestDepartureTime) {
prebook(List.of(new PersonLeg(agent, leg)), earliestDepartureTime);
}

public void prebook(List<PersonLeg> personsLegs, double earliestDepartureTime) {
nkuehnel marked this conversation as resolved.
Show resolved Hide resolved
for (PersonLeg personLeg : personsLegs) {
Preconditions.checkArgument(personLeg.leg().getMode().equals(mode), "Invalid mode for this prebooking manager");
Preconditions.checkState(!personLeg.agent().getState().equals(State.ABORT), "Cannot prebook aborted agent");
}

Id<Request> requestId = createRequestId();
double now = mobsimTimer.getTimeOfDay();

eventsManager.processEvent(new PassengerRequestBookedEvent(now, mode, requestId, person.getId()));
List<Id<Person>> personIds = personsLegs.stream().map(p -> p.agent().getId()).toList();
eventsManager.processEvent(new PassengerRequestBookedEvent(now, mode, requestId, personIds));

PassengerRequest request = requestCreator.createRequest(requestId, List.of(person.getId()), leg.getRoute(),
getLink(leg.getRoute().getStartLinkId()), getLink(leg.getRoute().getEndLinkId()), earliestDepartureTime,
Leg representativeLeg = personsLegs.get(0).leg();
PassengerRequest request = requestCreator.createRequest(requestId, personIds, representativeLeg.getRoute(),
getLink(representativeLeg.getRoute().getStartLinkId()), getLink(representativeLeg.getRoute().getEndLinkId()), earliestDepartureTime,
now);

Set<String> violations = requestValidator.validateRequest(request);

Plan plan = WithinDayAgentUtils.getModifiablePlan(person);
int currentLegIndex = WithinDayAgentUtils.getCurrentPlanElementIndex(person);
int prebookingLegIndex = plan.getPlanElements().indexOf(leg);
for (PersonLeg personLeg : personsLegs) {
Plan plan = WithinDayAgentUtils.getModifiablePlan(personLeg.agent());
int currentLegIndex = WithinDayAgentUtils.getCurrentPlanElementIndex(personLeg.agent());
int prebookingLegIndex = plan.getPlanElements().indexOf(personLeg.leg());

if (prebookingLegIndex <= currentLegIndex) {
violations = new HashSet<>(violations);
violations.add("past leg"); // the leg for which the booking was made has already happened
if (prebookingLegIndex <= currentLegIndex) {
violations = new HashSet<>(violations);
violations.add("past leg"); // the leg for which the booking was made has already happened
}
}

if (!violations.isEmpty()) {
String cause = String.join(", ", violations);
processRejection(request, cause);
} else {
leg.getAttributes().putAttribute(requestAttribute, request.getId().toString());
for (PersonLeg personLeg : personsLegs) {
personLeg.leg().getAttributes().putAttribute(requestAttribute, request.getId().toString());
}
bookingQueue.add(request);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.matsim.contrib.drt.prebooking;

import com.google.inject.Singleton;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.population.Population;
import org.matsim.contrib.drt.optimizer.VehicleEntry;
Expand All @@ -15,10 +16,7 @@
import org.matsim.contrib.drt.vrpagent.DrtActionCreator;
import org.matsim.contrib.dvrp.fleet.DvrpVehicleLookup;
import org.matsim.contrib.dvrp.optimizer.VrpOptimizer;
import org.matsim.contrib.dvrp.passenger.PassengerEngine;
import org.matsim.contrib.dvrp.passenger.PassengerHandler;
import org.matsim.contrib.dvrp.passenger.PassengerRequestCreator;
import org.matsim.contrib.dvrp.passenger.PassengerRequestValidator;
import org.matsim.contrib.dvrp.passenger.*;
import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule;
import org.matsim.contrib.dvrp.schedule.ScheduleTimingUpdater;
import org.matsim.core.api.experimental.events.EventsManager;
Expand All @@ -27,8 +25,6 @@
import org.matsim.core.router.util.LeastCostPathCalculator;
import org.matsim.core.router.util.TravelTime;

import com.google.inject.Singleton;

public class PrebookingModeQSimModule extends AbstractDvrpModeQSimModule {
private final PrebookingParams prebookingParams;

Expand Down Expand Up @@ -65,7 +61,7 @@ protected void configureQSim() {
addModalQSimComponentBinding().to(modalKey(PrebookingManager.class));

bindModal(PrebookingQueue.class).toProvider(modalProvider(getter -> {
return new PrebookingQueue(getter.getModal(PrebookingManager.class));
return new PrebookingQueue(getter.getModal(PrebookingManager.class), getter.getModal(PassengerGroupIdentifier.class));
})).in(Singleton.class);
addModalQSimComponentBinding().to(modalKey(PrebookingQueue.class));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package org.matsim.contrib.drt.prebooking.logic.helpers;

import java.util.PriorityQueue;

import com.google.common.base.Preconditions;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.population.Leg;
import org.matsim.contrib.drt.prebooking.PrebookingManager;
import org.matsim.contrib.dvrp.passenger.PassengerGroupIdentifier;
import org.matsim.core.mobsim.framework.MobsimAgent;
import org.matsim.core.mobsim.framework.MobsimPassengerAgent;
import org.matsim.core.mobsim.framework.events.MobsimBeforeSimStepEvent;
import org.matsim.core.mobsim.framework.listeners.MobsimBeforeSimStepListener;

import com.google.common.base.Preconditions;
import java.util.*;

/**
* This service helps to define a PrebookingLogic where at some point in time
* (usually at the beginning of the simulaton), it is known in advance that a
* request will happen at a specific time. Once we know that the request will be
* sent, we can use the present class to put it in a queue, making sure the
* request will be *booked* the the time we want.
*
*
* @author Sebastian Hörl (sebhoerl), IRT SystemX
*/
public class PrebookingQueue implements MobsimBeforeSimStepListener {
Expand All @@ -27,8 +29,11 @@ public class PrebookingQueue implements MobsimBeforeSimStepListener {

private double currentTime = Double.NEGATIVE_INFINITY;

public PrebookingQueue(PrebookingManager prebookingManager) {
private final PassengerGroupIdentifier groupIdentifier;

public PrebookingQueue(PrebookingManager prebookingManager, PassengerGroupIdentifier groupIdentifier) {
this.prebookingManager = prebookingManager;
this.groupIdentifier = groupIdentifier;
}

@Override
Expand All @@ -39,9 +44,19 @@ public void notifyMobsimBeforeSimStep(@SuppressWarnings("rawtypes") MobsimBefore
private void performSubmissions(double time) {
currentTime = time;

Map<Id<PassengerGroupIdentifier.PassengerGroup>, List<ScheduledSubmission>> groups = new LinkedHashMap<>();
while (!queue.isEmpty() && queue.peek().submissionTime <= time) {
var item = queue.poll();
prebookingManager.prebook(item.agent(), item.leg(), item.departuretime());
Optional<Id<PassengerGroupIdentifier.PassengerGroup>> groupId = groupIdentifier.getGroupId((MobsimPassengerAgent) item.agent);
if(groupId.isEmpty()) {
prebookingManager.prebook(item.agent(), item.leg(), item.departureTime());
} else {
groups.computeIfAbsent(groupId.get(), k -> new ArrayList<>()).add(item);
}
}
for (List<ScheduledSubmission> group : groups.values()) {
List<PrebookingManager.PersonLeg> personsLegs = group.stream().map(entry -> new PrebookingManager.PersonLeg(entry.agent, entry.leg)).toList();
prebookingManager.prebook(personsLegs, group.get(0).departureTime);
}
}

Expand All @@ -62,7 +77,7 @@ public void schedule(double submissionTime, MobsimAgent agent, Leg leg, double d
}
}

private record ScheduledSubmission(double submissionTime, MobsimAgent agent, Leg leg, double departuretime,
private record ScheduledSubmission(double submissionTime, MobsimAgent agent, Leg leg, double departureTime,
int sequence) implements Comparable<ScheduledSubmission> {
@Override
public int compareTo(ScheduledSubmission o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@

package org.matsim.contrib.drt.run;

import com.google.inject.Key;
import com.google.inject.Singleton;
import com.google.inject.name.Names;
Comment on lines +23 to +25
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General note (not limited to this PR): This PR contains lots of line changes due to different formatting standards, especially imports reordering/wildcarding. There are, for instance, no other changes in this file.

I hope this will get reduced after we switch to a formatting standard.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I see. Guess it's from my auto-formatting in IntelliJ...

import org.matsim.api.core.v01.network.Network;
import org.matsim.contrib.drt.analysis.DrtEventSequenceCollector;
import org.matsim.contrib.drt.fare.DrtFareHandler;
import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingModule;
import org.matsim.contrib.drt.prebooking.analysis.PrebookingModeAnalysisModule;
import org.matsim.contrib.drt.speedup.DrtSpeedUp;
import org.matsim.contrib.drt.stops.DefaultStopTimeCalculator;
import org.matsim.contrib.drt.stops.MinimumStopDurationAdapter;
import org.matsim.contrib.drt.stops.PassengerStopDurationProvider;
import org.matsim.contrib.drt.stops.PrebookingStopTimeCalculator;
import org.matsim.contrib.drt.stops.StaticPassengerStopDurationProvider;
import org.matsim.contrib.drt.stops.StopTimeCalculator;
import org.matsim.contrib.drt.stops.*;
import org.matsim.contrib.dvrp.fleet.FleetModule;
import org.matsim.contrib.dvrp.fleet.FleetSpecification;
import org.matsim.contrib.dvrp.router.DvrpModeRoutingNetworkModule;
Expand All @@ -44,10 +42,6 @@
import org.matsim.core.router.costcalculators.TravelDisutilityFactory;
import org.matsim.core.router.util.TravelTime;

import com.google.inject.Key;
import com.google.inject.Singleton;
import com.google.inject.name.Names;

/**
* @author michalm (Michal Maciejewski)
*/
Expand Down Expand Up @@ -87,15 +81,15 @@ public void install() {
getter.getModal(DrtEventSequenceCollector.class)))).asEagerSingleton();
addControlerListenerBinding().to(modalKey(DrtSpeedUp.class));
});

bindModal(PassengerStopDurationProvider.class).toProvider(modalProvider(getter -> {
return StaticPassengerStopDurationProvider.of(drtCfg.stopDuration, 0.0);
}));

bindModal(DefaultStopTimeCalculator.class).toProvider(modalProvider(getter -> {
return new DefaultStopTimeCalculator(drtCfg.stopDuration);
})).in(Singleton.class);

if (drtCfg.getPrebookingParams().isEmpty()) {
bindModal(StopTimeCalculator.class).toProvider(modalProvider(getter -> {
return new DefaultStopTimeCalculator(drtCfg.stopDuration);
Expand All @@ -105,7 +99,7 @@ public void install() {
PassengerStopDurationProvider provider = getter.getModal(PassengerStopDurationProvider.class);
return new MinimumStopDurationAdapter(new PrebookingStopTimeCalculator(provider), drtCfg.stopDuration);
}));

install(new PrebookingModeAnalysisModule(getMode()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public SharingMetricsModule(DrtConfigGroup drtConfigGroup) {
@Override
public void install() {
bindModal(SharingMetricsTracker.class).toProvider(modalProvider(getter ->
new SharingMetricsTracker(personId -> true))).asEagerSingleton();
new SharingMetricsTracker())).asEagerSingleton();
addEventHandlerBinding().to(modalKey(SharingMetricsTracker.class));
bindModal(SharingMetricsControlerListener.class).toProvider(modalProvider(getter ->
new SharingMetricsControlerListener(getConfig(), drtConfigGroup,
Expand Down
Loading
Loading