Skip to content

Commit

Permalink
add post phase to scheduled strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed Apr 4, 2024
1 parent 6cb210f commit 0a104e1
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -97,6 +111,7 @@ public void setTargetSwitchShare(double targetSwitchShare) {
this.targetSwitchShare = targetSwitchShare;
}


/**
* Return the defined mode target parameters.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -94,6 +91,8 @@ public void install() {
Collection<ReplanningConfigGroup.StrategySettings> 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) &&
Expand Down Expand Up @@ -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());

Expand All @@ -147,7 +146,7 @@ public void install() {
}
}

bindPlanSelectorForRemoval().to(WorstNotSelctedPlanSelector.class);
bindPlanSelectorForRemoval().to(WorstNotSelectedPlanSelector.class);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Plan, Person> {
public class WorstNotSelectedPlanSelector implements PlanSelector<Plan, Person> {

private static final String UNDEFINED_TYPE = "undefined";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -37,13 +39,19 @@ public class AllBestPlansStrategy extends AbstractMultithreadedModule implements
private final Config config;
private final ScheduledModeChoiceConfigGroup scheduleConfig;
private final Scenario scenario;
private final Provider<StrategyManager> strategyManager;
private final ThreadLocal<GeneratorContext> ctx;

/**
* Scheduled plans for all relevant persons.
*/
private Map<Id<Person>, List<PlanCandidate>> plans = new ConcurrentHashMap<>();

/**
* Index of candidate if it was selected at the beginning.
*/
private Map<Id<Person>, Integer> selectedCandidates = new ConcurrentHashMap<>();

/**
* If greater than -1, the strategy will apply next plan from the schedule.
*/
Expand All @@ -52,17 +60,19 @@ public class AllBestPlansStrategy extends AbstractMultithreadedModule implements
private ModeTarget target;

public AllBestPlansStrategy(Config config, Scenario scenario,
Provider<StrategyManager> strategyManager,
Provider<GeneratorContext> 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;
Expand Down Expand Up @@ -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
Expand All @@ -117,6 +126,15 @@ public void run(Person person) {

PlanModel model = PlanModel.newInstance(person.getSelectedPlan());
List<PlanCandidate> 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
Expand Down Expand Up @@ -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());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -34,12 +35,15 @@ public class AllBestPlansStrategyProvider implements Provider<PlanStrategy> {
@Inject
private Provider<GeneratorContext> generator;

@Inject
private Provider<StrategyManager> 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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
*/
public final class ScheduledStrategyChooser implements StrategyChooser<Plan, Person> {

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;

Expand All @@ -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;

Expand Down Expand Up @@ -78,7 +77,7 @@ public GenericPlanStrategy<Plan, Person> chooseStrategy(HasPlansAndId<Plan, Pers
double[] w = new double[weights.size()];
double total = 0;

int iterType = isScheduledIteration(replanningContext, scheduleConfig);
int iterType = isScheduledIteration(replanningContext.getIteration(), scheduleConfig);

for (int i = 0; i < weights.size(); i++) {

Expand All @@ -93,6 +92,9 @@ public GenericPlanStrategy<Plan, Person> chooseStrategy(HasPlansAndId<Plan, Pers
// all other than scheduler are disabled every other iteration
else if (iterType >= 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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ public ModeSchedulingSolver(int scheduleLength, ModeTarget target, double target
this.targetSwitchShare = targetSwitchShare;
}

public Map<Id<Person>, List<PlanCandidate>> solve(Map<Id<Person>, List<PlanCandidate>> 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<Id<Person>, List<PlanCandidate>> solve(Map<Id<Person>, List<PlanCandidate>> plans,
Map<Id<Person>, Integer> selectedCandidates) {

if (plans.isEmpty())
throw new IllegalArgumentException("No plans to optimize");
Expand Down Expand Up @@ -70,6 +76,10 @@ public Map<Id<Person>, List<PlanCandidate>> solve(Map<Id<Person>, List<PlanCandi
// All plans are available initially
IntStream.range(0, scheduleLength).forEach(schedule.availablePlans::add);

// Set the initial plan index
if (selectedCandidates.containsKey(kv.getKey()))
schedule.currentPlan = selectedCandidates.get(kv.getKey());

agents.add(schedule);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<localSearch>

<termination>
<unimprovedStepCountLimit>2500</unimprovedStepCountLimit>
<unimprovedStepCountLimit>3500</unimprovedStepCountLimit>
</termination>

<unionMoveSelector>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 0a104e1

Please sign in to comment.