MATSIM
BalancedInnovationStrategyChooser.java
Go to the documentation of this file.
1 package org.matsim.core.replanning.choosers;
2 
3 import com.google.inject.Binder;
4 import com.google.inject.Inject;
5 import com.google.inject.Singleton;
6 import com.google.inject.TypeLiteral;
7 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
8 import it.unimi.dsi.fastutil.ints.IntSet;
9 import it.unimi.dsi.fastutil.objects.Object2IntMap;
10 import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
11 import org.matsim.api.core.v01.population.*;
19 
20 import java.util.HashMap;
21 import java.util.Map;
22 
28 public class BalancedInnovationStrategyChooser<PL extends BasicPlan, AG extends HasPlansAndId<? extends BasicPlan, AG>> implements StrategyChooser<PL, AG> {
29 
33  private final Object2IntMap<String> total = new Object2IntOpenHashMap<>();
34 
38  private final Object2IntMap<String> seen = new Object2IntOpenHashMap<>();
39 
43  private final Object2IntMap<String> innovated = new Object2IntOpenHashMap<>();
44 
48  private final Object2IntMap<String> carryOver = new Object2IntOpenHashMap<>();
49 
53  private final Map<String, IntSet> oneAhead = new HashMap<>();
54 
58  private final Map<String, IntSet> twoAhead = new HashMap<>();
59 
60  @Inject
62 
63  for (Person person : population.getPersons().values()) {
64  String key = PopulationUtils.getSubpopulation(person);
65  total.mergeInt(key != null ? key : "__none__", 1, Integer::sum);
66  }
67 
68  for (String s : total.keySet()) {
69  oneAhead.put(s, new IntOpenHashSet());
70  twoAhead.put(s, new IntOpenHashSet());
71  carryOver.put(s, 0);
72  }
73  }
74 
80  public static void bind(Binder binder) {
81  binder.bind(new TypeLiteral<StrategyChooser<Plan, Person>>() {
82  }).to(new TypeLiteral<BalancedInnovationStrategyChooser<Plan, Person>>() {
83  }).in(Singleton.class);
84  }
85 
86 
90  public static void install(Controller controller) {
91  controller.addOverridingModule(new AbstractModule() {
92  @Override
93  public void install() {
95  }
96  });
97  }
98 
99  @Override
100  public void beforeReplanning(ReplanningContext replanningContext) {
101  innovated.clear();
102  seen.clear();
103  }
104 
105  @Override
106  public GenericPlanStrategy<PL, AG> chooseStrategy(HasPlansAndId<PL, AG> person, String subpopulation, ReplanningContext replanningContext, StrategyChooser.Weights<PL, AG> weights) {
107 
108  // Two separate arrays for innovation and selection strategies weights
109  double[] wInno = new double[weights.size()];
110  double totalInno = 0;
111 
112  double[] wSel = new double[weights.size()];
113  double totalSel = 0;
114 
115  for (int i = 0; i < weights.size(); i++) {
116  if (ReplanningUtils.isOnlySelector(weights.getStrategy(i))) {
117  wSel[i] = weights.getWeight(i);
118  totalSel += wSel[i];
119  } else {
120  wInno[i] = weights.getWeight(i);
121  totalInno += wInno[i];
122  }
123  }
124 
125  double rnd = MatsimRandom.getRandom().nextDouble() * (totalInno + totalSel);
126 
127  // Subpopulation can not be null
128  if (subpopulation == null) {
129  subpopulation = "__none__";
130  }
131 
132  IntSet oneAhead = this.oneAhead.get(subpopulation);
133  IntSet twoAhead = this.twoAhead.get(subpopulation);
134 
135  int id = person.getId().index();
136 
137  // Expected number of innovations (this iteration)
138  double expected = (seen.getInt(subpopulation) * totalInno) / (totalInno + totalSel);
139  double diff = expected - innovated.getInt(subpopulation);
140 
141  seen.mergeInt(subpopulation, 1, Integer::sum);
142 
143  if (rnd < totalInno) {
144  // Agent would innovate
145 
146  // Agent has already innovated, force selection and increase carry over
147  if (oneAhead.contains(id)) {
148  carryOver.mergeInt(subpopulation, 1, Integer::sum);
149  return chooseStrategy(totalSel, wSel, weights);
150  }
151 
152  oneAhead.add(id);
153  innovated.mergeInt(subpopulation, 1, Integer::sum);
154  advanceStep(subpopulation);
155 
156  return chooseStrategy(totalInno, wInno, weights);
157  } else {
158  // Agent would select
159 
160  // Force to innovate if there is carry over
161  if (carryOver.getInt(subpopulation) > 0 && !oneAhead.contains(id)) {
162  carryOver.mergeInt(subpopulation, -1, Integer::sum);
163 
164  oneAhead.add(id);
165  innovated.mergeInt(subpopulation, 1, Integer::sum);
166  advanceStep(subpopulation);
167  return chooseStrategy(totalInno, wInno, weights);
168  }
169 
170  // If the difference becomes too large, agents are allowed to innovate again
171  // some carry overs are always reserved for agent that need to innovate one step
172  if (carryOver.getInt(subpopulation) > 20 && diff > 50 && !twoAhead.contains(id)) {
173  carryOver.mergeInt(subpopulation, -1, Integer::sum);
174 
175  twoAhead.add(id);
176  innovated.mergeInt(subpopulation, 1, Integer::sum);
177  return chooseStrategy(totalInno, wInno, weights);
178  }
179 
180  return chooseStrategy(totalSel, wSel, weights);
181  }
182  }
183 
184  private void advanceStep(String subpopulation) {
185  IntSet oneAhead = this.oneAhead.get(subpopulation);
186 
187  if (oneAhead.size() == total.getInt(subpopulation)) {
188  IntSet twoAhead = this.twoAhead.get(subpopulation);
189 
190  oneAhead.clear();
191  oneAhead.addAll(twoAhead);
192  twoAhead.clear();
193  }
194  }
195 
196  private GenericPlanStrategy<PL, AG> chooseStrategy(double total, double[] w, StrategyChooser.Weights<PL, AG> weights) {
197  double rnd = MatsimRandom.getRandom().nextDouble() * total;
198  double sum = 0.0;
199  for (int i = 0, max = w.length; i < max; i++) {
200  sum += w[i];
201  if (rnd <= sum) {
202  return weights.getStrategy(i);
203  }
204  }
205  return null;
206  }
207 }
AllowsConfiguration addOverridingModule(AbstractModule abstractModule)
GenericPlanStrategy< PL, AG > chooseStrategy(HasPlansAndId< PL, AG > person, String subpopulation, ReplanningContext replanningContext, StrategyChooser.Weights< PL, AG > weights)
static< P extends BasicPlan, R > boolean isOnlySelector(GenericPlanStrategy< P, R > planStrategy)
Map< Id< Person >,? extends Person > getPersons()
static String getSubpopulation(HasPlansAndId<?, ?> person)
GenericPlanStrategy< PL, AG > chooseStrategy(double total, double[] w, StrategyChooser.Weights< PL, AG > weights)