// This is the standard DeltaBlue benchmark. A long chain of // equality constraints is constructed with a stay constraint on // one end. An edit constraint is then added to the opposite end // and the time is measured for adding and removing this // constraint, and extracting and executing a constraint // satisfaction plan. There are two cases. In case 1, the added // constraint is stronger than the stay constraint and values must // propagate down the entire length of the chain. In case 2, the // added constraint is weaker than the stay constraint so it cannot // be accomodated. The cost in this case is, of course, very // low. Typical situations lie somewhere between these two // extremes. // private void chainTest(int n) { planner = new Planner(); Variable prev = null, first = null, last = null; // Build chain of n equality constraints for (int i = 0; i <= n; i++) { String name = "v" + i; Variable v = new Variable(name); if (prev != null) new EqualityConstraint(prev, v, Strength.required); if (i == 0) first = v; if (i == n) last = v; prev = v; } new StayConstraint(last, Strength.strongDefault); Constraint editC = new EditConstraint(first, Strength.preferred); ArrayList editV = new ArrayList(); editV.Add(editC); Plan plan = planner.extractPlanFromConstraints(editV); for (int i = 0; i < 100; i++) { first.value = i; plan.execute(); if (last.value != i) error("Chain test failed!"); } editC.destroyConstraint(); deltablue.chains++; }
// Update the walkabout strengths and stay flags of all variables // downstream of the given constraint. Answer a collection of // unsatisfied constraints sorted in order of decreasing strength. // public ArrayList removePropagateFrom(Variable outvar) { outvar.determinedBy = null; outvar.walkStrength = Strength.weakest; outvar.stay = true; ArrayList unsatisfied = new ArrayList(); ArrayList todo = new ArrayList(); todo.Add(outvar); while (!(todo.Count == 0)) { #if USE_STACK Variable v = (Variable)todo[todo.Count - 1]; todo.RemoveAt(todo.Count - 1); #else Variable v= (Variable)todo[0]; todo.RemoveAt(0); #endif for (int i = 0; i < v.constraints.Count; ++i) { Constraint c = (Constraint)v.constraints[i]; if (!c.isSatisfied()) unsatisfied.Add(c); } Constraint determiningC = v.determinedBy; for (int i = 0; i < v.constraints.Count; ++i) { Constraint nextC = (Constraint)v.constraints[i]; if (nextC != determiningC && nextC.isSatisfied()) { nextC.recalculate(); todo.Add(nextC.output()); } } } return unsatisfied; }
public void addConstraintsConsumingTo(Variable v, ArrayList coll) { Constraint determiningC = v.determinedBy; ArrayList cc = v.constraints; for (int i = 0; i < cc.Count; ++i) { Constraint c = (Constraint)cc[i]; if (c != determiningC && c.isSatisfied()) coll.Add(c); } }
public Variable offset; // offset input variable // Install a scale constraint with the given strength on the given variables. public ScaleConstraint(Variable src, Variable scale, Variable offset, Variable dest, Strength strength) { // Curse this wretched language for insisting that constructor invocation // must be the first thing in a method... // ..because of that, we must copy the code from the inherited // constructors. this.strength = strength; v1 = src; v2 = dest; direction = nodirection; this.scale = scale; this.offset = offset; addConstraint(); }
// The given variable has changed. Propagate new values downstream. public void propagateFrom(Variable v) { ArrayList todo = new ArrayList(); addConstraintsConsumingTo(v, todo); while (!(todo.Count == 0)) { #if USE_STACK Constraint c = (Constraint)todo[todo.Count - 1]; todo.RemoveAt(0); #else Constraint c= (Constraint)todo[todo.Count-1]; todo.RemoveAt(0); #endif c.execute(); addConstraintsConsumingTo(c.output(), todo); } }
public BinaryConstraint() { } // this has to be here because of // Java's constructor idiocy. public BinaryConstraint(Variable var1, Variable var2, Strength strength) : base(strength) { v1 = var1; v2 = var2; direction = nodirection; addConstraint(); }
// Install a constraint with the given strength equating the given variables. public EqualityConstraint(Variable var1, Variable var2, Strength strength) : base(var1, var2, strength) { }
// Install a stay constraint with the given strength on the given variable. public StayConstraint(Variable v, Strength str) : base(v, str) { }
public EditConstraint(Variable v, Strength str) : base(v, str) { }
public Boolean satisfied; // true if I am currently satisfied public UnaryConstraint(Variable v, Strength strength) : base(strength) { myOutput = v; satisfied = false; addConstraint(); }
private void change(Variable var, int newValue) { EditConstraint editC = new EditConstraint(var, Strength.preferred); ArrayList editV = new ArrayList(); editV.Add(editC); Plan plan = planner.extractPlanFromConstraints(editV); for (int i = 0; i < 10; i++) { var.value = newValue; plan.execute(); } editC.destroyConstraint(); }
// This test constructs a two sets of variables related to each // other by a simple linear transformation (scale and offset). The // time is measured to change a variable on either side of the // mapping and to change the scale and offset factors. // private void projectionTest(int n) { planner = new Planner(); Variable scale = new Variable("scale", 10); Variable offset = new Variable("offset", 1000); Variable src = null, dst = null; ArrayList dests = new ArrayList(); for (int i = 0; i < n; ++i) { src = new Variable("src" + i, i); dst = new Variable("dst" + i, i); dests.Add(dst); new StayConstraint(src, Strength.normal); new ScaleConstraint(src, scale, offset, dst, Strength.required); } change(src, 17); if (dst.value != 1170) error("Projection test 1 failed!"); change(dst, 1050); if (src.value != 5) error("Projection test 2 failed!"); change(scale, 5); for (int i = 0; i < n - 1; ++i) { if (((Variable)dests[i]).value != i * 5 + 1000) error("Projection test 3 failed!"); } change(offset, 2000); for (int i = 0; i < n - 1; ++i) { if (((Variable)dests[i]).value != i * 5 + 2000) error("Projection test 4 failed!"); } deltablue.projections++; }