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