| Index: pkg/kernel/testcases/input/DeltaBlue.dart
 | 
| diff --git a/pkg/kernel/testcases/input/DeltaBlue.dart b/pkg/kernel/testcases/input/DeltaBlue.dart
 | 
| deleted file mode 100644
 | 
| index 1b58f52f5e18b55881b197b0d7aa89e6fe51285c..0000000000000000000000000000000000000000
 | 
| --- a/pkg/kernel/testcases/input/DeltaBlue.dart
 | 
| +++ /dev/null
 | 
| @@ -1,705 +0,0 @@
 | 
| -// Copyright 2011 Google Inc. All Rights Reserved.
 | 
| -// Copyright 1996 John Maloney and Mario Wolczko
 | 
| -//
 | 
| -// This file is part of GNU Smalltalk.
 | 
| -//
 | 
| -// GNU Smalltalk is free software; you can redistribute it and/or modify it
 | 
| -// under the terms of the GNU General Public License as published by the Free
 | 
| -// Software Foundation; either version 2, or (at your option) any later version.
 | 
| -//
 | 
| -// GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
 | 
| -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
| -// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 | 
| -// details.
 | 
| -//
 | 
| -// You should have received a copy of the GNU General Public License along with
 | 
| -// GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
 | 
| -// Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
| -//
 | 
| -// Translated first from Smalltalk to JavaScript, and finally to
 | 
| -// Dart by Google 2008-2010.
 | 
| -
 | 
| -/**
 | 
| - * A Dart implementation of the DeltaBlue constraint-solving
 | 
| - * algorithm, as described in:
 | 
| - *
 | 
| - * "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver"
 | 
| - *   Bjorn N. Freeman-Benson and John Maloney
 | 
| - *   January 1990 Communications of the ACM,
 | 
| - *   also available as University of Washington TR 89-08-06.
 | 
| - *
 | 
| - * Beware: this benchmark is written in a grotesque style where
 | 
| - * the constraint model is built by side-effects from constructors.
 | 
| - * I've kept it this way to avoid deviating too much from the original
 | 
| - * implementation.
 | 
| - */
 | 
| -
 | 
| -main() {
 | 
| -  new DeltaBlue().run();
 | 
| -}
 | 
| -
 | 
| -/// Benchmark class required to report results.
 | 
| -class DeltaBlue {
 | 
| -  void run() {
 | 
| -    chainTest(100);
 | 
| -    projectionTest(100);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * Strengths are used to measure the relative importance of constraints.
 | 
| - * New strengths may be inserted in the strength hierarchy without
 | 
| - * disrupting current constraints.  Strengths cannot be created outside
 | 
| - * this class, so == can be used for value comparison.
 | 
| - */
 | 
| -class Strength {
 | 
| -  final int value;
 | 
| -  final String name;
 | 
| -
 | 
| -  const Strength(this.value, this.name);
 | 
| -
 | 
| -  Strength nextWeaker() => const <Strength>[
 | 
| -        STRONG_PREFERRED,
 | 
| -        PREFERRED,
 | 
| -        STRONG_DEFAULT,
 | 
| -        NORMAL,
 | 
| -        WEAK_DEFAULT,
 | 
| -        WEAKEST
 | 
| -      ][value];
 | 
| -
 | 
| -  static bool stronger(Strength s1, Strength s2) {
 | 
| -    return s1.value < s2.value;
 | 
| -  }
 | 
| -
 | 
| -  static bool weaker(Strength s1, Strength s2) {
 | 
| -    return s1.value > s2.value;
 | 
| -  }
 | 
| -
 | 
| -  static Strength weakest(Strength s1, Strength s2) {
 | 
| -    return weaker(s1, s2) ? s1 : s2;
 | 
| -  }
 | 
| -
 | 
| -  static Strength strongest(Strength s1, Strength s2) {
 | 
| -    return stronger(s1, s2) ? s1 : s2;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -// Compile time computed constants.
 | 
| -const REQUIRED = const Strength(0, "required");
 | 
| -const STRONG_PREFERRED = const Strength(1, "strongPreferred");
 | 
| -const PREFERRED = const Strength(2, "preferred");
 | 
| -const STRONG_DEFAULT = const Strength(3, "strongDefault");
 | 
| -const NORMAL = const Strength(4, "normal");
 | 
| -const WEAK_DEFAULT = const Strength(5, "weakDefault");
 | 
| -const WEAKEST = const Strength(6, "weakest");
 | 
| -
 | 
| -abstract class Constraint {
 | 
| -  final Strength strength;
 | 
| -
 | 
| -  const Constraint(this.strength);
 | 
| -
 | 
| -  bool isSatisfied();
 | 
| -  void markUnsatisfied();
 | 
| -  void addToGraph();
 | 
| -  void removeFromGraph();
 | 
| -  void chooseMethod(int mark);
 | 
| -  void markInputs(int mark);
 | 
| -  bool inputsKnown(int mark);
 | 
| -  Variable output();
 | 
| -  void execute();
 | 
| -  void recalculate();
 | 
| -
 | 
| -  /// Activate this constraint and attempt to satisfy it.
 | 
| -  void addConstraint() {
 | 
| -    addToGraph();
 | 
| -    planner.incrementalAdd(this);
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Attempt to find a way to enforce this constraint. If successful,
 | 
| -   * record the solution, perhaps modifying the current dataflow
 | 
| -   * graph. Answer the constraint that this constraint overrides, if
 | 
| -   * there is one, or nil, if there isn't.
 | 
| -   * Assume: I am not already satisfied.
 | 
| -   */
 | 
| -  Constraint satisfy(mark) {
 | 
| -    chooseMethod(mark);
 | 
| -    if (!isSatisfied()) {
 | 
| -      if (strength == REQUIRED) {
 | 
| -        print("Could not satisfy a required constraint!");
 | 
| -      }
 | 
| -      return null;
 | 
| -    }
 | 
| -    markInputs(mark);
 | 
| -    Variable out = output();
 | 
| -    Constraint overridden = out.determinedBy;
 | 
| -    if (overridden != null) overridden.markUnsatisfied();
 | 
| -    out.determinedBy = this;
 | 
| -    if (!planner.addPropagate(this, mark)) print("Cycle encountered");
 | 
| -    out.mark = mark;
 | 
| -    return overridden;
 | 
| -  }
 | 
| -
 | 
| -  void destroyConstraint() {
 | 
| -    if (isSatisfied()) planner.incrementalRemove(this);
 | 
| -    removeFromGraph();
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Normal constraints are not input constraints.  An input constraint
 | 
| -   * is one that depends on external state, such as the mouse, the
 | 
| -   * keybord, a clock, or some arbitraty piece of imperative code.
 | 
| -   */
 | 
| -  bool isInput() => false;
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * Abstract superclass for constraints having a single possible output variable.
 | 
| - */
 | 
| -abstract class UnaryConstraint extends Constraint {
 | 
| -  final Variable myOutput;
 | 
| -  bool satisfied = false;
 | 
| -
 | 
| -  UnaryConstraint(this.myOutput, Strength strength) : super(strength) {
 | 
| -    addConstraint();
 | 
| -  }
 | 
| -
 | 
| -  /// Adds this constraint to the constraint graph
 | 
| -  void addToGraph() {
 | 
| -    myOutput.addConstraint(this);
 | 
| -    satisfied = false;
 | 
| -  }
 | 
| -
 | 
| -  /// Decides if this constraint can be satisfied and records that decision.
 | 
| -  void chooseMethod(int mark) {
 | 
| -    satisfied = (myOutput.mark != mark) &&
 | 
| -        Strength.stronger(strength, myOutput.walkStrength);
 | 
| -  }
 | 
| -
 | 
| -  /// Returns true if this constraint is satisfied in the current solution.
 | 
| -  bool isSatisfied() => satisfied;
 | 
| -
 | 
| -  void markInputs(int mark) {
 | 
| -    // has no inputs.
 | 
| -  }
 | 
| -
 | 
| -  /// Returns the current output variable.
 | 
| -  Variable output() => myOutput;
 | 
| -
 | 
| -  /**
 | 
| -   * Calculate the walkabout strength, the stay flag, and, if it is
 | 
| -   * 'stay', the value for the current output of this constraint. Assume
 | 
| -   * this constraint is satisfied.
 | 
| -   */
 | 
| -  void recalculate() {
 | 
| -    myOutput.walkStrength = strength;
 | 
| -    myOutput.stay = !isInput();
 | 
| -    if (myOutput.stay) execute(); // Stay optimization.
 | 
| -  }
 | 
| -
 | 
| -  /// Records that this constraint is unsatisfied.
 | 
| -  void markUnsatisfied() {
 | 
| -    satisfied = false;
 | 
| -  }
 | 
| -
 | 
| -  bool inputsKnown(int mark) => true;
 | 
| -
 | 
| -  void removeFromGraph() {
 | 
| -    if (myOutput != null) myOutput.removeConstraint(this);
 | 
| -    satisfied = false;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * Variables that should, with some level of preference, stay the same.
 | 
| - * Planners may exploit the fact that instances, if satisfied, will not
 | 
| - * change their output during plan execution.  This is called "stay
 | 
| - * optimization".
 | 
| - */
 | 
| -class StayConstraint extends UnaryConstraint {
 | 
| -  StayConstraint(Variable v, Strength str) : super(v, str);
 | 
| -
 | 
| -  void execute() {
 | 
| -    // Stay constraints do nothing.
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * A unary input constraint used to mark a variable that the client
 | 
| - * wishes to change.
 | 
| - */
 | 
| -class EditConstraint extends UnaryConstraint {
 | 
| -  EditConstraint(Variable v, Strength str) : super(v, str);
 | 
| -
 | 
| -  /// Edits indicate that a variable is to be changed by imperative code.
 | 
| -  bool isInput() => true;
 | 
| -
 | 
| -  void execute() {
 | 
| -    // Edit constraints do nothing.
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -// Directions.
 | 
| -const int NONE = 1;
 | 
| -const int FORWARD = 2;
 | 
| -const int BACKWARD = 0;
 | 
| -
 | 
| -/**
 | 
| - * Abstract superclass for constraints having two possible output
 | 
| - * variables.
 | 
| - */
 | 
| -abstract class BinaryConstraint extends Constraint {
 | 
| -  Variable v1;
 | 
| -  Variable v2;
 | 
| -  int direction = NONE;
 | 
| -
 | 
| -  BinaryConstraint(this.v1, this.v2, Strength strength) : super(strength) {
 | 
| -    addConstraint();
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Decides if this constraint can be satisfied and which way it
 | 
| -   * should flow based on the relative strength of the variables related,
 | 
| -   * and record that decision.
 | 
| -   */
 | 
| -  void chooseMethod(int mark) {
 | 
| -    if (v1.mark == mark) {
 | 
| -      direction =
 | 
| -          (v2.mark != mark && Strength.stronger(strength, v2.walkStrength))
 | 
| -              ? FORWARD
 | 
| -              : NONE;
 | 
| -    }
 | 
| -    if (v2.mark == mark) {
 | 
| -      direction =
 | 
| -          (v1.mark != mark && Strength.stronger(strength, v1.walkStrength))
 | 
| -              ? BACKWARD
 | 
| -              : NONE;
 | 
| -    }
 | 
| -    if (Strength.weaker(v1.walkStrength, v2.walkStrength)) {
 | 
| -      direction =
 | 
| -          Strength.stronger(strength, v1.walkStrength) ? BACKWARD : NONE;
 | 
| -    } else {
 | 
| -      direction =
 | 
| -          Strength.stronger(strength, v2.walkStrength) ? FORWARD : BACKWARD;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /// Add this constraint to the constraint graph.
 | 
| -  void addToGraph() {
 | 
| -    v1.addConstraint(this);
 | 
| -    v2.addConstraint(this);
 | 
| -    direction = NONE;
 | 
| -  }
 | 
| -
 | 
| -  /// Answer true if this constraint is satisfied in the current solution.
 | 
| -  bool isSatisfied() => direction != NONE;
 | 
| -
 | 
| -  /// Mark the input variable with the given mark.
 | 
| -  void markInputs(int mark) {
 | 
| -    input().mark = mark;
 | 
| -  }
 | 
| -
 | 
| -  /// Returns the current input variable
 | 
| -  Variable input() => direction == FORWARD ? v1 : v2;
 | 
| -
 | 
| -  /// Returns the current output variable.
 | 
| -  Variable output() => direction == FORWARD ? v2 : v1;
 | 
| -
 | 
| -  /**
 | 
| -   * Calculate the walkabout strength, the stay flag, and, if it is
 | 
| -   * 'stay', the value for the current output of this
 | 
| -   * constraint. Assume this constraint is satisfied.
 | 
| -   */
 | 
| -  void recalculate() {
 | 
| -    Variable ihn = input(), out = output();
 | 
| -    out.walkStrength = Strength.weakest(strength, ihn.walkStrength);
 | 
| -    out.stay = ihn.stay;
 | 
| -    if (out.stay) execute();
 | 
| -  }
 | 
| -
 | 
| -  /// Record the fact that this constraint is unsatisfied.
 | 
| -  void markUnsatisfied() {
 | 
| -    direction = NONE;
 | 
| -  }
 | 
| -
 | 
| -  bool inputsKnown(int mark) {
 | 
| -    Variable i = input();
 | 
| -    return i.mark == mark || i.stay || i.determinedBy == null;
 | 
| -  }
 | 
| -
 | 
| -  void removeFromGraph() {
 | 
| -    if (v1 != null) v1.removeConstraint(this);
 | 
| -    if (v2 != null) v2.removeConstraint(this);
 | 
| -    direction = NONE;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * Relates two variables by the linear scaling relationship: "v2 =
 | 
| - * (v1 * scale) + offset". Either v1 or v2 may be changed to maintain
 | 
| - * this relationship but the scale factor and offset are considered
 | 
| - * read-only.
 | 
| - */
 | 
| -
 | 
| -class ScaleConstraint extends BinaryConstraint {
 | 
| -  final Variable scale;
 | 
| -  final Variable offset;
 | 
| -
 | 
| -  ScaleConstraint(
 | 
| -      Variable src, this.scale, this.offset, Variable dest, Strength strength)
 | 
| -      : super(src, dest, strength);
 | 
| -
 | 
| -  /// Adds this constraint to the constraint graph.
 | 
| -  void addToGraph() {
 | 
| -    super.addToGraph();
 | 
| -    scale.addConstraint(this);
 | 
| -    offset.addConstraint(this);
 | 
| -  }
 | 
| -
 | 
| -  void removeFromGraph() {
 | 
| -    super.removeFromGraph();
 | 
| -    if (scale != null) scale.removeConstraint(this);
 | 
| -    if (offset != null) offset.removeConstraint(this);
 | 
| -  }
 | 
| -
 | 
| -  void markInputs(int mark) {
 | 
| -    super.markInputs(mark);
 | 
| -    scale.mark = offset.mark = mark;
 | 
| -  }
 | 
| -
 | 
| -  /// Enforce this constraint. Assume that it is satisfied.
 | 
| -  void execute() {
 | 
| -    if (direction == FORWARD) {
 | 
| -      v2.value = v1.value * scale.value + offset.value;
 | 
| -    } else {
 | 
| -      v1.value = (v2.value - offset.value) ~/ scale.value;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Calculate the walkabout strength, the stay flag, and, if it is
 | 
| -   * 'stay', the value for the current output of this constraint. Assume
 | 
| -   * this constraint is satisfied.
 | 
| -   */
 | 
| -  void recalculate() {
 | 
| -    Variable ihn = input(), out = output();
 | 
| -    out.walkStrength = Strength.weakest(strength, ihn.walkStrength);
 | 
| -    out.stay = ihn.stay && scale.stay && offset.stay;
 | 
| -    if (out.stay) execute();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * Constrains two variables to have the same value.
 | 
| - */
 | 
| -class EqualityConstraint extends BinaryConstraint {
 | 
| -  EqualityConstraint(Variable v1, Variable v2, Strength strength)
 | 
| -      : super(v1, v2, strength);
 | 
| -
 | 
| -  /// Enforce this constraint. Assume that it is satisfied.
 | 
| -  void execute() {
 | 
| -    output().value = input().value;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * A constrained variable. In addition to its value, it maintain the
 | 
| - * structure of the constraint graph, the current dataflow graph, and
 | 
| - * various parameters of interest to the DeltaBlue incremental
 | 
| - * constraint solver.
 | 
| - **/
 | 
| -class Variable {
 | 
| -  List<Constraint> constraints = <Constraint>[];
 | 
| -  Constraint determinedBy;
 | 
| -  int mark = 0;
 | 
| -  Strength walkStrength = WEAKEST;
 | 
| -  bool stay = true;
 | 
| -  int value;
 | 
| -  final String name;
 | 
| -
 | 
| -  Variable(this.name, this.value);
 | 
| -
 | 
| -  /**
 | 
| -   * Add the given constraint to the set of all constraints that refer
 | 
| -   * this variable.
 | 
| -   */
 | 
| -  void addConstraint(Constraint c) {
 | 
| -    constraints.add(c);
 | 
| -  }
 | 
| -
 | 
| -  /// Removes all traces of c from this variable.
 | 
| -  void removeConstraint(Constraint c) {
 | 
| -    constraints.remove(c);
 | 
| -    if (determinedBy == c) determinedBy = null;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -class Planner {
 | 
| -  int currentMark = 0;
 | 
| -
 | 
| -  /**
 | 
| -   * Attempt to satisfy the given constraint and, if successful,
 | 
| -   * incrementally update the dataflow graph.  Details: If satifying
 | 
| -   * the constraint is successful, it may override a weaker constraint
 | 
| -   * on its output. The algorithm attempts to resatisfy that
 | 
| -   * constraint using some other method. This process is repeated
 | 
| -   * until either a) it reaches a variable that was not previously
 | 
| -   * determined by any constraint or b) it reaches a constraint that
 | 
| -   * is too weak to be satisfied using any of its methods. The
 | 
| -   * variables of constraints that have been processed are marked with
 | 
| -   * a unique mark value so that we know where we've been. This allows
 | 
| -   * the algorithm to avoid getting into an infinite loop even if the
 | 
| -   * constraint graph has an inadvertent cycle.
 | 
| -   */
 | 
| -  void incrementalAdd(Constraint c) {
 | 
| -    int mark = newMark();
 | 
| -    for (Constraint overridden = c.satisfy(mark);
 | 
| -        overridden != null;
 | 
| -        overridden = overridden.satisfy(mark));
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Entry point for retracting a constraint. Remove the given
 | 
| -   * constraint and incrementally update the dataflow graph.
 | 
| -   * Details: Retracting the given constraint may allow some currently
 | 
| -   * unsatisfiable downstream constraint to be satisfied. We therefore collect
 | 
| -   * a list of unsatisfied downstream constraints and attempt to
 | 
| -   * satisfy each one in turn. This list is traversed by constraint
 | 
| -   * strength, strongest first, as a heuristic for avoiding
 | 
| -   * unnecessarily adding and then overriding weak constraints.
 | 
| -   * Assume: [c] is satisfied.
 | 
| -   */
 | 
| -  void incrementalRemove(Constraint c) {
 | 
| -    Variable out = c.output();
 | 
| -    c.markUnsatisfied();
 | 
| -    c.removeFromGraph();
 | 
| -    List<Constraint> unsatisfied = removePropagateFrom(out);
 | 
| -    Strength strength = REQUIRED;
 | 
| -    do {
 | 
| -      for (int i = 0; i < unsatisfied.length; i++) {
 | 
| -        Constraint u = unsatisfied[i];
 | 
| -        if (u.strength == strength) incrementalAdd(u);
 | 
| -      }
 | 
| -      strength = strength.nextWeaker();
 | 
| -    } while (strength != WEAKEST);
 | 
| -  }
 | 
| -
 | 
| -  /// Select a previously unused mark value.
 | 
| -  int newMark() => ++currentMark;
 | 
| -
 | 
| -  /**
 | 
| -   * Extract a plan for resatisfaction starting from the given source
 | 
| -   * constraints, usually a set of input constraints. This method
 | 
| -   * assumes that stay optimization is desired; the plan will contain
 | 
| -   * only constraints whose output variables are not stay. Constraints
 | 
| -   * that do no computation, such as stay and edit constraints, are
 | 
| -   * not included in the plan.
 | 
| -   * Details: The outputs of a constraint are marked when it is added
 | 
| -   * to the plan under construction. A constraint may be appended to
 | 
| -   * the plan when all its input variables are known. A variable is
 | 
| -   * known if either a) the variable is marked (indicating that has
 | 
| -   * been computed by a constraint appearing earlier in the plan), b)
 | 
| -   * the variable is 'stay' (i.e. it is a constant at plan execution
 | 
| -   * time), or c) the variable is not determined by any
 | 
| -   * constraint. The last provision is for past states of history
 | 
| -   * variables, which are not stay but which are also not computed by
 | 
| -   * any constraint.
 | 
| -   * Assume: [sources] are all satisfied.
 | 
| -   */
 | 
| -  Plan makePlan(List<Constraint> sources) {
 | 
| -    int mark = newMark();
 | 
| -    Plan plan = new Plan();
 | 
| -    List<Constraint> todo = sources;
 | 
| -    while (todo.length > 0) {
 | 
| -      Constraint c = todo.removeLast();
 | 
| -      if (c.output().mark != mark && c.inputsKnown(mark)) {
 | 
| -        plan.addConstraint(c);
 | 
| -        c.output().mark = mark;
 | 
| -        addConstraintsConsumingTo(c.output(), todo);
 | 
| -      }
 | 
| -    }
 | 
| -    return plan;
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Extract a plan for resatisfying starting from the output of the
 | 
| -   * given [constraints], usually a set of input constraints.
 | 
| -   */
 | 
| -  Plan extractPlanFromConstraints(List<Constraint> constraints) {
 | 
| -    List<Constraint> sources = <Constraint>[];
 | 
| -    for (int i = 0; i < constraints.length; i++) {
 | 
| -      Constraint c = constraints[i];
 | 
| -      // if not in plan already and eligible for inclusion.
 | 
| -      if (c.isInput() && c.isSatisfied()) sources.add(c);
 | 
| -    }
 | 
| -    return makePlan(sources);
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Recompute the walkabout strengths and stay flags of all variables
 | 
| -   * downstream of the given constraint and recompute the actual
 | 
| -   * values of all variables whose stay flag is true. If a cycle is
 | 
| -   * detected, remove the given constraint and answer
 | 
| -   * false. Otherwise, answer true.
 | 
| -   * Details: Cycles are detected when a marked variable is
 | 
| -   * encountered downstream of the given constraint. The sender is
 | 
| -   * assumed to have marked the inputs of the given constraint with
 | 
| -   * the given mark. Thus, encountering a marked node downstream of
 | 
| -   * the output constraint means that there is a path from the
 | 
| -   * constraint's output to one of its inputs.
 | 
| -   */
 | 
| -  bool addPropagate(Constraint c, int mark) {
 | 
| -    List<Constraint> todo = <Constraint>[c];
 | 
| -    while (todo.length > 0) {
 | 
| -      Constraint d = todo.removeLast();
 | 
| -      if (d.output().mark == mark) {
 | 
| -        incrementalRemove(c);
 | 
| -        return false;
 | 
| -      }
 | 
| -      d.recalculate();
 | 
| -      addConstraintsConsumingTo(d.output(), todo);
 | 
| -    }
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * 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.
 | 
| -   */
 | 
| -  List<Constraint> removePropagateFrom(Variable out) {
 | 
| -    out.determinedBy = null;
 | 
| -    out.walkStrength = WEAKEST;
 | 
| -    out.stay = true;
 | 
| -    List<Constraint> unsatisfied = <Constraint>[];
 | 
| -    List<Variable> todo = <Variable>[out];
 | 
| -    while (todo.length > 0) {
 | 
| -      Variable v = todo.removeLast();
 | 
| -      for (int i = 0; i < v.constraints.length; i++) {
 | 
| -        Constraint c = v.constraints[i];
 | 
| -        if (!c.isSatisfied()) unsatisfied.add(c);
 | 
| -      }
 | 
| -      Constraint determining = v.determinedBy;
 | 
| -      for (int i = 0; i < v.constraints.length; i++) {
 | 
| -        Constraint next = v.constraints[i];
 | 
| -        if (next != determining && next.isSatisfied()) {
 | 
| -          next.recalculate();
 | 
| -          todo.add(next.output());
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -    return unsatisfied;
 | 
| -  }
 | 
| -
 | 
| -  void addConstraintsConsumingTo(Variable v, List<Constraint> coll) {
 | 
| -    Constraint determining = v.determinedBy;
 | 
| -    for (int i = 0; i < v.constraints.length; i++) {
 | 
| -      Constraint c = v.constraints[i];
 | 
| -      if (c != determining && c.isSatisfied()) coll.add(c);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * A Plan is an ordered list of constraints to be executed in sequence
 | 
| - * to resatisfy all currently satisfiable constraints in the face of
 | 
| - * one or more changing inputs.
 | 
| - */
 | 
| -class Plan {
 | 
| -  List<Constraint> list = <Constraint>[];
 | 
| -
 | 
| -  void addConstraint(Constraint c) {
 | 
| -    list.add(c);
 | 
| -  }
 | 
| -
 | 
| -  int size() => list.length;
 | 
| -
 | 
| -  void execute() {
 | 
| -    for (int i = 0; i < list.length; i++) {
 | 
| -      list[i].execute();
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * 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.
 | 
| - */
 | 
| -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++) {
 | 
| -    Variable v = new Variable("v$i", 0);
 | 
| -    if (prev != null) new EqualityConstraint(prev, v, REQUIRED);
 | 
| -    if (i == 0) first = v;
 | 
| -    if (i == n) last = v;
 | 
| -    prev = v;
 | 
| -  }
 | 
| -  new StayConstraint(last, STRONG_DEFAULT);
 | 
| -  EditConstraint edit = new EditConstraint(first, PREFERRED);
 | 
| -  Plan plan = planner.extractPlanFromConstraints(<Constraint>[edit]);
 | 
| -  for (int i = 0; i < 100; i++) {
 | 
| -    first.value = i;
 | 
| -    plan.execute();
 | 
| -    if (last.value != i) {
 | 
| -      print("Chain test failed:");
 | 
| -      print("Expected last value to be $i but it was ${last.value}.");
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/**
 | 
| - * 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.
 | 
| - */
 | 
| -void projectionTest(int n) {
 | 
| -  planner = new Planner();
 | 
| -  Variable scale = new Variable("scale", 10);
 | 
| -  Variable offset = new Variable("offset", 1000);
 | 
| -  Variable src = null, dst = null;
 | 
| -
 | 
| -  List<Variable> dests = <Variable>[];
 | 
| -  for (int i = 0; i < n; i++) {
 | 
| -    src = new Variable("src", i);
 | 
| -    dst = new Variable("dst", i);
 | 
| -    dests.add(dst);
 | 
| -    new StayConstraint(src, NORMAL);
 | 
| -    new ScaleConstraint(src, scale, offset, dst, REQUIRED);
 | 
| -  }
 | 
| -  change(src, 17);
 | 
| -  if (dst.value != 1170) print("Projection 1 failed");
 | 
| -  change(dst, 1050);
 | 
| -  if (src.value != 5) print("Projection 2 failed");
 | 
| -  change(scale, 5);
 | 
| -  for (int i = 0; i < n - 1; i++) {
 | 
| -    if (dests[i].value != i * 5 + 1000) print("Projection 3 failed");
 | 
| -  }
 | 
| -  change(offset, 2000);
 | 
| -  for (int i = 0; i < n - 1; i++) {
 | 
| -    if (dests[i].value != i * 5 + 2000) print("Projection 4 failed");
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void change(Variable v, int newValue) {
 | 
| -  EditConstraint edit = new EditConstraint(v, PREFERRED);
 | 
| -  Plan plan = planner.extractPlanFromConstraints(<EditConstraint>[edit]);
 | 
| -  for (int i = 0; i < 10; i++) {
 | 
| -    v.value = newValue;
 | 
| -    plan.execute();
 | 
| -  }
 | 
| -  edit.destroyConstraint();
 | 
| -}
 | 
| -
 | 
| -Planner planner;
 | 
| 
 |