001 package net.sf.cpsolver.studentsct.model;
002
003 import java.util.List;
004
005 import net.sf.cpsolver.ifs.model.Variable;
006
007 /**
008 * Representation of a request of a student for a course(s) or a free time. This
009 * can be either {@link CourseRequest} or {@link FreeTimeRequest}. Each request
010 * contains id, priority, weight, and a student. A request can be also marked as
011 * alternative. <br>
012 * <br>
013 * For each student, all non-alternative requests should be satisfied (an
014 * enrollment is assigned to a request). If not, an alternative request can be
015 * assigned instead of a non-alternative course request. In the case when only
016 * one of two requests can be assigned, the one with the lowest priority is
017 * preferred. <br>
018 * <br>
019 *
020 * @version StudentSct 1.2 (Student Sectioning)<br>
021 * Copyright (C) 2007 - 2010 Tomas Muller<br>
022 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
023 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
024 * <br>
025 * This library is free software; you can redistribute it and/or modify
026 * it under the terms of the GNU Lesser General Public License as
027 * published by the Free Software Foundation; either version 3 of the
028 * License, or (at your option) any later version. <br>
029 * <br>
030 * This library is distributed in the hope that it will be useful, but
031 * WITHOUT ANY WARRANTY; without even the implied warranty of
032 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
033 * Lesser General Public License for more details. <br>
034 * <br>
035 * You should have received a copy of the GNU Lesser General Public
036 * License along with this library; if not see
037 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
038 */
039 public abstract class Request extends Variable<Request, Enrollment> {
040 private long iId = -1;
041 private int iPriority = 0;
042 private boolean iAlternative = false;
043 private Student iStudent = null;
044 private double iWeight = 1.0;
045 /** True means that method {@link Request#values()} will cache its results. */
046 public static boolean sCacheValues = false;
047
048 /**
049 * Constructor
050 *
051 * @param id
052 * course/free time request unique id
053 * @param priority
054 * request priority -- if there is a choice, request with lower
055 * priority is more preferred to be assigned
056 * @param alternative
057 * true if the request is alternative (alternative request can be
058 * assigned instead of a non-alternative course requests, if it
059 * is left unassigned)
060 * @param student
061 * student to which this request belongs
062 */
063 public Request(long id, int priority, boolean alternative, Student student) {
064 iId = id;
065 iPriority = priority;
066 iAlternative = alternative;
067 iStudent = student;
068 iStudent.getRequests().add(this);
069 }
070
071 /** Request id */
072 @Override
073 public long getId() {
074 return iId;
075 }
076
077 /**
078 * Request priority -- if there is a choice, request with lower priority is
079 * more preferred to be assigned
080 */
081 public int getPriority() {
082 return iPriority;
083 }
084
085 /** Set request priority */
086 public void setPriority(int priority) {
087 iPriority = priority;
088 }
089
090 /**
091 * True, if the request is alternative (alternative request can be assigned
092 * instead of a non-alternative course requests, if it is left unassigned)
093 */
094 public boolean isAlternative() {
095 return iAlternative;
096 }
097
098 /** Student to which this request belongs */
099 public Student getStudent() {
100 return iStudent;
101 }
102
103 /**
104 * Compare to requests, non-alternative requests go first, otherwise use
105 * priority (a request with lower priority goes first)
106 */
107 @Override
108 public int compareTo(Request r) {
109 if (getStudent().getId() == r.getStudent().getId())
110 return (isAlternative() != r.isAlternative() ? isAlternative() ? 1 : -1 : getPriority() < r.getPriority() ? -1 : 1);
111 else
112 return getStudent().compareTo(r.getStudent());
113 }
114
115 /** Compute available enrollments */
116 public abstract List<Enrollment> computeEnrollments();
117
118 /**
119 * Domain of this variable -- list of available enrollments. Method
120 * {@link Request#computeEnrollments()} is used.
121 */
122 @Override
123 public List<Enrollment> values() {
124 List<Enrollment> values = super.values();
125 if (values != null)
126 return values;
127 values = computeEnrollments();
128 if (sCacheValues)
129 setValues(values);
130 return values;
131 }
132
133 /**
134 * Assign given enrollment to this request. This method also calls
135 * {@link Assignment#assigned(Enrollment)} on for all the assignments of the
136 * enrollment.
137 */
138 @Override
139 public void assign(long iteration, Enrollment enrollment) {
140 super.assign(iteration, enrollment);
141 for (Assignment a : enrollment.getAssignments()) {
142 a.assigned(enrollment);
143 }
144 if (enrollment.getConfig() != null)
145 enrollment.getConfig().assigned(enrollment);
146 if (enrollment.getCourse() != null)
147 enrollment.getCourse().assigned(enrollment);
148 if (enrollment.getReservation() != null)
149 enrollment.getReservation().assigned(enrollment);
150 }
151
152 /**
153 * Unassign currently assigned enrollment from this request. This method
154 * also calls {@link Assignment#unassigned(Enrollment)} on for all the
155 * assignments of the current enrollment.
156 */
157 @Override
158 public void unassign(long iteration) {
159 if (getAssignment() != null) {
160 Enrollment enrollment = getAssignment();
161 for (Assignment a : enrollment.getAssignments()) {
162 a.unassigned(enrollment);
163 }
164 if (enrollment.getConfig() != null)
165 enrollment.getConfig().unassigned(enrollment);
166 if (enrollment.getCourse() != null)
167 enrollment.getCourse().unassigned(enrollment);
168 if (enrollment.getReservation() != null)
169 enrollment.getReservation().unassigned(enrollment);
170 }
171 super.unassign(iteration);
172 }
173
174 /** Get bound, i.e., the value of the best possible enrollment */
175 public abstract double getBound();
176
177 /**
178 * Request weight, set by default to 1.0, defines the amount of space which
179 * will be taken in the section by this request.
180 */
181 public double getWeight() {
182 return iWeight;
183 }
184
185 /**
186 * Set request weight. It defines the amount of space which will be taken in
187 * the section by this request.
188 */
189 public void setWeight(double weight) {
190 iWeight = weight;
191 }
192
193 /** Return true if request is assigned. */
194 public boolean isAssigned() {
195 return getAssignment() != null;
196 }
197
198 @Override
199 public int hashCode() {
200 return (int) (iId ^ (iId >>> 32) ^ getStudent().getId() ^ (getStudent().getId() >>> 32));
201 }
202
203 @Override
204 public boolean equals(Object o) {
205 if (o == null || !(o instanceof Request)) return false;
206 return getId() == ((Request)o).getId() && getStudent().getId() == ((Request)o).getStudent().getId();
207 }
208
209 }