diff --git a/matsim/src/main/java/org/matsim/api/core/v01/population/BasicPlan.java b/matsim/src/main/java/org/matsim/api/core/v01/population/BasicPlan.java index e19d7bbea3a..5bcf541d5a3 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/population/BasicPlan.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/population/BasicPlan.java @@ -23,8 +23,17 @@ public interface BasicPlan { - public abstract void setScore(Double score); + String UNDEFINED_PLAN_TYPE = "undefined"; - public abstract Double getScore(); - -} \ No newline at end of file + void setScore(Double score ); + + Double getScore(); + + /** + * Plan type, which may be used to ensure there is at least one plan of a certain type. + */ + default String getType() { + return UNDEFINED_PLAN_TYPE; + } + +} diff --git a/matsim/src/main/java/org/matsim/api/core/v01/population/Plan.java b/matsim/src/main/java/org/matsim/api/core/v01/population/Plan.java index 6329b62a626..ea9bc7d3e04 100644 --- a/matsim/src/main/java/org/matsim/api/core/v01/population/Plan.java +++ b/matsim/src/main/java/org/matsim/api/core/v01/population/Plan.java @@ -38,33 +38,27 @@ */ public interface Plan extends MatsimPopulationObject, Customizable, BasicPlan, Attributable, Identifiable { - public abstract List getPlanElements(); + List getPlanElements(); - public abstract void addLeg(final Leg leg); + void addLeg( final Leg leg ); - public abstract void addActivity(final Activity act); + void addActivity( final Activity act ); - - /** - * Plan type, which may be used to ensure there is at least one plan of a certain type. - */ - public abstract String getType(); - - public abstract void setType(final String type); + void setType( final String type ); - public abstract void setPlanId(Id planId); + void setPlanId( Id planId ); - public abstract Id getId(); + Id getId(); - public abstract int getIterationCreated(); + int getIterationCreated(); - public abstract void setIterationCreated(int iteration); + void setIterationCreated( int iteration ); - public abstract String getPlanMutator(); + String getPlanMutator(); - public abstract void setPlanMutator(String planMutator); + void setPlanMutator( String planMutator ); - public abstract Person getPerson(); + Person getPerson(); /** * Sets the reference to the person. @@ -72,7 +66,7 @@ public interface Plan extends MatsimPopulationObject, Customizable, BasicPlan, A * sure that the bidirectional reference is set correctly if * you are using this method!. */ - public abstract void setPerson(Person person); + void setPerson( Person person ); } diff --git a/matsim/src/main/java/org/matsim/core/replanning/selectors/GenericWorstPlanForRemovalSelector.java b/matsim/src/main/java/org/matsim/core/replanning/selectors/GenericWorstPlanForRemovalSelector.java index 116cd309427..61e2df24a2e 100644 --- a/matsim/src/main/java/org/matsim/core/replanning/selectors/GenericWorstPlanForRemovalSelector.java +++ b/matsim/src/main/java/org/matsim/core/replanning/selectors/GenericWorstPlanForRemovalSelector.java @@ -25,54 +25,82 @@ import org.matsim.api.core.v01.population.BasicPlan; import org.matsim.api.core.v01.population.HasPlansAndId; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.matsim.api.core.v01.population.BasicPlan.UNDEFINED_PLAN_TYPE; + /** - *

Selects the worst plan of a person (most likely for removal). + *

Selects the worst plan of a person (most likely for removal), but respects + * the set plan types in a way the no plan is selected that is the last one of + * its type.

+ *

(I would say that it can select the last of its type if it finds nothing else. However, this algo should only + * be used if an agent has more plans than maxPlansPerAgent, so make sure that that parameter is set large enough for + * your purposes. kai, oct'09)

*

Plans without a score are seen as worst and selected accordingly.

* * @author mrieser */ public class GenericWorstPlanForRemovalSelector implements PlanSelector { - private static final String UNDEFINED_TYPE = "undefined"; - - @Override - public T selectPlan(HasPlansAndId person) { - - T worst = null; - double worstScore = Double.POSITIVE_INFINITY; - for (T plan : person.getPlans()) { - - // if this plan has no score yet: - if (plan.getScore() == null || plan.getScore().isNaN() ) { - // say that the plan without score now is the "worst": - worst = plan; - - // make sure that this one remains the selected plan: - worstScore = Double.NEGATIVE_INFINITY; - - // otherwise do the usual logic to find the plan with the minimum score: - } else if (plan.getScore() < worstScore) { - worst = plan; - worstScore = plan.getScore(); - } - // (otherwise we just keep "worst=null") - - } - - if (worst == null) { - // there is exactly one plan, or we have of each plan-type exactly one. - // select the one with worst score globally, or the first one with score=null - for (T plan : person.getPlans()) { - if (plan.getScore() == null || plan.getScore().isNaN() ) { - return plan; - } - if (plan.getScore() < worstScore) { - worst = plan; - worstScore = plan.getScore(); - } - } - } - return worst; - } + @Override + public T selectPlan(HasPlansAndId person) { + + // hashmap that returns "Integer" count for given plans type: + Map typeCounts = new ConcurrentHashMap(); + + // count how many plans per type an agent has: + for (T plan : person.getPlans()) { + String type = plan.getType(); + if ( type==null ) { + type = UNDEFINED_PLAN_TYPE; + } + typeCounts.merge( type, 1, ( a, b ) -> a + b ); + } + + T worst = null; + double worstScore = Double.POSITIVE_INFINITY; + for (T plan : person.getPlans()) { + + String type = plan.getType(); + if ( type==null ) { + type = UNDEFINED_PLAN_TYPE; + } + if ( typeCounts.get( type ) > 1) { + // (if we have more than one plan of the same type:) + + // if this plan has no score yet: + if (plan.getScore() == null || plan.getScore().isNaN() ) { + // say that the plan without score now is the "worst": + worst = plan; + + // make sure that this one remains the selected plan: + worstScore = Double.NEGATIVE_INFINITY; + + // otherwise do the usual logic to find the plan with the minimum score: + } else if (plan.getScore() < worstScore) { + worst = plan; + worstScore = plan.getScore(); + } + } + // (otherwise we just keep "worst=null") + + } + + if (worst == null) { + // there is exactly one plan, or we have of each plan-type exactly one. + // select the one with worst score globally, or the first one with score=null + for (T plan : person.getPlans()) { + if (plan.getScore() == null || plan.getScore().isNaN() ) { + return plan; + } + if (plan.getScore() < worstScore) { + worst = plan; + worstScore = plan.getScore(); + } + } + } + return worst; + } }