package aima.core.search.csp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
/**
* Artificial Intelligence A Modern Approach (3rd Ed.): Section 6.1, Page 202.<br>
* <br>
* A constraint satisfaction problem or CSP consists of three components, X, D,
* and C:
* <ul>
* <li>X is a set of variables, {X1, ... ,Xn}.</li>
* <li>D is a set of domains, {D1, ... ,Dn}, one for each variable.</li>
* <li>C is a set of constraints that specify allowable combinations of values.</li>
* </ul>
*
* @author Ruediger Lunde
*/
public class CSP {
private List<Variable> variables;
private List<Domain> domains;
private List<Constraint> constraints;
/** Lookup, which maps a variable to its index in the list of variables. */
private Hashtable<Variable, Integer> varIndexHash;
/**
* Constraint network. Maps variables to those constraints in which they
* participate.
*/
private Hashtable<Variable, List<Constraint>> cnet;
private CSP() {
}
/** Creates a new CSP for a fixed set of variables. */
public CSP(List<Variable> vars) {
variables = new ArrayList<Variable>(vars.size());
domains = new ArrayList<Domain>(vars.size());
constraints = new ArrayList<Constraint>();
varIndexHash = new Hashtable<Variable, Integer>();
cnet = new Hashtable<Variable, List<Constraint>>();
Domain emptyDomain = new Domain(new ArrayList<Object>(0));
int index = 0;
for (Variable var : vars) {
variables.add(var);
domains.add(emptyDomain);
varIndexHash.put(var, index++);
cnet.put(var, new ArrayList<Constraint>());
}
}
public List<Variable> getVariables() {
return Collections.unmodifiableList(variables);
}
public int indexOf(Variable var) {
return varIndexHash.get(var);
}
public Domain getDomain(Variable var) {
return domains.get(varIndexHash.get(var));
}
public void setDomain(Variable var, Domain domain) {
domains.set(indexOf(var), domain);
}
/**
* Replaces the domain of the specified variable by new domain, which
* contains all values of the old domain except the specified value.
*/
public void removeValueFromDomain(Variable var, Object value) {
Domain currDomain = getDomain(var);
List<Object> values = new ArrayList<Object>(currDomain.size());
for (Object v : currDomain)
if (!v.equals(value))
values.add(v);
setDomain(var, new Domain(values));
}
public List<Constraint> getConstraints() {
return constraints;
}
/**
* Returns all constraints in which the specified variable participates.
*/
public List<Constraint> getConstraints(Variable var) {
return cnet.get(var);
}
public void addConstraint(Constraint constraint) {
constraints.add(constraint);
for (Variable var : constraint.getScope())
cnet.get(var).add(constraint);
}
/**
* Returns for binary constraints the other variable from the scope.
*
* @return a variable or null for non-binary constraints.
*/
public Variable getNeighbor(Variable var, Constraint constraint) {
List<Variable> scope = constraint.getScope();
if (scope.size() == 2) {
if (var == scope.get(0))
return scope.get(1);
else if (var == scope.get(1))
return scope.get(0);
}
return null;
}
/**
* Returns a copy which contains a copy of the domains list and is in all
* other aspects a flat copy of this.
*/
public CSP copyDomains() {
CSP result = new CSP();
result.variables = variables;
result.domains = new ArrayList<Domain>(domains.size());
result.domains.addAll(domains);
result.constraints = constraints;
result.varIndexHash = varIndexHash;
result.cnet = cnet;
return result;
}
}