Skip to content

Commit

Permalink
wip for new mode choice strategyy
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed Mar 30, 2024
1 parent fbdee21 commit 2e73198
Show file tree
Hide file tree
Showing 22 changed files with 1,669 additions and 16 deletions.
7 changes: 7 additions & 0 deletions contribs/informed-mode-choice/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
</exclusions>
</dependency>


<dependency>
<groupId>org.optaplanner</groupId>
<artifactId>optaplanner-core</artifactId>
<version>9.44.0.Final</version>
</dependency>

<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,17 @@
import java.util.Set;

/**
* The main and only module needed to install to use informed mode choice functionality.
* The main module needed to install to use informed mode choice functionality.
*
* @see Builder
*/
public final class InformedModeChoiceModule extends AbstractModule {

public static String SELECT_BEST_K_PLAN_MODES_STRATEGY = "SelectBestKPlanModes";

public static String SELECT_SINGLE_TRIP_MODE_STRATEGY = "SelectSingleTripMode";

public static String SELECT_SUBTOUR_MODE_STRATEGY = "SelectSubtourMode";
public static String RANDOM_SUBTOUR_MODE_STRATEGY = "RandomSubtourMode";


private final Builder builder;

private InformedModeChoiceModule(Builder builder) {
Expand Down Expand Up @@ -97,7 +94,6 @@ public void install() {
addPlanStrategyBinding(SELECT_SINGLE_TRIP_MODE_STRATEGY).toProvider(SelectSingleTripModeStrategyProvider.class);
addPlanStrategyBinding(SELECT_SUBTOUR_MODE_STRATEGY).toProvider(SelectSubtourModeStrategyProvider.class);
addPlanStrategyBinding(RANDOM_SUBTOUR_MODE_STRATEGY).toProvider(RandomSubtourModeStrategyProvider.class);
//addPlanStrategyBinding(INFORMED_MODE_CHOICE).toProvider(InformedModeChoiceStrategyProvider.class);

// Ensure that only one instance exists
bind(ModeChoiceWeightScheduler.class).in(Singleton.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,21 @@ public static double[] occurrences(List<String> modes, String type) {
/**
* Applies the routing modes of this candidate to a plan.
*
* @param plan
* @param plan plan to apply the modes to
* @param partial if true, only trips that have changed mode will be replaced
*/
public void applyTo(Plan plan) {
public void applyTo(Plan plan, boolean partial) {

plan.setScore(null);

String[] currentType = null;
if (partial) {
Object current = plan.getAttributes().getAttribute(TYPE_ATTR);
if (current instanceof String s) {
currentType = createModeArray(s);
}
}

applyAttributes(plan);

final List<PlanElement> planElements = plan.getPlanElements();
Expand All @@ -109,6 +118,11 @@ public void applyTo(Plan plan) {
if (mode == null)
continue;

// don't update the trip if it has the same mode
if (currentType != null && currentType.length > k && currentType[k].equals(mode)) {
continue;
}

// Replaces all trip elements and inserts single leg
final List<PlanElement> fullTrip =
planElements.subList(
Expand All @@ -122,6 +136,15 @@ public void applyTo(Plan plan) {
}
}

/**
* Applies the routing modes of this candidate to all trip in a plan.
*
* @param plan plan to apply the modes to
*/
public void applyTo(Plan plan) {
applyTo(plan, false);
}

/**
* Set estimates as plan attributes.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package org.matsim.modechoice;

import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import org.matsim.core.config.ConfigGroup;
import org.matsim.core.config.ReflectiveConfigGroup;

import java.util.*;

/**
* Config group for {@link ScheduledModeChoiceModule}.
*/
public class ScheduledModeChoiceConfigGroup extends ReflectiveConfigGroup {

private static final String NAME = "scheduledModeChoice";
private final List<ModeTargetParameters> modeTargetParameters = new ArrayList<>();
@Parameter
@PositiveOrZero
@Comment("Initial iterations before schedule starts")
private int warumUpIterations = 5;
@Parameter
@Positive
@Comment("Number of iterations to be scheduled")
private int scheduleIterations = 15;
@Parameter
@PositiveOrZero
@Comment("Number of iterations between scheduled mode choice")
private int betweenIterations = 1;

@Parameter
@Positive
@Comment("Target number of trip modes that should change between iterations")
private double targetSwitchShare = 0.15;

@Parameter
@Comment("Enable scheduled mode choice for these subpopulations by adjusting strategy settings.")
private Set<String> subpopulations = new HashSet<>();

@Parameter
@Comment("Automatically adjust number of iterations according to schedule and innovation switch off.")
private boolean adjustTargetIterations = false;

public ScheduledModeChoiceConfigGroup() {
super(NAME);
}

public int getWarumUpIterations() {
return warumUpIterations;
}

public void setWarumUpIterations(int warumUpIterations) {
this.warumUpIterations = warumUpIterations;
}

public int getScheduleIterations() {
return scheduleIterations;
}

public void setScheduleIterations(int scheduleIterations) {
this.scheduleIterations = scheduleIterations;
}

public int getBetweenIterations() {
return betweenIterations;
}

public void setBetweenIterations(int betweenIterations) {
this.betweenIterations = betweenIterations;
}

public Set<String> getSubpopulations() {
return subpopulations;
}

public void setSubpopulations(String... subpopulations) {
this.subpopulations = new HashSet<>(Arrays.asList(subpopulations));
}
public void setSubpopulations(Set<String> subpopulations) {
this.subpopulations = subpopulations;
}

public double getTargetSwitchShare() {
return targetSwitchShare;
}

public boolean isAdjustTargetIterations() {
return adjustTargetIterations;
}

public void setAdjustTargetIterations(boolean adjustTargetIterations) {
this.adjustTargetIterations = adjustTargetIterations;
}

public void setTargetSwitchShare(double targetSwitchShare) {
this.targetSwitchShare = targetSwitchShare;
}

/**
* Return the defined mode target parameters.
*/
public List<ModeTargetParameters> getModeTargetParameters() {
return Collections.unmodifiableList(modeTargetParameters);
}

/**
* Clear all defined mode target parameters.
*/
public void clearModeTargetParameters() {
modeTargetParameters.clear();
}

@Override
public ConfigGroup createParameterSet(String type) {
if (type.equals(ModeTargetParameters.GROUP_NAME)) {
return new ModeTargetParameters();
} else {
throw new IllegalArgumentException("Unsupported parameter set type: " + type);
}
}

@Override
public void addParameterSet(ConfigGroup set) {
if (set instanceof ModeTargetParameters p) {
super.addParameterSet(set);
modeTargetParameters.add(p);
} else {
throw new IllegalArgumentException("Unsupported parameter set class: " + set);
}
}

/**
* Target parameters for mode shares.
* This group allows arbitrary attributes to be defined, which are matched against person attributes.
*/
public static final class ModeTargetParameters extends ReflectiveConfigGroup {

private static final String GROUP_NAME = "modeTargetParameters";

@Parameter
@Comment("Target mode shares. Should only contain relevant modes.")
public Map<String, Double> shares = new HashMap<>();

public ModeTargetParameters() {
super(GROUP_NAME, true);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.matsim.modechoice;

import com.google.inject.TypeLiteral;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Plan;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.ReplanningConfigGroup;
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.scheduled.AllBestPlansStrategyProvider;
import org.matsim.modechoice.replanning.scheduled.ReRouteSelectedStrategyProvider;
import org.matsim.modechoice.replanning.scheduled.ScheduledStrategyChooser;

import java.util.*;

/**
* Module for to enable scheduled mode choice.
*/
public class ScheduledModeChoiceModule extends AbstractModule {

private static final Logger log = LogManager.getLogger(ScheduledModeChoiceModule.class);

public static String ALL_BEST_K_PLAN_MODES_STRATEGY = "AllBestKPlanModes";
/**
* Other mode choice strategies.
*/
private final static Set<String> EXCLUDED = Set.of(
DefaultPlanStrategiesModule.DefaultStrategy.SubtourModeChoice,
DefaultPlanStrategiesModule.DefaultStrategy.ChangeSingleTripMode,
DefaultPlanStrategiesModule.DefaultStrategy.ChangeTripMode,
DefaultPlanStrategiesModule.DefaultStrategy.ReRoute,
DefaultPlanStrategiesModule.DefaultStrategy.TimeAllocationMutator,
DefaultPlanStrategiesModule.DefaultStrategy.TimeAllocationMutator_ReRoute,
InformedModeChoiceModule.SELECT_SUBTOUR_MODE_STRATEGY,
InformedModeChoiceModule.SELECT_BEST_K_PLAN_MODES_STRATEGY,
InformedModeChoiceModule.SELECT_SINGLE_TRIP_MODE_STRATEGY,
InformedModeChoiceModule.RANDOM_SUBTOUR_MODE_STRATEGY,
ALL_BEST_K_PLAN_MODES_STRATEGY
);
public static String REROUTE_SELECTED = "ReRouteSelected";
private final Builder builder;

private ScheduledModeChoiceModule(Builder builder) {
this.builder = builder;
}

/**
* Create new builder to initialize the module.
*/
public static Builder newBuilder() {
return new Builder();
}

@Override
public void install() {

addPlanStrategyBinding(ALL_BEST_K_PLAN_MODES_STRATEGY).toProvider(AllBestPlansStrategyProvider.class);
addPlanStrategyBinding(REROUTE_SELECTED).toProvider(ReRouteSelectedStrategyProvider.class);

bind(new TypeLiteral<StrategyChooser<Plan, Person>>() {
}).to(ScheduledStrategyChooser.class);

ScheduledModeChoiceConfigGroup config = ConfigUtils.addOrGetModule(getConfig(), ScheduledModeChoiceConfigGroup.class);

Collection<ReplanningConfigGroup.StrategySettings> strategies = new ArrayList<>(getConfig().replanning().getStrategySettings());
getConfig().replanning().clearStrategySettings();

for (String subpopulation : config.getSubpopulations()) {

OptionalDouble reroute = strategies.stream().filter(s -> s.getStrategyName().equals(DefaultPlanStrategiesModule.DefaultStrategy.ReRoute) &&
s.getSubpopulation().equals(subpopulation))
.mapToDouble(ReplanningConfigGroup.StrategySettings::getWeight)
.findFirst();

strategies.removeIf(s -> s.getSubpopulation().equals(subpopulation) && EXCLUDED.contains(s.getStrategyName()));

ReplanningConfigGroup.StrategySettings strategy = new ReplanningConfigGroup.StrategySettings();
strategy.setStrategyName(ALL_BEST_K_PLAN_MODES_STRATEGY);
strategy.setSubpopulation(subpopulation);
strategy.setWeight(1.0);
strategies.add(strategy);

if (reroute.isPresent()) {
ReplanningConfigGroup.StrategySettings s = new ReplanningConfigGroup.StrategySettings();
s.setStrategyName(REROUTE_SELECTED);
s.setSubpopulation(subpopulation);
s.setWeight(reroute.getAsDouble());
strategies.add(s);
}
}

strategies.forEach(s -> getConfig().replanning().addStrategySettings(s));

if (config.isAdjustTargetIterations()) {

int iters = config.getWarumUpIterations() + config.getScheduleIterations() * (1 + config.getBetweenIterations());

int target = (int) Math.ceil(iters / getConfig().replanning().getFractionOfIterationsToDisableInnovation());

log.info("Adjusting number of iterations from {} to {}.", getConfig().controller().getLastIteration(), target);
getConfig().controller().setLastIteration(iters);
}

// bindPlanSelectorForRemoval().to()
// getConfig().replanning().setPlanSelectorForRemoval();

}

/**
* Builder to configure the module.
*/
public static final class Builder {
public ScheduledModeChoiceModule build() {
return new ScheduledModeChoiceModule(this);
}
}

}
Loading

0 comments on commit 2e73198

Please sign in to comment.