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