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.solver.Solver;
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 boolean init(Solver<Lecture, Placement> solver) {   
050        super.init(solver);
051        
052        iWeight = solver.getProperties().getPropertyDouble("FlexibleConstraint.Weight", 1.0d); 
053        iDebug = solver.getProperties().getPropertyBoolean("FlexibleConstraint.Debug", true); 
054        return true; 
055    }
056
057    @Override
058    public String getPlacementSelectionWeightName() {
059        return "Placement.FlexibleConstrPreferenceWeight";
060    }
061    
062    @Override
063    public void getInfo(Assignment<Lecture, Placement> assignment, Map<String, String> info) {
064        TimetableModel m = (TimetableModel)getModel();
065        if (m.getFlexibleConstraints().isEmpty()) return;
066        
067        for (FlexibleConstraintType type: FlexibleConstraintType.values()) {
068            StringBuilder debug = null;
069            int violated = 0, constraints = 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                        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 + ")");
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                StringBuilder debug = null;
107                for (FlexibleConstraint c : constraints) {            
108                    if (c.getContext(assignment).getPreference() > 0) {
109                        violated++;
110                        if (iDebug) {
111                            if (debug == null)
112                                debug = new StringBuilder(c.getOwner());
113                            else
114                                debug.append("; " + c.getOwner());
115                        }
116                    }        
117                }
118                info.put(type.getName() + " Constraints", getPerc(violated, 0, constraints.size()) + "% (" + violated + ")");
119                if (iDebug && violated > 0) info.put(type.getName() + " Violations", debug.toString());
120            }
121        }
122    }
123    
124    @Override
125    public double getValue(Assignment<Lecture, Placement> assignment, Collection<Lecture> variables) { 
126        Set<FlexibleConstraint> flexibleConstraints = new HashSet<FlexibleConstraint>();
127        for (Lecture lecture: variables){
128            flexibleConstraints.addAll(lecture.getFlexibleGroupConstraints());
129        }
130        int ret = 0;
131        for (FlexibleConstraint gc: flexibleConstraints){
132            ret += gc.getContext(assignment).getPreference();
133        }       
134        return ret;
135    }  
136    
137    @Override
138    public double getValue(Assignment<Lecture, Placement> assignment, Placement value, Set<Placement> conflicts) {
139        HashMap<Lecture, Placement> assignments = new HashMap<Lecture, Placement>();
140        assignments.put(value.variable(), value);      
141        
142        double ret = 0.0;        
143        for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints())
144            ret += gc.getCurrentPreference(assignment, conflicts, assignments);
145        
146        assignments.put(value.variable(), null);
147        for (FlexibleConstraint gc : value.variable().getFlexibleGroupConstraints())
148            ret -= gc.getCurrentPreference(assignment, conflicts, assignments);
149        
150        return ret;
151    }   
152}