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.Config; 020import org.cpsolver.studentsct.model.Course; 021import org.cpsolver.studentsct.model.CourseRequest; 022import org.cpsolver.studentsct.model.Enrollment; 023import org.cpsolver.studentsct.model.Offering; 024import org.cpsolver.studentsct.model.Request; 025import org.cpsolver.studentsct.model.SctAssignment; 026import org.cpsolver.studentsct.model.Section; 027import org.cpsolver.studentsct.model.Student; 028import org.cpsolver.studentsct.model.Subpart; 029 030 031/** 032 * Student weight is spread equally among student's course requests. Only alternatives have lower weight. 033 * The rest is inherited from {@link PriorityStudentWeights}. 034 * 035 * @version StudentSct 1.3 (Student Sectioning)<br> 036 * Copyright (C) 2007 - 2014 Tomas Muller<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 */ 054 055public class EqualStudentWeights extends PriorityStudentWeights { 056 057 public EqualStudentWeights(DataProperties config) { 058 super(config); 059 } 060 061 @Override 062 public double getWeight(Request request) { 063 if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) { 064 double weight = iProjectedStudentWeight; 065 if (request.isAlternative()) 066 weight *= iAlternativeRequestFactor; 067 return weight; 068 } 069 double weight = 1.0 / request.getStudent().nrRequests(); 070 if (request.isAlternative()) 071 weight *= iAlternativeRequestFactor; 072 return round(weight); 073 } 074 075 @Override 076 public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) { 077 if (currentSolution.getBestInfo() == null) return true; 078 if (iMPP) return super.isBetterThanBestSolution(currentSolution); 079 int unassigned = currentSolution.getModel().nrUnassignedVariables(currentSolution.getAssignment()); 080 if (currentSolution.getModel().getBestUnassignedVariables() != unassigned) 081 return currentSolution.getModel().getBestUnassignedVariables() > unassigned; 082 return currentSolution.getModel().getTotalValue(currentSolution.getAssignment()) < currentSolution.getBestValue(); 083 } 084 085 @Override 086 public boolean isFreeTimeAllowOverlaps() { 087 return true; 088 } 089 090 /** 091 * Test case -- run to see the weights for a few courses 092 * @param args program arguments 093 */ 094 public static void main(String[] args) { 095 EqualStudentWeights pw = new EqualStudentWeights(new DataProperties()); 096 DecimalFormat df = new DecimalFormat("0.0000"); 097 Student s = new Student(0l); 098 new CourseRequest(1l, 0, false, s, ToolBox.toList( 099 new Course(1, "A", "1", new Offering(0, "A")), 100 new Course(1, "A", "2", new Offering(0, "A")), 101 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 102 new CourseRequest(2l, 1, false, s, ToolBox.toList( 103 new Course(1, "B", "1", new Offering(0, "B")), 104 new Course(1, "B", "2", new Offering(0, "B")), 105 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 106 new CourseRequest(3l, 2, false, s, ToolBox.toList( 107 new Course(1, "C", "1", new Offering(0, "C")), 108 new Course(1, "C", "2", new Offering(0, "C")), 109 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 110 new CourseRequest(5l, 4, false, s, ToolBox.toList( 111 new Course(1, "E", "1", new Offering(0, "E")), 112 new Course(1, "E", "2", new Offering(0, "E")), 113 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 114 new CourseRequest(6l, 5, true, s, ToolBox.toList( 115 new Course(1, "F", "1", new Offering(0, "F")), 116 new Course(1, "F", "2", new Offering(0, "F")), 117 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 118 new CourseRequest(7l, 6, true, s, ToolBox.toList( 119 new Course(1, "G", "1", new Offering(0, "G")), 120 new Course(1, "G", "2", new Offering(0, "G")), 121 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 122 123 Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>(); 124 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 125 for (Request r: s.getRequests()) { 126 CourseRequest cr = (CourseRequest)r; 127 double[] w = new double[] {0.0, 0.0, 0.0}; 128 for (int i = 0; i < cr.getCourses().size(); i++) { 129 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 130 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 131 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 132 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 133 w[i] = pw.getWeight(assignment, e, null, null); 134 } 135 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 136 } 137 138 System.out.println("With one distance conflict:"); 139 for (Request r: s.getRequests()) { 140 CourseRequest cr = (CourseRequest)r; 141 double[] w = new double[] {0.0, 0.0, 0.0}; 142 for (int i = 0; i < cr.getCourses().size(); i++) { 143 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 144 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 145 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 146 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 147 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 148 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 149 w[i] = pw.getWeight(assignment, e, dc, null); 150 } 151 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 152 } 153 154 System.out.println("With two distance conflicts:"); 155 for (Request r: s.getRequests()) { 156 CourseRequest cr = (CourseRequest)r; 157 double[] w = new double[] {0.0, 0.0, 0.0}; 158 for (int i = 0; i < cr.getCourses().size(); i++) { 159 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 160 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 161 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 162 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 163 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 164 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 165 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 166 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null))); 167 w[i] = pw.getWeight(assignment, e, dc, null); 168 } 169 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 170 } 171 172 System.out.println("With 25% time overlapping conflict:"); 173 for (Request r: s.getRequests()) { 174 CourseRequest cr = (CourseRequest)r; 175 double[] w = new double[] {0.0, 0.0, 0.0}; 176 for (int i = 0; i < cr.getCourses().size(); i++) { 177 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 178 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 179 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 180 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 181 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 182 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 183 w[i] = pw.getWeight(assignment, e, null, toc); 184 } 185 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 186 } 187 188 System.out.println("Disbalanced sections (by 2 / 10 students):"); 189 for (Request r: s.getRequests()) { 190 CourseRequest cr = (CourseRequest)r; 191 double[] w = new double[] {0.0, 0.0, 0.0}; 192 for (int i = 0; i < cr.getCourses().size(); i++) { 193 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 194 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 195 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 196 Section a = new Section(0, 10, "x", x, p, null, null, null); 197 new Section(1, 10, "y", x, p, null, null, null); 198 sections.add(a); 199 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 200 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 201 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 202 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 203 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 204 w[i] = pw.getWeight(assignment, e, null, null); 205 } 206 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 207 } 208 209 System.out.println("Same choice sections:"); 210 pw.iMPP = true; 211 for (Request r: s.getRequests()) { 212 CourseRequest cr = (CourseRequest)r; 213 double[] w = new double[] {0.0, 0.0, 0.0}; 214 double dif = 0; 215 for (int i = 0; i < cr.getCourses().size(); i++) { 216 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 217 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 218 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 219 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 220 Set<SctAssignment> other = new HashSet<SctAssignment>(); 221 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 222 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, 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 time sections:"); 230 for (Request r: s.getRequests()) { 231 CourseRequest cr = (CourseRequest)r; 232 double dif = 0; 233 double[] w = new double[] {0.0, 0.0, 0.0}; 234 for (int i = 0; i < cr.getCourses().size(); i++) { 235 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 236 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 237 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 238 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 239 Set<SctAssignment> other = new HashSet<SctAssignment>(); 240 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, "1", "Josef Novak", null)); 241 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 242 w[i] = pw.getWeight(assignment, e, null, null); 243 dif = pw.getDifference(e); 244 } 245 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 246 } 247 248 System.out.println("Different time sections:"); 249 Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 250 for (Request r: s.getRequests()) { 251 CourseRequest cr = (CourseRequest)r; 252 double[] w = new double[] {0.0, 0.0, 0.0}; 253 double dif = 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, null, 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), q, null, null, 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("Two sections, one same choice, one same time:"); 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, null, null)); 277 sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, null, null)); 278 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 279 Set<SctAssignment> other = new HashSet<SctAssignment>(); 280 other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 281 other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, "1", "Josef Novak", null)); 282 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 283 w[i] = pw.getWeight(assignment, e, null, null); 284 dif = pw.getDifference(e); 285 } 286 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 287 } 288 } 289}