001package org.cpsolver.studentsct.extension;
002
003import java.util.HashSet;
004import java.util.Set;
005
006import org.apache.log4j.Logger;
007import org.cpsolver.ifs.assignment.Assignment;
008import org.cpsolver.ifs.assignment.context.AssignmentConstraintContext;
009import org.cpsolver.ifs.assignment.context.ExtensionWithContext;
010import org.cpsolver.ifs.solver.Solver;
011import org.cpsolver.ifs.util.DataProperties;
012import org.cpsolver.studentsct.StudentSectioningModel;
013import org.cpsolver.studentsct.StudentSectioningModel.StudentSectioningModelContext;
014import org.cpsolver.studentsct.model.Enrollment;
015import org.cpsolver.studentsct.model.FreeTimeRequest;
016import org.cpsolver.studentsct.model.Request;
017import org.cpsolver.studentsct.model.SctAssignment;
018import org.cpsolver.studentsct.model.Section;
019import org.cpsolver.studentsct.model.Student;
020import org.cpsolver.studentsct.model.Unavailability;
021
022
023/**
024 * This extension computes time overlaps. Only sections that allow overlaps
025 * (see {@link SctAssignment#isAllowOverlap()}) can overlap. This class counts
026 * how many overlapping slots there are so that this number can be minimized.
027 * 
028 * <br>
029 * <br>
030 * 
031 * @version StudentSct 1.3 (Student Sectioning)<br>
032 *          Copyright (C) 2007 - 2014 Tomas Muller<br>
033 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
034 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
035 * <br>
036 *          This library is free software; you can redistribute it and/or modify
037 *          it under the terms of the GNU Lesser General Public License as
038 *          published by the Free Software Foundation; either version 3 of the
039 *          License, or (at your option) any later version. <br>
040 * <br>
041 *          This library is distributed in the hope that it will be useful, but
042 *          WITHOUT ANY WARRANTY; without even the implied warranty of
043 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
044 *          Lesser General Public License for more details. <br>
045 * <br>
046 *          You should have received a copy of the GNU Lesser General Public
047 *          License along with this library; if not see
048 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
049 */
050
051public class TimeOverlapsCounter extends ExtensionWithContext<Request, Enrollment, TimeOverlapsCounter.TimeOverlapsCounterContext> {
052    private static Logger sLog = Logger.getLogger(TimeOverlapsCounter.class);
053    /** Debug flag */
054    public static boolean sDebug = false;
055
056    /**
057     * Constructor. Beside of other things, this constructor also uses
058     * {@link StudentSectioningModel#setTimeOverlaps(TimeOverlapsCounter)} to
059     * set the this instance to the model.
060     * 
061     * @param solver
062     *            constraint solver
063     * @param properties
064     *            configuration
065     */
066    public TimeOverlapsCounter(Solver<Request, Enrollment> solver, DataProperties properties) {
067        super(solver, properties);
068        if (solver != null)
069            ((StudentSectioningModel) solver.currentSolution().getModel()).setTimeOverlaps(this);
070    }
071
072    @Override
073    public String toString() {
074        return "TimeOverlaps";
075    }
076
077    /**
078     * Return true if the given two assignments are overlapping.
079     * 
080     * @param a1
081     *            an assignment
082     * @param a2
083     *            an assignment
084     * @return true, if the given sections are in an overlapping conflict
085     */
086    public boolean inConflict(SctAssignment a1, SctAssignment a2) {
087        if (a1.getTime() == null || a2.getTime() == null) return false;
088        if (a1 instanceof Section && a2 instanceof Section && ((Section)a1).isToIgnoreStudentConflictsWith(a2.getId())) return false;
089        return a1.getTime().hasIntersection(a2.getTime());
090    }
091    
092    /**
093     * If the two sections are overlapping, return the number of slots of the overlap.
094     * 
095     * @param a1
096     *            an assignment
097     * @param a2
098     *            an assignment
099     * @return the number of overlapping slots against the number of slots of the smallest section
100     */
101    public int share(SctAssignment a1, SctAssignment a2) {
102        if (!inConflict(a1, a2)) return 0;
103        return a1.getTime().nrSharedDays(a2.getTime()) * a1.getTime().nrSharedHours(a2.getTime());
104    }
105
106
107    /**
108     * Return number of time overlapping conflicts that are between two enrollments. It
109     * is the total share between pairs of assignments of these enrollments that are in a
110     * time overlap.
111     * 
112     * @param e1
113     *            an enrollment
114     * @param e2
115     *            an enrollment
116     * @return number of time overlapping conflict between given enrollments
117     */
118    public int nrConflicts(Enrollment e1, Enrollment e2) {
119        if (!e1.getStudent().equals(e2.getStudent())) return 0;
120        if (e1.getRequest() instanceof FreeTimeRequest && e2.getRequest() instanceof FreeTimeRequest) return 0;
121        int cnt = 0;
122        for (SctAssignment s1 : e1.getAssignments()) {
123            for (SctAssignment s2 : e2.getAssignments()) {
124                if (inConflict(s1, s2))
125                    cnt += share(s1, s2);
126            }
127        }
128        return cnt;
129    }
130
131    /**
132     * Return a set of time overlapping conflicts ({@link Conflict} objects) between
133     * given (course) enrollments.
134     * 
135     * @param e1
136     *            an enrollment
137     * @param e2
138     *            an enrollment
139     * @return list of time overlapping conflicts that are between assignment of the
140     *         given enrollments
141     */
142    public Set<Conflict> conflicts(Enrollment e1, Enrollment e2) {
143        Set<Conflict> ret = new HashSet<Conflict>();
144        if (!e1.getStudent().equals(e2.getStudent())) return ret;
145        if (e1.getRequest() instanceof FreeTimeRequest && e2.getRequest() instanceof FreeTimeRequest) return ret;
146        for (SctAssignment s1 : e1.getAssignments()) {
147            for (SctAssignment s2 : e2.getAssignments()) {
148                if (inConflict(s1, s2))
149                    ret.add(new Conflict(e1.getStudent(), share(s1, s2), e1, s1, e2, s2));
150            }
151        }
152        return ret;
153    }
154
155    /**
156     * Total sum of all free time conflict of the given enrollment.
157     * @param enrollment given enrollment
158     * @return number of all free time conflicts of the given enrollment
159     */
160    public int nrFreeTimeConflicts(Enrollment enrollment) {
161        if (enrollment.getRequest() instanceof FreeTimeRequest) return 0;
162        int cnt = 0;
163        for (Request request : enrollment.getStudent().getRequests()) {
164            if (request instanceof FreeTimeRequest) {
165                FreeTimeRequest ft = (FreeTimeRequest)request;
166                for (SctAssignment section: enrollment.getAssignments())
167                    cnt += share(section, ft);
168            }
169        }
170        return cnt;
171    }
172    
173    /**
174     * Return a set of free time conflict of the given enrollment.
175     * @param enrollment given enrollment
176     * @return set of all free time conflicts of the given enrollment
177     */
178    public Set<Conflict> freeTimeConflicts(Enrollment enrollment) {
179        Set<Conflict> ret = new HashSet<Conflict>();
180        if (enrollment.getRequest() instanceof FreeTimeRequest) return ret;
181        for (Request request : enrollment.getStudent().getRequests()) {
182            if (request instanceof FreeTimeRequest) {
183                FreeTimeRequest ft = (FreeTimeRequest)request;
184                for (SctAssignment section: enrollment.getAssignments()) {
185                    if (inConflict(section, ft))
186                        ret.add(new Conflict(enrollment.getStudent(), share(section, ft), enrollment, section, ft.createEnrollment(), ft));
187                }
188            }
189        }
190        return ret;
191    }
192    
193    /**
194     * Total sum of all unavailability time conflict of the given enrollment.
195     * @param enrollment given enrollment
196     * @return number of all unavailability time conflicts of the given enrollment
197     */
198    public int nrNotAvailableTimeConflicts(Enrollment enrollment) {
199        if (enrollment.getRequest() instanceof FreeTimeRequest) return 0;
200        int cnt = 0;
201        for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities())
202            for (SctAssignment section: enrollment.getAssignments())
203                cnt += share(section, unavailability);
204        return cnt;
205    }
206    
207    /**
208     * Return a set of unavailability time conflict of the given enrollment.
209     * @param enrollment given enrollment
210     * @return set of all unavailability time conflicts of the given enrollment
211     */
212    public Set<Conflict> notAvailableTimeConflicts(Enrollment enrollment) {
213        Set<Conflict> ret = new HashSet<Conflict>();
214        if (enrollment.getRequest() instanceof FreeTimeRequest) return ret;
215        for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities())
216            for (SctAssignment section: enrollment.getAssignments())
217                if (inConflict(section, unavailability))
218                    ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, null, unavailability));
219        return ret;
220    }
221    
222    /**
223     * Return a set of free and unavailability time conflict of the given enrollment.
224     * @param enrollment given enrollment
225     * @return set of all free time conflicts of the given enrollment
226     */
227    public Set<Conflict> conflicts(Enrollment enrollment) {
228        Set<Conflict> ret = new HashSet<Conflict>();
229        if (enrollment.getRequest() instanceof FreeTimeRequest) return ret;
230        for (Request request : enrollment.getStudent().getRequests()) {
231            if (request instanceof FreeTimeRequest) {
232                FreeTimeRequest ft = (FreeTimeRequest)request;
233                for (SctAssignment section: enrollment.getAssignments()) {
234                    if (inConflict(section, ft))
235                        ret.add(new Conflict(enrollment.getStudent(), share(section, ft), enrollment, section, ft.createEnrollment(), ft));
236                }
237            }
238        }
239        for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities())
240            for (SctAssignment section: enrollment.getAssignments())
241                if (inConflict(section, unavailability))
242                    ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, unavailability.createEnrollment(), unavailability));
243        return ret;
244    }
245
246    /** Actual number of all time overlapping conflicts 
247     * @param assignment current assignment
248     * @return total number of time overlapping conflicts
249     **/
250    public int getTotalNrConflicts(Assignment<Request, Enrollment> assignment) {
251        return getContext(assignment).getTotalNrConflicts();
252    }
253    
254    public void checkTotalNrConflicts(Assignment<Request, Enrollment> assignment) {
255        getContext(assignment).checkTotalNrConflicts(assignment);
256    }
257
258    /**
259     * Return a set of all time overlapping conflicts ({@link Conflict} objects).
260     * @param assignment current assignment
261     * @return set of all time overlapping conflicts in the assignment
262     */
263    public Set<Conflict> getAllConflicts(Assignment<Request, Enrollment> assignment) {
264        return getContext(assignment).getAllConflicts();
265    }
266
267    /**
268     * Called before a value is assigned to a variable.
269     */
270    @Override
271    public void beforeAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) {
272        getContext(assignment).beforeAssigned(assignment, iteration, value);
273    }
274
275    /**
276     * Called after a value is assigned to a variable.
277     */
278    @Override
279    public void afterAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) {
280        getContext(assignment).afterAssigned(assignment, iteration, value);
281    }
282
283    /**
284     * Called after a value is unassigned from a variable.
285     */
286    @Override
287    public void afterUnassigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) {
288        getContext(assignment).afterUnassigned(assignment, iteration, value);
289    }
290
291    /** A representation of a time overlapping conflict */
292    public static class Conflict {
293        private int iShare;
294        private Student iStudent;
295        private SctAssignment iA1, iA2;
296        private Enrollment iE1, iE2;
297        private int iHashCode;
298
299        /**
300         * Constructor
301         * 
302         * @param student
303         *            related student
304         * @param share number of slots in common between the two conflicting sections
305         * @param e1 first enrollment
306         * @param a1
307         *            first conflicting section
308         * @param e2 second enrollment
309         * @param a2
310         *            second conflicting section
311         */
312        public Conflict(Student student, int share, Enrollment e1, SctAssignment a1, Enrollment e2, SctAssignment a2) {
313            iStudent = student;
314            if (a1.compareById(a2) < 0 ) {
315                iA1 = a1;
316                iA2 = a2;
317                iE1 = e1;
318                iE2 = e2;
319            } else {
320                iA1 = a2;
321                iA2 = a1;
322                iE1 = e2;
323                iE2 = e1;
324            }
325            iHashCode = (iStudent.getId() + ":" + iA1.getId() + ":" + iA2.getId()).hashCode();
326            iShare = share;
327        }
328
329        /** Related student
330         * @return student
331         **/
332        public Student getStudent() {
333            return iStudent;
334        }
335
336        /** First section
337         * @return first section
338         **/
339        public SctAssignment getS1() {
340            return iA1;
341        }
342
343        /** Second section
344         * @return second section
345         **/
346        public SctAssignment getS2() {
347            return iA2;
348        }
349
350        /** First request
351         * @return first request
352         **/
353        public Request getR1() {
354            return iE1.getRequest();
355        }
356        
357        /** First request weight
358         * @return first request weight
359         **/
360        public double getR1Weight() {
361            return (iE1.getRequest() == null ? 0.0 : iE1.getRequest().getWeight());
362        }
363        
364        /** Second request weight
365         * @return second request weight
366         **/
367        public double getR2Weight() {
368            return (iE2.getRequest() == null ? 0.0 : iE2.getRequest().getWeight());
369        }
370        
371        /** Second request
372         * @return second request
373         **/
374        public Request getR2() {
375            return iE2.getRequest();
376        }
377        
378        /** First enrollment
379         * @return first enrollment
380         **/
381        public Enrollment getE1() {
382            return iE1;
383        }
384
385        /** Second enrollment
386         * @return second enrollment
387         **/
388        public Enrollment getE2() {
389            return iE2;
390        }
391        
392        @Override
393        public int hashCode() {
394            return iHashCode;
395        }
396
397        /** The number of overlapping slots against the number of slots of the smallest section
398         * @return number of overlapping slots between the two sections 
399         **/
400        public int getShare() {
401            return iShare;
402        }
403
404        @Override
405        public boolean equals(Object o) {
406            if (o == null || !(o instanceof Conflict)) return false;
407            Conflict c = (Conflict) o;
408            return getStudent().equals(c.getStudent()) && getS1().equals(c.getS1()) && getS2().equals(c.getS2());
409        }
410
411        @Override
412        public String toString() {
413            return getStudent() + ": (s:" + getShare() + ") " + getS1() + " -- " + getS2();
414        }
415    }
416    
417    /**
418     * The set of all conflicts ({@link Conflict} objects) of the given
419     * enrollment and other enrollments that are assigned to the same student.
420     * @param assignment current assignment
421     * @param enrollment given enrollment
422     * @return all conflicts of the given enrollment
423     */
424    public Set<Conflict> allConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
425        Set<Conflict> ret = new HashSet<Conflict>();
426        if (enrollment.getRequest() instanceof FreeTimeRequest) return ret;
427        for (Request request : enrollment.getStudent().getRequests()) {
428            if (request.equals(enrollment.getRequest())) continue;
429            Enrollment other = assignment.getValue(request);
430            if (request instanceof FreeTimeRequest) {
431                FreeTimeRequest ft = (FreeTimeRequest)request;
432                ret.addAll(conflicts(enrollment, ft.createEnrollment()));
433                continue;
434            } else if (other != null) {
435                ret.addAll(conflicts(enrollment, other));
436            }
437        }
438        for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities())
439            for (SctAssignment section: enrollment.getAssignments())
440                if (inConflict(section, unavailability))
441                    ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, unavailability.createEnrollment(), unavailability));
442        return ret;
443    }
444    
445    public class TimeOverlapsCounterContext implements AssignmentConstraintContext<Request, Enrollment> {
446        private int iTotalNrConflicts = 0;
447        private Set<Conflict> iAllConflicts = new HashSet<Conflict>();
448        private Request iOldVariable = null;
449        private Enrollment iUnassignedValue = null;
450
451        public TimeOverlapsCounterContext(Assignment<Request, Enrollment> assignment) {
452            iTotalNrConflicts = countTotalNrConflicts(assignment);
453            if (sDebug)
454                iAllConflicts = computeAllConflicts(assignment);
455            StudentSectioningModelContext cx = ((StudentSectioningModel)getModel()).getContext(assignment);
456            for (Conflict c: computeAllConflicts(assignment))
457                cx.add(assignment, c);
458        }
459
460        /**
461         * Called when a value is assigned to a variable. Internal number of
462         * time overlapping conflicts is updated, see
463         * {@link TimeOverlapsCounter#getTotalNrConflicts(Assignment)}.
464         */
465        @Override
466        public void assigned(Assignment<Request, Enrollment> assignment, Enrollment value) {
467            StudentSectioningModelContext cx = ((StudentSectioningModel)getModel()).getContext(assignment);
468            for (Conflict c: allConflicts(assignment, value)) {
469                iTotalNrConflicts += c.getShare();
470                cx.add(assignment, c);
471            }
472            if (sDebug) {
473                sLog.debug("A:" + value.variable() + " := " + value);
474                int inc = nrAllConflicts(assignment, value);
475                if (inc != 0) {
476                    sLog.debug("-- TOC+" + inc + " A: " + value.variable() + " := " + value);
477                    for (Conflict c: allConflicts(assignment, value)) {
478                        sLog.debug("  -- " + c);
479                        iAllConflicts.add(c);
480                        inc -= c.getShare();
481                    }
482                    if (inc != 0) {
483                        sLog.error("Different number of conflicts for the assigned value (difference: " + inc + ")!");
484                    }
485                }
486            }
487        }
488
489        /**
490         * Called when a value is unassigned from a variable. Internal number of
491         * time overlapping conflicts is updated, see
492         * {@link TimeOverlapsCounter#getTotalNrConflicts(Assignment)}.
493         */
494        @Override
495        public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment value) {
496            StudentSectioningModelContext cx = ((StudentSectioningModel)getModel()).getContext(assignment);
497            for (Conflict c: allConflicts(assignment, value)) {
498                iTotalNrConflicts -= c.getShare();
499                cx.remove(assignment, c);
500            }
501            if (sDebug) {
502                sLog.debug("U:" + value.variable() + " := " + value);
503                int dec = nrAllConflicts(assignment, value);
504                if (dec != 0) {
505                    sLog.debug("-- TOC-" + dec + " U: " + value.variable() + " := " + value);
506                    for (Conflict c: allConflicts(assignment, value)) {
507                        sLog.debug("  -- " + c);
508                        iAllConflicts.remove(c);
509                        dec -= c.getShare();
510                    }
511                    if (dec != 0) {
512                        sLog.error("Different number of conflicts for the unassigned value (difference: " + dec + ")!");
513                    }
514                }
515            }
516        }
517        
518        /**
519         * Called before a value is assigned to a variable.
520         * @param assignment current assignment
521         * @param iteration current iteration
522         * @param value value to be assigned
523         */
524        public void beforeAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) {
525            if (value != null) {
526                Enrollment old = assignment.getValue(value.variable());
527                if (old != null) {
528                    iUnassignedValue = old;
529                    unassigned(assignment, old);
530                }
531                iOldVariable = value.variable();
532            }
533        }
534
535        /**
536         * Called after a value is assigned to a variable.
537         * @param assignment current assignment
538         * @param iteration current iteration
539         * @param value value that was assigned
540         */
541        public void afterAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) {
542            iOldVariable = null;
543            iUnassignedValue = null;
544            if (value != null) {
545                assigned(assignment, value);
546            }
547        }
548
549        /**
550         * Called after a value is unassigned from a variable.
551         * @param assignment current assignment
552         * @param iteration current iteration
553         * @param value value that was unassigned
554         */
555        public void afterUnassigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) {
556            if (value != null && !value.equals(iUnassignedValue)) {
557                unassigned(assignment, value);
558            }
559        }
560        
561        /**
562         * Return a set of all time overlapping conflicts ({@link Conflict} objects).
563         * @return all conflicts
564         */
565        public Set<Conflict> getAllConflicts() {
566            return iAllConflicts;
567        }
568        
569        /** Actual number of all time overlapping conflicts
570         * @return total number of all conflicts
571         **/
572        public int getTotalNrConflicts() {
573            return iTotalNrConflicts;
574        }
575        
576        public void checkTotalNrConflicts(Assignment<Request, Enrollment> assignment) {
577            int total = countTotalNrConflicts(assignment);
578            if (total != iTotalNrConflicts) {
579                sLog.error("Number of conflicts does not match (actual: " + total + ", count: " + iTotalNrConflicts + ")!");
580                iTotalNrConflicts = total;
581                if (sDebug) {
582                    Set<Conflict> conflicts = computeAllConflicts(assignment);
583                    for (Conflict c: conflicts) {
584                        if (!iAllConflicts.contains(c))
585                            sLog.debug("  +add+ " + c);
586                    }
587                    for (Conflict c: iAllConflicts) {
588                        if (!conflicts.contains(c))
589                            sLog.debug("  -rem- " + c);
590                    }
591                    for (Conflict c: conflicts) {
592                        for (Conflict d: iAllConflicts) {
593                            if (c.equals(d) && c.getShare() != d.getShare()) {
594                                sLog.debug("  -dif- " + c + " (other: " + d.getShare() + ")");
595                            }
596                        }
597                    }                
598                    iAllConflicts = conflicts;
599                    // getSolver().stopSolver(false);
600                }
601            }
602        }
603        
604        /**
605         * Compute the actual number of all time overlapping conflicts. Should be equal to
606         * {@link TimeOverlapsCounter#getTotalNrConflicts(Assignment)}.
607         * @param assignment current assignment
608         * @return counted number of all time conflicts in the assignment
609         */
610        public int countTotalNrConflicts(Assignment<Request, Enrollment> assignment) {
611            int total = 0;
612            for (Request r1 : getModel().variables()) {
613                Enrollment e1 = assignment.getValue(r1);
614                if (e1 == null || r1 instanceof FreeTimeRequest || r1.equals(iOldVariable))
615                    continue;
616                for (Request r2 : r1.getStudent().getRequests()) {
617                    Enrollment e2 = assignment.getValue(r2);
618                    if (r2 instanceof FreeTimeRequest) {
619                        FreeTimeRequest ft = (FreeTimeRequest)r2;
620                        total += nrConflicts(e1, ft.createEnrollment());
621                    } else if (e2 != null && r1.getId() < r2.getId() && !r2.equals(iOldVariable)) {
622                        total += nrConflicts(e1, e2);
623                    }
624                }
625                total += nrNotAvailableTimeConflicts(e1);
626            }
627            return total;
628        }
629
630        /**
631         * Compute a set of all time overlapping conflicts ({@link Conflict} objects).
632         * @param assignment current assignment
633         * @return set of all time conflicts in the assignment
634         */
635        public Set<Conflict> computeAllConflicts(Assignment<Request, Enrollment> assignment) {
636            Set<Conflict> ret = new HashSet<Conflict>();
637            for (Request r1 : getModel().variables()) {
638                Enrollment e1 = assignment.getValue(r1);
639                if (e1 == null || r1 instanceof FreeTimeRequest || r1.equals(iOldVariable))
640                    continue;
641                for (Request r2 : r1.getStudent().getRequests()) {
642                    Enrollment e2 = assignment.getValue(r2);
643                    if (r2 instanceof FreeTimeRequest) {
644                        FreeTimeRequest ft = (FreeTimeRequest)r2;
645                        ret.addAll(conflicts(e1, ft.createEnrollment()));
646                    } else if (e2 != null && r1.getId() < r2.getId() && !r2.equals(iOldVariable)) {
647                        ret.addAll(conflicts(e1, e2));
648                    }                    
649                }
650                for (Unavailability unavailability: e1.getStudent().getUnavailabilities())
651                    for (SctAssignment section: e1.getAssignments())
652                        if (inConflict(section, unavailability))
653                            ret.add(new Conflict(e1.getStudent(), share(section, unavailability), e1, section, unavailability.createEnrollment(), unavailability));
654            }
655            return ret;
656        }
657
658        /**
659         * The set of all conflicts ({@link Conflict} objects) of the given
660         * enrollment and other enrollments that are assigned to the same student.
661         * @param assignment current assignment
662         * @param enrollment given enrollment
663         * @return set of all conflict of the given enrollment
664         */
665        public Set<Conflict> allConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
666            Set<Conflict> ret = new HashSet<Conflict>();
667            if (enrollment.getRequest() instanceof FreeTimeRequest) return ret;
668            for (Request request : enrollment.getStudent().getRequests()) {
669                if (request.equals(enrollment.getRequest())) continue;
670                if (request instanceof FreeTimeRequest) {
671                    FreeTimeRequest ft = (FreeTimeRequest)request;
672                    ret.addAll(conflicts(enrollment, ft.createEnrollment()));
673                    continue;
674                } else if (assignment.getValue(request) != null && !request.equals(iOldVariable)) {
675                    ret.addAll(conflicts(enrollment, assignment.getValue(request)));
676                }
677            }
678            for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities())
679                for (SctAssignment section: enrollment.getAssignments())
680                    if (inConflict(section, unavailability))
681                        ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, unavailability.createEnrollment(), unavailability));
682            return ret;
683        }
684        
685        /**
686         * Total sum of all conflict of the given enrollment and other enrollments
687         * that are assigned to the same student.
688         * @param assignment current assignment
689         * @param enrollment given enrollment
690         * @return number of all conflict of the given enrollment
691         */
692        public int nrAllConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
693            if (enrollment.getRequest() instanceof FreeTimeRequest) return 0;
694            int cnt = 0;
695            for (Request request : enrollment.getStudent().getRequests()) {
696                if (request.equals(enrollment.getRequest())) continue;
697                if (request instanceof FreeTimeRequest) {
698                    FreeTimeRequest ft = (FreeTimeRequest)request;
699                    cnt += nrConflicts(enrollment, ft.createEnrollment());
700                } else if (assignment.getValue(request) != null && !request.equals(iOldVariable)) {
701                    cnt += nrConflicts(enrollment, assignment.getValue(request));
702                }
703            }
704            cnt += nrNotAvailableTimeConflicts(enrollment);
705            return cnt;
706        }
707    }
708
709    @Override
710    public TimeOverlapsCounterContext createAssignmentContext(Assignment<Request, Enrollment> assignment) {
711        return new TimeOverlapsCounterContext(assignment);
712    }
713}