MATSIM
ExpBetaPlanSelector.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * ExpBetaPlanSelector.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.core.replanning.selectors;
22 
23 import java.util.LinkedHashMap;
24 import java.util.Map;
25 
26 import org.apache.logging.log4j.LogManager;
31 
38 public class ExpBetaPlanSelector<T extends BasicPlan, I> implements PlanSelector<T, I> {
39 
40  protected static final double MIN_WEIGHT = Double.MIN_VALUE;
41  protected final double beta;
42 
43  public ExpBetaPlanSelector( final double logitScaleFactor ) {
44  this.beta = logitScaleFactor ;
45  }
46 
47  public ExpBetaPlanSelector(ScoringConfigGroup charyparNagelScoringConfigGroup) {
48  this( charyparNagelScoringConfigGroup.getBrainExpBeta() ) ;
49  }
50 
54  @Override
55  public T selectPlan(final HasPlansAndId<T, I> person) {
56 
57  // get the weights of all plans
58  Map<T, Double> weights = this.calcWeights(person);
59 
60  double sumWeights = 0.0;
61  for (Double weight : weights.values()) {
62  sumWeights += weight;
63  }
64 
65  // choose a random number over interval [0, sumWeights[
66  double selnum = sumWeights * MatsimRandom.getRandom().nextDouble();
67  for (T plan : person.getPlans()) {
68  selnum -= weights.get(plan);
69  if (selnum <= 0.0) {
70  return plan;
71  }
72  }
73 
74  // hmm, no plan returned... either the person has no plans, or the plan(s) have no score.
75  if (person.getPlans().size() > 0) {
76  return person.getPlans().get(0);
77  }
78 
79  // this case should never happen, except a person has no plans at all.
80  return null;
81  }
82 
88  protected double calcPlanWeight(final T plan, final double maxScore) {
89  // NOTE: The deduction of "maxScore" from all scores is a numerical trick. It ensures that the values of exp(...)
90  // are in some normal range, instead of close to numerical infinity. The latter leads to numerically instable
91  // results (this is not fiction; we had that some time ago). kai, aug'12
92 
93  if (plan.getScore() == null) {
94  return Double.NaN;
95  }
96  double weight = Math.exp(this.beta * (plan.getScore() - maxScore));
97  if (weight < MIN_WEIGHT) weight = MIN_WEIGHT;
98  return weight;
99  }
100 
106  Map<T, Double> calcWeights(final HasPlansAndId<T, ?> person) {
107 
108  // - first find the max. score of all plans of this person
109  double maxScore = Double.NEGATIVE_INFINITY;
110  for (T plan1 : person.getPlans()) {
111  if ( (plan1.getScore() != null) && plan1.getScore().isNaN() ) {
112  LogManager.getLogger(this.getClass()).error("encountering getScore().isNaN(). This class is not well behaved in this situation. Continuing anyway ...") ;
113  }
114  if ((plan1.getScore() != null) && (plan1.getScore() > maxScore)) {
115  maxScore = plan1.getScore();
116  }
117  }
118 
119  Map<T, Double> weights = new LinkedHashMap<T, Double>(person.getPlans().size());
120 
121  for (T plan : person.getPlans()) {
122  weights.put(plan, this.calcPlanWeight(plan, maxScore));
123  // see note in calcPlanWeight!
124  }
125 
126  return weights;
127  }
128 
132  public static <T extends BasicPlan, I> double getSelectionProbability(ExpBetaPlanSelector<T, I> expBetaPlanSelector, HasPlansAndId<T, ?> person, final T plan) {
133  Map<T, Double> weights = expBetaPlanSelector.calcWeights(person);
134  double thisWeight = weights.get(plan);
135 
136  double sumWeights = 0.0;
137  for (Double weight : weights.values()) {
138  sumWeights += weight;
139  }
140 
141  return (thisWeight / sumWeights);
142  }
143 
144 }
double calcPlanWeight(final T plan, final double maxScore)
ExpBetaPlanSelector(ScoringConfigGroup charyparNagelScoringConfigGroup)
abstract List<? extends T > getPlans()
static< T extends BasicPlan, I > double getSelectionProbability(ExpBetaPlanSelector< T, I > expBetaPlanSelector, HasPlansAndId< T, ?> person, final T plan)