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 @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 }