001 package net.sf.cpsolver.exam.criteria;
002
003 import java.util.Map;
004 import java.util.Set;
005
006 import net.sf.cpsolver.exam.model.Exam;
007 import net.sf.cpsolver.exam.model.ExamModel;
008 import net.sf.cpsolver.exam.model.ExamPeriod;
009 import net.sf.cpsolver.exam.model.ExamPlacement;
010 import net.sf.cpsolver.exam.model.ExamStudent;
011 import net.sf.cpsolver.ifs.solver.Solver;
012 import net.sf.cpsolver.ifs.util.DataProperties;
013
014 /**
015 * Number of back-to-back distance student conflicts. I.e., number of
016 * cases when an exam is attended by a student that attends some other
017 * exam at the previous {@link ExamPeriod#prev()} or following
018 * {@link ExamPeriod#next()} period and the distance
019 * {@link ExamPlacement#getDistanceInMeters(ExamPlacement)} between these two exams
020 * is greater than {@link ExamModel#getBackToBackDistance()}. Distance
021 * back-to-back conflicts are only considered between consecutive periods
022 * that are of the same day.
023 * <br><br>
024 * Distance back-to-back student conflict weight can be set by problem
025 * property Exams.DistanceBackToBackConflictWeight, or in the
026 * input xml file, property distanceBackToBackConflictWeight.
027 *
028 * <br>
029 *
030 * @version ExamTT 1.2 (Examination Timetabling)<br>
031 * Copyright (C) 2008 - 2012 Tomas Muller<br>
032 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
033 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
034 * <br>
035 * This library is free software; you can redistribute it and/or modify
036 * it under the terms of the GNU Lesser General Public License as
037 * published by the Free Software Foundation; either version 3 of the
038 * License, or (at your option) any later version. <br>
039 * <br>
040 * This library is distributed in the hope that it will be useful, but
041 * WITHOUT ANY WARRANTY; without even the implied warranty of
042 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
043 * Lesser General Public License for more details. <br>
044 * <br>
045 * You should have received a copy of the GNU Lesser General Public
046 * License along with this library; if not see
047 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
048 */
049 public class StudentDistanceBackToBackConflicts extends ExamCriterion {
050 private double iBackToBackDistance = -1;
051
052 @Override
053 public boolean init(Solver<Exam, ExamPlacement> solver) {
054 boolean ret = super.init(solver);
055 iBackToBackDistance = solver.getProperties().getPropertyDouble("Exams.BackToBackDistance", iBackToBackDistance);
056 return ret;
057 }
058
059 @Override
060 public String getWeightName() {
061 return "Exams.DistanceBackToBackConflictWeight";
062 }
063
064 @Override
065 public String getXmlWeightName() {
066 return "distanceBackToBackConflictWeight";
067 }
068
069 @Override
070 public double getWeightDefault(DataProperties config) {
071 return 25.0;
072 }
073
074 /**
075 * Back-to-back distance. Can be set by
076 * problem property Exams.BackToBackDistance, or in the input xml file,
077 * property backToBackDistance)
078 */
079 public double getBackToBackDistance() {
080 return iBackToBackDistance;
081 }
082
083 /**
084 * Back-to-back distance. Can be set by
085 * problem property Exams.BackToBackDistance, or in the input xml file,
086 * property backToBackDistance)
087 */
088 public void setBackToBackDistance(double backToBackDistance) {
089 iBackToBackDistance = backToBackDistance;
090 }
091
092 @Override
093 public void getXmlParameters(Map<String, String> params) {
094 params.put(getXmlWeightName(), String.valueOf(getWeight()));
095 params.put("backToBackDistance", String.valueOf(getBackToBackDistance()));
096 }
097
098 @Override
099 public void setXmlParameters(Map<String, String> params) {
100 try {
101 setWeight(Double.valueOf(params.get(getXmlWeightName())));
102 } catch (NumberFormatException e) {} catch (NullPointerException e) {}
103 try {
104 setBackToBackDistance(Double.valueOf(params.get("backToBackDistance")));
105 } catch (NumberFormatException e) {} catch (NullPointerException e) {}
106 }
107
108 @Override
109 public double getValue(ExamPlacement value, Set<ExamPlacement> conflicts) {
110 Exam exam = value.variable();
111 if (getBackToBackDistance() < 0) return 0;
112 int penalty = 0;
113 for (ExamStudent s : exam.getStudents()) {
114 if (value.getPeriod().prev() != null) {
115 if (value.getPeriod().prev().getDay() == value.getPeriod().getDay()) {
116 for (Exam x : s.getExams(value.getPeriod().prev())) {
117 if (x.equals(exam))
118 continue;
119 if (value.getDistanceInMeters(x.getAssignment()) > getBackToBackDistance())
120 penalty++;
121 }
122 }
123 }
124 if (value.getPeriod().next() != null) {
125 if (value.getPeriod().next().getDay() == value.getPeriod().getDay()) {
126 for (Exam x : s.getExams(value.getPeriod().next())) {
127 if (x.equals(exam))
128 continue;
129 if (value.getDistanceInMeters(x.getAssignment()) > getBackToBackDistance())
130 penalty++;
131 }
132 }
133 }
134 }
135 return penalty;
136 }
137
138 @Override
139 public String getName() {
140 return "Distance Back-To-Back Conflicts";
141 }
142
143 @Override
144 public void getInfo(Map<String, String> info) {
145 if (getBackToBackDistance() >= 0.0 && getValue() != 0.0)
146 info.put(getName(), sDoubleFormat.format(getValue()));
147 }
148
149 @Override
150 public String toString() {
151 return (getValue() <= 0.0 ? "" : "BTBd:" + sDoubleFormat.format(getValue()));
152 }
153
154 @Override
155 public boolean isPeriodCriterion() { return false; }
156 }