001package net.sf.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 net.sf.cpsolver.coursett.model.Placement; 010import net.sf.cpsolver.coursett.model.RoomLocation; 011import net.sf.cpsolver.coursett.model.TimeLocation; 012import net.sf.cpsolver.ifs.solution.Solution; 013import net.sf.cpsolver.ifs.util.DataProperties; 014import net.sf.cpsolver.ifs.util.ToolBox; 015import net.sf.cpsolver.studentsct.extension.DistanceConflict; 016import net.sf.cpsolver.studentsct.extension.TimeOverlapsCounter; 017import net.sf.cpsolver.studentsct.model.Assignment; 018import net.sf.cpsolver.studentsct.model.Config; 019import net.sf.cpsolver.studentsct.model.Course; 020import net.sf.cpsolver.studentsct.model.CourseRequest; 021import net.sf.cpsolver.studentsct.model.Enrollment; 022import net.sf.cpsolver.studentsct.model.Offering; 023import net.sf.cpsolver.studentsct.model.Request; 024import net.sf.cpsolver.studentsct.model.Section; 025import net.sf.cpsolver.studentsct.model.Student; 026import net.sf.cpsolver.studentsct.model.Subpart; 027 028/** 029 * Student weight is spread equally among student's course requests. Only alternatives have lower weight. 030 * The rest is inherited from {@link PriorityStudentWeights}. 031 * 032 * @version StudentSct 1.2 (Student Sectioning)<br> 033 * Copyright (C) 2007 - 2010 Tomáš Müller<br> 034 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 035 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 036 * <br> 037 * This library is free software; you can redistribute it and/or modify 038 * it under the terms of the GNU Lesser General Public License as 039 * published by the Free Software Foundation; either version 3 of the 040 * License, or (at your option) any later version. <br> 041 * <br> 042 * This library is distributed in the hope that it will be useful, but 043 * WITHOUT ANY WARRANTY; without even the implied warranty of 044 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 045 * Lesser General Public License for more details. <br> 046 * <br> 047 * You should have received a copy of the GNU Lesser General Public 048 * License along with this library; if not see 049 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 050 */ 051 052public class EqualStudentWeights extends PriorityStudentWeights { 053 054 public EqualStudentWeights(DataProperties config) { 055 super(config); 056 } 057 058 @Override 059 public double getWeight(Request request) { 060 if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) { 061 double weight = iProjectedStudentWeight; 062 if (request.isAlternative()) 063 weight *= iAlternativeRequestFactor; 064 return weight; 065 } 066 double weight = 1.0 / request.getStudent().nrRequests(); 067 if (request.isAlternative()) 068 weight *= iAlternativeRequestFactor; 069 return round(weight); 070 } 071 072 @Override 073 public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) { 074 if (currentSolution.getBestInfo() == null) return true; 075 int unassigned = currentSolution.getModel().nrUnassignedVariables(); 076 if (currentSolution.getModel().getBestUnassignedVariables() != unassigned) 077 return currentSolution.getModel().getBestUnassignedVariables() > unassigned; 078 return currentSolution.getModel().getTotalValue() < currentSolution.getBestValue(); 079 } 080 081 @Override 082 public boolean isFreeTimeAllowOverlaps() { 083 return true; 084 } 085 086 /** 087 * Test case -- run to see the weights for a few courses 088 */ 089 public static void main(String[] args) { 090 EqualStudentWeights pw = new EqualStudentWeights(new DataProperties()); 091 DecimalFormat df = new DecimalFormat("0.0000"); 092 Student s = new Student(0l); 093 new CourseRequest(1l, 0, false, s, ToolBox.toList( 094 new Course(1, "A", "1", new Offering(0, "A")), 095 new Course(1, "A", "2", new Offering(0, "A")), 096 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 097 new CourseRequest(2l, 1, false, s, ToolBox.toList( 098 new Course(1, "B", "1", new Offering(0, "B")), 099 new Course(1, "B", "2", new Offering(0, "B")), 100 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 101 new CourseRequest(3l, 2, false, s, ToolBox.toList( 102 new Course(1, "C", "1", new Offering(0, "C")), 103 new Course(1, "C", "2", new Offering(0, "C")), 104 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 105 new CourseRequest(5l, 4, false, s, ToolBox.toList( 106 new Course(1, "E", "1", new Offering(0, "E")), 107 new Course(1, "E", "2", new Offering(0, "E")), 108 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 109 new CourseRequest(6l, 5, true, s, ToolBox.toList( 110 new Course(1, "F", "1", new Offering(0, "F")), 111 new Course(1, "F", "2", new Offering(0, "F")), 112 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 113 new CourseRequest(7l, 6, true, s, ToolBox.toList( 114 new Course(1, "G", "1", new Offering(0, "G")), 115 new Course(1, "G", "2", new Offering(0, "G")), 116 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 117 118 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 119 for (Request r: s.getRequests()) { 120 CourseRequest cr = (CourseRequest)r; 121 double[] w = new double[] {0.0, 0.0, 0.0}; 122 for (int i = 0; i < cr.getCourses().size(); i++) { 123 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 124 Set<Assignment> sections = new HashSet<Assignment>(); 125 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 126 Enrollment e = new Enrollment(cr, i, cfg, sections); 127 w[i] = pw.getWeight(e, null, null); 128 } 129 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 130 } 131 132 System.out.println("With one distance conflict:"); 133 for (Request r: s.getRequests()) { 134 CourseRequest cr = (CourseRequest)r; 135 double[] w = new double[] {0.0, 0.0, 0.0}; 136 for (int i = 0; i < cr.getCourses().size(); i++) { 137 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 138 Set<Assignment> sections = new HashSet<Assignment>(); 139 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 140 Enrollment e = new Enrollment(cr, i, cfg, sections); 141 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 142 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 143 w[i] = pw.getWeight(e, dc, null); 144 } 145 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 146 } 147 148 System.out.println("With two distance conflicts:"); 149 for (Request r: s.getRequests()) { 150 CourseRequest cr = (CourseRequest)r; 151 double[] w = new double[] {0.0, 0.0, 0.0}; 152 for (int i = 0; i < cr.getCourses().size(); i++) { 153 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 154 Set<Assignment> sections = new HashSet<Assignment>(); 155 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 156 Enrollment e = new Enrollment(cr, i, cfg, sections); 157 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 158 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 159 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 160 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null))); 161 w[i] = pw.getWeight(e, dc, null); 162 } 163 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 164 } 165 166 System.out.println("With 25% time overlapping conflict:"); 167 for (Request r: s.getRequests()) { 168 CourseRequest cr = (CourseRequest)r; 169 double[] w = new double[] {0.0, 0.0, 0.0}; 170 for (int i = 0; i < cr.getCourses().size(); i++) { 171 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 172 Set<Assignment> sections = new HashSet<Assignment>(); 173 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 174 Enrollment e = new Enrollment(cr, i, cfg, sections); 175 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 176 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 177 w[i] = pw.getWeight(e, null, toc); 178 } 179 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 180 } 181 182 System.out.println("Disbalanced sections (by 2 / 10 students):"); 183 for (Request r: s.getRequests()) { 184 CourseRequest cr = (CourseRequest)r; 185 double[] w = new double[] {0.0, 0.0, 0.0}; 186 for (int i = 0; i < cr.getCourses().size(); i++) { 187 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 188 Set<Assignment> sections = new HashSet<Assignment>(); 189 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 190 Section a = new Section(0, 10, "x", x, p, null, null, null); 191 new Section(1, 10, "y", x, p, null, null, null); 192 sections.add(a); 193 a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 194 a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 195 cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 196 cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 197 Enrollment e = new Enrollment(cr, i, cfg, sections); 198 w[i] = pw.getWeight(e, null, null); 199 } 200 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 201 } 202 } 203}