MATSIM
GenericStrategyManagerImpl.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.* *
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2008 by the members listed in the COPYING, *
7  * LICENSE and WARRANTY file. *
8  * email : info at matsim dot org *
9  * *
10  * *********************************************************************** *
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * See also COPYING, LICENSE and WARRANTY file *
17  * *
18  * *********************************************************************** */
19 package org.matsim.core.replanning;
20 
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.TreeMap;
29 
30 import org.apache.logging.log4j.LogManager;
31 import org.apache.logging.log4j.Logger;
32 import org.matsim.api.core.v01.population.*;
40 
52 public class GenericStrategyManagerImpl<PL extends BasicPlan, AG extends HasPlansAndId<? extends BasicPlan, AG>> implements GenericStrategyManager<PL, AG>{
53  // the "I extends ... <, I>" is correct, although it feels odd. kai, nov'15
54 
55  private static final Logger log = LogManager.getLogger( GenericStrategyManagerImpl.class );
56 
57 
58  static class StrategyWeights<T extends BasicPlan, I> implements StrategyChooser.Weights<T, I> {
59  final List<GenericPlanStrategy<T, I>> strategies = new ArrayList<>();
60  final List<GenericPlanStrategy<T, I>> unmodifiableStrategies = Collections.unmodifiableList( strategies );
61  final List<Double> weights = new ArrayList<>();
62  final List<Double> unmodifiableWeights = Collections.unmodifiableList(weights);
63  double totalWeights = 0.0;
64  final Map<Integer, Map<GenericPlanStrategy<T, I>, Double>> changeRequests = new TreeMap<>();
65 
66  @Override public int size() {
67  return weights.size();
68  }
69 
70  @Override public double getWeight(int idx) {
71  return weights.get(idx);
72  }
73 
74  @Override public GenericPlanStrategy<T, I> getStrategy(int idx) {
75  return strategies.get(idx);
76  }
77 
78  @Override public double getTotalWeights() {
79  return totalWeights;
80  }
81  }
82 
83  private final Map<String, StrategyWeights<PL, AG>> weightsPerSubpopulation = new HashMap<>();
84 
85  private int maxPlansPerAgent = 0;
86 
88 
90 
91 
92 // private String subpopulationAttributeName = null;
93 
95  this(new WeightedStrategyChooser<>());
96  }
97 
99  this.strategyChooser = strategyChooser;
100  }
101 
102  // /**
103 // * @param name the name of the subpopulation attribute
104 // * in the person's object attributes.
105 // */
106 // public final void setSubpopulationAttributeName(final String name) {
107 // this.subpopulationAttributeName = name;
108 // }
109 
116  @Override public final void addStrategy(
117  final GenericPlanStrategy<PL, AG> strategy,
118  final String subpopulation,
119  final double weight )
120  {
121  final StrategyWeights<PL, AG> weights = getStrategyWeights( subpopulation );
122  if ( weights.strategies.contains( strategy ) ) {
123  log.error( "Strategy "+strategy+" is already defined for subpopulation "+subpopulation );
124  log.error( "This can lead to undefined behavior. Please only specify each strategy once" );
125  throw new IllegalStateException( "Strategy "+strategy+" is already defined for subpopulation "+subpopulation );
126  }
127  weights.strategies.add(strategy);
128  weights.weights.add(weight);
129  weights.totalWeights += weight;
130  }
131 
140  final boolean removeStrategy(
141  final GenericPlanStrategy<PL, AG> strategy,
142  final String subpopulation)
143  {
144  final StrategyWeights<PL, AG> weights = getStrategyWeights( subpopulation );
145  int idx = weights.strategies.indexOf(strategy);
146  if (idx != -1) {
147  weights.strategies.remove(idx);
148  double weight = weights.weights.remove(idx);
149  weights.totalWeights -= weight;
150  return true;
151  }
152  return false;
153  }
154 
155 
156 
157  private StrategyWeights<PL, AG> getStrategyWeights(final String subpop) {
158  StrategyWeights<PL, AG> weights = weightsPerSubpopulation.get(subpop);
159 
160  if ( weights == null ) {
161  weights = new StrategyWeights<>();
162  weightsPerSubpopulation.put(subpop, weights);
163  }
164 
165  return weights;
166  }
167 
174  final boolean changeWeightOfStrategy(
175  final GenericPlanStrategy<PL, AG> strategy,
176  final String subpopulation,
177  final double newWeight) {
178  final StrategyWeights<PL, AG> weights = getStrategyWeights(subpopulation);
179  int idx = weights.strategies.indexOf(strategy);
180  if (idx != -1) {
181  double oldWeight = weights.weights.set(idx, newWeight);
182  weights.totalWeights += (newWeight - oldWeight);
183  LogManager.getLogger(this.getClass()).info( strategy.toString() + ": oldWeight=" + oldWeight + " newWeight=" + newWeight );
184  return true;
185  }
186  return false;
187  }
188 
196  @Override public final void run(
197  final Iterable<? extends HasPlansAndId<PL, AG>> persons,
198  final int iteration,
199  final ReplanningContext replanningContext ) {
200  handleChangeRequests(iteration);
201  run(persons, replanningContext );
202  }
203 
209  final void run(
210  final Iterable<? extends HasPlansAndId<PL, AG>> persons,
211  final ReplanningContext replanningContext )
212  {
213  this.strategyChooser.beforeReplanning(replanningContext);
214 
215  // initialize all strategies
217  strategy.init(replanningContext);
218  }
219 
220  // then go through the population and ...
221  for (HasPlansAndId<PL, AG> person : persons ) {
222 
223  // ... reduce the number of plans to the allowed maximum (in evol comp lang this is "selection")
224  if ((this.maxPlansPerAgent > 0) && (person.getPlans().size() > this.maxPlansPerAgent)) {
225  removePlans( person, this.maxPlansPerAgent);
226  }
227 
228  // ... choose the strategy to be used for this person (in evol comp lang this would be the choice of the mutation operator)
229 // String subpopName = null;
230 // if (this.subpopulationAttributeName != null) {
231 // subpopName = (String) PopulationUtils.getPersonAttribute( person, this.subpopulationAttributeName) ;
232 // }
233  String subpopName = PopulationUtils.getSubpopulation( person );
234  GenericPlanStrategy<PL, AG> strategy = this.chooseStrategy(person, subpopName, replanningContext);
235 
236  if (strategy==null) {
237  throw new RuntimeException("No strategy found! Have you defined at least one replanning strategy per subpopulation? Current subpopulation = " + subpopName);
238  }
239 
240  // ... and run the strategy:
241  strategy.run(person);
242  }
243 
244  // finally make sure all strategies have finished there work
246  strategy.finish();
247  }
248 
249  }
250 
251  private Collection<GenericPlanStrategy<PL, AG>> distinctStrategies() {
252  // Leaving out duplicate strategies in different subpopulations
253  Collection<GenericPlanStrategy<PL, AG>> strategies = new LinkedHashSet<>();
254  for (StrategyWeights<PL, AG> weights : weightsPerSubpopulation.values()) {
255  strategies.addAll(weights.strategies);
256  }
257  return strategies;
258  }
259 
260  private void removePlans(final HasPlansAndId<PL, AG> person, final int maxNumberOfPlans) {
261  while (person.getPlans().size() > maxNumberOfPlans) {
262  PL plan = this.removalPlanSelector.selectPlan(person);
263  person.removePlan(plan);
264  if (plan == person.getSelectedPlan()) {
265  final PL newPlanToSelect = new RandomPlanSelector<PL, AG>().selectPlan(person) ;
266  if ( newPlanToSelect == null ) {
267  throw new IllegalStateException( "could not find a plan to select for person "+person );
268  }
269  person.setSelectedPlan( newPlanToSelect );
270  }
271  }
272  }
273 
278  final void handleChangeRequests(final int iteration) {
279  for ( int ii = 0 ; ii <= iteration ; ii++ ) {
280  // (playing back history for those installations which recreate the strategy manager in every iteration)
281  for ( Map.Entry<String, StrategyWeights<PL, AG>> wentry : weightsPerSubpopulation.entrySet() ) {
282  final String subpop = wentry.getKey();
283  final StrategyWeights<PL, AG> weights = wentry.getValue();
284  Map<GenericPlanStrategy<PL, AG>, Double> changes = weights.changeRequests.remove(ii);
285  if (changes != null) {
286  for (Map.Entry<GenericPlanStrategy<PL, AG>, Double> entry : changes.entrySet()) {
287  changeWeightOfStrategy( entry.getKey(), subpop, entry.getValue());
288  }
289  }
290  }
291  }
292  }
293 
299  /* deliberately package */ GenericPlanStrategy<PL, AG> chooseStrategy(HasPlansAndId<PL, AG> person, final String subpopulation, ReplanningContext replanningContext) {
300  return strategyChooser.chooseStrategy(person, subpopulation, replanningContext, this.getStrategyWeights(subpopulation)) ;
301  }
302 
310  @Override public final void setMaxPlansPerAgent( final int maxPlansPerAgent ) {
311  this.maxPlansPerAgent = maxPlansPerAgent;
312  }
313 
319  @Override public final void addChangeRequest(
320  final int iteration,
321  final GenericPlanStrategy<PL, AG> strategy,
322  final String subpopulation,
323  final double newWeight ) {
324  final StrategyWeights<PL, AG> weights = getStrategyWeights( subpopulation );
325  Integer iter = iteration;
326  Map<GenericPlanStrategy<PL, AG>, Double> iterationRequests = weights.changeRequests.get(iter);
327  if (iterationRequests == null) {
328  iterationRequests = new HashMap<>(3);
329  weights.changeRequests.put(iter, iterationRequests);
330  }
331  iterationRequests.put(strategy, newWeight);
332  LogManager.getLogger(this.getClass()).info( "added change request: "
333  + " iteration=" + iter + " newWeight=" + newWeight + " strategy=" + strategy.toString() );
334  }
335 
363  @Override public final void setPlanSelectorForRemoval( final PlanSelector<PL, AG> planSelector ) {
364  LogManager.getLogger(this.getClass()).info("setting PlanSelectorForRemoval to " + planSelector.getClass() ) ;
365  this.removalPlanSelector = planSelector;
366  }
367 
368  final int getMaxPlansPerAgent() {
369  return this.maxPlansPerAgent ;
370  }
371 
372  @Override public final List<GenericPlanStrategy<PL, AG>> getStrategies( String subpopulation ) {
373  return getStrategyWeights( subpopulation ).unmodifiableStrategies;
374  }
375 
376  @Override public final List<Double> getWeights( String subpopulation ) {
377  return getStrategyWeights( subpopulation ).unmodifiableWeights;
378  }
379 
380 }
StrategyWeights< PL, AG > getStrategyWeights(final String subpop)
final void addChangeRequest(final int iteration, final GenericPlanStrategy< PL, AG > strategy, final String subpopulation, final double newWeight)
void removePlans(final HasPlansAndId< PL, AG > person, final int maxNumberOfPlans)
T selectPlan(HasPlansAndId< T, I > member)
GenericPlanStrategy< T, I > chooseStrategy(HasPlansAndId< T, I > person, final String subpopulation, ReplanningContext replanningContext, Weights< T, I > weights)
void run(final HasPlansAndId< T, I > person)
Collection< GenericPlanStrategy< PL, AG > > distinctStrategies()
final List< GenericPlanStrategy< PL, AG > > getStrategies(String subpopulation)
GenericStrategyManagerImpl(StrategyChooser< PL, AG > strategyChooser)
static String getSubpopulation(HasPlansAndId<?, ?> person)
void init(ReplanningContext replanningContext)
final void run(final Iterable<? extends HasPlansAndId< PL, AG >> persons, final int iteration, final ReplanningContext replanningContext)
final void addStrategy(final GenericPlanStrategy< PL, AG > strategy, final String subpopulation, final double weight)
abstract void setSelectedPlan(T selectedPlan)
final Map< String, StrategyWeights< PL, AG > > weightsPerSubpopulation
default void beforeReplanning(ReplanningContext replanningContext)
final void setPlanSelectorForRemoval(final PlanSelector< PL, AG > planSelector)
abstract List<? extends T > getPlans()