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 iNoTimeFactor = 0.0100;
076    protected double iAlternativeRequestFactor = 0.1260;
077    protected double iProjectedStudentWeight = 0.0100;
078    protected boolean iMPP = false;
079    protected double iPerturbationFactor = 0.100;
080    protected double iSelectionFactor = 0.100;
081    protected double iSameChoiceWeight = 0.900;
082    protected double iSameTimeWeight = 0.700;
083    protected double iSameConfigWeight = 0.500;
084    protected double iGroupFactor = 0.100;
085    protected double iGroupBestRatio = 0.95;
086    protected double iGroupFillRatio = 0.05;
087    
088    public PriorityStudentWeights(DataProperties config) {
089        iPriorityFactor = config.getPropertyDouble("StudentWeights.Priority", iPriorityFactor);
090        iFirstAlternativeFactor = config.getPropertyDouble("StudentWeights.FirstAlternative", iFirstAlternativeFactor);
091        iSecondAlternativeFactor = config.getPropertyDouble("StudentWeights.SecondAlternative", iSecondAlternativeFactor);
092        iDistanceConflict = config.getPropertyDouble("StudentWeights.DistanceConflict", iDistanceConflict);
093        iShortDistanceConflict = config.getPropertyDouble("StudentWeights.ShortDistanceConflict", iShortDistanceConflict);
094        iTimeOverlapFactor = config.getPropertyDouble("StudentWeights.TimeOverlapFactor", iTimeOverlapFactor);
095        iTimeOverlapMaxLimit = config.getPropertyDouble("StudentWeights.TimeOverlapMaxLimit", iTimeOverlapMaxLimit);
096        iLeftoverSpread = config.getPropertyBoolean("StudentWeights.LeftoverSpread", iLeftoverSpread);
097        iBalancingFactor = config.getPropertyDouble("StudentWeights.BalancingFactor", iBalancingFactor);
098        iAlternativeRequestFactor = config.getPropertyDouble("StudentWeights.AlternativeRequestFactor", iAlternativeRequestFactor);
099        iProjectedStudentWeight = config.getPropertyDouble("StudentWeights.ProjectedStudentWeight", iProjectedStudentWeight);
100        iMPP = config.getPropertyBoolean("General.MPP", false);
101        iPerturbationFactor = config.getPropertyDouble("StudentWeights.Perturbation", iPerturbationFactor);
102        iSelectionFactor = config.getPropertyDouble("StudentWeights.Selection", iSelectionFactor);
103        iSameChoiceWeight = config.getPropertyDouble("StudentWeights.SameChoice", iSameChoiceWeight);
104        iSameTimeWeight = config.getPropertyDouble("StudentWeights.SameTime", iSameTimeWeight);
105        iSameConfigWeight = config.getPropertyDouble("StudentWeights.SameConfig", iSameConfigWeight);
106        iGroupFactor = config.getPropertyDouble("StudentWeights.SameGroup", iGroupFactor);
107        iGroupBestRatio = config.getPropertyDouble("StudentWeights.GroupBestRatio", iGroupBestRatio);
108        iGroupFillRatio = config.getPropertyDouble("StudentWeights.GroupFillRatio", iGroupFillRatio);
109        iNoTimeFactor = config.getPropertyDouble("StudentWeights.NoTimeFactor", iNoTimeFactor);
110    }
111        
112    public double getWeight(Request request) {
113        if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) {
114            double weight = iProjectedStudentWeight;
115            if (request.isAlternative())
116                weight *= iAlternativeRequestFactor;
117            return weight;
118        }
119        double total = 10000.0;
120        int nrReq = request.getStudent().nrRequests();
121        double remain = (iLeftoverSpread ? Math.floor(10000.0 * Math.pow(iPriorityFactor, nrReq) / nrReq) : 0.0);
122        for (int idx = 0; idx < request.getStudent().getRequests().size(); idx++) {
123            Request r = request.getStudent().getRequests().get(idx);
124            boolean last = (idx + 1 == request.getStudent().getRequests().size());
125            boolean lastNotAlt = !r.isAlternative() && (last || request.getStudent().getRequests().get(1 + idx).isAlternative());
126            double w = Math.ceil(iPriorityFactor * total) + remain;
127            if (lastNotAlt || last) {
128                w = total;
129            } else {
130                total -= w;
131            }
132            if (r.equals(request)) {
133                return w / 10000.0;
134            }
135        }
136        return 0.0;
137    }
138    
139    public double getCachedWeight(Request request) {
140        Double w = (Double)request.getExtra();
141        if (w == null) {
142            w = getWeight(request);
143            request.setExtra(w);
144        }
145        return w;
146    }
147    
148    /**
149     * Return how much the given enrollment is different from the initial enrollment
150     * @param enrollment given enrollment
151     * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times)
152     */
153    protected double getDifference(Enrollment enrollment) {
154        if (enrollment.getStudent().isDummy()) return 1.0;
155        Enrollment other = enrollment.getRequest().getInitialAssignment();
156        if (other != null) {
157            double similarSections = 0.0;
158            if (enrollment.getConfig().equals(other.getConfig())) {
159                // same configurations -- compare sections of matching subpart
160                for (Section section: enrollment.getSections()) {
161                    for (Section initial: other.getSections()) {
162                        if (section.getSubpart().equals(initial.getSubpart())) {
163                            if (section.equals(initial)) {
164                                similarSections += 1.0;
165                            } else if (section.sameChoice(initial)) {
166                                similarSections += iSameChoiceWeight;
167                            } else if (section.sameTime(initial)) {
168                                similarSections += iSameTimeWeight;
169                            }
170                            break;
171                        }
172                    }
173                }
174            } else {
175                // different configurations -- compare sections of matching itype
176                for (Section section: enrollment.getSections()) {
177                    for (Section initial: other.getSections()) {
178                        if (section.sameChoice(initial)) {
179                            similarSections += iSameChoiceWeight;
180                            break;
181                        } else if (section.sameInstructionalType(initial) && section.sameTime(initial)) {
182                            similarSections += iSameTimeWeight;
183                            break;
184                        }
185                    }
186                }
187            }
188            return 1.0 - similarSections / enrollment.getAssignments().size();
189        }
190        return 1.0;
191    }
192    
193    /**
194     * Return how much the given enrollment is different from the selection (if any)
195     * @param enrollment given enrollment
196     * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times)
197     */
198    public double getSelection(Enrollment enrollment) {
199        if (enrollment.getStudent().isDummy()) return 1.0;
200        if (enrollment.isCourseRequest()) {
201            CourseRequest cr = (CourseRequest)enrollment.getRequest();
202            if (!cr.getSelectedChoices().isEmpty()) {
203                double similarSections = 0.0;
204                for (Section section: enrollment.getSections()) {
205                    double bestChoice = 0.0;
206                    for (Choice ch: cr.getSelectedChoices()) {
207                        if (bestChoice < 1.0 && ch.sameSection(section)) {
208                            bestChoice = 1.0;
209                        } else if (bestChoice < iSameChoiceWeight && ch.sameChoice(section)) {
210                            bestChoice = iSameChoiceWeight;
211                        } else if (bestChoice < iSameTimeWeight && ch.sameInstructionalType(section) && ch.sameTime(section)) {
212                            bestChoice = iSameTimeWeight;
213                        } else if (bestChoice < iSameConfigWeight && ch.sameConfiguration(section)) {
214                            bestChoice = iSameConfigWeight;
215                        }
216                    }
217                    similarSections += bestChoice;
218                }
219                return 1.0 - similarSections / enrollment.getAssignments().size();
220            } else {
221                return 1.0;
222            }
223        } else {
224            return 1.0;
225        }
226    }
227    
228
229    @Override
230    public double getBound(Request request) {
231        return getCachedWeight(request);
232    }
233    
234    protected double round(double value) {
235        return Math.ceil(10000.0 * value) / 10000.0;
236    }
237    
238    @Override
239    public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
240        double weight = getCachedWeight(enrollment.getRequest());
241        switch (enrollment.getPriority()) {
242            case 0: break;
243            case 1: weight *= iFirstAlternativeFactor; break;
244            case 2: weight *= iSecondAlternativeFactor; break;
245            default:
246                weight *= Math.pow(iFirstAlternativeFactor, enrollment.getPriority());
247        }
248        if (enrollment.isCourseRequest() && iNoTimeFactor != 0.0) {
249            int noTimeSections = 0, total = 0;
250            for (Section section: enrollment.getSections()) {
251                if (section.getTime() == null) noTimeSections ++;
252                total ++;
253            }
254            if (noTimeSections > 0)
255                weight *= (1.0 - iNoTimeFactor * noTimeSections / total);
256        }
257        if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) {
258            double configUsed = enrollment.getConfig().getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
259            double disbalanced = 0;
260            double total = 0;
261            for (Section section: enrollment.getSections()) {
262                Subpart subpart = section.getSubpart();
263                if (subpart.getSections().size() <= 1) continue;
264                double used = section.getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight();
265                // sections have limits -> desired size is section limit x (total enrollment / total limit)
266                // unlimited sections -> desired size is total enrollment / number of sections
267                double desired = (subpart.getLimit() > 0
268                        ? section.getLimit() * (configUsed / subpart.getLimit())
269                        : configUsed / subpart.getSections().size());
270                if (used > desired)
271                    disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight();
272                else
273                    disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight();
274                total ++;
275            }
276            if (disbalanced > 0)
277                weight *= (1.0 - disbalanced / total * iBalancingFactor);
278        }
279        if (iMPP) {
280            double difference = getDifference(enrollment);
281            if (difference > 0.0)
282                weight *= (1.0 - difference * iPerturbationFactor);
283        }
284        if (iSelectionFactor != 0.0) {
285            double selection = getSelection(enrollment);
286            if (selection > 0.0)
287                weight *= (1.0 - selection * iSelectionFactor);
288        }
289        if (enrollment.isCourseRequest() && iGroupFactor != 0.0) {
290            double sameGroup = 0.0; int groupCount = 0;
291            for (RequestGroup g: ((CourseRequest)enrollment.getRequest()).getRequestGroups()) {
292                if (g.getCourse().equals(enrollment.getCourse())) {
293                    sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio);
294                    groupCount ++;
295                }
296            }
297            if (groupCount > 0) {
298                double difference = 1.0 - sameGroup / groupCount;
299                weight *= (1.0 - difference * iGroupFactor);
300            }
301        }
302        return round(weight);
303    }
304    
305    @Override
306    public double getDistanceConflictWeight(Assignment<Request, Enrollment> assignment, DistanceConflict.Conflict c) {
307        if (c.getR1().getPriority() < c.getR2().getPriority()) {
308            return round(getWeight(assignment, c.getE2()) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict));
309        } else {
310            return round(getWeight(assignment, c.getE1()) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict));
311        }
312    }
313    
314    @Override
315    public double getTimeOverlapConflictWeight(Assignment<Request, Enrollment> assignment, Enrollment e, TimeOverlapsCounter.Conflict c) {
316        if (e == null || e.getRequest() == null) return 0.0;
317        double toc = Math.min(iTimeOverlapMaxLimit * c.getShare() / e.getNrSlots(), iTimeOverlapMaxLimit);
318        return round(getWeight(assignment, e) * toc);
319    }
320    
321    @Override
322    public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<DistanceConflict.Conflict> distanceConflicts, Set<TimeOverlapsCounter.Conflict> timeOverlappingConflicts) {
323        double base = getWeight(assignment, enrollment);
324        double dc = 0.0;
325        if (distanceConflicts != null) {
326            for (DistanceConflict.Conflict c: distanceConflicts) {
327                Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1());
328                if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority())
329                    dc += base * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict);
330                else
331                    dc += getWeight(assignment, other) * (c.getStudent().isNeedShortDistances() ? iShortDistanceConflict : iDistanceConflict);
332            }
333        }
334        double toc = 0.0;
335        if (timeOverlappingConflicts != null) {
336            for (TimeOverlapsCounter.Conflict c: timeOverlappingConflicts) {
337                toc += base * Math.min(iTimeOverlapFactor * c.getShare() / enrollment.getNrSlots(), iTimeOverlapMaxLimit);
338                Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1());
339                if (other.getRequest() != null)
340                    toc += getWeight(assignment, other) * Math.min(iTimeOverlapFactor * c.getShare() / other.getNrSlots(), iTimeOverlapMaxLimit);
341            }
342        }
343        return round(base - dc - toc);
344    }
345    
346    
347    @Override
348    public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) {
349        return currentSolution.getBestInfo() == null || currentSolution.getModel().getTotalValue(currentSolution.getAssignment()) < currentSolution.getBestValue();
350    }
351    
352    @Override
353    public boolean isFreeTimeAllowOverlaps() {
354        return false;
355    }
356    
357    /**
358     * Test case -- run to see the weights for a few courses
359     * @param args program arguments
360     */
361    public static void main(String[] args) {
362        PriorityStudentWeights pw = new PriorityStudentWeights(new DataProperties());
363        DecimalFormat df = new DecimalFormat("0.0000");
364        Student s = new Student(0l);
365        new CourseRequest(1l, 0, false, s, ToolBox.toList(
366                new Course(1, "A", "1", new Offering(0, "A")),
367                new Course(1, "A", "2", new Offering(0, "A")),
368                new Course(1, "A", "3", new Offering(0, "A"))), false, null);
369        new CourseRequest(2l, 1, false, s, ToolBox.toList(
370                new Course(1, "B", "1", new Offering(0, "B")),
371                new Course(1, "B", "2", new Offering(0, "B")),
372                new Course(1, "B", "3", new Offering(0, "B"))), false, null);
373        new CourseRequest(3l, 2, false, s, ToolBox.toList(
374                new Course(1, "C", "1", new Offering(0, "C")),
375                new Course(1, "C", "2", new Offering(0, "C")),
376                new Course(1, "C", "3", new Offering(0, "C"))), false, null);
377        new CourseRequest(4l, 3, false, s, ToolBox.toList(
378                new Course(1, "D", "1", new Offering(0, "D")),
379                new Course(1, "D", "2", new Offering(0, "D")),
380                new Course(1, "D", "3", new Offering(0, "D"))), false, null);
381        new CourseRequest(5l, 4, false, s, ToolBox.toList(
382                new Course(1, "E", "1", new Offering(0, "E")),
383                new Course(1, "E", "2", new Offering(0, "E")),
384                new Course(1, "E", "3", new Offering(0, "E"))), false, null);
385        new CourseRequest(6l, 5, true, s, ToolBox.toList(
386                new Course(1, "F", "1", new Offering(0, "F")),
387                new Course(1, "F", "2", new Offering(0, "F")),
388                new Course(1, "F", "3", new Offering(0, "F"))), false, null);
389        new CourseRequest(7l, 6, true, s, ToolBox.toList(
390                new Course(1, "G", "1", new Offering(0, "G")),
391                new Course(1, "G", "2", new Offering(0, "G")),
392                new Course(1, "G", "3", new Offering(0, "G"))), false, null);
393        
394        Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>();
395        Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
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                w[i] = pw.getWeight(assignment, e, null, null);
405            }
406            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
407        }
408
409        System.out.println("With one distance conflict:");
410        for (Request r: s.getRequests()) {
411            CourseRequest cr = (CourseRequest)r;
412            double[] w = new double[] {0.0, 0.0, 0.0};
413            for (int i = 0; i < cr.getCourses().size(); i++) {
414                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
415                Set<SctAssignment> sections = new HashSet<SctAssignment>();
416                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
417                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
418                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
419                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
420                w[i] = pw.getWeight(assignment, e, dc, null);
421            }
422            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
423        }
424
425        System.out.println("With two distance conflicts:");
426        for (Request r: s.getRequests()) {
427            CourseRequest cr = (CourseRequest)r;
428            double[] w = new double[] {0.0, 0.0, 0.0};
429            for (int i = 0; i < cr.getCourses().size(); i++) {
430                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
431                Set<SctAssignment> sections = new HashSet<SctAssignment>();
432                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
433                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
434                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
435                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
436                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e,
437                        new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)));
438                w[i] = pw.getWeight(assignment, e, dc, null);
439            }
440            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
441        }
442
443        System.out.println("With 25% time overlapping conflict:");
444        for (Request r: s.getRequests()) {
445            CourseRequest cr = (CourseRequest)r;
446            double[] w = new double[] {0.0, 0.0, 0.0};
447            for (int i = 0; i < cr.getCourses().size(); i++) {
448                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
449                Set<SctAssignment> sections = new HashSet<SctAssignment>();
450                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
451                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
452                Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
453                toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
454                w[i] = pw.getWeight(assignment, e, null, toc);
455            }
456            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
457        }
458        
459        System.out.println("Disbalanced sections (by 2 / 10 students):");
460        for (Request r: s.getRequests()) {
461            CourseRequest cr = (CourseRequest)r;
462            double[] w = new double[] {0.0, 0.0, 0.0};
463            for (int i = 0; i < cr.getCourses().size(); i++) {
464                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
465                Set<SctAssignment> sections = new HashSet<SctAssignment>();
466                Subpart x = new Subpart(0, "Lec", "Lec", cfg, null);
467                Section a = new Section(0, 10, "x", x, p, null);
468                new Section(1, 10, "y", x, p, null);
469                sections.add(a);
470                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
471                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
472                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
473                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
474                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
475                w[i] = pw.getWeight(assignment, e, null, null);
476            }
477            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
478        }
479        
480        System.out.println("Same choice sections:");
481        pw.iMPP = true;
482        for (Request r: s.getRequests()) {
483            CourseRequest cr = (CourseRequest)r;
484            double[] w = new double[] {0.0, 0.0, 0.0};
485            for (int i = 0; i < cr.getCourses().size(); i++) {
486                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
487                Set<SctAssignment> sections = new HashSet<SctAssignment>();
488                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
489                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
490                Set<SctAssignment> other = new HashSet<SctAssignment>();
491                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
492                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
493                w[i] = pw.getWeight(assignment, e, null, null);
494            }
495            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
496        }
497        
498        System.out.println("Same time sections:");
499        for (Request r: s.getRequests()) {
500            CourseRequest cr = (CourseRequest)r;
501            double[] w = new double[] {0.0, 0.0, 0.0};
502            for (int i = 0; i < cr.getCourses().size(); i++) {
503                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
504                Set<SctAssignment> sections = new HashSet<SctAssignment>();
505                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
506                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
507                Set<SctAssignment> other = new HashSet<SctAssignment>();
508                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null)));
509                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
510                w[i] = pw.getWeight(assignment, e, null, null);
511            }
512            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
513        }
514        
515        System.out.println("Different time sections:");
516        Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
517        for (Request r: s.getRequests()) {
518            CourseRequest cr = (CourseRequest)r;
519            double[] w = new double[] {0.0, 0.0, 0.0};
520            for (int i = 0; i < cr.getCourses().size(); i++) {
521                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
522                Set<SctAssignment> sections = new HashSet<SctAssignment>();
523                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
524                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
525                Set<SctAssignment> other = new HashSet<SctAssignment>();
526                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null));
527                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
528                w[i] = pw.getWeight(assignment, e, null, null);
529            }
530            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
531        }
532        
533        System.out.println("Two sections, one same choice, one same time:");
534        for (Request r: s.getRequests()) {
535            CourseRequest cr = (CourseRequest)r;
536            double[] w = new double[] {0.0, 0.0, 0.0};
537            for (int i = 0; i < cr.getCourses().size(); i++) {
538                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
539                Set<SctAssignment> sections = new HashSet<SctAssignment>();
540                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
541                sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null));
542                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
543                Set<SctAssignment> other = new HashSet<SctAssignment>();
544                other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
545                other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null)));
546                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
547                w[i] = pw.getWeight(assignment, e, null, null);
548            }
549            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
550        }
551
552    }
553}