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