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 int unassigned = currentSolution.getModel().nrUnassignedVariables(currentSolution.getAssignment()); 079 if (currentSolution.getModel().getBestUnassignedVariables() != unassigned) 080 return currentSolution.getModel().getBestUnassignedVariables() > unassigned; 081 return currentSolution.getModel().getTotalValue(currentSolution.getAssignment()) < currentSolution.getBestValue(); 082 } 083 084 @Override 085 public boolean isFreeTimeAllowOverlaps() { 086 return true; 087 } 088 089 /** 090 * Test case -- run to see the weights for a few courses 091 * @param args program arguments 092 */ 093 public static void main(String[] args) { 094 EqualStudentWeights pw = new EqualStudentWeights(new DataProperties()); 095 DecimalFormat df = new DecimalFormat("0.0000"); 096 Student s = new Student(0l); 097 new CourseRequest(1l, 0, false, s, ToolBox.toList( 098 new Course(1, "A", "1", new Offering(0, "A")), 099 new Course(1, "A", "2", new Offering(0, "A")), 100 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 101 new CourseRequest(2l, 1, false, s, ToolBox.toList( 102 new Course(1, "B", "1", new Offering(0, "B")), 103 new Course(1, "B", "2", new Offering(0, "B")), 104 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 105 new CourseRequest(3l, 2, false, s, ToolBox.toList( 106 new Course(1, "C", "1", new Offering(0, "C")), 107 new Course(1, "C", "2", new Offering(0, "C")), 108 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 109 new CourseRequest(5l, 4, false, s, ToolBox.toList( 110 new Course(1, "E", "1", new Offering(0, "E")), 111 new Course(1, "E", "2", new Offering(0, "E")), 112 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 113 new CourseRequest(6l, 5, true, s, ToolBox.toList( 114 new Course(1, "F", "1", new Offering(0, "F")), 115 new Course(1, "F", "2", new Offering(0, "F")), 116 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 117 new CourseRequest(7l, 6, true, s, ToolBox.toList( 118 new Course(1, "G", "1", new Offering(0, "G")), 119 new Course(1, "G", "2", new Offering(0, "G")), 120 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 121 122 Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>(); 123 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 124 for (Request r: s.getRequests()) { 125 CourseRequest cr = (CourseRequest)r; 126 double[] w = new double[] {0.0, 0.0, 0.0}; 127 for (int i = 0; i < cr.getCourses().size(); i++) { 128 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 129 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 130 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 131 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 132 w[i] = pw.getWeight(assignment, e, null, null); 133 } 134 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 135 } 136 137 System.out.println("With one distance conflict:"); 138 for (Request r: s.getRequests()) { 139 CourseRequest cr = (CourseRequest)r; 140 double[] w = new double[] {0.0, 0.0, 0.0}; 141 for (int i = 0; i < cr.getCourses().size(); i++) { 142 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 143 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 144 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 145 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 146 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 147 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 148 w[i] = pw.getWeight(assignment, e, dc, null); 149 } 150 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 151 } 152 153 System.out.println("With two distance conflicts:"); 154 for (Request r: s.getRequests()) { 155 CourseRequest cr = (CourseRequest)r; 156 double[] w = new double[] {0.0, 0.0, 0.0}; 157 for (int i = 0; i < cr.getCourses().size(); i++) { 158 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 159 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 160 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 161 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 162 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 163 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 164 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 165 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null))); 166 w[i] = pw.getWeight(assignment, e, dc, null); 167 } 168 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 169 } 170 171 System.out.println("With 25% time overlapping conflict:"); 172 for (Request r: s.getRequests()) { 173 CourseRequest cr = (CourseRequest)r; 174 double[] w = new double[] {0.0, 0.0, 0.0}; 175 for (int i = 0; i < cr.getCourses().size(); i++) { 176 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 177 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 178 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)); 179 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 180 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 181 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 182 w[i] = pw.getWeight(assignment, e, null, toc); 183 } 184 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 185 } 186 187 System.out.println("Disbalanced sections (by 2 / 10 students):"); 188 for (Request r: s.getRequests()) { 189 CourseRequest cr = (CourseRequest)r; 190 double[] w = new double[] {0.0, 0.0, 0.0}; 191 for (int i = 0; i < cr.getCourses().size(); i++) { 192 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 193 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 194 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 195 Section a = new Section(0, 10, "x", x, p, null, null, null); 196 new Section(1, 10, "y", x, p, null, null, null); 197 sections.add(a); 198 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 199 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 200 cfg.getContext(assignment).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 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 203 w[i] = pw.getWeight(assignment, e, null, null); 204 } 205 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 206 } 207 } 208}