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