001package org.cpsolver.ifs.assignment; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.List; 006 007import org.cpsolver.ifs.assignment.context.AssignmentContext; 008import org.cpsolver.ifs.assignment.context.AssignmentContextHolder; 009import org.cpsolver.ifs.assignment.context.AssignmentContextReference; 010import org.cpsolver.ifs.assignment.context.HasAssignmentContext; 011import org.cpsolver.ifs.constant.ConstantVariable; 012import org.cpsolver.ifs.criteria.Criterion; 013import org.cpsolver.ifs.model.Constraint; 014import org.cpsolver.ifs.model.GlobalConstraint; 015import org.cpsolver.ifs.model.Model; 016import org.cpsolver.ifs.model.Value; 017import org.cpsolver.ifs.model.Variable; 018 019 020/** 021 * An abstract implementation of an {@link Assignment} object. It contains an instance of 022 * a given assignment context holder (see {@link AssignmentContextHolder}) and 023 * implements the assignment logic. But the actual process of storing and retrieving values 024 * is left on the assignment implementation. 025 * 026 * @see Assignment 027 * 028 * @version IFS 1.3 (Iterative Forward Search)<br> 029 * Copyright (C) 2014 Tomáš Müller<br> 030 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 031 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 032 * <br> 033 * This library is free software; you can redistribute it and/or modify 034 * it under the terms of the GNU Lesser General Public License as 035 * published by the Free Software Foundation; either version 3 of the 036 * License, or (at your option) any later version. <br> 037 * <br> 038 * This library is distributed in the hope that it will be useful, but 039 * WITHOUT ANY WARRANTY; without even the implied warranty of 040 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 041 * Lesser General Public License for more details. <br> 042 * <br> 043 * You should have received a copy of the GNU Lesser General Public 044 * License along with this library; if not see <a href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>. 045 * @param <V> Variable 046 * @param <T> Value 047 **/ 048public abstract class AssignmentAbstract<V extends Variable<V, T>, T extends Value<V, T>> implements Assignment<V, T> { 049 protected AssignmentContextHolder<V, T> iContexts; 050 protected boolean iHasInitialzedContext = false; 051 052 /** 053 * Constructor 054 * @param contexts an instance of the assignment context holder 055 */ 056 public AssignmentAbstract(AssignmentContextHolder<V, T> contexts) { 057 iContexts = contexts; 058 } 059 060 /** 061 * Checks if the variable is {@link ConstantVariable}, returns {@link AssignmentAbstract#getValueInternal(Variable)} 062 * if the variable is not a constant. 063 */ 064 @Override 065 @SuppressWarnings("unchecked") 066 public T getValue(V variable) { 067 if (variable instanceof ConstantVariable<?> && ((ConstantVariable<?>)variable).isConstant()) 068 return ((ConstantVariable<T>)variable).getConstantValue(); 069 return getValueInternal(variable); 070 } 071 072 /** 073 * Returns assignment of a variable, null if not assigned. To be implemented. 074 * @param variable a variable in question 075 * @return assigned value 076 **/ 077 protected abstract T getValueInternal(V variable); 078 079 /** 080 * Sets an assignment to a variable (unassigns a variable if the given value is null). To be implemented. 081 * @param iteration current iteration 082 * @param variable a variable to be assigned 083 * @param value new assignment, null if to be unassigned 084 **/ 085 protected abstract void setValueInternal(long iteration, V variable, T value); 086 087 /** Assigns a variable with the given value. All the appropriate classes are notified about the change. 088 * It is using {@link AssignmentAbstract#setValueInternal(long, Variable, Value)} to store the new 089 * assignment. 090 * @param iteration current iteration 091 * @param variable a variable 092 * @param value one of its values, null if the variable is to be unassigned 093 * @return previous assignment of the variable 094 **/ 095 @SuppressWarnings("unchecked") 096 protected T assign(long iteration, V variable, T value) { 097 if (variable instanceof ConstantVariable<?> && ((ConstantVariable<?>)variable).isConstant()) 098 return ((ConstantVariable<T>)variable).getConstantValue(); 099 100 assert variable.getModel() != null && (value == null || variable.equals(value.variable())); 101 Model<V, T> model = variable.getModel(); 102 103 // ensure all model, criterion, and constraint assignment contexts are initialized before changing the assignment value 104 ensureInitializedContext(variable); 105 106 // unassign old value, if assigned 107 T old = getValueInternal(variable); 108 if (old != null) { 109 if (old.equals(value)) return old; 110 if (model != null) 111 model.beforeUnassigned(this, iteration, old); 112 setValueInternal(iteration, variable, null); 113 for (Constraint<V, T> constraint : variable.constraints()) 114 constraint.unassigned(this, iteration, old); 115 if (model != null) 116 for (GlobalConstraint<V, T> constraint : model.globalConstraints()) 117 constraint.unassigned(this, iteration, old); 118 variable.variableUnassigned(this, iteration, old); 119 if (model != null) 120 model.afterUnassigned(this, iteration, old); 121 } 122 123 // assign new value, if provided 124 if (value != null) { 125 if (model != null) 126 model.beforeAssigned(this, iteration, value); 127 setValueInternal(iteration, variable, value); 128 for (Constraint<V, T> constraint : variable.constraints()) 129 constraint.assigned(this, iteration, value); 130 if (model != null) 131 for (GlobalConstraint<V, T> constraint : model.globalConstraints()) 132 constraint.assigned(this, iteration, value); 133 variable.variableAssigned(this, iteration, value); 134 if (model != null) 135 model.afterAssigned(this, iteration, value); 136 } 137 138 // return old value 139 return old; 140 } 141 142 @Override 143 public T assign(long iteration, T value) { 144 return assign(iteration, value.variable(), value); 145 } 146 147 @Override 148 public T unassign(long iteration, V variable) { 149 return assign(iteration, variable, null); 150 } 151 152 @Override 153 public T unassign(long iteration, V variable, T value) { 154 T current = getValue(variable); 155 if (current == null && value == null) { 156 return current; 157 } else if (current != null && current.equals(value)) { 158 return current; 159 } else { 160 return assign(iteration, variable, null); 161 } 162 } 163 164 @Override 165 public int nrAssignedVariables() { 166 return assignedVariables().size(); 167 } 168 169 @Override 170 public Collection<T> assignedValues() { 171 List<T> values = new ArrayList<T>(); 172 for (V variable: assignedVariables()) 173 values.add(getValueInternal(variable)); 174 return values; 175 } 176 177 @Override 178 public Collection<V> unassignedVariables(Model<V, T> model) { 179 List<V> unassigned = new ArrayList<V>(); 180 for (V variable: model.variables()) 181 if (getValue(variable) == null) 182 unassigned.add(variable); 183 return unassigned; 184 } 185 186 @Override 187 public int nrUnassignedVariables(Model<V, T> model) { 188 return model.variables().size() - nrAssignedVariables(); 189 } 190 191 @Override 192 public <C extends AssignmentContext> C getAssignmentContext(AssignmentContextReference<V, T, C> reference) { 193 return iContexts.getAssignmentContext(this, reference); 194 } 195 196 @Override 197 public <C extends AssignmentContext> void clearContext(AssignmentContextReference<V, T, C> reference) { 198 iContexts.clearContext(reference); 199 } 200 201 @Override 202 public int getIndex() { 203 return -1; 204 } 205 206 /** 207 * Ensure that the model, all criteria, all global constraints and all the related constraints have their assignment contexts initialized. 208 * @param variable a variable to be changed 209 */ 210 @SuppressWarnings("unchecked") 211 protected void ensureInitializedContext(V variable) { 212 if (!iHasInitialzedContext && variable.getModel() != null) { 213 if (variable.getModel() instanceof HasAssignmentContext) 214 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)variable.getModel()).getAssignmentContextReference()); 215 for (Criterion<V, T> criterion: variable.getModel().getCriteria()) 216 if (criterion instanceof HasAssignmentContext) 217 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)criterion).getAssignmentContextReference()); 218 for (GlobalConstraint<V, T> constraint: variable.getModel().globalConstraints()) 219 if (constraint instanceof HasAssignmentContext) 220 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)constraint).getAssignmentContextReference()); 221 iHasInitialzedContext = true; 222 } 223 for (Constraint<V, T> constraint: variable.constraints()) 224 if (constraint instanceof HasAssignmentContext) 225 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)constraint).getAssignmentContextReference()); 226 } 227}