    001    package ifs.model;
    002
    003    import ifs.util.*;
    004    import java.util.*;
    005
    006    /**
    007     * Generic variable.
    008     * <br><br>
    009     * Besides a domain of values, a variable also contains information about assigned value,
    010     * the value assigned in the best ever found solution and also the initial value (minimal
    011     * perturbations problem). It also knows what constraints are associated with this variable and
    012     * has a unique id.
    013     *
    014     * @see Value
    015     * @see Model
    016     * @see ifs.solver.Solver
    017     *
    018     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
    019     * @version 1.0
    020     */
    021    public class Variable implements Comparable {
    022        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Variable.class);
    023        private static IdGenerator iIdGenerator = new IdGenerator();
    024
    025        private long iId = -1;
    026        private Model iModel = null;
    027
    028        private Value iInitialValue = null; // initial value
    029        /** Assigned value */
    030        protected Value iValue = null; // assigned value
    031        private Value iBestValue = null; // best value
    032        private long iBestAssignmentIteration = 0;
    033        private Vector iValues = null;
    034
    035        private Value iRecentlyRemovedValue = null;
    036
    037        private long iAssignmentCounter = 0;
    038        private long iLastAssignmentIteration = -1;
    039        private long iLastUnassignmentIteration = -1;
    040        private Object iExtra = null;
    041
    042        private Vector iConstraints = new FastVector();
    043        private Vector iHardConstraints = new FastVector();
    044        private Vector iSoftConstraints = new FastVector();
    045        private Vector iVariableListeners = null;
    046
    047        private Hashtable iConstraintVariables = null;
    048
    049        /** Constructor */
    050        public Variable() {
    051            this(null);
    052        }
    053
    054        /** Constructor
    055         * @param initialValue initial value (minimal-perturbation problem)
    056         */
    057        public Variable(Value initialValue) {
    058            iId = iIdGenerator.newId();
    059            setInitialAssignment(initialValue);
    060        }
    061
    062        /** Model, the variable belong to */
    063        public Model getModel() { return iModel; }
    064        /** Set the model to which the variable belongs to */
    065        public void setModel(Model model) { iModel = model; }
    066
    067        /** Domain */
    068        public Vector values() {
    069            return iValues;
    070        }
    071        /** Sets the domain */
    072        protected void setValues(Vector values) {
    073            iValues = values;
    074        }
    075
    076        /** Returns current assignment */
    077        public Value getAssignment() { return iValue; }
    078        /** Returns true if the variable is assigned */
    079        public boolean hasAssignment() { return iValue!=null; }
    080        /** Returns initial assignment */
    081        public Value getInitialAssignment() { return iInitialValue; }
    082        /** Sets initial assignment */
    083        public void setInitialAssignment(Value initialValue) {
    084            iInitialValue = initialValue;
    085            if (iInitialValue!=null && iInitialValue.variable()==null) iInitialValue.setVariable(this);
    086        }
    087        /** Returns true if the variable has an initial assignment */
    088        public boolean hasInitialAssignment() { return iInitialValue!=null; }
    089
    090        /** Assign value to this variable. If the variable has already assigned another value, it is
    091         * unassigned first. Also, all conflicting values are unassigned before the given value is assigned
    092         * to this variable.
    093         * @param iteration current iteration
    094         * @param value the value to be assigned
    095         */
    096        public void assign(long iteration, Value value) {
    097            getModel().beforeAssigned(iteration,value);
    098            iLastAssignmentIteration = iteration;
    099            if (iValue!=null) unassign(iteration);
    100            if (iRecentlyRemovedValue!=null && iRecentlyRemovedValue.equals(value)) {
    101                iRecentlyRemovedValue = null;
    102                return;
    103            }
    104            if (value==null) return;
    105            iValue = value;
    106            for (Enumeration e=iConstraints.elements(); e.hasMoreElements();) {
    107                Constraint constraint = (Constraint)e.nextElement();
    108                constraint.assigned(iteration, value);
    109            }
    110            iAssignmentCounter++;
    111            value.assigned(iteration);
    112            if (iVariableListeners!=null)
    113                for (Enumeration e=iVariableListeners.elements(); e.hasMoreElements();)
    114                    ((VariableListener)e.nextElement()).variableAssigned(iteration, value);
    115            getModel().afterAssigned(iteration,value);
    116        }
    117
    118        /** Unassign value from this variable.
    119         * @param iteration current iteration
    120         */
    121        public void unassign(long iteration) {
    122            if (iValue==null) return;
    123            getModel().beforeUnassigned(iteration,iValue);
    124            iLastUnassignmentIteration = iteration;
    125            Value oldValue = iValue;
    126            iValue = null;
    127            for (Enumeration e=iConstraints.elements(); e.hasMoreElements();) {
    128                Constraint constraint = (Constraint)e.nextElement();
    129                constraint.unassigned(iteration, oldValue);
    130            }
    131            oldValue.unassigned(iteration);
    132            if (iVariableListeners!=null)
    133                for (Enumeration e=iVariableListeners.elements(); e.hasMoreElements();)
    134                    ((VariableListener)e.nextElement()).variableUnassigned(iteration, oldValue);
    135            getModel().afterUnassigned(iteration,oldValue);
    136        }
    137        /** Return how many times was this variable assigned in the past. */
    138        public long countAssignments() { return iAssignmentCounter; }
    139
    140        /** Adds a constraint. Called automatically when the constraint is added to the model, i.e.,
    141         * {@link Model#addConstraint(Constraint)} is called.
    142         * @param constraint added constraint
    143         */
    144        public void addContstraint(Constraint constraint) {
    145            iConstraints.addElement(constraint);
    146            if (constraint.isHard()) {
    147                iHardConstraints.addElement(constraint);
    148                iConstraintVariables = null;
    149            } else iSoftConstraints.addElement(constraint);
    150        }
    151
    152        /** Removes a constraint. Called automatically when the constraint is removed from the model, i.e.,
    153         * {@link Model#removeConstraint(Constraint)} is called.
    154         * @param constraint added constraint
    155         */
    156        public void removeContstraint(Constraint constraint) {
    157            iConstraints.removeElement(constraint);
    158            if (iHardConstraints.contains(constraint)) {
    159                iHardConstraints.removeElement(constraint);
    160                iConstraintVariables = null;
    161            } else iSoftConstraints.removeElement(constraint);
    162        }
    163
    164        /** Return the list of constraints associated with this variable */
    165        public Vector constraints() { return iConstraints; }
    166        /** Return the list of hard constraints associated with this variable */
    167        public Vector hardConstraints() { return iHardConstraints; }
    168        /** Return the list of soft constraints associated with this variable */
    169        public Vector softConstraints() { return iSoftConstraints; }
    170
    171        public String toString() {
    172            return "Variable{name="+getName()+", initial="+getInitialAssignment()+", current="+getAssignment()+", values="+values().size()+", constraints="+iConstraints.size()+"}";
    173        }
    174
    175        /** Unique id */
    176        public long getId() { return iId;}
    177
    178        public int hashCode() { return (int)iId; }
    179        /** Variable's name -- for printing purposes */
    180        public String getName() { return String.valueOf(iId); }
    181        /** Variable's description -- for printing purposes */
    182        public String getDescription() { return null; }
    183
    184        /** Sets variable's value of the best ever found solution. Called when {@link Model#saveBest()} is called. */
    185        public void setBestAssignment(Value value) { iBestValue = value; iBestAssignmentIteration = (value==null?0l:value.lastAssignmentIteration()); }
    186        /** Returns the value from the best ever found soultion. */
    187        public Value getBestAssignment() { return iBestValue; }
    188        /** Returns the iteration when the best value was assigned */
    189        public long getBestAssignmentIteration() { return iBestAssignmentIteration; }
    190
    191        /** Returns the iteration when the variable was assigned for the last time (-1 if never) */
    192        public long lastAssignmentIteration() { return iLastAssignmentIteration; }
    193        /** Returns the iteration when the variable was unassigned for the last time (-1 if never) */
    194        public long lastUnassignmentIteration() { return iLastUnassignmentIteration; }
    195
    196        public int compareTo(Object o) {
    197            if (o==null || !(o instanceof Variable)) return -1;
    198            Variable v = (Variable)o;
    199            return getName().compareTo(v.getName());
    200        }
    201
    202        public boolean equals(Object o) {
    203            try {
    204                Variable v = (Variable)o;
    205                return getId()==v.getId();
    206            } catch (Exception e) {
    207                return false;
    208            }
    209        }
    210
    211        /** Adds variable listener */
    212        public void addVariableListener(VariableListener listener) {
    213            if (iVariableListeners==null) iVariableListeners=new FastVector();
    214            iVariableListeners.addElement(listener);
    215        }
    216        /** Removess variable listener */
    217        public void removeVariableListener(VariableListener listener) {
    218            if (iVariableListeners==null) iVariableListeners=new FastVector();
    219            iVariableListeners.removeElement(listener);
    220        }
    221
    222        /** Extra information to which can be used by an extension (see {@link ifs.extension.Extension}). */
    223        public void setExtra(Object object) { iExtra = object; }
    224        /** Extra information to which can be used by an extension (see {@link ifs.extension.Extension}). */
    225        public Object getExtra() { return iExtra; }
    226
    227        /** Permanently remove a value from variables domain. */
    228        public void removeValue(long iteration, Value value) {
    229            if (iValue!=null && iValue.equals(value)) unassign(iteration);
    230            if (iValues==null) return;
    231            iValues.remove(value);
    232            if (iInitialValue!=null && iInitialValue.equals(value)) iInitialValue=null;
    233            if (iVariableListeners!=null)
    234                for (Enumeration e=iVariableListeners.elements(); e.hasMoreElements();)
    235                    ((VariableListener)e.nextElement()).valueRemoved(iteration, value);
    236            iRecentlyRemovedValue = value;
    237        }
    238
    239        /** Returns a table of all variables linked with this variable by a constraint.
    240         * @return table (variable, constraint)
    241         */
    242        public Hashtable constraintVariables() {
    243            if (iConstraintVariables == null) {
    244                iConstraintVariables = new Hashtable();
    245                for (Enumeration e1=constraints().elements();e1.hasMoreElements();) {
    246                    Constraint constraint = (Constraint)e1.nextElement();
    247                    for (Enumeration e2=constraint.variables().elements();e2.hasMoreElements();) {
    248                        Variable variable = (Variable)e2.nextElement();
    249                        if (!variable.equals(this)) {
    250                            Vector constraints = (Vector)iConstraintVariables.get(variable);
    251                            if (constraints==null) {
    252                                constraints = new FastVector(1,10);
    253                                iConstraintVariables.put(variable, constraints);
    254                            }
    255                            constraints.add(constraint);
    256                        }
    257                    }
    258                }
    259            }
    260            return iConstraintVariables;
    261        }
    262
    263        /** Permanently remove the initial value from the variable's domain -- for testing MPP */
    264        public void removeInitialValue() {
    265            if (iInitialValue==null) return;
    266            if (iValues==null) return;
    267            if (getAssignment()!=null && getAssignment().equals(iInitialValue)) unassign(0);
    268            iValues.remove(iInitialValue);
    269            iInitialValue=null;
    270        }
    271    }