001 package ifs.perturbations;
002
003 import ifs.solution.*;
004 import ifs.solver.*;
005 import ifs.model.*;
006 import ifs.util.*;
007 import ifs.extension.*;
008 import java.util.*;
009
010 /**
011 * Default computation of perturbation penalty (minimal perturbation problem).
012 * <br><br>
013 * A distance function can be defined with the help of perturbations. A perturbation is a variable that has a different
014 * value in the solutions of the initial and the new problem. Some perturbations must be present in each new solution.
015 * So called input perturbation means that a variable must have different values in the initial and changed problem
016 * because of some input changes (e.g., a course must be scheduled at a different time in the changed problem).
017 * The distance function can be defined as the number of additional perturbations. They are given by subtraction of
018 * the final number of perturbations and the number of input perturbations (variables without initial assignments).
019 * <br><br>
020 * This implementation is easily extendable. It disassemble all the available cases into a comparison of the initial and
021 * the assigned value different each other. So, the only method which is needed to be changed is
022 * {@link DefaultPerturbationsCounter#getPenalty(Value, Value)}. Its current implementation is: <ul><code>
023 * protected double getPenalty(Value assignedValue, Value initialValue) {<br>
024 * return 1.0;<br>
025 * }<br>
026 * </code></ul>
027 * It is called only when assignedValue is different to initialValue.
028 *
029 * @see Solver
030 * @see Solution
031 * @see Variable
032 *
033 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
034 * @version 1.0
035 */
036
037 public class DefaultPerturbationsCounter implements PerturbationsCounter {
038 private ViolatedInitials iViolatedInitials = null;
039 protected static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.00",new java.text.DecimalFormatSymbols(Locale.US));
040
041 /** Constructor
042 * @param properties input configuration
043 */
044 public DefaultPerturbationsCounter(DataProperties properties) {
045 }
046
047 /** Initialization */
048 public void init(Solver solver) {
049 for (Enumeration i=solver.getExtensions().elements();i.hasMoreElements();) {
050 Extension extension = (Extension)i.nextElement();
051 if (extension instanceof ViolatedInitials)
052 iViolatedInitials = (ViolatedInitials)extension;
053 }
054 }
055
056 public double getPerturbationPenalty(Solution solution) {
057 double penalty = 0.0;
058 for (Enumeration e=solution.getModel().perturbVariables().elements();e.hasMoreElements();) {
059 Variable variable = (Variable)e.nextElement();
060 if (variable.getAssignment()!=null && variable.getInitialAssignment()!=null && !variable.getAssignment().equals(variable.getInitialAssignment()))
061 penalty += getPenaltyD(variable.getAssignment(),variable.getInitialAssignment());
062 }
063 return penalty;
064 }
065
066 protected ViolatedInitials getViolatedInitials() { return iViolatedInitials; }
067
068 /** Computes perturbation penalty between assigned and initial value of the same lecture.
069 * It is called only when assignedValue is different to initialValue.
070 * @param assignedValue value assigned to a varuable (null when variable is unassigned)
071 * @param initialValue initial value of the same varaible (always not null)
072 */
073 protected double getPenalty(Value assignedValue, Value initialValue) {
074 return 1.0;
075 }
076
077 /** Case A: initial value of a different unassigned variable cannot be assigned (computed by {@link ViolatedInitials})
078 * @param selectedValue value which is going to be assigned to its variable
079 * @param initialValue value of a different variable, which is currently assigned but which need to be unassifned
080 * Different variable, which is unassigned and whose initial value is in conflict with the selected value.*/
081 protected double getPenaltyA(Value selectedValue, Value initialValue) {
082 return getPenalty(null, initialValue);
083 }
084
085 /** Case B: initial value is unassigned from a conflicting variable.
086 * @param selectedValue value which is going to be unassigned to its variable
087 * @param assignedValue value currently assigned to a conflicting variable (different from the one of selectedVariable)
088 * @param initialValue initial value of the conflicting variable of assignedValue
089 */
090 protected double getPenaltyB(Value selectedValue, Value assignedValue, Value initialValue) {
091 return getPenalty(assignedValue, initialValue);
092 }
093
094 /** Case C: non-initial value is unassigned from a conflicting variable.
095 * @param selectedValue value which is going to be unassigned to its variable
096 * @param assignedValue value currently assigned to a conflicting variable (different from the one of selectedVariable)
097 * @param initialValue initial value of the conflicting variable of assignedValue
098 */
099 protected double getPenaltyC(Value selectedValue, Value assignedValue, Value initialValue) {
100 return -getPenalty(assignedValue, initialValue);
101 }
102
103 /** Case D: different than initial value is assigned to the varaible
104 * @param selectedValue value which is going to be unassigned to its variable
105 * @param initialValue initial value of the same variable
106 */
107 protected double getPenaltyD(Value selectedValue, Value initialValue) {
108 return getPenalty(selectedValue, initialValue);
109 }
110
111 public double getPerturbationPenalty(Solution solution, Value selectedValue, Collection conflicts) {
112 double penalty = 0;
113 Set violations = (getViolatedInitials()==null?null:getViolatedInitials().getViolatedInitials(selectedValue));
114 if (violations!=null)
115 for (Iterator it1=violations.iterator(); it1.hasNext(); ) {
116 Value aValue = (Value)it1.next();
117 if (aValue.variable().getAssignment()==null)
118 penalty += getPenaltyA(selectedValue,aValue);
119 }
120 for (Iterator it1=conflicts.iterator(); it1.hasNext(); ) {
121 Value conflictValue = (Value)it1.next();
122 Value initialValue = conflictValue.variable().getInitialAssignment();
123 if (initialValue!=null) {
124 if (initialValue.equals(conflictValue))
125 penalty += getPenaltyB(selectedValue, conflictValue, initialValue);
126 else {
127 if (violations==null || !violations.contains(initialValue))
128 penalty += getPenaltyC(selectedValue, conflictValue, initialValue);
129 }
130 }
131 }
132 if (selectedValue.variable().getInitialAssignment()!=null && !selectedValue.equals(selectedValue.variable().getInitialAssignment()))
133 penalty += getPenaltyD(selectedValue, selectedValue.variable().getInitialAssignment());
134 return penalty;
135 }
136
137 public void getInfo(Dictionary info, Solution solution) {
138 info.put("Perturbations: Total penalty", sDoubleFormat.format(getPerturbationPenalty(solution)));
139 }
140
141 }