001 package net.sf.cpsolver.studentsct.constraint; 002 003 import java.util.Enumeration; 004 import java.util.Set; 005 import java.util.Vector; 006 007 import net.sf.cpsolver.ifs.model.Constraint; 008 import net.sf.cpsolver.ifs.model.Value; 009 import net.sf.cpsolver.ifs.util.ToolBox; 010 import net.sf.cpsolver.studentsct.model.CourseRequest; 011 import net.sf.cpsolver.studentsct.model.Enrollment; 012 import net.sf.cpsolver.studentsct.model.Student; 013 014 /** 015 * Abstract reservation constraint. This constraint allow some section, courses, and other 016 * parts to be reserved to particular group of students. A reservation can be unlimited 017 * (any number of students of that particular group can attend a course, section, etc.) or 018 * with a limit (only given number of seats is reserved to the students of the particular 019 * group). 020 * 021 * <br><br> 022 * 023 * @version 024 * StudentSct 1.1 (Student Sectioning)<br> 025 * Copyright (C) 2007 Tomáš Müller<br> 026 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 027 * Lazenska 391, 76314 Zlin, Czech Republic<br> 028 * <br> 029 * This library is free software; you can redistribute it and/or 030 * modify it under the terms of the GNU Lesser General Public 031 * License as published by the Free Software Foundation; either 032 * version 2.1 of the License, or (at your option) any later version. 033 * <br><br> 034 * This library is distributed in the hope that it will be useful, 035 * but WITHOUT ANY WARRANTY; without even the implied warranty of 036 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 037 * Lesser General Public License for more details. 038 * <br><br> 039 * You should have received a copy of the GNU Lesser General Public 040 * License along with this library; if not, write to the Free Software 041 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 042 */ 043 public abstract class Reservation extends Constraint { 044 /** Student cannot be enrolled */ 045 public static int CAN_ENROLL_NO = 0; 046 /** Student can be enrolled */ 047 public static int CAN_ENROLL_YES = 1; 048 /** Student can be enrolled, however, some other student has to dropped out of the section, course, etc. */ 049 public static int CAN_ENROLL_INSTEAD = 2; 050 051 /** 052 * Check, whether a student can be enrolled into the given section, course, etc. 053 * @param student given student 054 * @return {@link Reservation#CAN_ENROLL_YES}, {@link Reservation#CAN_ENROLL_NO}, or {@link Reservation#CAN_ENROLL_INSTEAD} 055 */ 056 public abstract int canEnroll(Student student); 057 058 /** 059 * Check whether the given student can be enrolled instead of another student 060 * @param student student that is to be enrolled in the particular course, section, etc. 061 * @param insteadOfStudent student, that is currently enrolled, which is going to be 062 * bumped out of the course, section, etc. in order to enroll given studen 063 * @return true, if the move is permitted 064 */ 065 public abstract boolean canEnrollInstead(Student student, Student insteadOfStudent); 066 067 /** 068 * Check whether the reservation is applicable to the given enrollment. 069 * This means that the given enrollment contains the particular section, course, etc. 070 * @param enrollment enrollment of a student that is being considered 071 * @return true, if the reservation applies to the enrollment 072 */ 073 public abstract boolean isApplicable(Enrollment enrollment); 074 075 /** 076 * Implementation of the constraint primitives. 077 * See {@link Constraint#computeConflicts(Value, Set)} for more details. 078 */ 079 public void computeConflicts(Value value, Set conflicts) { 080 Enrollment enrollment = (Enrollment)value; 081 082 if (!isApplicable(enrollment)) return; 083 084 int ce = canEnroll(enrollment.getStudent()); 085 086 if (ce==CAN_ENROLL_YES) return; 087 088 if (ce==CAN_ENROLL_NO) { 089 // Unable to bump out some other student 090 conflicts.add(enrollment); 091 return; 092 } 093 094 // Try other bump out some other student 095 Vector conflictEnrollments = null; 096 double conflictValue = 0; 097 for (Enumeration e=assignedVariables().elements();e.hasMoreElements();) { 098 CourseRequest request = (CourseRequest) e.nextElement(); 099 if (canEnrollInstead(enrollment.getStudent(),request.getStudent())) { 100 if (conflictEnrollments==null || conflictValue>enrollment.toDouble()) { 101 if (conflictEnrollments==null) 102 conflictEnrollments = new Vector(); 103 else 104 conflictEnrollments.clear(); 105 conflictEnrollments.add(request.getAssignment()); 106 conflictValue = request.getAssignment().toDouble(); 107 } 108 } 109 } 110 if (conflictEnrollments!=null && !conflictEnrollments.isEmpty()) { 111 conflicts.add(ToolBox.random(conflictEnrollments)); 112 return; 113 } 114 115 // Unable to bump out some other student 116 conflicts.add(enrollment); 117 } 118 119 /** 120 * Implementation of the constraint primitives. 121 * See {@link Constraint#inConflict(Value)} for more details. 122 */ 123 public boolean inConflict(Value value) { 124 Enrollment enrollment = (Enrollment)value; 125 126 if (!isApplicable(enrollment)) return false; 127 128 return canEnroll(enrollment.getStudent())!=CAN_ENROLL_YES; 129 } 130 131 }