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}