/******************************************************************************* * Copyright 2006 - 2012 Vienna University of Technology, * Department of Software Technology and Interactive Systems, IFS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package eu.scape_project.planning.model.kbrowser; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import javax.persistence.CascadeType; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Transient; import javax.validation.Valid; import org.hibernate.annotations.IndexColumn; @Entity @DiscriminatorValue("N") public class CriteriaNode extends CriteriaTreeNode { private static final long serialVersionUID = 7843526513261328018L; @Transient private long nrOfRelevantPlans = -1L; @Valid @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "parent_fk") @IndexColumn(name="indexcol",base=1) protected List<CriteriaTreeNode> children = new ArrayList<CriteriaTreeNode>(); public CriteriaNode() { } public CriteriaNode(long nrOfRelevantPlans) { this.nrOfRelevantPlans = nrOfRelevantPlans; } // -------- universal functions -------- @Override public boolean isLeaf() { return false; } /** * Method responsible for adding a child-node. * * @param child child-node to add. */ public void addChild(CriteriaTreeNode child) { child.setParent(this); children.add(child); } /** * Method responsible for removing a child-node. * * @param child child-node to remove. */ public void removeChild(CriteriaTreeNode child) { children.remove(child); child.setParent(null); } /** * Method responsible for returning all successive treenodes. * @return Successive treenodes. */ public List<CriteriaTreeNode> getAllSuccessiveTreeNodes() { List<CriteriaTreeNode> successiveTreeNodes = new ArrayList<CriteriaTreeNode>(); for (CriteriaTreeNode child : this.children) { successiveTreeNodes.add(child); if (child instanceof CriteriaNode) { CriteriaNode childNode = (CriteriaNode) child; successiveTreeNodes.addAll(childNode.getAllSuccessiveTreeNodes()); } } return successiveTreeNodes; } /** * Method responsible for returning all successive leaves. * @return Successive leaves. */ public List<CriteriaLeaf> getAllSuccessiveLeaves() { List<CriteriaLeaf> successiveLeaves = new ArrayList<CriteriaLeaf>(); for (CriteriaTreeNode node : getAllSuccessiveTreeNodes()) { if (node instanceof CriteriaLeaf) { CriteriaLeaf leaf = (CriteriaLeaf) node; successiveLeaves.add(leaf); } } return successiveLeaves; } /** * Method responsible for returning the number of successive leaves * @return Number of successive leaves. */ public int getNrOfSuccessiveLeaves() { return getAllSuccessiveLeaves().size(); } // -------- criteria set importance factors -------- /** * Method responsible for calculating the criteria set importance factor SIF1. * SIF1(Spread) is specified by the average spread of the criteria in the set. * @return Criteria set importance factor SIF1. */ public double getImportanceFactorSIF1() { double sum = 0; double count = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF2(); sum += value; count++; } if (count == 0) { return 0; } return sum / count; } /** * Method responsible for calculating the criteria set importance factor SIF2. * SIF2(Coverage) is specified by the percentage of plans using at least one of the criteria in the set. * SIF2 = plans using at least one of the criteria / number of all plans * @return Criteria set importance factor SIF1. */ public double getImportanceFactorSIF2() { if (nrOfRelevantPlans == 0) { return 0; } HashSet<Integer> plansUsingAtLeastOneOfTheCriteria = new HashSet<Integer>(); for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { plansUsingAtLeastOneOfTheCriteria.addAll(criteriaLeaf.getUsingPlans()); } double coverage = (double) plansUsingAtLeastOneOfTheCriteria.size() / (double) nrOfRelevantPlans; return coverage; } /** * Method responsible for calculating the criteria set importance factor SIF3. * SIF3(Weight) is specified by the average of the per plan accumulated criteria weights. * SIF3 = sum of criteria leaf IF4(Discounted Weight) * @return Criteria set importance factor SIF3. */ public double getImportanceFactorSIF3(){ double sum = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF4(); sum += value; } return sum; } /** * Method responsible for calculating the criteria set importance factor SIF4. * SIF4(Potential) is specified by the average of the per plan accumulated criteria potentials. * SIF4 = sum of criteria leaf IF7(Discounted Potential) * @return Criteria set importance factor SIF4. */ public double getImportanceFactorSIF4(){ double sum = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF7(); sum += value; } return sum; } /** * Method responsible for calculating the criteria set importance factor SIF5. * SIF5(Maximum Potential) is specified by the maximum the per plan accumulated criteria potential. * SIF3 = max(per plan accumulated potential) * @return Criteria set importance factor SIF5. */ public double getImportanceFactorSIF5(){ // data structure for storing accumulated values per plan <plan, accumulated potential> - values are aggregated by summing them up Hashtable<Integer, Double> planAccumulation = new Hashtable<Integer, Double>(); // iterate all criterionLeaves for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { // iterate all corresponding plan leaves and separate the values per plan for (VPlanLeaf planLeaf : criteriaLeaf.getPlanLeaves()) { int planId = planLeaf.getPlanId(); double por = planLeaf.getPotentialOutputRange(); if (!planAccumulation.containsKey(planId)) { planAccumulation.put(planId, por); } else { double oldValue = planAccumulation.get(planId); double newValue = oldValue + por; planAccumulation.put(planId, newValue); } } } // now aggregate over accumulation results double max = 0; for (Integer planId : planAccumulation.keySet()) { double planAgg = planAccumulation.get(planId); if (planAgg > max) { max = planAgg; } } return max; } /** * Method responsible for calculating the criteria set importance factor SIF5. * SIF6(Range) is specified by the average of the per plan accumulated criteria ranges. * SIF6 = sum of criteria leaf IF8(Discounted Range) * @return Criteria set importance factor SIF6. */ public double getImportanceFactorSIF6(){ double sum = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF8(); sum += value; } return sum; } /** * Method responsible for calculating the criteria set importance factor SIF7. * SIF7(Maximum Range) is specified by the maximum the per plan accumulated criteria range. * SIF7 = max(per plan accumulated range) * @return Criteria set importance factor SIF7. */ public double getImportanceFactorSIF7(){ // data structure for storing accumulated values per plan <plan, accumulated potential> - values are aggregated by summing them up Hashtable<Integer, Double> planAccumulation = new Hashtable<Integer, Double>(); // iterate all criterionLeaves for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { // iterate all corresponding plan leaves and separate the values per plan for (VPlanLeaf planLeaf : criteriaLeaf.getPlanLeaves()) { int planId = planLeaf.getPlanId(); double aor = planLeaf.getActualOutputRange(); if (!planAccumulation.containsKey(planId)) { planAccumulation.put(planId, aor); } else { double oldValue = planAccumulation.get(planId); double newValue = oldValue + aor; planAccumulation.put(planId, newValue); } } } // now aggregate over accumulation results double max = 0; for (Integer planId : planAccumulation.keySet()) { double planAgg = planAccumulation.get(planId); if (planAgg > max) { max = planAgg; } } return max; } /** * Method responsible for calculating the criteria set importance factor SIF8. * SIF8(Variation) is specified by the average of all criteria relative output ranges. * SIF8 = average mean of criteria leaf IF11(Variation) * @return Criteria set importance factor SIF8. */ public double getImportanceFactorSIF8(){ double sum = 0; double count = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF11(); sum += value; count++; } if (count == 0) { return 0; } return sum / count; } /** * Method responsible for calculating the criteria set importance factor SIF9. * SIF9(Maximum Variation) is specified by the average of all criteria maximum relative output ranges. * SIF9 = average mean of criteria leaf IF12(Maximum Variation) * @return Criteria set importance factor SIF9. */ public double getImportanceFactorSIF9(){ double sum = 0; double count = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF12(); sum += value; count++; } if (count == 0) { return 0; } return sum / count; } /** * Method responsible for calculating the criteria set importance factor SIF10. * SIF10(Rejection Potential Count) is specified by the number of decision criteria with alternative rejection potential. * SIF10 = sum of single criteria factor IF13(Rejection Potential Count) * @return Criteria set importance factor SIF10. */ public double getImportanceFactorSIF10(){ double sum = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF13(); sum += value; } return sum; } /** * Method responsible for calculating the criteria set importance factor SIF11. * SIF11(Rejection Potential Rate) is specified by the percentage of decision criteria with alternative rejection potential. * SIF11 = sum of single criteria factor IF13(Rejection Potential Count) / number of decision criteria * @return Criteria set importance factor SIF11. */ public double getImportanceFactorSIF11(){ double sum = 0; double count = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF13(); sum += value; count = count + criteriaLeaf.getPlanLeaves().size(); } if (count == 0) { return 0; } return sum / count; } /** * Method responsible for calculating the criteria set importance factor SIF12. * SIF12(Rejection Count) is specified by the number of decision criteria actually rejecting alternatives. * SIF12 = sum of single criteria factor IF15(Rejection Count) * @return Criteria set importance factor SIF12. */ public double getImportanceFactorSIF12(){ double sum = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF15(); sum += value; } return sum; } /** * Method responsible for calculating the criteria set importance factor SIF13. * SIF13(Rejection Rate) is specified by the percentage of decision criteria actually rejecting alternatives. * SIF13 = sum of single criteria factor IF15(Rejection Potential Count) / number of decision criteria * @return Criteria set importance factor SIF13. */ public double getImportanceFactorSIF13(){ double sum = 0; double count = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF15(); sum += value; count = count + criteriaLeaf.getPlanLeaves().size(); } if (count == 0) { return 0; } return sum / count; } /** * Method responsible for calculating the criteria set importance factor SIF14. * SIF14(Rejection Spread) is specified by the percentage of plans affected by a actual alternative reject out of this criteria set. * @return Criteria set importance factor SIF14. */ public double getImportanceFactorSIF14(){ if (nrOfRelevantPlans == 0) { return 0; } // data structure for storing aggregated values per plan <plan, aggregated weight> - values are aggregated by summing them up HashSet<Integer> koPlans = new HashSet<Integer>(); // iterate all criterion leaves contained by this structural node for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { // iterate all plan leaves and separate the values per plan for (VPlanLeaf planLeaf : criteriaLeaf.getPlanLeaves()) { int planId = planLeaf.getPlanId(); double ako = planLeaf.getActualKO(); if (ako > 0) { koPlans.add(planId); } } } double koPlansCount = koPlans.size(); double result = koPlansCount / (double) nrOfRelevantPlans; return result; } /** * Method responsible for calculating the criteria set importance factor SIF15. * SIF15(Reject Count) is specified by the number alternatives actually rejected. * SIF15 = sum of single criteria factor IF17(Rejection Count) * @return Criteria set importance factor SIF15. */ public double getImportanceFactorSIF15(){ HashSet<String> koAlternatives = new HashSet<String>(); for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { for (VPlanLeaf planLeaf : criteriaLeaf.getPlanLeaves()) { Map<String,Double> alternativeEvaluations = planLeaf.getAlternativeResultsAsMap(); for (String alternative : alternativeEvaluations.keySet()) { if (alternativeEvaluations.get(alternative) == 0) { koAlternatives.add(planLeaf.getPlanId() + "-" + alternative); } } } } double result = koAlternatives.size(); return result; /* double sum = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { double value = criteriaLeaf.getImportanceFactorIF17(); sum += value; } return sum; */ } /** * Method responsible for calculating the criteria set importance factor SIF16. * SIF16(Reject Rate) is specified by the percentage of alternatives actually rejected. * SIF16 = sum of single criteria factor IF15(Reject Count) / number of all alternatives * @return Criteria set importance factor SIF16. */ public double getImportanceFactorSIF16(){ HashSet<String> allAlternatives = new HashSet<String>(); HashSet<String> koAlternatives = new HashSet<String>(); for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { for (VPlanLeaf planLeaf : criteriaLeaf.getPlanLeaves()) { Map<String,Double> alternativeEvaluations = planLeaf.getAlternativeResultsAsMap(); for (String alternative : alternativeEvaluations.keySet()) { allAlternatives.add(planLeaf.getPlanId() + "-" + alternative); if (alternativeEvaluations.get(alternative) == 0) { koAlternatives.add(planLeaf.getPlanId() + "-" + alternative); } } } } double allAlternativesCount = allAlternatives.size(); double koAlternativesCount = koAlternatives.size(); if (allAlternativesCount == 0) { double result = 0; return result; } double result = koAlternativesCount / allAlternativesCount; return result; /* double sum = 0; double count = 0; for (CriteriaLeaf criteriaLeaf : getAllSuccessiveLeaves()) { for (VPlanLeaf planLeaf : criteriaLeaf.getPlanLeaves()) { sum = sum + planLeaf.getActualKO(); count = count + planLeaf.getValueMap().size(); } } if (count == 0) { return 0; } return sum / count; */ } // -------- view formatting -------- public String getStringFormattedImportanceFactorSIF1() { DecimalFormat format = new DecimalFormat("#.##"); return format.format(getImportanceFactorSIF1() * 100) + "%"; } public String getStringFormattedImportanceFactorSIF2() { DecimalFormat format = new DecimalFormat("#.##"); return format.format(getImportanceFactorSIF2() * 100) + "%"; } public String getStringFormattedImportanceFactorSIF3() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF3()); } public String getStringFormattedImportanceFactorSIF4() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF4()); } public String getStringFormattedImportanceFactorSIF5() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF5()); } public String getStringFormattedImportanceFactorSIF6() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF6()); } public String getStringFormattedImportanceFactorSIF7() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF7()); } public String getStringFormattedImportanceFactorSIF8() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF8()); } public String getStringFormattedImportanceFactorSIF9() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF9()); } public String getStringFormattedImportanceFactorSIF10() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF10()); } public String getStringFormattedImportanceFactorSIF11() { DecimalFormat format = new DecimalFormat("#.##"); return format.format(getImportanceFactorSIF11() * 100) + "%"; } public String getStringFormattedImportanceFactorSIF12() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF12()); } public String getStringFormattedImportanceFactorSIF13() { DecimalFormat format = new DecimalFormat("#.##"); return format.format(getImportanceFactorSIF13() * 100) + "%"; } public String getStringFormattedImportanceFactorSIF14() { DecimalFormat format = new DecimalFormat("#.##"); return format.format(getImportanceFactorSIF14() * 100) + "%"; } public String getStringFormattedImportanceFactorSIF15() { DecimalFormat format = new DecimalFormat("#.###"); return format.format(getImportanceFactorSIF15()); } public String getStringFormattedImportanceFactorSIF16() { DecimalFormat format = new DecimalFormat("#.##"); return format.format(getImportanceFactorSIF16() * 100) + "%"; } // -------- getter/setter -------- public void setNrOfRelevantPlans(long nrOfRelevantPlans) { this.nrOfRelevantPlans = nrOfRelevantPlans; } public long getNrOfRelevantPlans() { return nrOfRelevantPlans; } public void setChildren(List<CriteriaTreeNode> children) { this.children = children; } public List<CriteriaTreeNode> getChildren() { return children; } }