001    package net.sf.cpsolver.coursett.criteria;
002    
003    import java.util.Collection;
004    import java.util.HashMap;
005    import java.util.HashSet;
006    import java.util.Map;
007    import java.util.Set;
008    
009    import net.sf.cpsolver.coursett.constraint.FlexibleConstraint;
010    import net.sf.cpsolver.coursett.constraint.FlexibleConstraint.FlexibleConstraintType;
011    import net.sf.cpsolver.coursett.model.Lecture;
012    import net.sf.cpsolver.coursett.model.Placement;
013    import net.sf.cpsolver.coursett.model.TimetableModel;
014    import net.sf.cpsolver.ifs.solver.Solver;
015    
016    /**
017     * The class encapsulates various flexible constraints concerning compact timetables of
018     * instructors. 
019     * 
020     * <br>
021     * @version CourseTT 1.2 (University Course Timetabling)<br>
022     *          Copyright (C) 2012 Matej Lukac<br>
023     * <br>
024     *          This library is free software; you can redistribute it and/or modify
025     *          it under the terms of the GNU Lesser General Public License as
026     *          published by the Free Software Foundation; either version 3 of the
027     *          License, or (at your option) any later version. <br>
028     * <br>
029     *          This library is distributed in the hope that it will be useful, but
030     *          WITHOUT ANY WARRANTY; without even the implied warranty of
031     *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
032     *          Lesser General Public License for more details. <br>
033     * <br>
034     *          You should have received a copy of the GNU Lesser General Public
035     *          License along with this library; if not see
036     *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
037     */
038    public class FlexibleConstraintCriterion extends TimetablingCriterion  {
039        
040        private boolean iDebug;
041        
042        public FlexibleConstraintCriterion(){       
043            iValueUpdateType = ValueUpdateType.NoUpdate;
044        }
045    
046        @Override
047        public boolean init(Solver<Lecture, Placement> solver) {   
048            super.init(solver);
049            
050            iWeight = solver.getProperties().getPropertyDouble("FlexibleConstraint.Weight", 1.0d); 
051            iDebug = solver.getProperties().getPropertyBoolean("FlexibleConstraint.Debug", true); 
052            return true; 
053        }
054    
055        @Override
056        public String getPlacementSelectionWeightName() {
057            return "Placement.FlexibleConstrPreferenceWeight";
058        }
059        
060        @Override
061        public void getInfo(Map<String, String> info) {
062            TimetableModel m = (TimetableModel)getModel();
063            if (m.getFlexibleConstraints().isEmpty()) return;
064            
065            for (FlexibleConstraintType type: FlexibleConstraintType.values()) {
066                StringBuilder debug = null;
067                int violated = 0, constraints = 0;
068    
069                for (FlexibleConstraint c : m.getFlexibleConstraints()) {
070                    if (type.equals(c.getType())) {
071                        constraints ++;
072                        if (!c.isConsistent(null, null)) {
073                            violated++;
074                            if (iDebug) {
075                                if (debug == null)
076                                    debug = new StringBuilder(c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(new HashSet<Placement>(), null)) + ")");
077                                else
078                                    debug.append("; " + c.getOwner() + " (" + sDoubleFormat.format(c.getNrViolations(new HashSet<Placement>(), null)) + ")");
079                            }
080                        }
081                    }
082                }
083                
084                if (constraints > 0) {
085                    info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints) + "% (" + violated + ")");
086                    if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString());
087                }
088            }
089        }
090        
091        @Override
092        public void getInfo(Map<String, String> info, Collection<Lecture> variables) {
093            for (FlexibleConstraintType type: FlexibleConstraintType.values()) {
094                
095                Set<FlexibleConstraint> constraints = new HashSet<FlexibleConstraint>();
096                for (Lecture lecture : variables) {
097                    for (FlexibleConstraint c : lecture.getFlexibleGroupConstraints()) {
098                        if (type.equals(c.getType())) constraints.add(c);
099                    }
100                }
101                
102                if (!constraints.isEmpty()) {
103                    int violated = 0;
104                    StringBuilder debug = null;
105                    for (FlexibleConstraint c : constraints) {            
106                        if (!c.isConsistent(null, null)) {
107                            violated++;
108                            if (iDebug) {
109                                if (debug == null)
110                                    debug = new StringBuilder(c.getOwner());
111                                else
112                                    debug.append("; " + c.getOwner());
113                            }
114                        }        
115                    }
116                    info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints.size()) + "% (" + violated + ")");
117                    if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString());
118                }
119            }
120        }
121        
122        @Override
123        public double getValue(Collection<Lecture> variables) { 
124            Set<FlexibleConstraint> flexibleConstraints = new HashSet<FlexibleConstraint>();
125            for (Lecture lecture: variables){
126                flexibleConstraints.addAll(lecture.getFlexibleGroupConstraints());
127            }
128            int ret = 0;
129            for (FlexibleConstraint gc: flexibleConstraints){
130                ret += gc.getCurrentPreference(null, null);
131            }       
132            return ret;
133        }  
134        
135        @Override
136        public double getValue(Placement value, Set<Placement> conflicts) {
137            HashMap<Lecture, Placement> assignments = new HashMap<Lecture, Placement>();
138            if (value != null) assignments.put(value.variable(), value);      
139            
140            double ret = 0.0;        
141            for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints())
142                ret += gc.getCurrentPreference(conflicts, assignments);
143            return ret;
144        }   
145    }