001 package ttsolver.heuristics;
002
003 import ifs.util.*;
004 import java.util.*;
005
006 /**
007 * General hierarchical selection.
008 * <br><br>
009 * We have implemented a hierarchical handling of the value selection criteria. There are three levels of comparison. At
010 * each level a weighted sum of the criteria described below is computed. Only solutions with the smallest sum are
011 * considered in the next level. The weights express how quickly a complete solution should be found. Only hard
012 * constraints are satisfied in the first level sum. Distance from the initial solution (MPP), and a weighting of
013 * major preferences (including time, classroom requirements and student conflicts), are considered in the next level.
014 * In the third level, other minor criteria are considered. In general, a criterion can be used in more than one level,
015 * e.g., with different weights.
016 * <br><br>
017 * The above sums order the values lexicographically: the best value having the smallest first level sum, the smallest
018 * second level sum among values with the smallest first level sum, and the smallest third level sum among these values.
019 * As mentioned above, this allows diversification between the importance of individual criteria.
020 * <br><br>
021 * Furthermore, the value selection heuristics also support some limits (e.g., that all values with a first level sum
022 * smaller than a given percentage Pth above the best value [typically 10%] will go to the second level comparison
023 * and so on). This allows for the continued feasibility of a value near to the best that may yet be much better in the
024 * next level of comparison. If there is more than one solution after these three levels of comparison, one is
025 * selected randomly. This approach helped us to significantly improve the quality of the resultant solutions.
026 * <br><br>
027 * In general, there can be more than three levels of these weighted sums, however three of them seem to be sufficient for
028 * spreading weights of various criteria for our problem.
029 *
030 * @see PlacementSelection
031 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
032 * @version 1.0
033 */
034 public class HeuristicSelector {
035 private double[] iThreshKoef;
036 private Vector iElements = new FastVector();
037 private double iBestValueZero = 0.0;
038
039 /** Constructor
040 * @param threshKoef limit for each level, e.g., new double[] {0.1, 0.1, 0.1} for three level selection with 10% limit on each level
041 */
042 public HeuristicSelector(double[] threshKoef) {
043 iThreshKoef = threshKoef;
044 }
045
046 /** Adds an object to selection
047 * @param values weighted sum for each level
048 * @param object object to be returned if selected
049 * @return true if added (it is not added if it is obvious that it cannot be selected)
050 */
051 public boolean add(double[] values, Object object) {
052 if (iElements.isEmpty() || values[0] < iBestValueZero) {
053 iBestValueZero = values[0];
054 iElements.addElement(new Element(values, object));
055 return true;
056 } else if (values[0] <= iBestValueZero * (iBestValueZero<0.0?1.0-iThreshKoef[0]:1.0+iThreshKoef[0])) {
057 iElements.addElement(new Element(values, object));
058 return true;
059 }
060 return false;
061 }
062
063 /** Do the selection.
064 * @return inserted objects which met the criteria
065 */
066 public Vector selection() {
067 Vector selection = iElements;
068 double bestValue = iBestValueZero;
069 for (int level=0; level<iThreshKoef.length; level++) {
070 Vector x = new FastVector(selection.size());
071 double threshold = (bestValue<0.0?1.0-iThreshKoef[level]:1.0+iThreshKoef[level]) * bestValue;
072 //System.out.println("B"+(level+1)+": "+bestValue);
073 //System.out.println("T"+(level+1)+": "+threshold);
074 double nextBestValue = 0.0;
075 boolean lastLevel = (level+1==iThreshKoef.length);
076 for (Enumeration e=selection.elements();e.hasMoreElements();) {
077 Element element = (Element)e.nextElement();
078 if (element.getValue(level)<=threshold) {
079 if (!lastLevel && (x.isEmpty() || element.getValue(level+1)<nextBestValue))
080 nextBestValue=element.getValue(level+1);
081 x.addElement(element);
082 }
083 }
084 selection = x;
085 bestValue = nextBestValue;
086 }
087 return selection;
088 }
089
090 /** An element in heuristical selection*/
091 public class Element {
092 private double[] iValues;
093 private Object iObject;
094 private Element(double[] values, Object object) {
095 iValues = values; iObject = object;
096 }
097 /** weighted sum in each level*/
098 public double[] getValues() { return iValues; }
099 /** weighted sum in the given level*/
100 public double getValue(int level) { return iValues[level]; }
101 /** given object */
102 public Object getObject() { return iObject; }
103 public String toString() {
104 StringBuffer sb = new StringBuffer();
105 for (int i=0;i<iValues.length;i++) sb.append(i==0?"":",").append(iValues[i]);
106 return "["+sb+"]:"+iObject;
107 }
108 }
109 }