001    package net.sf.cpsolver.exam.criteria;
002    
003    import java.util.Collection;
004    import java.util.Map;
005    import java.util.Set;
006    
007    import net.sf.cpsolver.exam.model.Exam;
008    import net.sf.cpsolver.exam.model.ExamModel;
009    import net.sf.cpsolver.exam.model.ExamPlacement;
010    import net.sf.cpsolver.ifs.solver.Solver;
011    import net.sf.cpsolver.ifs.util.DataProperties;
012    
013    /**
014     * Front load penalty. I.e., large exam is discouraged to be placed on or after a
015     * certain period.
016     * <br><br>
017     * <b>largeSize</b>: An exam is considered large, if its size is greater or equal to 
018     * this number. Value -1 means all exams are small. It can be set by problem
019     * property Exams.LargeSize, or in the input xml file, property largeSize.
020     * <br><br>
021     * <b>largePeriod</b>: Period index (number of periods multiplied by this number) for front load
022     * criteria for large exams. Can be set by problem property
023     * Exams.LargePeriod, or in the input xml file, property largePeriod.
024     * <br><br>
025     * Weight of the front load criterion, i.e., a weight for assigning a large exam
026     * after large period can be set by problem property Exams.LargeWeight, or
027     * in the input xml file, property largeWeight.
028     * 
029     * <br>
030     * 
031     * @version ExamTT 1.2 (Examination Timetabling)<br>
032     *          Copyright (C) 2008 - 2012 Tomas Muller<br>
033     *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
034     *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
035     * <br>
036     *          This library is free software; you can redistribute it and/or modify
037     *          it under the terms of the GNU Lesser General Public License as
038     *          published by the Free Software Foundation; either version 3 of the
039     *          License, or (at your option) any later version. <br>
040     * <br>
041     *          This library is distributed in the hope that it will be useful, but
042     *          WITHOUT ANY WARRANTY; without even the implied warranty of
043     *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
044     *          Lesser General Public License for more details. <br>
045     * <br>
046     *          You should have received a copy of the GNU Lesser General Public
047     *          License along with this library; if not see
048     *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
049     */
050    public class LargeExamsPenalty extends ExamCriterion {
051        private int iLargeSize = -1;
052        private double iLargePeriod = 0.67;
053        
054        @Override
055        public String getWeightName() {
056            return "Exams.LargeWeight";
057        }
058        
059        @Override
060        public String getXmlWeightName() {
061            return "largeWeight";
062        }
063        
064        @Override
065        public void getXmlParameters(Map<String, String> params) {
066            params.put(getXmlWeightName(), String.valueOf(getWeight()));
067            params.put("largeSize", String.valueOf(getLargeSize()));
068            params.put("largePeriod", String.valueOf(getLargePeriod()));
069        }
070        
071        @Override
072        public void setXmlParameters(Map<String, String> params) {
073            try {
074                setWeight(Double.valueOf(params.get(getXmlWeightName())));
075            } catch (NumberFormatException e) {} catch (NullPointerException e) {}
076            try {
077                setLargeSize(Integer.valueOf(params.get("largeSize")));
078            } catch (NumberFormatException e) {} catch (NullPointerException e) {}
079            try {
080                setLargePeriod(Double.valueOf(params.get("largePeriod")));
081            } catch (NumberFormatException e) {} catch (NullPointerException e) {}
082        }
083        
084        @Override
085        public double getWeightDefault(DataProperties config) {
086            return 1.0;
087        }
088        
089        @Override
090        public boolean init(Solver<Exam, ExamPlacement> solver) {
091            boolean ret = super.init(solver);
092            iLargeSize = solver.getProperties().getPropertyInt("Exams.LargeSize", iLargeSize);
093            iLargePeriod = solver.getProperties().getPropertyDouble("Exams.LargePeriod", iLargePeriod);
094            return ret;
095        }
096        
097        /**
098         * An exam is considered large, if its size is greater or equal to this
099         * large size. Value -1 means all exams are small. Can be set by problem
100         * property Exams.LargeSize, or in the input xml file, property largeSize)
101         **/
102        public int getLargeSize() {
103            return iLargeSize;
104        }
105        
106        /**
107         * An exam is considered large, if its size is greater or equal to this
108         * large size. Value -1 means all exams are small. Can be set by problem
109         * property Exams.LargeSize, or in the input xml file, property largeSize)
110         **/
111        public void setLargeSize(int largeSize) {
112            iLargeSize = largeSize;
113        }
114        
115        /**
116         * Period index (number of periods multiplied by this number) for front load
117         * criteria for large exams. Can be set by problem property
118         * Exams.LargePeriod, or in the input xml file, property largePeriod)
119         **/
120        public double getLargePeriod() {
121            return iLargePeriod;
122        }
123        
124        /**
125         * Period index (number of periods multiplied by this number) for front load
126         * criteria for large exams. Can be set by problem property
127         * Exams.LargePeriod, or in the input xml file, property largePeriod)
128         **/
129        public void setLargePeriod(double largePeriod) {
130            iLargePeriod = largePeriod;
131        }
132    
133        
134        public int getLargePeriodIndex() {
135            return (int) Math.round(((ExamModel)getModel()).getPeriods().size() * iLargePeriod);
136        }
137    
138        @Override
139        public double getValue(ExamPlacement value, Set<ExamPlacement> conflicts) {
140            Exam exam = value.variable();
141            if (getLargeSize() < 0 || exam.getSize() < getLargeSize()) return 0;
142            return (value.getPeriod().getIndex() < getLargePeriodIndex() ? 0 : 1);
143        }
144    
145        @Override
146        public double[] getBounds(Collection<Exam> variables) {
147            double[] bounds = new double[] { 0.0, 0.0 };
148            for (Exam exam : variables) {
149                if (getLargeSize() >= 0 && exam.getSize() >= getLargeSize())
150                    bounds[1] += 1.0;
151            }
152            return bounds;
153        }
154    
155        @Override
156        public String toString() {
157            return (getValue() <= 0.0 ? "" : "LP:" + sDoubleFormat.format(getValue()));
158        }
159    }