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