/*******************************************************************************
* 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.
*
* This work originates from the Planets project, co-funded by the European Union under the Sixth Framework Programme.
******************************************************************************/
package eu.scape_project.planning.model.sensitivity;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import eu.scape_project.planning.model.Alternative;
import eu.scape_project.planning.model.aggregators.IAggregator;
import eu.scape_project.planning.model.beans.ResultNode;
import eu.scape_project.planning.model.tree.TreeNode;
/**
* This sensitivity analysis test uses the order of the alternatives to determine which nodes are sensitive.
* At start (with the normal importance weights) the order of the alternatives is evaluated - which
* alternative is currently the best, which is second best etc. This is the "normal order".
*
* After each iteration (changes to the importance weights) the alternatives are evaluated once again. If the order
* changes (compared to "normal order") then the currently processed node is considered sentitive.
*
* @author Jan Zarnikov
*
*/
public class OrderChangeTest implements ISensitivityTest {
/**
* This is just a helper class so we can store the alternatives along with
* theire evaluated result values in a SortedSet.
*
* @author Jan Zarnikov
*
*/
protected class ComparableAlternative implements Comparable<ComparableAlternative> {
private double value = 0;
private Alternative alternative;
public ComparableAlternative(Alternative alternative, IAggregator aggregator, TreeNode root) {
this.alternative = alternative;
this.value = aggregator.getAggregatedValue(root, alternative);
}
public double getValue() {
return value;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*
* We use the aggreated value for comparison (which alternative is the best).
* In case of equal values we use alphabetical order (the alternative's name).
*/
public int compareTo(ComparableAlternative o) {
if(this.getValue() < o.getValue()) {
return -1;
} else if(this.getValue() > o.getValue()) {
return 1;
} else {
return this.alternative.getName().compareTo(o.alternative.getName());
}
}
public boolean equals(Object other) {
if(other instanceof ComparableAlternative) {
ComparableAlternative oa = (ComparableAlternative) other;
return this.alternative.equals(oa.alternative);
} else {
return false;
}
}
public int hashCode() {
return 13 * alternative.hashCode();
}
public String toString() {
return alternative.getName() + ": " + value;
}
}
protected SortedSet<ComparableAlternative> normalOrder;
protected List<Alternative> alternatives;
private TreeNode root;
private IAggregator aggregator;
private boolean orderChanged = false;
/**
* Constructs a new ChangeOrderTest.
* @param root The root node of the tree.
* @param aggregator The aggregator used to evaluate the alternatives. This should be the same aggregator that is used for evaluating the alternatives.
* @param alternatives The alternatives that should be evaluated during the test.
*/
public OrderChangeTest(TreeNode root, IAggregator aggregator, List<Alternative> alternatives) {
this.root = root;
this.aggregator = aggregator;
this.alternatives = alternatives;
normalOrder = getOrder();
}
/**
* Evaluate all alternatives using the aggregator given at creation time.
* @return A set of alternatives sorted by their value (highest first).
*/
protected SortedSet<ComparableAlternative> getOrder() {
SortedSet<ComparableAlternative> result = new TreeSet<ComparableAlternative>();
for(Alternative a : alternatives) {
result.add(new ComparableAlternative(a, aggregator, root));
}
return result;
}
public void afterIteration(ResultNode node) {
SortedSet<ComparableAlternative> order = getOrder();
// unfortunately we cannot compare order and normalOrder using equals()
Iterator<ComparableAlternative> normalOrderIterator = normalOrder.iterator();
if(order.size() != normalOrder.size()) {
// huh?! how did this happen? someone has modified the alternatives list
return;
}
//we iterate over both sets (the "normal order" and current order).
for(ComparableAlternative ca : order) {
// this is actually an inner loop - notice the next().
if(!ca.equals(normalOrderIterator.next())) {
orderChanged = true;
}
}
}
public void afterNode(ResultNode node) {
node.setSensitivityAnalysisResult(new OrderChangeResult(orderChanged));
}
public void beforeIteration(ResultNode node) {
}
public void beforeNode(ResultNode node) {
orderChanged = false;
}
private class OrderChangeResult implements ISensitivityAnalysisResult {
private boolean changed;
public OrderChangeResult(boolean changed) {
this.changed = changed;
}
public String toString() {
if(changed) {
return "!";
} else {
return "";
}
}
public boolean isSensitive() {
return changed;
}
public double getSensitivityCoefficient() {
return changed ? 1 : 0;
}
public double getSensitivityThreashold() {
return 0.5;
}
}
}