001package org.cpsolver.studentsct.weights; 002 003import java.text.DecimalFormat; 004import java.util.ArrayList; 005import java.util.BitSet; 006import java.util.HashSet; 007import java.util.Set; 008 009import org.cpsolver.coursett.model.Placement; 010import org.cpsolver.coursett.model.RoomLocation; 011import org.cpsolver.coursett.model.TimeLocation; 012import org.cpsolver.ifs.assignment.Assignment; 013import org.cpsolver.ifs.assignment.DefaultSingleAssignment; 014import org.cpsolver.ifs.solution.Solution; 015import org.cpsolver.ifs.util.DataProperties; 016import org.cpsolver.ifs.util.ToolBox; 017import org.cpsolver.studentsct.StudentSectioningModel; 018import org.cpsolver.studentsct.extension.DistanceConflict; 019import org.cpsolver.studentsct.extension.TimeOverlapsCounter; 020import org.cpsolver.studentsct.model.Choice; 021import org.cpsolver.studentsct.model.Config; 022import org.cpsolver.studentsct.model.Course; 023import org.cpsolver.studentsct.model.CourseRequest; 024import org.cpsolver.studentsct.model.Enrollment; 025import org.cpsolver.studentsct.model.Instructor; 026import org.cpsolver.studentsct.model.Offering; 027import org.cpsolver.studentsct.model.Request; 028import org.cpsolver.studentsct.model.SctAssignment; 029import org.cpsolver.studentsct.model.Section; 030import org.cpsolver.studentsct.model.Student; 031import org.cpsolver.studentsct.model.Subpart; 032 033 034/** 035 * Student weight is spread equally among student's course requests. Only alternatives have lower weight. 036 * The rest is inherited from {@link PriorityStudentWeights}. 037 * 038 * @author Tomáš Müller 039 * @version StudentSct 1.3 (Student Sectioning)<br> 040 * Copyright (C) 2007 - 2014 Tomáš Müller<br> 041 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 042 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 043 * <br> 044 * This library is free software; you can redistribute it and/or modify 045 * it under the terms of the GNU Lesser General Public License as 046 * published by the Free Software Foundation; either version 3 of the 047 * License, or (at your option) any later version. <br> 048 * <br> 049 * This library is distributed in the hope that it will be useful, but 050 * WITHOUT ANY WARRANTY; without even the implied warranty of 051 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 052 * Lesser General Public License for more details. <br> 053 * <br> 054 * You should have received a copy of the GNU Lesser General Public 055 * License along with this library; if not see 056 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 057 */ 058 059public class EqualStudentWeights extends PriorityStudentWeights { 060 061 public EqualStudentWeights(DataProperties config) { 062 super(config); 063 } 064 065 @Override 066 public double getWeight(Request request) { 067 if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) { 068 double weight = iProjectedStudentWeight; 069 if (request.isAlternative()) 070 weight *= iAlternativeRequestFactor; 071 return weight; 072 } 073 double weight = 1.0 / request.getStudent().nrRequests(); 074 if (request.isAlternative()) 075 weight *= iAlternativeRequestFactor; 076 return round(weight); 077 } 078 079 @Override 080 public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) { 081 if (currentSolution.getBestInfo() == null) return true; 082 if (iMPP) return super.isBetterThanBestSolution(currentSolution); 083 int unassigned = currentSolution.getModel().nrUnassignedVariables(currentSolution.getAssignment()); 084 if (currentSolution.getModel().getBestUnassignedVariables() != unassigned) 085 return currentSolution.getModel().getBestUnassignedVariables() > unassigned; 086 return ((StudentSectioningModel)currentSolution.getModel()).getTotalValue(currentSolution.getAssignment(), iPreciseComparison) < currentSolution.getBestValue(); 087 } 088 089 @Override 090 public boolean isFreeTimeAllowOverlaps() { 091 return true; 092 } 093 094 /** 095 * Test case -- run to see the weights for a few courses 096 * @param args program arguments 097 */ 098 public static void main(String[] args) { 099 EqualStudentWeights pw = new EqualStudentWeights(new DataProperties()); 100 DecimalFormat df = new DecimalFormat("0.0000"); 101 Student s = new Student(0l); 102 new CourseRequest(1l, 0, false, s, ToolBox.toList( 103 new Course(1, "A", "1", new Offering(0, "A")), 104 new Course(1, "A", "2", new Offering(0, "A")), 105 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 106 new CourseRequest(2l, 1, false, s, ToolBox.toList( 107 new Course(1, "B", "1", new Offering(0, "B")), 108 new Course(1, "B", "2", new Offering(0, "B")), 109 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 110 new CourseRequest(3l, 2, false, s, ToolBox.toList( 111 new Course(1, "C", "1", new Offering(0, "C")), 112 new Course(1, "C", "2", new Offering(0, "C")), 113 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 114 new CourseRequest(5l, 4, false, s, ToolBox.toList( 115 new Course(1, "E", "1", new Offering(0, "E")), 116 new Course(1, "E", "2", new Offering(0, "E")), 117 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 118 new CourseRequest(6l, 5, true, s, ToolBox.toList( 119 new Course(1, "F", "1", new Offering(0, "F")), 120 new Course(1, "F", "2", new Offering(0, "F")), 121 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 122 new CourseRequest(7l, 6, true, s, ToolBox.toList( 123 new Course(1, "G", "1", new Offering(0, "G")), 124 new Course(1, "G", "2", new Offering(0, "G")), 125 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 126 127 Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>(); 128 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 129 for (Request r: s.getRequests()) { 130 CourseRequest cr = (CourseRequest)r; 131 double[] w = new double[] {0.0, 0.0, 0.0}; 132 for (int i = 0; i < cr.getCourses().size(); i++) { 133 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 134 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 135 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 136 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 137 w[i] = pw.getWeight(assignment, e, null, null); 138 } 139 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 140 } 141 142 System.out.println("With one distance conflict:"); 143 for (Request r: s.getRequests()) { 144 CourseRequest cr = (CourseRequest)r; 145 double[] w = new double[] {0.0, 0.0, 0.0}; 146 for (int i = 0; i < cr.getCourses().size(); i++) { 147 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 148 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 149 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 150 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 151 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 152 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 153 w[i] = pw.getWeight(assignment, e, dc, null); 154 } 155 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 156 } 157 158 System.out.println("With two distance conflicts:"); 159 for (Request r: s.getRequests()) { 160 CourseRequest cr = (CourseRequest)r; 161 double[] w = new double[] {0.0, 0.0, 0.0}; 162 for (int i = 0; i < cr.getCourses().size(); i++) { 163 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 164 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 165 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 166 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 167 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 168 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 169 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 170 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null))); 171 w[i] = pw.getWeight(assignment, e, dc, null); 172 } 173 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 174 } 175 176 System.out.println("With 25% time overlapping conflict:"); 177 for (Request r: s.getRequests()) { 178 CourseRequest cr = (CourseRequest)r; 179 double[] w = new double[] {0.0, 0.0, 0.0}; 180 for (int i = 0; i < cr.getCourses().size(); i++) { 181 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 182 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 183 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 184 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 185 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 186 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 187 w[i] = pw.getWeight(assignment, e, null, toc); 188 } 189 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 190 } 191 192 System.out.println("Disbalanced sections (by 2 / 10 students):"); 193 for (Request r: s.getRequests()) { 194 CourseRequest cr = (CourseRequest)r; 195 double[] w = new double[] {0.0, 0.0, 0.0}; 196 for (int i = 0; i < cr.getCourses().size(); i++) { 197 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 198 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 199 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 200 Section a = new Section(0, 10, "x", x, p, null); 201 new Section(1, 10, "y", x, p, null); 202 sections.add(a); 203 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 204 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 205 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 206 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 207 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 208 w[i] = pw.getWeight(assignment, e, null, null); 209 } 210 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 211 } 212 213 System.out.println("Same sections:"); 214 pw.iMPP = true; 215 for (Request r: s.getRequests()) { 216 CourseRequest cr = (CourseRequest)r; 217 double[] w = new double[] {0.0, 0.0, 0.0}; 218 double dif = 0; 219 for (int i = 0; i < cr.getCourses().size(); i++) { 220 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 221 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 222 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 223 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 224 cr.setInitialAssignment(new Enrollment(cr, i, cfg, sections, assignment)); 225 w[i] = pw.getWeight(assignment, e, null, null); 226 dif = pw.getDifference(e); 227 } 228 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 229 } 230 231 System.out.println("Same choice sections:"); 232 pw.iMPP = true; 233 for (Request r: s.getRequests()) { 234 CourseRequest cr = (CourseRequest)r; 235 double[] w = new double[] {0.0, 0.0, 0.0}; 236 double dif = 0; 237 for (int i = 0; i < cr.getCourses().size(); i++) { 238 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 239 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 240 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 241 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 242 Set<SctAssignment> other = new HashSet<SctAssignment>(); 243 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 244 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 245 w[i] = pw.getWeight(assignment, e, null, null); 246 dif = pw.getDifference(e); 247 } 248 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 249 } 250 251 System.out.println("Same time sections:"); 252 for (Request r: s.getRequests()) { 253 CourseRequest cr = (CourseRequest)r; 254 double dif = 0; 255 double[] w = new double[] {0.0, 0.0, 0.0}; 256 for (int i = 0; i < cr.getCourses().size(); i++) { 257 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 258 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 259 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 260 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 261 Set<SctAssignment> other = new HashSet<SctAssignment>(); 262 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1, null, "Josef Novak", null))); 263 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 264 w[i] = pw.getWeight(assignment, e, null, null); 265 dif = pw.getDifference(e); 266 } 267 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 268 } 269 270 System.out.println("Same configuration sections:"); 271 for (Request r: s.getRequests()) { 272 CourseRequest cr = (CourseRequest)r; 273 double[] w = new double[] {0.0, 0.0, 0.0}; 274 double dif = 0; 275 for (int i = 0; i < cr.getCourses().size(); i++) { 276 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 277 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 278 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 279 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 280 cr.getSelectedChoices().add(new Choice(cfg)); 281 cr.setInitialAssignment(null); 282 w[i] = pw.getWeight(assignment, e, null, null); 283 dif = pw.getDifference(e); 284 } 285 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 286 } 287 288 System.out.println("Different time sections:"); 289 Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 290 for (Request r: s.getRequests()) { 291 CourseRequest cr = (CourseRequest)r; 292 double[] w = new double[] {0.0, 0.0, 0.0}; 293 double dif = 0; 294 for (int i = 0; i < cr.getCourses().size(); i++) { 295 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 296 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 297 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 298 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 299 Set<SctAssignment> other = new HashSet<SctAssignment>(); 300 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null)); 301 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 302 w[i] = pw.getWeight(assignment, e, null, null); 303 dif = pw.getDifference(e); 304 } 305 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 306 } 307 308 System.out.println("Two sections, one same choice, one same time:"); 309 for (Request r: s.getRequests()) { 310 CourseRequest cr = (CourseRequest)r; 311 double[] w = new double[] {0.0, 0.0, 0.0}; 312 double dif = 0; 313 for (int i = 0; i < cr.getCourses().size(); i++) { 314 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 315 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 316 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 317 sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null)); 318 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 319 Set<SctAssignment> other = new HashSet<SctAssignment>(); 320 other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 321 other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1, null, "Josef Novak", null))); 322 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 323 w[i] = pw.getWeight(assignment, e, null, null); 324 dif = pw.getDifference(e); 325 } 326 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 327 } 328 } 329}