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 Tomas Muller<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 (model != null) 110 model.beforeUnassigned(this, iteration, old); 111 setValueInternal(iteration, variable, null); 112 for (Constraint<V, T> constraint : variable.constraints()) 113 constraint.unassigned(this, iteration, old); 114 if (model != null) 115 for (GlobalConstraint<V, T> constraint : model.globalConstraints()) 116 constraint.unassigned(this, iteration, old); 117 variable.variableUnassigned(this, iteration, old); 118 if (model != null) 119 model.afterUnassigned(this, iteration, old); 120 } 121 122 // assign new value, if provided 123 if (value != null) { 124 if (model != null) 125 model.beforeAssigned(this, iteration, value); 126 setValueInternal(iteration, variable, value); 127 for (Constraint<V, T> constraint : variable.constraints()) 128 constraint.assigned(this, iteration, value); 129 if (model != null) 130 for (GlobalConstraint<V, T> constraint : model.globalConstraints()) 131 constraint.assigned(this, iteration, value); 132 variable.variableAssigned(this, iteration, value); 133 if (model != null) 134 model.afterAssigned(this, iteration, value); 135 } 136 137 // return old value 138 return old; 139 } 140 141 @Override 142 public T assign(long iteration, T value) { 143 return assign(iteration, value.variable(), value); 144 } 145 146 @Override 147 public T unassign(long iteration, V variable) { 148 return assign(iteration, variable, null); 149 } 150 151 @Override 152 public int nrAssignedVariables() { 153 return assignedVariables().size(); 154 } 155 156 @Override 157 public Collection<T> assignedValues() { 158 List<T> values = new ArrayList<T>(); 159 for (V variable: assignedVariables()) 160 values.add(getValueInternal(variable)); 161 return values; 162 } 163 164 @Override 165 public Collection<V> unassignedVariables(Model<V, T> model) { 166 List<V> unassigned = new ArrayList<V>(); 167 for (V variable: model.variables()) 168 if (getValue(variable) == null) 169 unassigned.add(variable); 170 return unassigned; 171 } 172 173 @Override 174 public int nrUnassignedVariables(Model<V, T> model) { 175 return model.variables().size() - nrAssignedVariables(); 176 } 177 178 @Override 179 public <C extends AssignmentContext> C getAssignmentContext(AssignmentContextReference<V, T, C> reference) { 180 return iContexts.getAssignmentContext(this, reference); 181 } 182 183 @Override 184 public <C extends AssignmentContext> void clearContext(AssignmentContextReference<V, T, C> reference) { 185 iContexts.clearContext(reference); 186 } 187 188 @Override 189 public int getIndex() { 190 return -1; 191 } 192 193 /** 194 * Ensure that the model, all criteria, all global constraints and all the related constraints have their assignment contexts initialized. 195 * @param variable a variable to be changed 196 */ 197 @SuppressWarnings("unchecked") 198 protected void ensureInitializedContext(V variable) { 199 if (!iHasInitialzedContext && variable.getModel() != null) { 200 if (variable.getModel() instanceof HasAssignmentContext) 201 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)variable.getModel()).getAssignmentContextReference()); 202 for (Criterion<V, T> criterion: variable.getModel().getCriteria()) 203 if (criterion instanceof HasAssignmentContext) 204 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)criterion).getAssignmentContextReference()); 205 for (GlobalConstraint<V, T> constraint: variable.getModel().globalConstraints()) 206 if (constraint instanceof HasAssignmentContext) 207 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)constraint).getAssignmentContextReference()); 208 iHasInitialzedContext = true; 209 } 210 for (Constraint<V, T> constraint: variable.constraints()) 211 if (constraint instanceof HasAssignmentContext) 212 iContexts.getAssignmentContext(this, ((HasAssignmentContext<V, T, ?>)constraint).getAssignmentContextReference()); 213 } 214}