package eu.scape_project.planning.criteria.bean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import eu.scape_project.planning.model.kbrowser.VPlanLeaf;
/**
* Calculator for dominates measures and sets of measures.
*/
public abstract class DominatedSets {
/**
* Aggregation mode of calculations.
*/
public enum Aggregation {
/**
* Must be true for ALL plans.
*/
ALL,
/**
* Must be true for ANY plans.
*/
ANY
};
private List<PlanInfo> selectedPlans = new ArrayList<PlanInfo>();
private HashMap<String, Map<PlanInfo, Set<VPlanLeaf>>> leavesOfMeasures = new HashMap<String, Map<PlanInfo, Set<VPlanLeaf>>>();
/**
* Creates a new DominatedSetCalculator.
*
* @param selectedPlans
* PlanInfos to use
* @param selectedLeaves
* leaves to use
*/
public DominatedSets(final List<PlanInfo> selectedPlans, final List<VPlanLeaf> selectedLeaves) {
this.selectedPlans = selectedPlans;
fillCriterionVPlanLeaves(selectedLeaves);
}
/**
* Fills the map of used VPlanLeaves per criterion.
*
* @param selectedLeaves
* the leaves to store
*/
private void fillCriterionVPlanLeaves(final List<VPlanLeaf> selectedLeaves) {
for (VPlanLeaf leaf : selectedLeaves) {
if (leaf.isMapped()) {
Map<PlanInfo, Set<VPlanLeaf>> leavesOfPlans = leavesOfMeasures.get(leaf.getMeasure().getUri());
if (leavesOfPlans == null) {
leavesOfPlans = new HashMap<PlanInfo, Set<VPlanLeaf>>();
leavesOfMeasures.put(leaf.getMeasure().getUri(), leavesOfPlans);
}
PlanInfo planInfo = getSelectedPlanInfo(leaf.getPlanId());
Set<VPlanLeaf> leavesOfPlan = leavesOfPlans.get(planInfo);
if (leavesOfPlan == null) {
leavesOfPlan = new HashSet<VPlanLeaf>();
leavesOfPlans.put(planInfo, leavesOfPlan);
}
leavesOfPlan.add(leaf);
}
}
}
/**
* Returns the plan info with the given ID.
*
* @param id
* plan id
* @return the plan info of the plan
*/
private PlanInfo getSelectedPlanInfo(final int id) {
for (PlanInfo planInfo : selectedPlans) {
if (planInfo.getId() == id) {
return planInfo;
}
}
return null;
}
/**
* Checks the powerset of measures for potential to change the ranking of
* plans of this calculator.
*
* @param aggregation
* aggregation mode over plans
* @return the largest sets of measures
*/
public List<List<String>> getDominatedSets(Aggregation aggregation) {
return getDominatedSupersets(new ArrayList<String>(leavesOfMeasures.keySet()), 0,
new ArrayList<List<String>>(0), new ArrayList<String>(leavesOfMeasures.keySet().size()), aggregation);
}
/**
* Checks subsets of all measures for potential to change the ranking for
* plans of this calculator. Recursively checks all measures, starting from
* index.
*
* Note: For performance reasons the sets are stored in lists. Thus
* allMeasureUris should not contain duplicates.
*
* @param allMeasureUris
* all measures that should be considered
* @param index
* the beginning index of all measures
* @param currentRankChangingSets
* rank-changing sets already found for current measures
* @param currentMeasures
* the current list of measures used as starting point
* @param aggregation
* aggregation mode over plans
* @return a list of dominated supersets of the currentMeasures
*/
private List<List<String>> getDominatedSupersets(final List<String> allMeasureUris, final int index,
final List<List<String>> currentRankChangingSets, List<String> currentMeasures, Aggregation aggregation) {
List<List<String>> rankChangingSets = new ArrayList<List<String>>(currentRankChangingSets);
for (int i = index; i < allMeasureUris.size(); i++) {
currentMeasures.add(allMeasureUris.get(i));
// Check if current measures are already in rank-changing sets
List<List<String>> setsOfCurrentMeasures = getSetsContainingMeasure(rankChangingSets, allMeasureUris.get(i));
if (setsOfCurrentMeasures.size() > 0) {
// Current measures is already in rank-changing sets, check
// supersets
List<List<String>> setsOfSuperMeasures = getDominatedSupersets(allMeasureUris, i + 1,
setsOfCurrentMeasures, currentMeasures, aggregation);
// Add rank-changing supersets
addNewSets(setsOfCurrentMeasures, setsOfSuperMeasures, rankChangingSets);
} else {
// Current measures not yet in rank-changing sets, check if
// dominated
if (isLeafSetDominated(getLeavesOfMeasureUris(currentMeasures), aggregation)) {
// Rank-changing, check supersets
List<List<String>> setsOfSuperMeasures = getDominatedSupersets(allMeasureUris, i + 1,
setsOfCurrentMeasures, currentMeasures, aggregation);
if (setsOfSuperMeasures.size() > setsOfCurrentMeasures.size()) {
// Rank-changing supersets, add them
addNewSets(setsOfCurrentMeasures, setsOfSuperMeasures, rankChangingSets);
} else {
// No dominated supersets, add current measures
rankChangingSets.add(new ArrayList<String>(currentMeasures));
}
}
}
currentMeasures.remove(currentMeasures.size() - 1);
}
return rankChangingSets;
}
/**
* Returns a list of sets that contain the provided measureUri.
*
* @param sets
* the list of sets to search
* @param measureUri
* measure URI to search for
* @return a list of sets
*/
private List<List<String>> getSetsContainingMeasure(final List<List<String>> sets, final String measureUri) {
List<List<String>> foundSets = new ArrayList<List<String>>(sets.size());
for (List<String> set : sets) {
if (set.contains(measureUri)) {
foundSets.add(set);
}
}
return foundSets;
}
/**
* Takes an old set and the corresponding superset and adds all elements of
* the superset not contained in the old set to target.
*
* Note: The sets are stored as lists, the superset must contain the old set
* at the beginning.
*
* @param oldSet
* the old set
* @param superSet
* superset of the old set
* @param target
* target list
*/
private void addNewSets(final List<List<String>> oldSet, final List<List<String>> superSet,
List<List<String>> target) {
for (int i = oldSet.size(); i < superSet.size(); i++) {
target.add(superSet.get(i));
}
}
/**
* Returns a set of leaves that are mapped to the provided measures.
*
* Note: When a single measures URI is provided, the returned map is not a
* copy but the actual map from leavesOfMesaures. Thus you should not modify
* the map.
*
* @param measureUris
* collection of measure URIs
* @return a map of plans with a set of leaves for each plan
*/
protected Map<PlanInfo, Set<VPlanLeaf>> getLeavesOfMeasureUris(final Collection<String> measureUris) {
// Single measure
if (measureUris.size() == 1) {
Map<PlanInfo, Set<VPlanLeaf>> leavesOfPlans = leavesOfMeasures.get(measureUris.iterator().next());
if (leavesOfPlans != null) {
return leavesOfPlans;
} else {
return new HashMap<PlanInfo, Set<VPlanLeaf>>();
}
}
// Multiple measures
Map<PlanInfo, Set<VPlanLeaf>> allLeaves = new HashMap<PlanInfo, Set<VPlanLeaf>>();
for (String measure : measureUris) {
Map<PlanInfo, Set<VPlanLeaf>> leavesOfPlans = leavesOfMeasures.get(measure);
if (leavesOfPlans != null) {
for (Map.Entry<PlanInfo, Set<VPlanLeaf>> entry : leavesOfPlans.entrySet()) {
Set<VPlanLeaf> leavesOfPlan = allLeaves.get(entry.getKey());
if (leavesOfPlan == null) {
leavesOfPlan = new HashSet<VPlanLeaf>();
allLeaves.put(entry.getKey(), leavesOfPlan);
}
leavesOfPlan.addAll(entry.getValue());
}
}
}
return allLeaves;
}
/**
* Checks if the provided measure could change the ranking of alternatives.
*
* @param measureUri
* URI of measure to check
* @param aggregation
* aggregation mode over plans
* @return true if the measure are dominated, false otherwise
*/
public boolean isMeasureDominated(final String measureUri, Aggregation aggregation) {
Map<PlanInfo, Set<VPlanLeaf>> leavesOfPlans = leavesOfMeasures.get(measureUri);
if (leavesOfPlans == null) {
return true;
}
return isLeafSetDominated(leavesOfPlans, aggregation);
}
/**
* Checks if the provided set of measures are dominated.
*
* @param measureUris
* URIs of measures to check
* @param aggregation
* aggregation mode over plans
* @return true if the measures are dominated, false otherwise
*/
public boolean isMeasureSetDominated(Collection<String> measureUris, Aggregation aggregation) {
return isLeafSetDominated(getLeavesOfMeasureUris(measureUris), aggregation);
}
/**
* Checks if the leaves are dominated for all plans.
*
* @param planLeaves
* plans and corresponding leaves
* @param aggregation
* aggregation mode over plans
* @return true if dominated, false otherwise
*/
private boolean isLeafSetDominated(final Map<PlanInfo, Set<VPlanLeaf>> planLeaves, Aggregation aggregation) {
if (aggregation == Aggregation.ALL) {
for (Map.Entry<PlanInfo, Set<VPlanLeaf>> entry : planLeaves.entrySet()) {
if (!isLeafSetDominated(entry.getKey(), entry.getValue())) {
return false;
}
}
return true;
} else {
for (Map.Entry<PlanInfo, Set<VPlanLeaf>> entry : planLeaves.entrySet()) {
if (isLeafSetDominated(entry.getKey(), entry.getValue())) {
return true;
}
}
return false;
}
}
/**
* Returns plans that are dominated for this measure.
*
* @param measureUri
* measure URI to check
* @return a set of dominated plans
*/
public Set<PlanInfo> getDominatedPlans(final String measureUri) {
Set<PlanInfo> dominatedPlans = new HashSet<PlanInfo>();
Map<PlanInfo, Set<VPlanLeaf>> leavesOfPlans = leavesOfMeasures.get(measureUri);
// Check if leaf set is dominated for the plans
for (Map.Entry<PlanInfo, Set<VPlanLeaf>> entry : leavesOfPlans.entrySet()) {
if (isLeafSetDominated(entry.getKey(), entry.getValue())) {
dominatedPlans.add(entry.getKey());
}
}
return dominatedPlans;
}
/**
* Returns plans that are dominated for this set of measures.
*
* @param measureUris
* measure URIs to check
* @return a set of dominated plans
*/
public Set<PlanInfo> getDominatedPlans(final Collection<String> measureUris) {
Set<PlanInfo> dominatedPlans = new HashSet<PlanInfo>();
Map<PlanInfo, Set<VPlanLeaf>> leavesOfPlans = getLeavesOfMeasureUris(measureUris);
// Check if leaf set is dominated for the plans
for (Map.Entry<PlanInfo, Set<VPlanLeaf>> entry : leavesOfPlans.entrySet()) {
if (isLeafSetDominated(entry.getKey(), entry.getValue())) {
dominatedPlans.add(entry.getKey());
}
}
return dominatedPlans;
}
/**
* Checks if the leafSet of the provided planInfo is dominated.
*
* @param planInfo
* the plan to check
* @param leafSet
* leaves of the plan
* @return true if the leaves are dominated, false otherwise
*/
protected abstract boolean isLeafSetDominated(final PlanInfo planInfo, final Set<VPlanLeaf> leafSet);
}