    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}