001package net.sf.cpsolver.studentsct; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.Iterator; 006import java.util.List; 007import java.util.Set; 008 009import net.sf.cpsolver.ifs.model.Model; 010import net.sf.cpsolver.ifs.model.Neighbour; 011import net.sf.cpsolver.ifs.solution.Solution; 012import net.sf.cpsolver.ifs.util.DataProperties; 013import net.sf.cpsolver.studentsct.constraint.SectionLimit; 014import net.sf.cpsolver.studentsct.constraint.StudentConflict; 015import net.sf.cpsolver.studentsct.heuristics.selection.BranchBoundSelection; 016import net.sf.cpsolver.studentsct.model.Course; 017import net.sf.cpsolver.studentsct.model.CourseRequest; 018import net.sf.cpsolver.studentsct.model.Enrollment; 019import net.sf.cpsolver.studentsct.model.Request; 020import net.sf.cpsolver.studentsct.model.Student; 021 022/** 023 * Online student sectioning test (using {@link BranchBoundSelection} 024 * selection). This class is used by the online student sectioning mock-up page. <br> 025 * <br> 026 * Usage: <code> 027 * StudentSctBBTest test = new StudentSctBBTest(student); //student already has all his/her requests defined<br> 028 * Solution sectioningSolution = test.getSolution(); //solution contains only one student (the given one) with his/her schedule<br> 029 * Vector sectioningMessages = test.getMessages(); //sectioning messages (to be printed in the GUI). 030 * </code> 031 * 032 * <br> 033 * <br> 034 * 035 * @version StudentSct 1.2 (Student Sectioning)<br> 036 * Copyright (C) 2007 - 2010 Tomáš Müller<br> 037 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 038 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 039 * <br> 040 * This library is free software; you can redistribute it and/or modify 041 * it under the terms of the GNU Lesser General Public License as 042 * published by the Free Software Foundation; either version 3 of the 043 * License, or (at your option) any later version. <br> 044 * <br> 045 * This library is distributed in the hope that it will be useful, but 046 * WITHOUT ANY WARRANTY; without even the implied warranty of 047 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 048 * Lesser General Public License for more details. <br> 049 * <br> 050 * You should have received a copy of the GNU Lesser General Public 051 * License along with this library; if not see 052 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 053 */ 054public class StudentSctBBTest extends Model<Request, Enrollment> { 055 private Student iStudent = null; 056 private Solution<Request, Enrollment> iSolution = null; 057 private long iTime; 058 private boolean iTimeoutReached = false; 059 060 /** 061 * Constructor 062 * 063 * @param student 064 * a student to be sectioned 065 */ 066 public StudentSctBBTest(Student student) { 067 iStudent = student; 068 for (Request request : iStudent.getRequests()) 069 addVariable(request); 070 addGlobalConstraint(new SectionLimit(new DataProperties())); 071 addConstraint(new StudentConflict(student)); 072 } 073 074 /** Return the given student */ 075 public Student getStudent() { 076 return iStudent; 077 } 078 079 /** 080 * Compute and return the sectioning solution. It contains only the given 081 * student with his/her schedule 082 */ 083 public Solution<Request, Enrollment> getSolution() { 084 if (iSolution == null) { 085 iSolution = new Solution<Request, Enrollment>(this); 086 BranchBoundSelection.Selection selection = new BranchBoundSelection(new DataProperties()) 087 .getSelection(getStudent()); 088 Neighbour<Request, Enrollment> neighbour = selection.select(); 089 if (neighbour != null) 090 neighbour.assign(0); 091 iTime = selection.getTime(); 092 iTimeoutReached = selection.isTimeoutReached(); 093 } 094 return iSolution; 095 } 096 097 /** 098 * Return a list of messages ({@link Message} objects) from the sectioning 099 * of the given student 100 */ 101 public List<Message> getMessages() { 102 List<Message> ret = new ArrayList<Message>(); 103 ret.add(new Message(Message.sMsgLevelInfo, null, "<li>Solution found in " + iTime + " ms.")); 104 if (iTimeoutReached) 105 ret.add(new Message(Message.sMsgLevelInfo, null, 106 "<li>Time out reached, solution optimality can not be guaranteed.")); 107 for (Request request : getStudent().getRequests()) { 108 if (!request.isAlternative() && request.getAssignment() == null) { 109 ret 110 .add(new Message(Message.sMsgLevelWarn, request, 111 "<li>Unable to enroll to " 112 + request 113 + ", " 114 + (request instanceof CourseRequest ? ((CourseRequest) request).getCourses() 115 .size() == 1 ? "course is" : "courses are" : "time is") 116 + " not available.")); 117 Collection<Enrollment> values = (request instanceof CourseRequest ? (Collection<Enrollment>) ((CourseRequest) request) 118 .getAvaiableEnrollmentsSkipSameTime() 119 : request.computeEnrollments()); 120 for (Iterator<Enrollment> f = values.iterator(); f.hasNext();) { 121 Enrollment enrollment = f.next(); 122 Set<Enrollment> conf = conflictValues(enrollment); 123 if (conf != null && !conf.isEmpty()) { 124 Enrollment conflict = conf.iterator().next(); 125 if (conflict.equals(enrollment)) 126 ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of " 127 + enrollment.getName().replaceAll("\n", "<br> ") 128 + "<br> is not available.")); 129 else 130 ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of " 131 + enrollment.getName().replaceAll("\n", "<br> ") 132 + "<br> conflicts with " 133 + conflict.getName().replaceAll("\n", "<br> ") + "</ul>")); 134 } 135 } 136 } 137 if (request instanceof CourseRequest && request.getAssignment() != null) { 138 CourseRequest courseRequest = (CourseRequest) request; 139 Enrollment enrollment = request.getAssignment(); 140 List<Enrollment> selectedEnrollments = courseRequest.getSelectedEnrollments(false); 141 if (selectedEnrollments != null && !selectedEnrollments.isEmpty() 142 && !selectedEnrollments.contains(enrollment)) { 143 Course course = (courseRequest.getSelectedChoices().iterator().next()).getOffering().getCourse( 144 getStudent()); 145 Enrollment selected = selectedEnrollments.get(0); 146 Set<Enrollment> conf = conflictValues(selected); 147 if (conf != null && !conf.isEmpty()) { 148 ret.add(new Message(Message.sMsgLevelWarn, request, 149 "<li>Unable to enroll selected enrollment for " + course.getName() + ", seleted " 150 + (courseRequest.getSelectedChoices().size() == 1 ? "class is" : "classes are") 151 + " conflicting with other choices.")); 152 Enrollment conflict = conf.iterator().next(); 153 if (conflict.equals(selected)) 154 ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of " 155 + selected.getName().replaceAll("\n", "<br> ") 156 + "<br> is not available.")); 157 else 158 ret.add(new Message(Message.sMsgLevelInfo, request, "<ul>Assignment of " 159 + selected.getName().replaceAll("\n", "<br> ") 160 + "<br> conflicts with " 161 + conflict.getName().replaceAll("\n", "<br> ") + "</ul>")); 162 } else { 163 ret.add(new Message(Message.sMsgLevelWarn, request, 164 "<li>Unable to enroll selected enrollment for " + course.getName() + ".")); 165 } 166 } 167 } 168 } 169 return ret; 170 } 171 172 /** Sectioning message */ 173 public static class Message { 174 /** Message levels */ 175 public static String[] sMsgLevels = { "INFO", "WARN", "ERROR" }; 176 /** Info message level */ 177 public static int sMsgLevelInfo = 0; 178 /** Warning message level */ 179 public static int sMsgLevelWarn = 1; 180 /** Error message level */ 181 public static int sMsgLevelError = 2; 182 183 private int iLevel; 184 private Request iRequest; 185 private String iMessage; 186 187 /** 188 * Constructor 189 * 190 * @param level 191 * message level (one of 192 * {@link StudentSctBBTest.Message#sMsgLevelInfo}, 193 * {@link StudentSctBBTest.Message#sMsgLevelWarn}, and 194 * {@link StudentSctBBTest.Message#sMsgLevelError}) 195 * @param request 196 * related course / free time request 197 * @param message 198 * a message 199 */ 200 public Message(int level, Request request, String message) { 201 iLevel = level; 202 iRequest = request; 203 iMessage = message; 204 } 205 206 /** 207 * Message level (one of {@link StudentSctBBTest.Message#sMsgLevelInfo}, 208 * {@link StudentSctBBTest.Message#sMsgLevelWarn}, and 209 * {@link StudentSctBBTest.Message#sMsgLevelError}) 210 */ 211 public int getLevel() { 212 return iLevel; 213 } 214 215 /** Message level as string */ 216 public String getLevelString() { 217 return sMsgLevels[iLevel]; 218 } 219 220 /** Related course / free time request */ 221 public Request getRequest() { 222 return iRequest; 223 } 224 225 /** Message */ 226 public String getMessage() { 227 return iMessage; 228 } 229 230 /** String representation (message level: message) */ 231 @Override 232 public String toString() { 233 return getLevelString() + ":" + getMessage(); 234 } 235 } 236}