Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for planTypes in GenericWorstPlanForRemovalSelector #3184

Merged
merged 5 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,17 @@

public interface BasicPlan {

public abstract void setScore(Double score);
String UNDEFINED_PLAN_TYPE = "undefined";

public abstract Double getScore();

}
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;
}

}
30 changes: 12 additions & 18 deletions matsim/src/main/java/org/matsim/api/core/v01/population/Plan.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,41 +38,35 @@
*/
public interface Plan extends MatsimPopulationObject, Customizable, BasicPlan, Attributable, Identifiable<Plan> {

public abstract List<PlanElement> getPlanElements();
List<PlanElement> 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<Plan> planId);
void setPlanId( Id<Plan> planId );

public abstract Id<Plan> getId();
Id<Plan> 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.
* This is done automatically if using Person.addPlan(). Make
* sure that the bidirectional reference is set correctly if
* you are using this method!.
*/
public abstract void setPerson(Person person);
void setPerson( Person person );


}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
* <p>Selects the worst plan of a person (most likely for removal).
* <p>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.</p>
* <p>(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)</p>
* <p>Plans without a score are seen as worst and selected accordingly.</p>
*
* @author mrieser
*/
public class GenericWorstPlanForRemovalSelector<T extends BasicPlan, I> implements PlanSelector<T, I> {

private static final String UNDEFINED_TYPE = "undefined";

@Override
public T selectPlan(HasPlansAndId<T, I> 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<T, I> person) {

// hashmap that returns "Integer" count for given plans type:
Map<String, Integer> typeCounts = new ConcurrentHashMap<String, Integer>();

// 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;
}

}
Loading