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