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