001 package net.sf.cpsolver.studentsct.weights; 002 003 import java.text.DecimalFormat; 004 import java.util.ArrayList; 005 import java.util.BitSet; 006 import java.util.HashSet; 007 import java.util.Set; 008 009 import net.sf.cpsolver.coursett.model.Placement; 010 import net.sf.cpsolver.coursett.model.RoomLocation; 011 import net.sf.cpsolver.coursett.model.TimeLocation; 012 import net.sf.cpsolver.ifs.solution.Solution; 013 import net.sf.cpsolver.ifs.util.DataProperties; 014 import net.sf.cpsolver.ifs.util.ToolBox; 015 import net.sf.cpsolver.studentsct.extension.DistanceConflict; 016 import net.sf.cpsolver.studentsct.extension.TimeOverlapsCounter; 017 import net.sf.cpsolver.studentsct.model.Assignment; 018 import net.sf.cpsolver.studentsct.model.Config; 019 import net.sf.cpsolver.studentsct.model.Course; 020 import net.sf.cpsolver.studentsct.model.CourseRequest; 021 import net.sf.cpsolver.studentsct.model.Enrollment; 022 import net.sf.cpsolver.studentsct.model.Offering; 023 import net.sf.cpsolver.studentsct.model.Request; 024 import net.sf.cpsolver.studentsct.model.Section; 025 import net.sf.cpsolver.studentsct.model.Student; 026 import 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 Tomas Muller<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 052 public 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 /** 082 * Test case -- run to see the weights for a few courses 083 */ 084 public static void main(String[] args) { 085 EqualStudentWeights pw = new EqualStudentWeights(new DataProperties()); 086 DecimalFormat df = new DecimalFormat("0.0000"); 087 Student s = new Student(0l); 088 new CourseRequest(1l, 0, false, s, ToolBox.toList( 089 new Course(1, "A", "1", new Offering(0, "A")), 090 new Course(1, "A", "2", new Offering(0, "A")), 091 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 092 new CourseRequest(2l, 1, false, s, ToolBox.toList( 093 new Course(1, "B", "1", new Offering(0, "B")), 094 new Course(1, "B", "2", new Offering(0, "B")), 095 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 096 new CourseRequest(3l, 2, false, s, ToolBox.toList( 097 new Course(1, "C", "1", new Offering(0, "C")), 098 new Course(1, "C", "2", new Offering(0, "C")), 099 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 100 new CourseRequest(5l, 4, false, s, ToolBox.toList( 101 new Course(1, "E", "1", new Offering(0, "E")), 102 new Course(1, "E", "2", new Offering(0, "E")), 103 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 104 new CourseRequest(6l, 5, true, s, ToolBox.toList( 105 new Course(1, "F", "1", new Offering(0, "F")), 106 new Course(1, "F", "2", new Offering(0, "F")), 107 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 108 new CourseRequest(7l, 6, true, s, ToolBox.toList( 109 new Course(1, "G", "1", new Offering(0, "G")), 110 new Course(1, "G", "2", new Offering(0, "G")), 111 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 112 113 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 114 for (Request r: s.getRequests()) { 115 CourseRequest cr = (CourseRequest)r; 116 double[] w = new double[] {0.0, 0.0, 0.0}; 117 for (int i = 0; i < cr.getCourses().size(); i++) { 118 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 119 Set<Assignment> sections = new HashSet<Assignment>(); 120 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 121 Enrollment e = new Enrollment(cr, i, cfg, sections); 122 w[i] = pw.getWeight(e, null, null); 123 } 124 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 125 } 126 127 System.out.println("With one distance conflict:"); 128 for (Request r: s.getRequests()) { 129 CourseRequest cr = (CourseRequest)r; 130 double[] w = new double[] {0.0, 0.0, 0.0}; 131 for (int i = 0; i < cr.getCourses().size(); i++) { 132 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 133 Set<Assignment> sections = new HashSet<Assignment>(); 134 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 135 Enrollment e = new Enrollment(cr, i, cfg, sections); 136 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 137 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 138 w[i] = pw.getWeight(e, dc, null); 139 } 140 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 141 } 142 143 System.out.println("With two distance conflicts:"); 144 for (Request r: s.getRequests()) { 145 CourseRequest cr = (CourseRequest)r; 146 double[] w = new double[] {0.0, 0.0, 0.0}; 147 for (int i = 0; i < cr.getCourses().size(); i++) { 148 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 149 Set<Assignment> sections = new HashSet<Assignment>(); 150 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 151 Enrollment e = new Enrollment(cr, i, cfg, sections); 152 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 153 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 154 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 155 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null))); 156 w[i] = pw.getWeight(e, dc, null); 157 } 158 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 159 } 160 161 System.out.println("With 25% time overlapping conflict:"); 162 for (Request r: s.getRequests()) { 163 CourseRequest cr = (CourseRequest)r; 164 double[] w = new double[] {0.0, 0.0, 0.0}; 165 for (int i = 0; i < cr.getCourses().size(); i++) { 166 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 167 Set<Assignment> sections = new HashSet<Assignment>(); 168 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 169 Enrollment e = new Enrollment(cr, i, cfg, sections); 170 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 171 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 172 w[i] = pw.getWeight(e, null, toc); 173 } 174 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 175 } 176 177 System.out.println("Disbalanced sections (by 2 / 10 students):"); 178 for (Request r: s.getRequests()) { 179 CourseRequest cr = (CourseRequest)r; 180 double[] w = new double[] {0.0, 0.0, 0.0}; 181 for (int i = 0; i < cr.getCourses().size(); i++) { 182 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 183 Set<Assignment> sections = new HashSet<Assignment>(); 184 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 185 Section a = new Section(0, 10, "x", x, p, null, null, null); 186 new Section(1, 10, "y", x, p, null, null, null); 187 sections.add(a); 188 a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 189 a.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 190 cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 191 cfg.assigned(new Enrollment(s.getRequests().get(0), i, cfg, sections)); 192 Enrollment e = new Enrollment(cr, i, cfg, sections); 193 w[i] = pw.getWeight(e, null, null); 194 } 195 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 196 } 197 } 198 }