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.Choice;
020import org.cpsolver.studentsct.model.Config;
021import org.cpsolver.studentsct.model.Course;
022import org.cpsolver.studentsct.model.CourseRequest;
023import org.cpsolver.studentsct.model.Enrollment;
024import org.cpsolver.studentsct.model.Offering;
025import org.cpsolver.studentsct.model.Request;
026import org.cpsolver.studentsct.model.RequestGroup;
027import org.cpsolver.studentsct.model.SctAssignment;
028import org.cpsolver.studentsct.model.Section;
029import org.cpsolver.studentsct.model.Student;
030import org.cpsolver.studentsct.model.Subpart;
031
032
033/**
034 * New weighting model. It tries to obey the following principles:
035 * <ul>
036 *      <li> Total student weight is between zero and one (one means student got the best schedule)
037 *      <li> Weight of the given priority course is higher than sum of the remaining weights the student can get
038 *      <li> First alternative is better than the following course
039 *      <li> Second alternative is better than the second following course
040 *      <li> Distance conflicts are considered secondary (priorities should be maximized first)
041 *      <li> If alternative sections are otherwise equal, use the better balanced one
042 * </ul>
043 * 
044 * @version StudentSct 1.3 (Student Sectioning)<br>
045 *          Copyright (C) 2007 - 2014 Tomas Muller<br>
046 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
047 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
048 * <br>
049 *          This library is free software; you can redistribute it and/or modify
050 *          it under the terms of the GNU Lesser General Public License as
051 *          published by the Free Software Foundation; either version 3 of the
052 *          License, or (at your option) any later version. <br>
053 * <br>
054 *          This library is distributed in the hope that it will be useful, but
055 *          WITHOUT ANY WARRANTY; without even the implied warranty of
056 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
057 *          Lesser General Public License for more details. <br>
058 * <br>
059 *          You should have received a copy of the GNU Lesser General Public
060 *          License along with this library; if not see
061 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
062 */
063
064public class PriorityStudentWeights implements StudentWeights {
065    protected double iPriorityFactor = 0.5010;
066    protected double iFirstAlternativeFactor = 0.5010;
067    protected double iSecondAlternativeFactor = 0.2510;
068    protected double iDistanceConflict = 0.0100;
069    protected double iTimeOverlapFactor = 0.5000;
070    protected double iTimeOverlapMaxLimit = 0.5000;
071    protected boolean iLeftoverSpread = false;
072    protected double iBalancingFactor = 0.0050;
073    protected double iAlternativeRequestFactor = 0.1260;
074    protected double iProjectedStudentWeight = 0.0100;
075    protected boolean iMPP = false;
076    protected double iPerturbationFactor = 0.100;
077    protected double iSameChoiceWeight = 0.900;
078    protected double iSameTimeWeight = 0.700;
079    protected double iGroupFactor = 0.100;
080    protected double iGroupBestRatio = 0.95;
081    protected double iGroupFillRatio = 0.05;
082    
083    public PriorityStudentWeights(DataProperties config) {
084        iPriorityFactor = config.getPropertyDouble("StudentWeights.Priority", iPriorityFactor);
085        iFirstAlternativeFactor = config.getPropertyDouble("StudentWeights.FirstAlternative", iFirstAlternativeFactor);
086        iSecondAlternativeFactor = config.getPropertyDouble("StudentWeights.SecondAlternative", iSecondAlternativeFactor);
087        iDistanceConflict = config.getPropertyDouble("StudentWeights.DistanceConflict", iDistanceConflict);
088        iTimeOverlapFactor = config.getPropertyDouble("StudentWeights.TimeOverlapFactor", iTimeOverlapFactor);
089        iTimeOverlapMaxLimit = config.getPropertyDouble("StudentWeights.TimeOverlapMaxLimit", iTimeOverlapMaxLimit);
090        iLeftoverSpread = config.getPropertyBoolean("StudentWeights.LeftoverSpread", iLeftoverSpread);
091        iBalancingFactor = config.getPropertyDouble("StudentWeights.BalancingFactor", iBalancingFactor);
092        iAlternativeRequestFactor = config.getPropertyDouble("StudentWeights.AlternativeRequestFactor", iAlternativeRequestFactor);
093        iProjectedStudentWeight = config.getPropertyDouble("StudentWeights.ProjectedStudentWeight", iProjectedStudentWeight);
094        iMPP = config.getPropertyBoolean("General.MPP", false);
095        iPerturbationFactor = config.getPropertyDouble("StudentWeights.Perturbation", iPerturbationFactor);
096        iSameChoiceWeight = config.getPropertyDouble("StudentWeights.SameChoice", iSameChoiceWeight);
097        iSameTimeWeight = config.getPropertyDouble("StudentWeights.SameTime", iSameTimeWeight);
098        iGroupFactor = config.getPropertyDouble("StudentWeights.SameGroup", iGroupFactor);
099        iGroupBestRatio = config.getPropertyDouble("StudentWeights.GroupBestRatio", iGroupBestRatio);
100        iGroupFillRatio = config.getPropertyDouble("StudentWeights.GroupFillRatio", iGroupFillRatio);
101    }
102        
103    public double getWeight(Request request) {
104        if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) {
105            double weight = iProjectedStudentWeight;
106            if (request.isAlternative())
107                weight *= iAlternativeRequestFactor;
108            return weight;
109        }
110        double total = 10000.0;
111        int nrReq = request.getStudent().nrRequests();
112        double remain = (iLeftoverSpread ? Math.floor(10000.0 * Math.pow(iPriorityFactor, nrReq) / nrReq) : 0.0);
113        for (int idx = 0; idx < request.getStudent().getRequests().size(); idx++) {
114            Request r = request.getStudent().getRequests().get(idx);
115            boolean last = (idx + 1 == request.getStudent().getRequests().size());
116            boolean lastNotAlt = !r.isAlternative() && (last || request.getStudent().getRequests().get(1 + idx).isAlternative());
117            double w = Math.ceil(iPriorityFactor * total) + remain;
118            if (lastNotAlt || last) {
119                w = total;
120            } else {
121                total -= w;
122            }
123            if (r.equals(request)) {
124                return w / 10000.0;
125            }
126        }
127        return 0.0;
128    }
129    
130    public double getCachedWeight(Request request) {
131        Double w = (Double)request.getExtra();
132        if (w == null) {
133            w = getWeight(request);
134            request.setExtra(w);
135        }
136        return w;
137    }
138    
139    /**
140     * Return how much the given enrollment is different from the initial enrollment
141     * @param enrollment given enrollment
142     * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times)
143     */
144    protected double getDifference(Enrollment enrollment) {
145        if (!enrollment.getRequest().isMPP()) return 1.0;
146        Enrollment other = enrollment.getRequest().getInitialAssignment();
147        if (other != null) {
148            double similarSections = 0.0;
149            if (enrollment.getConfig().equals(other.getConfig())) {
150                // same configurations -- compare sections of matching subpart
151                for (Section section: enrollment.getSections()) {
152                    for (Section initial: other.getSections()) {
153                        if (section.getSubpart().equals(initial.getSubpart())) {
154                            if (section.equals(initial)) {
155                                similarSections += 1.0;
156                            } else if (section.getChoice().equals(initial.getChoice())) {
157                                similarSections += iSameChoiceWeight;
158                            } else if (section.sameTime(initial)) {
159                                similarSections += iSameTimeWeight;
160                            }
161                            break;
162                        }
163                    }
164                }
165            } else {
166                // different configurations -- compare sections of matching itype
167                for (Section section: enrollment.getSections()) {
168                    for (Section initial: other.getSections()) {
169                        if (section.getChoice().equals(initial.getChoice())) {
170                            similarSections += iSameChoiceWeight;
171                            break;
172                        } else if (section.getChoice().sameTime(initial.getChoice())) {
173                            similarSections += iSameTimeWeight;
174                            break;
175                        }
176                    }
177                }
178            }
179            return 1.0 - similarSections / enrollment.getAssignments().size();
180        } else if (enrollment.isCourseRequest()) {
181            CourseRequest cr = (CourseRequest)enrollment.getRequest();
182            if (!cr.getSelectedChoices().isEmpty()) {
183                double similarSections = 0.0;
184                for (Section section: enrollment.getSections()) {
185                    for (Choice ch: cr.getSelectedChoices()) {
186                        if (ch.equals(section.getChoice())) {
187                            similarSections += iSameChoiceWeight;
188                            break;
189                        } else if (ch.sameTime(section.getChoice())) {
190                            similarSections += iSameTimeWeight;
191                            break;
192                        }
193                    }
194                }
195                return 1.0 - similarSections / enrollment.getAssignments().size();
196            } else {
197                return 1.0;
198            }
199        } else {
200            return 1.0;
201        }
202    }
203
204    @Override
205    public double getBound(Request request) {
206        return getCachedWeight(request);
207    }
208    
209    protected double round(double value) {
210        return Math.ceil(10000.0 * value) / 10000.0;
211    }
212    
213    @Override
214    public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
215        double weight = getCachedWeight(enrollment.getRequest());
216        switch (enrollment.getPriority()) {
217            case 1: weight *= iFirstAlternativeFactor; break;
218            case 2: weight *= iSecondAlternativeFactor; break;
219        }
220        if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) {
221            double configUsed = enrollment.getConfig().getEnrollmentWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
222            double disbalanced = 0;
223            double total = 0;
224            for (Section section: enrollment.getSections()) {
225                Subpart subpart = section.getSubpart();
226                if (subpart.getSections().size() <= 1) continue;
227                double used = section.getEnrollmentWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
228                // sections have limits -> desired size is section limit x (total enrollment / total limit)
229                // unlimited sections -> desired size is total enrollment / number of sections
230                double desired = (subpart.getLimit() > 0
231                        ? section.getLimit() * (configUsed / subpart.getLimit())
232                        : configUsed / subpart.getSections().size());
233                if (used > desired)
234                    disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight();
235                else
236                    disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight();
237                total ++;
238            }
239            if (disbalanced > 0)
240                weight *= (1.0 - disbalanced / total * iBalancingFactor);
241        }
242        if (iMPP) {
243            double difference = getDifference(enrollment);
244            if (difference > 0.0)
245                weight *= (1.0 - difference * iPerturbationFactor);
246        }
247        if (enrollment.isCourseRequest() && iGroupFactor != 0.0) {
248            double sameGroup = 0.0; int groupCount = 0;
249            for (RequestGroup g: ((CourseRequest)enrollment.getRequest()).getRequestGroups()) {
250                if (g.getCourse().equals(enrollment.getCourse())) {
251                    sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio);
252                    groupCount ++;
253                }
254            }
255            if (groupCount > 0) {
256                double difference = 1.0 - sameGroup / groupCount;
257                weight *= (1.0 - difference * iGroupFactor);
258            }
259        }
260        return round(weight);
261    }
262    
263    @Override
264    public double getDistanceConflictWeight(Assignment<Request, Enrollment> assignment, DistanceConflict.Conflict c) {
265        if (c.getR1().getPriority() < c.getR2().getPriority()) {
266            return round(getWeight(assignment, c.getE2()) * iDistanceConflict);
267        } else {
268            return round(getWeight(assignment, c.getE1()) * iDistanceConflict);
269        }
270    }
271    
272    @Override
273    public double getTimeOverlapConflictWeight(Assignment<Request, Enrollment> assignment, Enrollment e, TimeOverlapsCounter.Conflict c) {
274        double toc = Math.min(iTimeOverlapMaxLimit * c.getShare() / e.getNrSlots(), iTimeOverlapMaxLimit);
275        return round(getWeight(assignment, e) * toc);
276    }
277    
278    @Override
279    public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<DistanceConflict.Conflict> distanceConflicts, Set<TimeOverlapsCounter.Conflict> timeOverlappingConflicts) {
280        double base = getWeight(assignment, enrollment);
281        double dc = 0.0;
282        if (distanceConflicts != null) {
283            for (DistanceConflict.Conflict c: distanceConflicts) {
284                Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1());
285                if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority())
286                    dc += base * iDistanceConflict;
287                else
288                    dc += getWeight(assignment, other) * iDistanceConflict;
289            }
290        }
291        double toc = 0.0;
292        if (timeOverlappingConflicts != null) {
293            for (TimeOverlapsCounter.Conflict c: timeOverlappingConflicts) {
294                toc += base * Math.min(iTimeOverlapFactor * c.getShare() / enrollment.getNrSlots(), iTimeOverlapMaxLimit);
295                Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1());
296                toc += getWeight(assignment, other) * Math.min(iTimeOverlapFactor * c.getShare() / other.getNrSlots(), iTimeOverlapMaxLimit);
297            }
298        }
299        return round(base - dc - toc);
300    }
301    
302    
303    @Override
304    public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) {
305        return currentSolution.getBestInfo() == null || currentSolution.getModel().getTotalValue(currentSolution.getAssignment()) < currentSolution.getBestValue();
306    }
307    
308    @Override
309    public boolean isFreeTimeAllowOverlaps() {
310        return false;
311    }
312    
313    /**
314     * Test case -- run to see the weights for a few courses
315     * @param args program arguments
316     */
317    public static void main(String[] args) {
318        PriorityStudentWeights pw = new PriorityStudentWeights(new DataProperties());
319        DecimalFormat df = new DecimalFormat("0.0000");
320        Student s = new Student(0l);
321        new CourseRequest(1l, 0, false, s, ToolBox.toList(
322                new Course(1, "A", "1", new Offering(0, "A")),
323                new Course(1, "A", "2", new Offering(0, "A")),
324                new Course(1, "A", "3", new Offering(0, "A"))), false, null);
325        new CourseRequest(2l, 1, false, s, ToolBox.toList(
326                new Course(1, "B", "1", new Offering(0, "B")),
327                new Course(1, "B", "2", new Offering(0, "B")),
328                new Course(1, "B", "3", new Offering(0, "B"))), false, null);
329        new CourseRequest(3l, 2, false, s, ToolBox.toList(
330                new Course(1, "C", "1", new Offering(0, "C")),
331                new Course(1, "C", "2", new Offering(0, "C")),
332                new Course(1, "C", "3", new Offering(0, "C"))), false, null);
333        new CourseRequest(4l, 3, false, s, ToolBox.toList(
334                new Course(1, "D", "1", new Offering(0, "D")),
335                new Course(1, "D", "2", new Offering(0, "D")),
336                new Course(1, "D", "3", new Offering(0, "D"))), false, null);
337        new CourseRequest(5l, 4, false, s, ToolBox.toList(
338                new Course(1, "E", "1", new Offering(0, "E")),
339                new Course(1, "E", "2", new Offering(0, "E")),
340                new Course(1, "E", "3", new Offering(0, "E"))), false, null);
341        new CourseRequest(6l, 5, true, s, ToolBox.toList(
342                new Course(1, "F", "1", new Offering(0, "F")),
343                new Course(1, "F", "2", new Offering(0, "F")),
344                new Course(1, "F", "3", new Offering(0, "F"))), false, null);
345        new CourseRequest(7l, 6, true, s, ToolBox.toList(
346                new Course(1, "G", "1", new Offering(0, "G")),
347                new Course(1, "G", "2", new Offering(0, "G")),
348                new Course(1, "G", "3", new Offering(0, "G"))), false, null);
349        
350        Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>();
351        Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
352        for (Request r: s.getRequests()) {
353            CourseRequest cr = (CourseRequest)r;
354            double[] w = new double[] {0.0, 0.0, 0.0};
355            for (int i = 0; i < cr.getCourses().size(); i++) {
356                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
357                Set<SctAssignment> sections = new HashSet<SctAssignment>();
358                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
359                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
360                w[i] = pw.getWeight(assignment, e, null, null);
361            }
362            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
363        }
364
365        System.out.println("With one distance conflict:");
366        for (Request r: s.getRequests()) {
367            CourseRequest cr = (CourseRequest)r;
368            double[] w = new double[] {0.0, 0.0, 0.0};
369            for (int i = 0; i < cr.getCourses().size(); i++) {
370                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
371                Set<SctAssignment> sections = new HashSet<SctAssignment>();
372                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
373                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
374                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
375                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
376                w[i] = pw.getWeight(assignment, e, dc, null);
377            }
378            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
379        }
380
381        System.out.println("With two distance conflicts:");
382        for (Request r: s.getRequests()) {
383            CourseRequest cr = (CourseRequest)r;
384            double[] w = new double[] {0.0, 0.0, 0.0};
385            for (int i = 0; i < cr.getCourses().size(); i++) {
386                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
387                Set<SctAssignment> sections = new HashSet<SctAssignment>();
388                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
389                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
390                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
391                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
392                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e,
393                        new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null)));
394                w[i] = pw.getWeight(assignment, e, dc, null);
395            }
396            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
397        }
398
399        System.out.println("With 25% time overlapping conflict:");
400        for (Request r: s.getRequests()) {
401            CourseRequest cr = (CourseRequest)r;
402            double[] w = new double[] {0.0, 0.0, 0.0};
403            for (int i = 0; i < cr.getCourses().size(); i++) {
404                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
405                Set<SctAssignment> sections = new HashSet<SctAssignment>();
406                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
407                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
408                Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
409                toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
410                w[i] = pw.getWeight(assignment, e, null, toc);
411            }
412            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
413        }
414        
415        System.out.println("Disbalanced sections (by 2 / 10 students):");
416        for (Request r: s.getRequests()) {
417            CourseRequest cr = (CourseRequest)r;
418            double[] w = new double[] {0.0, 0.0, 0.0};
419            for (int i = 0; i < cr.getCourses().size(); i++) {
420                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
421                Set<SctAssignment> sections = new HashSet<SctAssignment>();
422                Subpart x = new Subpart(0, "Lec", "Lec", cfg, null);
423                Section a = new Section(0, 10, "x", x, p, null, null, null);
424                new Section(1, 10, "y", x, p, null, null, null);
425                sections.add(a);
426                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
427                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
428                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
429                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
430                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
431                w[i] = pw.getWeight(assignment, e, null, null);
432            }
433            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
434        }
435        
436        System.out.println("Same choice sections:");
437        pw.iMPP = true;
438        for (Request r: s.getRequests()) {
439            CourseRequest cr = (CourseRequest)r;
440            double[] w = new double[] {0.0, 0.0, 0.0};
441            for (int i = 0; i < cr.getCourses().size(); i++) {
442                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
443                Set<SctAssignment> sections = new HashSet<SctAssignment>();
444                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
445                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
446                Set<SctAssignment> other = new HashSet<SctAssignment>();
447                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
448                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
449                w[i] = pw.getWeight(assignment, e, null, null);
450            }
451            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
452        }
453        
454        System.out.println("Same time sections:");
455        for (Request r: s.getRequests()) {
456            CourseRequest cr = (CourseRequest)r;
457            double[] w = new double[] {0.0, 0.0, 0.0};
458            for (int i = 0; i < cr.getCourses().size(); i++) {
459                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
460                Set<SctAssignment> sections = new HashSet<SctAssignment>();
461                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
462                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
463                Set<SctAssignment> other = new HashSet<SctAssignment>();
464                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, "1", "Josef Novak", null));
465                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
466                w[i] = pw.getWeight(assignment, e, null, null);
467            }
468            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
469        }
470        
471        System.out.println("Different time sections:");
472        Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
473        for (Request r: s.getRequests()) {
474            CourseRequest cr = (CourseRequest)r;
475            double[] w = new double[] {0.0, 0.0, 0.0};
476            for (int i = 0; i < cr.getCourses().size(); i++) {
477                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
478                Set<SctAssignment> sections = new HashSet<SctAssignment>();
479                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
480                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
481                Set<SctAssignment> other = new HashSet<SctAssignment>();
482                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null, null, null));
483                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
484                w[i] = pw.getWeight(assignment, e, null, null);
485            }
486            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
487        }
488        
489        System.out.println("Two sections, one same choice, one same time:");
490        for (Request r: s.getRequests()) {
491            CourseRequest cr = (CourseRequest)r;
492            double[] w = new double[] {0.0, 0.0, 0.0};
493            for (int i = 0; i < cr.getCourses().size(); i++) {
494                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
495                Set<SctAssignment> sections = new HashSet<SctAssignment>();
496                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
497                sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, null, null));
498                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
499                Set<SctAssignment> other = new HashSet<SctAssignment>();
500                other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, null, null));
501                other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, "1", "Josef Novak", null));
502                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
503                w[i] = pw.getWeight(assignment, e, null, null);
504            }
505            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
506        }
507
508    }
509}