From 0a104e157ef389f3272e63d658f4ef09253552e0 Mon Sep 17 00:00:00 2001 From: rakow Date: Thu, 4 Apr 2024 21:29:30 +0200 Subject: [PATCH] add post phase to scheduled strategy --- .../ScheduledModeChoiceConfigGroup.java | 15 ++++++ .../modechoice/ScheduledModeChoiceModule.java | 13 +++-- ...java => WorstNotSelectedPlanSelector.java} | 2 +- .../scheduled/AllBestPlansStrategy.java | 36 ++++++++++---- .../AllBestPlansStrategyProvider.java | 6 ++- .../scheduled/ScheduleListener.java | 49 +++++++++++++++++++ .../scheduled/ScheduledStrategyChooser.java | 14 +++--- .../solver/ModeSchedulingSolver.java | 12 ++++- .../matsim/modechoice/scheduled/solver.xml | 2 +- .../scheduled/AllBestPlansStrategyTest.java | 2 +- 10 files changed, 124 insertions(+), 27 deletions(-) rename contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/{WorstNotSelctedPlanSelector.java => WorstNotSelectedPlanSelector.java} (97%) create mode 100644 contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduleListener.java diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceConfigGroup.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceConfigGroup.java index 5737a811564..2a5f26dcd24 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceConfigGroup.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceConfigGroup.java @@ -20,10 +20,17 @@ public class ScheduledModeChoiceConfigGroup extends ReflectiveConfigGroup { @PositiveOrZero @Comment("Initial iterations before schedule starts") private int warumUpIterations = 5; + @Parameter @Positive @Comment("Number of iterations to be scheduled") private int scheduleIterations = 24; + + @Parameter + @PositiveOrZero + @Comment("Iterations after the schedule ended") + private int postIterations = 20; + @Parameter @PositiveOrZero @Comment("Number of iterations between scheduled mode choice") @@ -62,6 +69,13 @@ public void setScheduleIterations(int scheduleIterations) { this.scheduleIterations = scheduleIterations; } + public int getPostIterations() { + return postIterations; + } + + public void setPostIterations(int postIterations) { + this.postIterations = postIterations; + } public int getBetweenIterations() { return betweenIterations; } @@ -97,6 +111,7 @@ public void setTargetSwitchShare(double targetSwitchShare) { this.targetSwitchShare = targetSwitchShare; } + /** * Return the defined mode target parameters. */ diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceModule.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceModule.java index 58f9cdd54eb..bd7e881cca0 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceModule.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/ScheduledModeChoiceModule.java @@ -10,11 +10,8 @@ import org.matsim.core.controler.AbstractModule; import org.matsim.core.replanning.choosers.StrategyChooser; import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; -import org.matsim.modechoice.replanning.WorstNotSelctedPlanSelector; -import org.matsim.modechoice.replanning.scheduled.AllBestPlansStrategyProvider; -import org.matsim.modechoice.replanning.scheduled.ReRouteSelectedStrategyProvider; -import org.matsim.modechoice.replanning.scheduled.ScheduledStrategyChooser; -import org.matsim.modechoice.replanning.scheduled.TimeMutateSelectedStrategyProvider; +import org.matsim.modechoice.replanning.WorstNotSelectedPlanSelector; +import org.matsim.modechoice.replanning.scheduled.*; import org.matsim.modechoice.replanning.scheduled.solver.ModeSchedulingSolver; import java.util.ArrayList; @@ -94,6 +91,8 @@ public void install() { Collection strategies = new ArrayList<>(getConfig().replanning().getStrategySettings()); getConfig().replanning().clearStrategySettings(); + addControlerListenerBinding().to(ScheduleListener.class); + for (String subpopulation : config.getSubpopulations()) { OptionalDouble reroute = strategies.stream().filter(s -> s.getStrategyName().equals(DefaultPlanStrategiesModule.DefaultStrategy.ReRoute) && @@ -137,7 +136,7 @@ public void install() { if (config.isAdjustTargetIterations()) { - int iters = config.getWarumUpIterations() + config.getScheduleIterations() * (1 + config.getBetweenIterations()); + int iters = config.getWarumUpIterations() + config.getScheduleIterations() * (1 + config.getBetweenIterations()) + config.getPostIterations(); int target = (int) Math.ceil(iters / getConfig().replanning().getFractionOfIterationsToDisableInnovation()); @@ -147,7 +146,7 @@ public void install() { } } - bindPlanSelectorForRemoval().to(WorstNotSelctedPlanSelector.class); + bindPlanSelectorForRemoval().to(WorstNotSelectedPlanSelector.class); } } diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/WorstNotSelctedPlanSelector.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/WorstNotSelectedPlanSelector.java similarity index 97% rename from contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/WorstNotSelctedPlanSelector.java rename to contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/WorstNotSelectedPlanSelector.java index e2e2a8e5284..2df831ba616 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/WorstNotSelctedPlanSelector.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/WorstNotSelectedPlanSelector.java @@ -31,7 +31,7 @@ * See {@link org.matsim.core.replanning.selectors.WorstPlanForRemovalSelector}. * This class is the same except the selected plan is not removed. */ -public class WorstNotSelctedPlanSelector implements PlanSelector { +public class WorstNotSelectedPlanSelector implements PlanSelector { private static final String UNDEFINED_TYPE = "undefined"; diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategy.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategy.java index b037e69bc92..d2a20a19298 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategy.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategy.java @@ -15,17 +15,19 @@ import org.matsim.core.population.algorithms.PersonAlgorithm; import org.matsim.core.population.algorithms.PlanAlgorithm; import org.matsim.core.replanning.ReplanningContext; +import org.matsim.core.replanning.StrategyManager; import org.matsim.core.replanning.modules.AbstractMultithreadedModule; -import org.matsim.modechoice.*; +import org.matsim.modechoice.ModeTargetParameters; +import org.matsim.modechoice.PlanCandidate; +import org.matsim.modechoice.PlanModel; +import org.matsim.modechoice.ScheduledModeChoiceConfigGroup; import org.matsim.modechoice.replanning.GeneratorContext; import org.matsim.modechoice.replanning.scheduled.solver.ModeSchedulingSolver; import org.matsim.modechoice.replanning.scheduled.solver.ModeTarget; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.IntStream; /** * Strategy that tries all best plans deterministically while keeping the mode share fixed. @@ -37,6 +39,7 @@ public class AllBestPlansStrategy extends AbstractMultithreadedModule implements private final Config config; private final ScheduledModeChoiceConfigGroup scheduleConfig; private final Scenario scenario; + private final Provider strategyManager; private final ThreadLocal ctx; /** @@ -44,6 +47,11 @@ public class AllBestPlansStrategy extends AbstractMultithreadedModule implements */ private Map, List> plans = new ConcurrentHashMap<>(); + /** + * Index of candidate if it was selected at the beginning. + */ + private Map, Integer> selectedCandidates = new ConcurrentHashMap<>(); + /** * If greater than -1, the strategy will apply next plan from the schedule. */ @@ -52,17 +60,19 @@ public class AllBestPlansStrategy extends AbstractMultithreadedModule implements private ModeTarget target; public AllBestPlansStrategy(Config config, Scenario scenario, + Provider strategyManager, Provider generator) { super(config.global()); this.config = config; this.scheduleConfig = ConfigUtils.addOrGetModule(config, ScheduledModeChoiceConfigGroup.class); this.scenario = scenario; + this.strategyManager = strategyManager; this.ctx = ThreadLocal.withInitial(generator::get); } @Override protected void beforePrepareReplanningHook(ReplanningContext replanningContextTmp) { - applyIdx = ScheduledStrategyChooser.isScheduledIteration(replanningContextTmp, scheduleConfig); + applyIdx = ScheduledStrategyChooser.isScheduledIteration(replanningContextTmp.getIteration(), scheduleConfig); if (applyIdx < 0) return; @@ -91,13 +101,12 @@ protected void beforePrepareReplanningHook(ReplanningContext replanningContextTm ParallelPersonAlgorithmUtils.run(scenario.getPopulation(), config.global().getNumberOfThreads(), this); log.info("Creating plan schedule for {} agents.", target.mapping().size()); - InformedModeChoiceConfigGroup imc = ConfigUtils.addOrGetModule(config, InformedModeChoiceConfigGroup.class); ModeSchedulingSolver solver = new ModeSchedulingSolver(scheduleConfig.getScheduleIterations(), target, scheduleConfig.getTargetSwitchShare()); // make sure plans always have the same order - plans = solver.solve(new TreeMap<>(plans)); + plans = solver.solve(new TreeMap<>(plans), selectedCandidates); } @Override @@ -117,6 +126,15 @@ public void run(Person person) { PlanModel model = PlanModel.newInstance(person.getSelectedPlan()); List candidates = ctx.get().generator.generate(model); + + OptionalInt idx = IntStream.range(0, candidates.size()) + .filter(i -> Arrays.equals(candidates.get(i).getModes(), model.getCurrentModesMutable())) + .findFirst(); + + if (idx.isPresent()) { + selectedCandidates.put(person.getId(), idx.getAsInt()); + } + plans.put(person.getId(), candidates); // Only relevant are put in the mapping, others will be ignored @@ -149,7 +167,7 @@ public void run(Plan plan) { PlanCandidate candidate = schedule.get(applyIdx); candidate.applyTo(plan, true); - plan.setType(candidate.getPlanType()); +// plan.setType(candidate.getPlanType()); } } } diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyProvider.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyProvider.java index 4fd4196b92e..ce44ea82d47 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyProvider.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyProvider.java @@ -7,6 +7,7 @@ import org.matsim.core.config.groups.GlobalConfigGroup; import org.matsim.core.replanning.PlanStrategy; import org.matsim.core.replanning.PlanStrategyImpl; +import org.matsim.core.replanning.StrategyManager; import org.matsim.core.replanning.modules.ReRoute; import org.matsim.core.replanning.selectors.KeepSelected; import org.matsim.core.replanning.selectors.RandomPlanSelector; @@ -34,12 +35,15 @@ public class AllBestPlansStrategyProvider implements Provider { @Inject private Provider generator; + @Inject + private Provider strategyManager; + @Override public PlanStrategy get() { PlanStrategyImpl.Builder builder = new PlanStrategyImpl.Builder(new KeepSelected<>()); - builder.addStrategyModule(new AllBestPlansStrategy(config, scenario, generator)); + builder.addStrategyModule(new AllBestPlansStrategy(config, scenario, strategyManager, generator)); builder.addStrategyModule(new PartialReRoute(facilities, tripRouterProvider, config.global(), timeInterpretation)); return builder.build(); diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduleListener.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduleListener.java new file mode 100644 index 00000000000..6b894af8a52 --- /dev/null +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduleListener.java @@ -0,0 +1,49 @@ +package org.matsim.modechoice.replanning.scheduled; + +import jakarta.inject.Inject; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Plan; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.events.IterationEndsEvent; +import org.matsim.core.controler.listener.IterationEndsListener; +import org.matsim.core.replanning.StrategyManager; +import org.matsim.core.replanning.selectors.WorstPlanForRemovalSelector; +import org.matsim.modechoice.ScheduledModeChoiceConfigGroup; + +/** + * Helper listener. + */ +public class ScheduleListener implements IterationEndsListener { + + private final StrategyManager strategyManager; + private final ScheduledModeChoiceConfigGroup config; + + private boolean iterOver = false; + + @Inject + public ScheduleListener(StrategyManager strategyManager, Config config) { + this.strategyManager = strategyManager; + this.config = ConfigUtils.addOrGetModule(config, ScheduledModeChoiceConfigGroup.class); + } + + @Override + public void notifyIterationEnds(IterationEndsEvent event) { + + int applyIdx = ScheduledStrategyChooser.isScheduledIteration(event.getIteration(), config); + + if (applyIdx == ScheduledStrategyChooser.ITER_OVER && !iterOver) { + // restore the default removal selector for final phase + strategyManager.setPlanSelectorForRemoval(new WorstPlanForRemovalSelector()); + + // Reset plan types at the end so plan can be removed freely + for (Person person : event.getServices().getScenario().getPopulation().getPersons().values()) { + for (Plan plan : person.getPlans()) { + plan.setType(null); + } + } + + iterOver = true; + } + } +} diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduledStrategyChooser.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduledStrategyChooser.java index 5d2860688b1..9ff06f3abd0 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduledStrategyChooser.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/ScheduledStrategyChooser.java @@ -21,9 +21,9 @@ */ public final class ScheduledStrategyChooser implements StrategyChooser { - private static final int ITER_WARMUP = -1; - private static final int ITER_BETWEEN = -2; - private static final int ITER_OVER = -3; + static final int ITER_WARMUP = -1; + static final int ITER_BETWEEN = -2; + static final int ITER_OVER = -3; private final ScheduledModeChoiceConfigGroup scheduleConfig; @@ -38,9 +38,8 @@ public ScheduledStrategyChooser(Config config) { /** * Return the index of the schedule if it should be applied, -1 otherwise. -2 if the schedule is over. */ - public static int isScheduledIteration(ReplanningContext replanningContext, ScheduledModeChoiceConfigGroup config) { + static int isScheduledIteration(int it, ScheduledModeChoiceConfigGroup config) { - int it = replanningContext.getIteration(); if (it < config.getWarumUpIterations()) return ITER_WARMUP; @@ -78,7 +77,7 @@ public GenericPlanStrategy chooseStrategy(HasPlansAndId chooseStrategy(HasPlansAndId= 0 && !isSchedule) w[i] = 0; + // scheduler is disabled before start and after end + else if ( (iterType == ITER_OVER || iterType == ITER_WARMUP) && isSchedule) + w[i] = 0; else w[i] = weights.getWeight(i); diff --git a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/solver/ModeSchedulingSolver.java b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/solver/ModeSchedulingSolver.java index 2ec5be3fe0b..0921a3ccc4e 100644 --- a/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/solver/ModeSchedulingSolver.java +++ b/contribs/informed-mode-choice/src/main/java/org/matsim/modechoice/replanning/scheduled/solver/ModeSchedulingSolver.java @@ -39,7 +39,13 @@ public ModeSchedulingSolver(int scheduleLength, ModeTarget target, double target this.targetSwitchShare = targetSwitchShare; } - public Map, List> solve(Map, List> plans) { + /** + * Solve schedule problem for given set of candidates. + * @param plans list of candidates for all agents + * @param selectedCandidates index of candidate if it was selected at the beginning + */ + public Map, List> solve(Map, List> plans, + Map, Integer> selectedCandidates) { if (plans.isEmpty()) throw new IllegalArgumentException("No plans to optimize"); @@ -70,6 +76,10 @@ public Map, List> solve(Map, List - 2500 + 3500 diff --git a/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyTest.java b/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyTest.java index c1b8dfc0dd4..81485493534 100644 --- a/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyTest.java +++ b/contribs/informed-mode-choice/src/test/java/org/matsim/modechoice/replanning/scheduled/AllBestPlansStrategyTest.java @@ -17,7 +17,7 @@ class AllBestPlansStrategyTest extends ScenarioTest { protected void prepareConfig(Config config) { InformedModeChoiceConfigGroup imc = ConfigUtils.addOrGetModule(config, InformedModeChoiceConfigGroup.class); - imc.setTopK(15); + imc.setTopK(12); imc.setConstraintCheck(InformedModeChoiceConfigGroup.ConstraintCheck.none); config.replanning().addStrategySettings(new ReplanningConfigGroup.StrategySettings()