001package net.sf.cpsolver.coursett.criteria;
002
003import java.util.Collection;
004import java.util.HashMap;
005import java.util.HashSet;
006import java.util.Map;
007import java.util.Set;
008
009import net.sf.cpsolver.coursett.constraint.FlexibleConstraint;
010import net.sf.cpsolver.coursett.constraint.FlexibleConstraint.FlexibleConstraintType;
011import net.sf.cpsolver.coursett.model.Lecture;
012import net.sf.cpsolver.coursett.model.Placement;
013import net.sf.cpsolver.coursett.model.TimetableModel;
014import 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 */
038public 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        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        
144        assignments.put(value.variable(), null);
145        for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints())
146            ret -= gc.getCurrentPreference(conflicts, assignments);
147        
148        return ret;
149    }   
150}