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