JACK: JASE Example
// A simple SChoice which enumerates a set of Finite Domains variables
public class SFDEnuChoice implements SChoice
{
final private ObjectContainer vars; // variables to be enumerated
final private ObjectContainer varNames; // only for toString()
final private int curVar; // index of the variable in
// this particular choice
final private SChoice continuation; // if we are finished, try
// this (outputs the solution, etc.)
private boolean isFailure; // last call to choose() resulted in a
// failure
final private boolean trace; // debug?
public SFDEnuChoice(ObjectContainer vars,ObjectContainer varNames,
int curVar,SChoice continuation,boolean trace)
{
this.vars=vars;
this.varNames=varNames;
this.curVar=curVar;
this.continuation=continuation;
this.trace=trace;
}
public SChoice choose(ConstraintSystem system,boolean firstChoice)
{
isFailure=false;
Object variable=vars.get(curVar);
// If the variable is bound, we basically do nothing.
boolean variableIsBound=system.hasVarValue(variable);
// Query the domain of the variable (by reading out the
// fdEnu constraint)
UDConstraint domainConstraint=null;
Object firstValue=null;
boolean hasMoreValues=false;
nl domain=null;
if (!variableIsBound)
{
// Note that getVariableDomainConstraint() does exactly
// the same here as getVariableDomain(), since we already
// know that the variable is not bound.
domainConstraint=FDUtil.getVariableDomainConstraint(system,
variable);
if (domainConstraint!=null)
domain=((nl)domainConstraint.getArgAt(1));
// Empty domain -> nothing can be done. This case should not
// happen, but does sometimes (investigate XXX TODO)
if (domain==null || domain.first==null)
{
isFailure=true;
return null;
}
firstValue=domain.first;
hasMoreValues=(domain.rest!=null);
}
if (firstChoice)
{
if (!variableIsBound)
{
// Fix the variable to its first value
// We can assume that the domain is not empty; in that
// case, the solver would have removed it already.
// Bind the variable (for value recovery)
system.setVarValue(variable,firstValue);
// Also, insert a fdEnu constraint (the fd solver
// doesn't work with bound variables). Note: although
// this of not necessary, and of course takes a bit of
// time, the benefit of smaller variable domains
// outweights it for, e.g., 5-Queens, so it seems
// worthwile.
system.removeGoalConstraint(domainConstraint); // for performance only
system.addGoalConstraint(new FDENUConstraint(variable,
new nl(firstValue)));
// Perform a solving step
if (!callGoal(system)) return null;
}
// If that was the last value, return the continuation;
// else create an enumerator for the next variable
if (curVar+1>=vars.size())
return continuation;
return new SFDEnuChoice(vars,varNames,curVar+1,continuation,trace);
}
else // second choice
{
// If no more values, we fail.
if (variableIsBound || !hasMoreValues)
{
isFailure=true;
return null;
}
// Remove the first value from the variable domain
system.removeGoalConstraint(domainConstraint); // for performance only
system.addGoalConstraint(new FDENUConstraint(variable,
domain.rest));
// The following works, too, but is slightly less efficient:
// system.addGoalConstraint(new FDNEConstraint(variable,
// firstValue));
// Perform a solving step
if (!callGoal(system))
return null;
// We can continue with this same SChoice
// No problem in re-using the instance, because all member
// variables of SFDEnuChoice are "final" anyway. Note that
// this won't work if a subclass has its own member
// variables, in which case we need to clone this object.
return this;
}
}
public boolean failed()
{
return isFailure;
}
public void reset()
{
isFailure=false;
}
// Activate the constraint solver
private boolean callGoal(ConstraintSystem system)
{
if (!system.callGoal(trace))
{
isFailure=true;
return false;
}
return true;
}
public String toString()
{
return "SFDEnuChoice["+varNames+", current="+curVar+"]";
}
}
Last modified: Mon Apr 9 12:13:54 CEST 2001