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