    001package org.cpsolver.ifs.model;
    002
    003import java.util.ArrayList;
    004import java.util.Collection;
    005import java.util.Collections;
    006import java.util.Comparator;
    007import java.util.HashSet;
    008import java.util.HashMap;
    009import java.util.List;
    010import java.util.Locale;
    011import java.util.Map;
    012import java.util.Set;
    013import java.util.TreeSet;
    014import java.util.concurrent.locks.ReentrantReadWriteLock;
    015
    016import org.cpsolver.coursett.criteria.TimetablingCriterion;
    017import org.cpsolver.ifs.assignment.Assignment;
    018import org.cpsolver.ifs.assignment.DefaultInheritedAssignment;
    019import org.cpsolver.ifs.assignment.DefaultSingleAssignment;
    020import org.cpsolver.ifs.assignment.EmptyAssignment;
    021import org.cpsolver.ifs.assignment.InheritedAssignment;
    022import org.cpsolver.ifs.assignment.context.AssignmentContext;
    023import org.cpsolver.ifs.assignment.context.AssignmentContextReference;
    024import org.cpsolver.ifs.assignment.context.HasAssignmentContext;
    025import org.cpsolver.ifs.criteria.Criterion;
    026import org.cpsolver.ifs.solution.Solution;
    027import org.cpsolver.ifs.solver.Solver;
    028import org.cpsolver.ifs.util.ToolBox;
    029
    030
    031/**
    032 * Generic model (definition of a problem). <br>
    033 * <br>
    034 * It consists of variables and constraints. It has also capability of
    035 * memorizing the current and the best ever found assignment. <br>
    036 * <br>
    037 * Example usage:<br>
    038 * <pre>
    039 * <code>
    040 * MyModel model = new MyModel();
    041 * Variable a = new MyVariable("A");
    042 * model.addVariable(a);
    043 * Variable b = new MyVariable("B");
    044 * model.addVariable(b);
    045 * Variable c = new MyVariable("C");
    046 * model.addVariable(c);
    047 * Constraint constr = MyConstraint("all-different");
    048 * model.addConstraint(constr);
    049 * constr.addVariable(a);
    050 * constr.addVariable(b);
    051 * constr.addVariable(c);
    052 * solver.setInitialSolution(model);
    053 * </code>
    054 * </pre>
    055 *
    056 * @see Variable
    057 * @see Constraint
    058 * @see org.cpsolver.ifs.solution.Solution
    059 * @see org.cpsolver.ifs.solver.Solver
    060 *
    061 * @author  Tomáš Müller
    062 * @version IFS 1.3 (Iterative Forward Search)<br>
    063 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
    064 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    065 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    066 * <br>
    067 *          This library is free software; you can redistribute it and/or modify
    068 *          it under the terms of the GNU Lesser General Public License as
    069 *          published by the Free Software Foundation; either version 3 of the
    070 *          License, or (at your option) any later version. <br>
    071 * <br>
    072 *          This library is distributed in the hope that it will be useful, but
    073 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    074 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    075 *          Lesser General Public License for more details. <br>
    076 * <br>
    077 *          You should have received a copy of the GNU Lesser General Public
    078 *          License along with this library; if not see
    079 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    080 *
    081 * @param <V> Variable
    082 * @param <T> Value
    083 */
    084public class Model<V extends Variable<V, T>, T extends Value<V, T>> {
    085    private static org.apache.logging.log4j.Logger sLogger = org.apache.logging.log4j.LogManager.getLogger(Model.class);
    086    protected static java.text.DecimalFormat sTimeFormat = new java.text.DecimalFormat("0.00",
    087            new java.text.DecimalFormatSymbols(Locale.US));
    088    protected static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.00",
    089            new java.text.DecimalFormatSymbols(Locale.US));
    090    protected static java.text.DecimalFormat sPercentageFormat = new java.text.DecimalFormat("0.00",
    091            new java.text.DecimalFormatSymbols(Locale.US));
    092
    093    private List<V> iVariables = new ArrayList<V>();
    094    private List<Constraint<V, T>> iConstraints = new ArrayList<Constraint<V, T>>();
    095    private List<GlobalConstraint<V, T>> iGlobalConstraints = new ArrayList<GlobalConstraint<V, T>>();
    096    private Collection<V> iVariablesWithInitialValueCache = null;
    097    private final ReentrantReadWriteLock iVariablesWithInitialValueLock = new ReentrantReadWriteLock();
    098
    099    private List<ModelListener<V, T>> iModelListeners = new ArrayList<ModelListener<V, T>>();
    100    private List<InfoProvider<V, T>> iInfoProviders = new ArrayList<InfoProvider<V, T>>();
    101    private HashMap<String, Criterion<V, T>> iCriteria = new HashMap<String, Criterion<V,T>>();
    102
    103    private int iBestUnassignedVariables = -1;
    104    private int iBestPerturbations = 0;
    105    private double iBestValue = 0.0;
    106    private int iNextReferenceId = 0;
    107    private int iNextVariableIndex = 0;
    108    @Deprecated
    109    private Assignment<V, T> iAssignment = null;
    110    private Assignment<V, T> iEmptyAssignment = null;
    111    private Map<Integer, AssignmentContextReference<V, T, ? extends AssignmentContext>> iAssignmentContextReferences = new HashMap<Integer, AssignmentContextReference<V, T, ? extends AssignmentContext>>();
    112
    113    /** Constructor */
    114    public Model() {
    115    }
    116
    117    /** The list of variables in the model
    118     * @return list of variables in the model
    119     **/
    120    public List<V> variables() {
    121        return iVariables;
    122    }
    123
    124    /** The number of variables in the model
    125     * @return number of variables in the model
    126     **/
    127    public int countVariables() {
    128        return iVariables.size();
    129    }
    130
    131    /** Adds a variable to the model
    132     * @param variable a variable
    133     **/
    134    @SuppressWarnings("unchecked")
    135    public void addVariable(V variable) {
    136        variable.setModel(this);
    137        variable.setIndex(iNextVariableIndex++);
    138        iVariables.add(variable);
    139        if (variable instanceof InfoProvider<?, ?>)
    140            iInfoProviders.add((InfoProvider<V, T>) variable);
    141        for (ModelListener<V, T> listener : iModelListeners)
    142            listener.variableAdded(variable);
    143        invalidateVariablesWithInitialValueCache();
    144    }
    145
    146    /** Removes a variable from the model
    147     * @param variable a variable
    148     **/
    149    @SuppressWarnings("unchecked")
    150    public void removeVariable(V variable) {
    151        variable.setModel(null);
    152        iVariables.remove(variable);
    153        if (variable instanceof InfoProvider<?, ?>)
    154            iInfoProviders.remove((InfoProvider<?, ?>)variable);
    155        for (ModelListener<V, T> listener : iModelListeners)
    156            listener.variableRemoved(variable);
    157        invalidateVariablesWithInitialValueCache();
    158        if (variable instanceof HasAssignmentContext)
    159            removeReference((HasAssignmentContext<V, T, ?>)variable);
    160    }
    161
    162    /** The list of constraints in the model
    163     * @return list of constraints in the model
    164     **/
    165    public List<Constraint<V, T>> constraints() {
    166        return iConstraints;
    167    }
    168
    169    /** The number of constraints in the model
    170     * @return number of constraints in the model
    171     **/
    172    public int countConstraints() {
    173        return iConstraints.size();
    174    }
    175
    176    /** Adds a constraint to the model
    177     * @param constraint a constraint
    178     **/
    179    @SuppressWarnings("unchecked")
    180    public void addConstraint(Constraint<V, T> constraint) {
    181        constraint.setModel(this);
    182        iConstraints.add(constraint);
    183        if (constraint instanceof InfoProvider<?, ?>)
    184            iInfoProviders.add((InfoProvider<V, T>) constraint);
    185        for (ModelListener<V, T> listener : iModelListeners)
    186            listener.constraintAdded(constraint);
    187    }
    188
    189    /** Removes a constraint from the model
    190     * @param constraint a constraint
    191     **/
    192    @SuppressWarnings("unchecked")
    193    public void removeConstraint(Constraint<V, T> constraint) {
    194        constraint.setModel(null);
    195        iConstraints.remove(constraint);
    196        if (constraint instanceof InfoProvider<?, ?>)
    197            iInfoProviders.remove((InfoProvider<?, ?>)constraint);
    198        for (ModelListener<V, T> listener : iModelListeners)
    199            listener.constraintRemoved(constraint);
    200        if (constraint instanceof HasAssignmentContext)
    201            removeReference((HasAssignmentContext<V, T, ?>)constraint);
    202    }
    203
    204    /** The list of global constraints in the model
    205     * @return  list of global constraints in the model
    206     **/
    207    public List<GlobalConstraint<V, T>> globalConstraints() {
    208        return iGlobalConstraints;
    209    }
    210
    211    /** The number of global constraints in the model
    212     * @return number of global constraints in the model
    213     **/
    214    public int countGlobalConstraints() {
    215        return iGlobalConstraints.size();
    216    }
    217
    218    /** Adds a global constraint to the model
    219     * @param constraint a global constraint
    220     **/
    221    @SuppressWarnings("unchecked")
    222    public void addGlobalConstraint(GlobalConstraint<V, T> constraint) {
    223        constraint.setModel(this);
    224        iGlobalConstraints.add(constraint);
    225        if (constraint instanceof InfoProvider<?, ?>)
    226            iInfoProviders.add((InfoProvider<V, T>) constraint);
    227        for (ModelListener<V, T> listener : iModelListeners)
    228            listener.constraintAdded(constraint);
    229        if (constraint instanceof ModelListener<?, ?>)
    230            iModelListeners.add((ModelListener<V, T>) constraint);
    231    }
    232
    233    /** Removes a global constraint from the model
    234     * @param constraint a global constraint
    235     **/
    236    @SuppressWarnings("unchecked")
    237    public void removeGlobalConstraint(GlobalConstraint<V, T> constraint) {
    238        constraint.setModel(null);
    239        iGlobalConstraints.remove(constraint);
    240        if (constraint instanceof InfoProvider<?, ?>)
    241            iInfoProviders.remove((InfoProvider<?, ?>) constraint);
    242        if (constraint instanceof ModelListener<?, ?>)
    243            iModelListeners.remove((ModelListener<V, T>) constraint);
    244        for (ModelListener<V, T> listener : iModelListeners)
    245            listener.constraintRemoved(constraint);
    246        if (constraint instanceof HasAssignmentContext)
    247            removeReference((HasAssignmentContext<V, T, ?>)constraint);
    248    }
    249
    250    /**
    251     * The list of unassigned variables in the model.
    252     * Use {@link Model#unassignedVariables(Assignment)} or {@link Assignment#unassignedVariables(Model)} instead.
    253     * @return list of unassigned variables in the model
    254     **/
    255    @Deprecated
    256    public Collection<V> unassignedVariables() {
    257        return unassignedVariables(getDefaultAssignment());
    258    }
    259
    260    /** The list of unassigned variables in the model
    261     * @param assignment current assignment
    262     * @return list of unassigned variables in the model
    263     **/
    264    public Collection<V> unassignedVariables(Assignment<V, T> assignment) {
    265        return assignment.unassignedVariables(this);
    266    }
    267
    268    /**
    269     * Number of unassigned variables.
    270     * Use {@link Model#nrUnassignedVariables(Assignment)} or {@link Assignment#nrUnassignedVariables(Model)} instead.
    271     * @return number of unassigned variables in the model
    272     **/
    273    @Deprecated
    274    public int nrUnassignedVariables() {
    275        return nrUnassignedVariables(getDefaultAssignment());
    276    }
    277
    278    /** Number of unassigned variables
    279     * @param assignment current assignment
    280     * @return number of unassigned variables in the model
    281     **/
    282    public int nrUnassignedVariables(Assignment<V, T> assignment) {
    283        return assignment.nrUnassignedVariables(this);
    284    }
    285
    286    /**
    287     * The list of assigned variables in the model.
    288     * Use {@link Model#assignedVariables(Assignment)} or {@link Assignment#assignedVariables()} instead.
    289     * @return list of assigned variables in the model
    290     **/
    291    @Deprecated
    292    public Collection<V> assignedVariables() {
    293        return assignedVariables(getDefaultAssignment());
    294    }
    295
    296    /** The list of assigned variables in the model
    297     * @param assignment current assignment
    298     * @return list of assigned variables in the model
    299     **/
    300    public Collection<V> assignedVariables(Assignment<V, T> assignment) {
    301        return assignment.assignedVariables();
    302    }
    303
    304    /**
    305     * Number of assigned variables.
    306     * Use {@link Model#nrAssignedVariables(Assignment)} or {@link Assignment#nrAssignedVariables()} instead.
    307     * @return number of assigned variables in the model
    308     **/
    309    @Deprecated
    310    public int nrAssignedVariables() {
    311        return nrAssignedVariables(getDefaultAssignment());
    312    }
    313
    314    /** Number of assigned variables
    315     * @param assignment current assignment
    316     * @return number of assigned variables in the model
    317     **/
    318    public int nrAssignedVariables(Assignment<V, T> assignment) {
    319        return assignment.nrAssignedVariables();
    320    }
    321
    322    /**
    323     * The list of perturbation variables in the model, i.e., the variables
    324     * which has an initial value but which are not assigned with this value.
    325     * Use {@link Model#perturbVariables(Assignment)} instead.
    326     * @return list of perturbation variables in the model
    327     */
    328    @Deprecated
    329    public Collection<V> perturbVariables() {
    330        return perturbVariables(getDefaultAssignment(), variablesWithInitialValue());
    331    }
    332
    333    /**
    334     * The list of perturbation variables in the model, i.e., the variables
    335     * which has an initial value but which are not assigned with this value.
    336     * @param assignment current assignment
    337     * @return list of perturbation variables in the model
    338     */
    339    public Collection<V> perturbVariables(Assignment<V, T> assignment) {
    340        return perturbVariables(assignment, variablesWithInitialValue());
    341    }
    342
    343    /**
    344     * The list of perturbation variables in the model, i.e., the variables
    345     * which has an initial value but which are not assigned with this value.
    346     * Only variables from the given set are considered.
    347     * Use {@link Model#perturbVariables(Assignment, Collection)} instead.
    348     * @param variables sub-problem
    349     * @return list of perturbation variables in the sub-problem
    350     */
    351    @Deprecated
    352    public List<V> perturbVariables(Collection<V> variables) {
    353        return perturbVariables(getDefaultAssignment(), variables);
    354    }
    355
    356    /**
    357     * The list of perturbation variables in the model, i.e., the variables
    358     * which has an initial value but which are not assigned with this value.
    359     * Only variables from the given set are considered.
    360     * @param assignment current assignment
    361     * @param variables sub-problem
    362     * @return list of perturbation variables in the sub-problem
    363     */
    364    public List<V> perturbVariables(Assignment<V, T> assignment, Collection<V> variables) {
    365        return perturbVariables(assignment, variables, true);
    366    }
    367
    368    /**
    369     * The list of perturbation variables in the model, i.e., the variables
    370     * which has an initial value but which are not assigned with this value.
    371     * Only variables from the given set are considered.
    372     * @param assignment current assignment
    373     * @param variables sub-problem
    374     * @param includeNotAssigned when true, include not assigned variables with a hard conflict (that cannot be assigned)
    375     * @return list of perturbation variables in the sub-problem
    376     */
    377    public List<V> perturbVariables(Assignment<V, T> assignment, Collection<V> variables, boolean includeNotAssigned) {
    378        List<V> perturbances = new ArrayList<V>();
    379        for (V variable : variables) {
    380            if (variable.getInitialAssignment() == null)
    381                continue;
    382            T value = assignment.getValue(variable);
    383            if (value != null) {
    384                if (!variable.getInitialAssignment().equals(value))
    385                    perturbances.add(variable);
    386            } else if (includeNotAssigned) {
    387                boolean hasPerturbance = false;
    388                for (Constraint<V, T> constraint : variable.hardConstraints()) {
    389                    if (constraint.inConflict(assignment, variable.getInitialAssignment())) {
    390                        hasPerturbance = true;
    391                        break;
    392                    }
    393                }
    394                if (!hasPerturbance)
    395                    for (GlobalConstraint<V, T> constraint : globalConstraints()) {
    396                        if (constraint.inConflict(assignment, variable.getInitialAssignment())) {
    397                            hasPerturbance = true;
    398                            break;
    399                        }
    400                    }
    401                if (hasPerturbance)
    402                    perturbances.add(variable);
    403            }
    404        }
    405        return perturbances;
    406    }
    407
    408    /**
    409     * Returns the set of conflicting variables with this value, if it is
    410     * assigned to its variable
    411     * Use {@link Model#conflictValues(Assignment, Value)} instead.
    412     * @param value a value to be assigned
    413     * @return a set of conflicting values, i.e., values that would have to be unassigned if the given value is assigned to its variable
    414     */
    415    @Deprecated
    416    public Set<T> conflictValues(T value) {
    417        return conflictValues(getDefaultAssignment(), value);
    418    }
    419
    420    /**
    421     * Returns the set of conflicting variables with this value, if it is
    422     * assigned to its variable
    423     * @param assignment current assignment
    424     * @param value a value to be assigned
    425     * @return a set of conflicting values, i.e., values that would have to be unassigned if the given value is assigned to its variable
    426     */
    427    public Set<T> conflictValues(Assignment<V, T> assignment, T value) {
    428        Set<T> conflictValues = new HashSet<T>();
    429        for (Constraint<V, T> constraint : value.variable().hardConstraints())
    430            constraint.computeConflicts(assignment, value, conflictValues);
    431        for (GlobalConstraint<V, T> constraint : globalConstraints())
    432            constraint.computeConflicts(assignment, value, conflictValues);
    433        return conflictValues;
    434    }
    435
    436    /**
    437     * Return true if the given value is in conflict with a hard constraint
    438     * Use {@link Model#inConflict(Assignment, Value)} instead.
    439     * @param value a value in question
    440     * @return true if there is a conflict, i.e., there is at least one value that would have to be unassigned if the given value is assigned to its variable
    441     **/
    442    @Deprecated
    443    public boolean inConflict(T value) {
    444        return inConflict(getDefaultAssignment(), value);
    445    }
    446
    447    /** Return true if the given value is in conflict with a hard constraint
    448     * @param assignment current assignment
    449     * @param value a value in question
    450     * @return true if there is a conflict, i.e., there is at least one value that would have to be unassigned if the given value is assigned to its variable
    451     **/
    452    public boolean inConflict(Assignment<V, T> assignment, T value) {
    453        for (Constraint<V, T> constraint : value.variable().hardConstraints())
    454            if (constraint.inConflict(assignment, value))
    455                return true;
    456        for (GlobalConstraint<V, T> constraint : globalConstraints())
    457            if (constraint.inConflict(assignment, value))
    458                return true;
    459        return false;
    460    }
    461
    462    /** The list of variables with an initial value (i.e., variables with {@link Variable#getInitialAssignment()} not null)
    463     * @return list of variables with an initial value
    464     **/
    465    public Collection<V> variablesWithInitialValue() {
    466        iVariablesWithInitialValueLock.readLock().lock();
    467        try {
    468            if (iVariablesWithInitialValueCache != null)
    469                return iVariablesWithInitialValueCache;
    470        } finally {
    471            iVariablesWithInitialValueLock.readLock().unlock();
    472        }
    473        iVariablesWithInitialValueLock.writeLock().lock();
    474        try {
    475            if (iVariablesWithInitialValueCache != null)
    476                return iVariablesWithInitialValueCache;
    477            iVariablesWithInitialValueCache = new ArrayList<V>();
    478            for (V variable : iVariables) {
    479                if (variable.getInitialAssignment() != null)
    480                    iVariablesWithInitialValueCache.add(variable);
    481            }
    482            return iVariablesWithInitialValueCache;
    483        } finally {
    484            iVariablesWithInitialValueLock.writeLock().unlock();
    485        }
    486    }
    487
    488    /** Invalidates cache containing all variables that possess an initial value */
    489    protected void invalidateVariablesWithInitialValueCache() {
    490        iVariablesWithInitialValueLock.writeLock().lock();
    491        iVariablesWithInitialValueCache = null;
    492        iVariablesWithInitialValueLock.writeLock().unlock();
    493    }
    494
    495    /** Called before a value is assigned to its variable
    496     * @param iteration current iteration
    497     * @param value a value to be assigned
    498     **/
    499    @Deprecated
    500    public void beforeAssigned(long iteration, T value) {
    501    }
    502
    503    /** Called before a value is assigned to its variable
    504     * @param assignment current assignment
    505     * @param iteration current iteration
    506     * @param value a value to be assigned
    507     **/
    508    public void beforeAssigned(Assignment<V, T> assignment, long iteration, T value) {
    509        beforeAssigned(iteration, value);
    510        for (ModelListener<V, T> listener : iModelListeners)
    511            listener.beforeAssigned(assignment, iteration, value);
    512    }
    513
    514    /** Called before a value is unassigned from its variable
    515     * @param iteration current iteration
    516     * @param value a value to be unassigned
    517     **/
    518    @Deprecated
    519    public void beforeUnassigned(long iteration, T value) {
    520    }
    521
    522    /** Called before a value is unassigned from its variable
    523     * @param assignment current assignment
    524     * @param iteration current iteration
    525     * @param value a value to be unassigned
    526     **/
    527    public void beforeUnassigned(Assignment<V, T> assignment, long iteration, T value) {
    528        beforeUnassigned(iteration, value);
    529        for (ModelListener<V, T> listener : iModelListeners)
    530            listener.beforeUnassigned(assignment, iteration, value);
    531    }
    532
    533    /** Called after a value is assigned to its variable
    534     * @param iteration current iteration
    535     * @param value a value that was assigned
    536     **/
    537    @Deprecated
    538    public void afterAssigned(long iteration, T value) {
    539    }
    540
    541    /** Called after a value is assigned to its variable
    542     * @param assignment current assignment
    543     * @param iteration current iteration
    544     * @param value a value that was assigned
    545     **/
    546    public void afterAssigned(Assignment<V, T> assignment,  long iteration, T value) {
    547        afterAssigned(iteration, value);
    548        for (ModelListener<V, T> listener : iModelListeners)
    549            listener.afterAssigned(assignment, iteration, value);
    550    }
    551
    552    /** Called after a value is unassigned from its variable
    553     * @param iteration current iteration
    554     * @param value a value that was unassigned
    555     **/
    556    @Deprecated
    557    public void afterUnassigned(long iteration, T value) {
    558    }
    559
    560    /** Called after a value is unassigned from its variable
    561     * @param assignment current assignment
    562     * @param iteration current iteration
    563     * @param value a value that was unassigned
    564     **/
    565    public void afterUnassigned(Assignment<V, T> assignment, long iteration, T value) {
    566        afterUnassigned(iteration, value);
    567        for (ModelListener<V, T> listener : iModelListeners)
    568            listener.afterUnassigned(assignment, iteration, value);
    569    }
    570
    571    @Override
    572    public String toString() {
    573        return "Model{\n    variables=" + ToolBox.col2string(variables(), 2) + ",\n    constraints=" + ToolBox.col2string(constraints(), 2) + ",\n  }";
    574    }
    575
    576    /**
    577     * String representation -- returns a list of values of objective criteria
    578     * @param assignment current assignment
    579     * @return comma separated string of {@link TimetablingCriterion#toString(Assignment)}
    580     */
    581    public String toString(Assignment<V, T> assignment) {
    582        List<Criterion<V, T>> criteria = new ArrayList<Criterion<V,T>>(getCriteria());
    583        Collections.sort(criteria, new Comparator<Criterion<V, T>>() {
    584            @Override
    585            public int compare(Criterion<V, T> c1, Criterion<V, T> c2) {
    586                int cmp = -Double.compare(c1.getWeight(), c2.getWeight());
    587                if (cmp != 0) return cmp;
    588                return c1.getName().compareTo(c2.getName());
    589            }
    590        });
    591        String ret = "";
    592        for (Criterion<V, T> criterion: criteria) {
    593            String val = criterion.toString(assignment);
    594            if (val != null && !val.isEmpty())
    595                ret += ", " + val;
    596        }
    597        return (nrUnassignedVariables(assignment) == 0 ? "" : "V:" + nrAssignedVariables(assignment) + "/" + variables().size() + ", ") + "T:" + sDoubleFormat.format(getTotalValue(assignment)) + ret;
    598    }
    599
    600    protected String getPerc(double value, double min, double max) {
    601        if (max == min)
    602            return sPercentageFormat.format(100.0);
    603        return sPercentageFormat.format(100.0 - 100.0 * (value - min) / (max - min));
    604    }
    605
    606    protected String getPercRev(double value, double min, double max) {
    607        if (max == min)
    608            return sPercentageFormat.format(0.0);
    609        return sPercentageFormat.format(100.0 * (value - min) / (max - min));
    610    }
    611
    612    /**
    613     * Returns information about the current solution. Information from all
    614     * model listeners and constraints is also included.
    615     * Use {@link Model#getInfo(Assignment)} instead.
    616     * @return info table
    617     */
    618    @Deprecated
    619    public Map<String, String> getInfo() {
    620        return getInfo(getDefaultAssignment());
    621    }
    622
    623    /**
    624     * Returns information about the current solution. Information from all
    625     * model listeners and constraints is also included.
    626     * @param assignment current assignment
    627     * @return info table
    628     */
    629    public Map<String, String> getInfo(Assignment<V, T> assignment) {
    630        Map<String, String> ret = new HashMap<String, String>();
    631        ret.put("Assigned variables", getPercRev(assignment.nrAssignedVariables(), 0, variables().size()) + "% (" + assignment.nrAssignedVariables() + "/" + variables().size() + ")");
    632        Collection<V> varsWithInitialValue = variablesWithInitialValue();
    633        int nrVarsWithInitialValue = varsWithInitialValue.size();
    634        if (nrVarsWithInitialValue > 0) {
    635            Collection<V> pv = perturbVariables(assignment, varsWithInitialValue, false);
    636            ret.put("Perturbation variables", getPercRev(pv.size(), 0, nrVarsWithInitialValue) + "% (" + pv.size() + " + " + (variables().size() - nrVarsWithInitialValue) + ")");
    637        }
    638        ret.put("Overall solution value", sDoubleFormat.format(getTotalValue(assignment)));
    639        for (InfoProvider<V, T> provider : iInfoProviders)
    640            provider.getInfo(assignment, ret);
    641        return ret;
    642    }
    643
    644    /**
    645     * Extended information about current solution. Similar to
    646     * {@link Model#getInfo(Assignment)}, but some more information (that is more
    647     * expensive to compute) might be added.
    648     * Use {@link Model#getExtendedInfo(Assignment)} instead.
    649     * @return extended info table
    650     */
    651    @Deprecated
    652    public Map<String, String> getExtendedInfo() {
    653        return getExtendedInfo(getDefaultAssignment());
    654    }
    655
    656    /**
    657     * Extended information about current solution. Similar to
    658     * {@link Model#getInfo(Assignment)}, but some more information (that is more
    659     * expensive to compute) might be added.
    660     * @param assignment current assignment
    661     * @return extended info table
    662     */
    663    public Map<String, String> getExtendedInfo(Assignment<V, T> assignment) {
    664        Map<String, String> ret = getInfo(assignment);
    665        for (InfoProvider<V, T> provider : iInfoProviders)
    666            if (provider instanceof ExtendedInfoProvider)
    667                ((ExtendedInfoProvider<V, T>)provider).getExtendedInfo(assignment, ret);
    668        return ret;
    669    }
    670
    671    /**
    672     * Returns information about the current solution. Information from all
    673     * model listeners and constraints is also included. Only variables from the
    674     * given set are considered.
    675     * Use {@link Model#getInfo(Assignment, Collection)} instead.
    676     * @param variables sub-problem
    677     * @return info table
    678     **/
    679    @Deprecated
    680    public Map<String, String> getInfo(Collection<V> variables) {
    681        return getInfo(getDefaultAssignment(), variables);
    682    }
    683
    684    /**
    685     * Returns information about the current solution. Information from all
    686     * model listeners and constraints is also included. Only variables from the
    687     * given set are considered.
    688     * @param assignment current assignment
    689     * @param variables sub-problem
    690     * @return info table
    691     */
    692    public Map<String, String> getInfo(Assignment<V, T> assignment, Collection<V> variables) {
    693        Map<String, String> ret = new HashMap<String, String>();
    694        int assigned = 0, perturb = 0, nrVarsWithInitialValue = 0;
    695        for (V variable : variables) {
    696            T value = assignment.getValue(variable);
    697            if (value != null)
    698                assigned++;
    699            if (variable.getInitialAssignment() != null) {
    700                nrVarsWithInitialValue++;
    701                if (value != null) {
    702                    if (!variable.getInitialAssignment().equals(value))
    703                        perturb++;
    704                } else {
    705                    boolean hasPerturbance = false;
    706                    for (Constraint<V, T> constraint : variable.hardConstraints()) {
    707                        if (constraint.inConflict(assignment, variable.getInitialAssignment())) {
    708                            hasPerturbance = true;
    709                            break;
    710                        }
    711                    }
    712                    if (!hasPerturbance)
    713                        for (GlobalConstraint<V, T> constraint : globalConstraints()) {
    714                            if (constraint.inConflict(assignment, variable.getInitialAssignment())) {
    715                                hasPerturbance = true;
    716                                break;
    717                            }
    718                        }
    719                    if (hasPerturbance)
    720                        perturb++;
    721                }
    722            }
    723        }
    724        ret.put("Assigned variables", getPercRev(assigned, 0, variables.size()) + "% (" + assigned + "/" + variables.size() + ")");
    725        if (nrVarsWithInitialValue > 0) {
    726            ret.put("Perturbation variables", getPercRev(perturb, 0, nrVarsWithInitialValue) + "% (" + perturb + " + " + (variables.size() - nrVarsWithInitialValue) + ")");
    727        }
    728        ret.put("Overall solution value", sDoubleFormat.format(getTotalValue(assignment, variables)));
    729        for (InfoProvider<V, T> provider : iInfoProviders)
    730            provider.getInfo(assignment, ret, variables);
    731        return ret;
    732    }
    733
    734    /**
    735     * Returns the number of unassigned variables in the best ever found
    736     * solution
    737     * @return number of unassigned variables in the best solution
    738     */
    739    public int getBestUnassignedVariables() {
    740        return iBestUnassignedVariables;
    741    }
    742
    743    /**
    744     * Returns the number of perturbation variables in the best ever found
    745     * solution
    746     * @return number of perturbation variables in the best solution
    747     */
    748    public int getBestPerturbations() {
    749        return iBestPerturbations;
    750    }
    751
    752    /**
    753     * Total value of the best ever found solution -- sum of all assigned values
    754     * (see {@link Value#toDouble(Assignment)}).
    755     * @return value of the best solution
    756     */
    757    public double getBestValue() {
    758        return iBestValue;
    759    }
    760
    761    /** Set total value of the best ever found solution
    762     * @param bestValue value of the best solution
    763     **/
    764    public void setBestValue(double bestValue) {
    765        iBestValue = bestValue;
    766    }
    767
    768    /**
    769     * Save the current assignment as the best ever found assignment
    770     * Use {@link Model#saveBest(Assignment)} instead.
    771     **/
    772    @Deprecated
    773    public void saveBest() {
    774        saveBest(getDefaultAssignment());
    775    }
    776
    777    /** Save the current assignment as the best ever found assignment
    778     * @param assignment current assignment
    779     **/
    780    public void saveBest(Assignment<V, T> assignment) {
    781        iBestUnassignedVariables = iVariables.size() - assignment.nrAssignedVariables();
    782        iBestPerturbations = perturbVariables(assignment).size();
    783        iBestValue = getTotalValue(assignment);
    784        for (V variable : iVariables) {
    785            variable.setBestAssignment(assignment.getValue(variable), assignment.getIteration(variable));
    786        }
    787        for (Criterion<V, T> criterion: getCriteria()) {
    788            criterion.bestSaved(assignment);
    789        }
    790    }
    791
    792    /** Clear the best ever found assignment */
    793    public void clearBest() {
    794        iBestUnassignedVariables = -1;
    795        iBestPerturbations = 0;
    796        iBestValue = 0;
    797        for (V variable : iVariables) {
    798            variable.setBestAssignment(null, 0);
    799        }
    800    }
    801
    802    /**
    803     * Restore the best ever found assignment into the current assignment
    804     * Use {@link Model#restoreBest(Assignment)} instead.
    805     **/
    806    @Deprecated
    807    protected void restoreBest() {
    808        restoreBest(getDefaultAssignment());
    809    }
    810
    811    /** Restore the best ever found assignment into the current assignment
    812     * @param assignment current assignment
    813     * @param assignmentOrder assignment order of the variables
    814     **/
    815    @SuppressWarnings("unchecked")
    816    protected void restoreBest(Assignment<V, T> assignment, Comparator<V> assignmentOrder) {
    817        TreeSet<V> sortedVariables = new TreeSet<V>(assignmentOrder);
    818        for (V variable : iVariables) {
    819            T value = assignment.getValue(variable);
    820            if (value == null) {
    821                if (variable.getBestAssignment() != null)
    822                    sortedVariables.add(variable);
    823            } else if (!value.equals(variable.getBestAssignment())) {
    824                assignment.unassign(0, variable);
    825                if (variable.getBestAssignment() != null)
    826                    sortedVariables.add(variable);
    827            }
    828        }
    829        Set<T> problems = new HashSet<T>();
    830        for (V variable : sortedVariables) {
    831            Set<T> confs = conflictValues(assignment, variable.getBestAssignment());
    832            if (!confs.isEmpty()) {
    833                sLogger.error("restore best problem: assignment " + variable.getName() + " = " + variable.getBestAssignment().getName());
    834                boolean weakened = false;
    835                for (Constraint<V, T> c : variable.hardConstraints()) {
    836                    Set<T> x = new HashSet<T>();
    837                    c.computeConflicts(assignment, variable.getBestAssignment(), x);
    838                    if (!x.isEmpty()) {
    839                        if (c instanceof WeakeningConstraint) {
    840                            ((WeakeningConstraint<V, T>)c).weaken(assignment, variable.getBestAssignment());
    841                            sLogger.info("  constraint " + c.getClass().getSimpleName() + " " + c.getName() + " had to be weakened");
    842                            weakened = true;
    843                        } else {
    844                            sLogger.error("  constraint " + c.getClass().getSimpleName() + " " + c.getName() + " causes the following conflicts " + x);
    845                        }
    846                    }
    847                }
    848                for (GlobalConstraint<V, T> c : globalConstraints()) {
    849                    Set<T> x = new HashSet<T>();
    850                    c.computeConflicts(assignment, variable.getBestAssignment(), x);
    851                    if (!x.isEmpty()) {
    852                        if (c instanceof WeakeningConstraint) {
    853                            ((WeakeningConstraint<V, T>)c).weaken(assignment, variable.getBestAssignment());
    854                            sLogger.info("  constraint " + c.getClass().getSimpleName() + " " + c.getName() + " had to be weakened");
    855                            weakened = true;
    856                        } else {
    857                            sLogger.error("  global constraint " + c.getClass().getSimpleName() + " " + c.getName() + " causes the following conflicts " + x);
    858                        }
    859                    }
    860                }
    861                if (weakened && conflictValues(assignment, variable.getBestAssignment()).isEmpty())
    862                    assignment.assign(0, variable.getBestAssignment());
    863                else
    864                    problems.add(variable.getBestAssignment());
    865            } else
    866                assignment.assign(0, variable.getBestAssignment());
    867        }
    868        int attempt = 0, maxAttempts = 3 * problems.size();
    869        while (!problems.isEmpty() && attempt <= maxAttempts) {
    870            attempt++;
    871            T value = ToolBox.random(problems);
    872            problems.remove(value);
    873            V variable = value.variable();
    874            Set<T> confs = conflictValues(assignment, value);
    875            if (!confs.isEmpty()) {
    876                sLogger.error("restore best problem (again, att=" + attempt + "): assignment " + variable.getName() + " = " + value.getName());
    877                for (Constraint<V, T> c : variable.hardConstraints()) {
    878                    Set<T> x = new HashSet<T>();
    879                    c.computeConflicts(assignment, value, x);
    880                    if (!x.isEmpty())
    881                        sLogger.error("  constraint " + c.getClass().getSimpleName() + " " + c.getName() + " causes the following conflicts " + x);
    882                }
    883                for (GlobalConstraint<V, T> c : globalConstraints()) {
    884                    Set<T> x = new HashSet<T>();
    885                    c.computeConflicts(assignment, value, x);
    886                    if (!x.isEmpty())
    887                        sLogger.error("  constraint " + c.getClass().getSimpleName() + " " + c.getName() + " causes the following conflicts " + x);
    888                }
    889                for (T conf : confs)
    890                    assignment.unassign(0, conf.variable());
    891                problems.addAll(confs);
    892            }
    893            assignment.assign(0, value);
    894        }
    895        for (Criterion<V, T> criterion: getCriteria()) {
    896            criterion.bestRestored(assignment);
    897        }
    898    }
    899
    900    /** Restore the best ever found assignment into the current assignment
    901     * @param assignment current assignment
    902     **/
    903    public void restoreBest(Assignment<V, T> assignment) {
    904        restoreBest(assignment, new Comparator<V>() {
    905            @Override
    906            public int compare(V v1, V v2) {
    907                if (v1.getBestAssignmentIteration() < v2.getBestAssignmentIteration()) return -1;
    908                if (v1.getBestAssignmentIteration() > v2.getBestAssignmentIteration()) return 1;
    909                return v1.compareTo(v2);
    910            }
    911        });
    912    }
    913
    914    /**
    915     * The list of unassigned variables in the best ever found solution.
    916     * Use {@link Model#bestUnassignedVariables(Assignment)} instead.
    917     * @return variables list of unassigned variables in the best solution
    918     **/
    919    @Deprecated
    920    public Collection<V> bestUnassignedVariables() {
    921        return bestUnassignedVariables(getDefaultAssignment());
    922    }
    923
    924    /** The list of unassigned variables in the best ever found solution
    925     * @param assignment current assignment
    926     * @return variables list of unassigned variables in the best solution
    927     **/
    928    public Collection<V> bestUnassignedVariables(Assignment<V, T> assignment) {
    929        Collection<V> ret = new ArrayList<V>(variables().size());
    930        if (iBestUnassignedVariables < 0) {
    931            for (V variable : variables()) {
    932                if (assignment.getValue(variable) == null)
    933                    ret.add(variable);
    934            }
    935        } else {
    936            for (V variable : variables()) {
    937                if (variable.getBestAssignment() == null)
    938                    ret.add(variable);
    939            }
    940        }
    941        return ret;
    942    }
    943
    944    /**
    945     * Value of the current solution. It is the sum of all assigned values,
    946     * i.e., {@link Value#toDouble(Assignment)}.
    947     * Use {@link Model#getTotalValue(Assignment)} instead.
    948     * @return solution value
    949     */
    950    @Deprecated
    951    public double getTotalValue() {
    952        return getTotalValue(getDefaultAssignment());
    953    }
    954
    955    /**
    956     * Value of the current solution. It is the sum of all assigned values,
    957     * i.e., {@link Value#toDouble(Assignment)}.
    958     * @param assignment current assignment
    959     * @return solution value
    960     */
    961    public double getTotalValue(Assignment<V, T> assignment) {
    962        double ret = 0.0;
    963        if (getCriteria().isEmpty())
    964            for (T t: assignment.assignedValues())
    965                ret += t.toDouble(assignment);
    966        else
    967            for (Criterion<V, T> c: getCriteria())
    968                ret += c.getWeightedValue(assignment);
    969        return ret;
    970    }
    971
    972    /**
    973     * Value of the current solution. It is the sum of all assigned values,
    974     * i.e., {@link Value#toDouble(Assignment)}. Only variables from the given set are
    975     * considered.
    976     * Use {@link Model#getTotalValue(Assignment, Collection)} instead.
    977     * @param variables sub-problem
    978     * @return solution value
    979     **/
    980    @Deprecated
    981    public double getTotalValue(Collection<V> variables) {
    982        return getTotalValue(getDefaultAssignment(), variables);
    983    }
    984
    985    /**
    986     * Value of the current solution. It is the sum of all assigned values,
    987     * i.e., {@link Value#toDouble(Assignment)}. Only variables from the given set are
    988     * considered.
    989     * @param assignment current assignment
    990     * @param variables sub-problem
    991     * @return solution value
    992     **/
    993    public double getTotalValue(Assignment<V, T> assignment, Collection<V> variables) {
    994        double ret = 0.0;
    995        for (V v: variables) {
    996            T t = assignment.getValue(v);
    997            if (t != null)
    998                ret += t.toDouble(assignment);
    999        }
    1000        return ret;
    1001    }
    1002
    1003    /** Adds a model listener
    1004     * @param listener a model listener
    1005     **/
    1006    @SuppressWarnings("unchecked")
    1007    public void addModelListener(ModelListener<V, T> listener) {
    1008        iModelListeners.add(listener);
    1009        if (listener instanceof InfoProvider<?, ?>)
    1010            iInfoProviders.add((InfoProvider<V, T>) listener);
    1011        for (Constraint<V, T> constraint : iConstraints)
    1012            listener.constraintAdded(constraint);
    1013        for (Constraint<V, T> constraint : iGlobalConstraints)
    1014            listener.constraintAdded(constraint);
    1015        for (V variable : iVariables)
    1016            listener.variableAdded(variable);
    1017    }
    1018
    1019    /** Removes a model listener
    1020     * @param listener a model listener
    1021     **/
    1022    public void removeModelListener(ModelListener<V, T> listener) {
    1023        if (listener instanceof InfoProvider<?, ?>)
    1024            iInfoProviders.remove((InfoProvider<?, ?>)listener);
    1025        for (V variable : iVariables)
    1026            listener.variableRemoved(variable);
    1027        for (Constraint<V, T> constraint : iConstraints)
    1028            listener.constraintRemoved(constraint);
    1029        for (Constraint<V, T> constraint : iGlobalConstraints)
    1030            listener.constraintRemoved(constraint);
    1031        iModelListeners.remove(listener);
    1032    }
    1033
    1034    /** Model initialization
    1035     * @param solver current solver
    1036     * @return true if successfully initialized
    1037     **/
    1038    public boolean init(Solver<V, T> solver) {
    1039        for (ModelListener<V, T> listener : new ArrayList<ModelListener<V, T>>(iModelListeners)) {
    1040            if (!listener.init(solver))
    1041                return false;
    1042        }
    1043        return true;
    1044    }
    1045
    1046    /** The list of model listeners
    1047     * @return list of model listeners
    1048     **/
    1049    public List<ModelListener<V, T>> getModelListeners() {
    1050        return iModelListeners;
    1051    }
    1052
    1053    /** The list of model listeners that are of the given class
    1054     * @param type model listener type
    1055     * @return list of model listeners that are of the given class
    1056     **/
    1057    public ModelListener<V, T> modelListenerOfType(Class<ModelListener<V, T>> type) {
    1058        for (ModelListener<V, T> listener : iModelListeners) {
    1059            if (listener.getClass() == type)
    1060                return listener;
    1061        }
    1062        return null;
    1063    }
    1064
    1065    /**
    1066     * The list of constraints which are in a conflict with the given value if
    1067     * it is assigned to its variable. This means the constraints, which adds a
    1068     * value into the set of conflicting values in
    1069     * {@link Constraint#computeConflicts(Assignment, Value, Set)}.
    1070     * @param assignment current assignment
    1071     * @param value given value
    1072     * @return hard constraints and their conflicts that are conflicting with the given value
    1073     */
    1074    public Map<Constraint<V, T>, Set<T>> conflictConstraints(Assignment<V, T> assignment, T value) {
    1075        Map<Constraint<V, T>, Set<T>> conflictConstraints = new HashMap<Constraint<V, T>, Set<T>>();
    1076        for (Constraint<V, T> constraint : value.variable().hardConstraints()) {
    1077            Set<T> conflicts = new HashSet<T>();
    1078            constraint.computeConflicts(assignment, value, conflicts);
    1079            if (!conflicts.isEmpty()) {
    1080                conflictConstraints.put(constraint, conflicts);
    1081            }
    1082        }
    1083        for (GlobalConstraint<V, T> constraint : globalConstraints()) {
    1084            Set<T> conflicts = new HashSet<T>();
    1085            constraint.computeConflicts(assignment, value, conflicts);
    1086            if (!conflicts.isEmpty()) {
    1087                conflictConstraints.put(constraint, conflicts);
    1088            }
    1089        }
    1090        return conflictConstraints;
    1091    }
    1092
    1093    /**
    1094     * The list of hard constraints which contain at least one variable that is
    1095     * not assigned.
    1096     * @param assignment current assignment
    1097     * @return list of hard constraints which contain at least one variable that is not assigned
    1098     */
    1099    public List<Constraint<V, T>> unassignedHardConstraints(Assignment<V, T> assignment) {
    1100        List<Constraint<V, T>> ret = new ArrayList<Constraint<V, T>>();
    1101        constraints: for (Constraint<V, T> constraint : constraints()) {
    1102            if (!constraint.isHard())
    1103                continue;
    1104            for (V v : constraint.variables()) {
    1105                if (assignment.getValue(v) == null) {
    1106                    ret.add(constraint);
    1107                    continue constraints;
    1108                }
    1109            }
    1110        }
    1111        if (iVariables.size() > assignment.nrAssignedVariables())
    1112            ret.addAll(globalConstraints());
    1113        return ret;
    1114    }
    1115
    1116    /** Registered info providers (see {@link InfoProvider})
    1117     * @return list of registered info providers
    1118     **/
    1119    protected List<InfoProvider<V, T>> getInfoProviders() {
    1120        return iInfoProviders;
    1121    }
    1122
    1123    /** Register a new criterion
    1124     * @param criterion a criterion
    1125     **/
    1126    public void addCriterion(Criterion<V,T> criterion) {
    1127        iCriteria.put(criterion.getClass().getName(), criterion);
    1128        criterion.setModel(this);
    1129        addModelListener(criterion);
    1130    }
    1131
    1132    /** Unregister an existing criterion
    1133     * @param criterion a criterion
    1134     **/
    1135    public void removeCriterion(Criterion<V,T> criterion) {
    1136        iCriteria.remove(criterion.getClass().getName());
    1137        criterion.setModel(null);
    1138        removeModelListener(criterion);
    1139    }
    1140
    1141    /** Unregister an existing criterion
    1142     * @param criterion a criterion
    1143     **/
    1144    public void removeCriterion(Class<? extends Criterion<V, T>> criterion) {
    1145        Criterion<V,T> c = iCriteria.remove(criterion.getName());
    1146        if (c != null)
    1147            removeModelListener(c);
    1148    }
    1149
    1150    /** Return a registered criterion of the given type.
    1151     * @param criterion criterion type
    1152     * @return registered criterion of the given type
    1153     **/
    1154    public Criterion<V, T> getCriterion(Class<? extends Criterion<V, T>> criterion) {
    1155        return iCriteria.get(criterion.getName());
    1156    }
    1157
    1158    /** List all registered criteria
    1159     * @return list all registered criteria
    1160     **/
    1161    public Collection<Criterion<V, T>> getCriteria() {
    1162        return iCriteria.values();
    1163    }
    1164
    1165    /**
    1166     * Weaken all weakening constraint so that the given value can be assigned without
    1167     * them creating a conflict using {@link WeakeningConstraint#weaken(Assignment, Value)}.
    1168     * This method is handy for instance when an existing solution is being loaded
    1169     * into the solver.
    1170     * @param assignment current assignment
    1171     * @param value given value
    1172     */
    1173    @SuppressWarnings("unchecked")
    1174    public void weaken(Assignment<V, T> assignment, T value) {
    1175        for (Constraint<V, T> constraint : value.variable().hardConstraints()) {
    1176            if (constraint instanceof WeakeningConstraint)
    1177                ((WeakeningConstraint<V,T>)constraint).weaken(assignment, value);
    1178        }
    1179        for (GlobalConstraint<V, T> constraint : globalConstraints()) {
    1180            if (constraint instanceof WeakeningConstraint)
    1181                ((WeakeningConstraint<V,T>)constraint).weaken(assignment, value);
    1182        }
    1183    }
    1184
    1185    /**
    1186     * Create a reference to an assignment context for a class that is in a need of one. Through this
    1187     * reference an assignment context (see {@link AssignmentContext}) can be accessed using
    1188     * {@link Assignment#getAssignmentContext(AssignmentContextReference)}.
    1189     * @param parent class needing an assignment context
    1190     * @param <C> assignment context type
    1191     * @return reference to an assignment context
    1192     */
    1193    public synchronized <C extends AssignmentContext> AssignmentContextReference<V,T,C> createReference(HasAssignmentContext<V, T, C> parent) {
    1194        AssignmentContextReference<V, T, C> ref = new AssignmentContextReference<V, T, C>(parent, iNextReferenceId);
    1195        iAssignmentContextReferences.put(iNextReferenceId, ref);
    1196        iNextReferenceId++;
    1197        return ref;
    1198    }
    1199
    1200    /**
    1201     * Clear all assignment contexts for the given assignment
    1202     * @param assignment given {@link Assignment}
    1203     */
    1204    public synchronized void clearAssignmentContexts(Assignment<V, T> assignment) {
    1205        for (AssignmentContextReference<V,T,? extends AssignmentContext> ref: iAssignmentContextReferences.values())
    1206            assignment.clearContext(ref);
    1207    }
    1208
    1209    /**
    1210     * Remove a reference to an assignment context for the model
    1211     * @param parent class with an assignment context
    1212     * @param <C> assignment context type
    1213     * @return reference to an assignment context that was removed from the model (if any)
    1214     */
    1215    @SuppressWarnings("unchecked")
    1216    public synchronized <C extends AssignmentContext> AssignmentContextReference<V,T,C> removeReference(HasAssignmentContext<V, T, C> parent) {
    1217        AssignmentContextReference<V,T,C> reference = parent.getAssignmentContextReference();
    1218        if (reference != null)
    1219            return (AssignmentContextReference<V,T,C>) iAssignmentContextReferences.remove(reference.getIndex());
    1220        return null;
    1221    }
    1222
    1223    /**
    1224     * Create all assignment contexts for the given assignment
    1225     * @param assignment given {@link Assignment}
    1226     * @param clear if true {@link Assignment#clearContext(AssignmentContextReference)} is called first
    1227     */
    1228    public synchronized void createAssignmentContexts(Assignment<V, T> assignment, boolean clear) {
    1229        for (AssignmentContextReference<V,T,? extends AssignmentContext> ref: iAssignmentContextReferences.values()) {
    1230            if (clear) assignment.clearContext(ref);
    1231            assignment.getAssignmentContext(ref);
    1232        }
    1233    }
    1234
    1235    /**
    1236     * Return default assignment that is using the old {@link Variable#getAssignment()} assignments.
    1237     * @return as instance of {@link DefaultSingleAssignment}
    1238     */
    1239    @Deprecated
    1240    public Assignment<V, T> getDefaultAssignment() {
    1241        if (iAssignment == null)
    1242            iAssignment = new DefaultSingleAssignment<V, T>();
    1243        return iAssignment;
    1244    }
    1245
    1246    /**
    1247     * Set default assignment
    1248     * @param assignment current assignment to become default
    1249     */
    1250    @Deprecated
    1251    public void setDefaultAssignment(Assignment<V, T> assignment) {
    1252        iAssignment = assignment;
    1253    }
    1254
    1255    /**
    1256     * Returns an instance of an empty assignment (using {@link EmptyAssignment})
    1257     * @return an empty assignment
    1258     */
    1259    public Assignment<V, T> getEmptyAssignment() {
    1260        if (iEmptyAssignment == null)
    1261            iEmptyAssignment = new EmptyAssignment<V, T>();
    1262        return iEmptyAssignment;
    1263    }
    1264
    1265
    1266    /**
    1267     * Create a new inherited assignment from the given solution
    1268     * @param solution a solution that is using this model
    1269     * @param index thread index of the new assignment
    1270     * @return a new inherited assignment
    1271     */
    1272    public InheritedAssignment<V, T> createInheritedAssignment(Solution<V, T> solution, int index) {
    1273        return new DefaultInheritedAssignment<V, T>(solution, index);
    1274    }
    1275}