    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}