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