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().getEnrollmentTotalWeight(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.getEnrollmentTotalWeight(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        if (e == null || e.getRequest() == null) return 0.0;
301        double toc = Math.min(iTimeOverlapMaxLimit * c.getShare() / e.getNrSlots(), iTimeOverlapMaxLimit);
302        return round(getWeight(assignment, e) * toc);
303    }
304    
305    @Override
306    public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<DistanceConflict.Conflict> distanceConflicts, Set<TimeOverlapsCounter.Conflict> timeOverlappingConflicts) {
307        double base = getWeight(assignment, enrollment);
308        double dc = 0.0;
309        if (distanceConflicts != null) {
310            for (DistanceConflict.Conflict c: distanceConflicts) {
311                Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1());
312                if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority())
313                    dc += base * iDistanceConflict;
314                else
315                    dc += getWeight(assignment, other) * iDistanceConflict;
316            }
317        }
318        double toc = 0.0;
319        if (timeOverlappingConflicts != null) {
320            for (TimeOverlapsCounter.Conflict c: timeOverlappingConflicts) {
321                toc += base * Math.min(iTimeOverlapFactor * c.getShare() / enrollment.getNrSlots(), iTimeOverlapMaxLimit);
322                Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1());
323                if (other.getRequest() != null)
324                    toc += getWeight(assignment, other) * Math.min(iTimeOverlapFactor * c.getShare() / other.getNrSlots(), iTimeOverlapMaxLimit);
325            }
326        }
327        return round(base - dc - toc);
328    }
329    
330    
331    @Override
332    public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) {
333        return currentSolution.getBestInfo() == null || currentSolution.getModel().getTotalValue(currentSolution.getAssignment()) < currentSolution.getBestValue();
334    }
335    
336    @Override
337    public boolean isFreeTimeAllowOverlaps() {
338        return false;
339    }
340    
341    /**
342     * Test case -- run to see the weights for a few courses
343     * @param args program arguments
344     */
345    public static void main(String[] args) {
346        PriorityStudentWeights pw = new PriorityStudentWeights(new DataProperties());
347        DecimalFormat df = new DecimalFormat("0.0000");
348        Student s = new Student(0l);
349        new CourseRequest(1l, 0, false, s, ToolBox.toList(
350                new Course(1, "A", "1", new Offering(0, "A")),
351                new Course(1, "A", "2", new Offering(0, "A")),
352                new Course(1, "A", "3", new Offering(0, "A"))), false, null);
353        new CourseRequest(2l, 1, false, s, ToolBox.toList(
354                new Course(1, "B", "1", new Offering(0, "B")),
355                new Course(1, "B", "2", new Offering(0, "B")),
356                new Course(1, "B", "3", new Offering(0, "B"))), false, null);
357        new CourseRequest(3l, 2, false, s, ToolBox.toList(
358                new Course(1, "C", "1", new Offering(0, "C")),
359                new Course(1, "C", "2", new Offering(0, "C")),
360                new Course(1, "C", "3", new Offering(0, "C"))), false, null);
361        new CourseRequest(4l, 3, false, s, ToolBox.toList(
362                new Course(1, "D", "1", new Offering(0, "D")),
363                new Course(1, "D", "2", new Offering(0, "D")),
364                new Course(1, "D", "3", new Offering(0, "D"))), false, null);
365        new CourseRequest(5l, 4, false, s, ToolBox.toList(
366                new Course(1, "E", "1", new Offering(0, "E")),
367                new Course(1, "E", "2", new Offering(0, "E")),
368                new Course(1, "E", "3", new Offering(0, "E"))), false, null);
369        new CourseRequest(6l, 5, true, s, ToolBox.toList(
370                new Course(1, "F", "1", new Offering(0, "F")),
371                new Course(1, "F", "2", new Offering(0, "F")),
372                new Course(1, "F", "3", new Offering(0, "F"))), false, null);
373        new CourseRequest(7l, 6, true, s, ToolBox.toList(
374                new Course(1, "G", "1", new Offering(0, "G")),
375                new Course(1, "G", "2", new Offering(0, "G")),
376                new Course(1, "G", "3", new Offering(0, "G"))), false, null);
377        
378        Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>();
379        Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
380        for (Request r: s.getRequests()) {
381            CourseRequest cr = (CourseRequest)r;
382            double[] w = new double[] {0.0, 0.0, 0.0};
383            for (int i = 0; i < cr.getCourses().size(); i++) {
384                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
385                Set<SctAssignment> sections = new HashSet<SctAssignment>();
386                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
387                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
388                w[i] = pw.getWeight(assignment, e, null, null);
389            }
390            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
391        }
392
393        System.out.println("With one distance conflict:");
394        for (Request r: s.getRequests()) {
395            CourseRequest cr = (CourseRequest)r;
396            double[] w = new double[] {0.0, 0.0, 0.0};
397            for (int i = 0; i < cr.getCourses().size(); i++) {
398                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
399                Set<SctAssignment> sections = new HashSet<SctAssignment>();
400                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
401                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
402                Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>();
403                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next()));
404                w[i] = pw.getWeight(assignment, e, dc, 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 two distance conflicts:");
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                dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e,
421                        new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)));
422                w[i] = pw.getWeight(assignment, e, dc, null);
423            }
424            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
425        }
426
427        System.out.println("With 25% time overlapping conflict:");
428        for (Request r: s.getRequests()) {
429            CourseRequest cr = (CourseRequest)r;
430            double[] w = new double[] {0.0, 0.0, 0.0};
431            for (int i = 0; i < cr.getCourses().size(); i++) {
432                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
433                Set<SctAssignment> sections = new HashSet<SctAssignment>();
434                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
435                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
436                Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>();
437                toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next()));
438                w[i] = pw.getWeight(assignment, e, null, toc);
439            }
440            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
441        }
442        
443        System.out.println("Disbalanced sections (by 2 / 10 students):");
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                Subpart x = new Subpart(0, "Lec", "Lec", cfg, null);
451                Section a = new Section(0, 10, "x", x, p, null);
452                new Section(1, 10, "y", x, p, null);
453                sections.add(a);
454                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
455                a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
456                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
457                cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment));
458                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
459                w[i] = pw.getWeight(assignment, e, null, null);
460            }
461            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
462        }
463        
464        System.out.println("Same choice sections:");
465        pw.iMPP = true;
466        for (Request r: s.getRequests()) {
467            CourseRequest cr = (CourseRequest)r;
468            double[] w = new double[] {0.0, 0.0, 0.0};
469            for (int i = 0; i < cr.getCourses().size(); i++) {
470                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
471                Set<SctAssignment> sections = new HashSet<SctAssignment>();
472                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
473                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
474                Set<SctAssignment> other = new HashSet<SctAssignment>();
475                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
476                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
477                w[i] = pw.getWeight(assignment, e, null, null);
478            }
479            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
480        }
481        
482        System.out.println("Same time sections:");
483        for (Request r: s.getRequests()) {
484            CourseRequest cr = (CourseRequest)r;
485            double[] w = new double[] {0.0, 0.0, 0.0};
486            for (int i = 0; i < cr.getCourses().size(); i++) {
487                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
488                Set<SctAssignment> sections = new HashSet<SctAssignment>();
489                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
490                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
491                Set<SctAssignment> other = new HashSet<SctAssignment>();
492                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null)));
493                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
494                w[i] = pw.getWeight(assignment, e, null, null);
495            }
496            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
497        }
498        
499        System.out.println("Different time sections:");
500        Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>());
501        for (Request r: s.getRequests()) {
502            CourseRequest cr = (CourseRequest)r;
503            double[] w = new double[] {0.0, 0.0, 0.0};
504            for (int i = 0; i < cr.getCourses().size(); i++) {
505                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
506                Set<SctAssignment> sections = new HashSet<SctAssignment>();
507                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
508                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
509                Set<SctAssignment> other = new HashSet<SctAssignment>();
510                other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null));
511                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
512                w[i] = pw.getWeight(assignment, e, null, null);
513            }
514            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
515        }
516        
517        System.out.println("Two sections, one same choice, one same time:");
518        for (Request r: s.getRequests()) {
519            CourseRequest cr = (CourseRequest)r;
520            double[] w = new double[] {0.0, 0.0, 0.0};
521            for (int i = 0; i < cr.getCourses().size(); i++) {
522                Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering());
523                Set<SctAssignment> sections = new HashSet<SctAssignment>();
524                sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
525                sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null));
526                Enrollment e = new Enrollment(cr, i, cfg, sections, assignment);
527                Set<SctAssignment> other = new HashSet<SctAssignment>();
528                other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null));
529                other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null)));
530                cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment));
531                w[i] = pw.getWeight(assignment, e, null, null);
532            }
533            System.out.println(cr + ": " + df.format(w[0]) + "  " + df.format(w[1]) + "  " + df.format(w[2]));
534        }
535
536    }
537}