blob: bc34a9b9e64bd00b0efd1d067a52eff71c397bdf [file] [log] [blame] [edit]
dart_library.library('DeltaBlue', null, /* Imports */[
'dart/_runtime',
'BenchmarkBase',
'dart/core'
], /* Lazy imports */[
], function(exports, dart, BenchmarkBase, core) {
'use strict';
let dartx = dart.dartx;
function main() {
new DeltaBlue().report();
}
dart.fn(main);
class DeltaBlue extends BenchmarkBase.BenchmarkBase {
DeltaBlue() {
super.BenchmarkBase("DeltaBlue");
}
run() {
chainTest(100);
projectionTest(100);
}
}
dart.setSignature(DeltaBlue, {
constructors: () => ({DeltaBlue: [DeltaBlue, []]})
});
class Strength extends core.Object {
Strength(value, name) {
this.value = value;
this.name = name;
}
nextWeaker() {
return dart.const(dart.list([STRONG_PREFERRED, PREFERRED, STRONG_DEFAULT, NORMAL, WEAK_DEFAULT, WEAKEST], Strength))[dartx.get](this.value);
}
static stronger(s1, s2) {
return dart.notNull(s1.value) < dart.notNull(s2.value);
}
static weaker(s1, s2) {
return dart.notNull(s1.value) > dart.notNull(s2.value);
}
static weakest(s1, s2) {
return dart.notNull(Strength.weaker(s1, s2)) ? s1 : s2;
}
static strongest(s1, s2) {
return dart.notNull(Strength.stronger(s1, s2)) ? s1 : s2;
}
}
dart.setSignature(Strength, {
constructors: () => ({Strength: [Strength, [core.int, core.String]]}),
methods: () => ({nextWeaker: [Strength, []]}),
statics: () => ({
stronger: [core.bool, [Strength, Strength]],
weaker: [core.bool, [Strength, Strength]],
weakest: [Strength, [Strength, Strength]],
strongest: [Strength, [Strength, Strength]]
}),
names: ['stronger', 'weaker', 'weakest', 'strongest']
});
const REQUIRED = dart.const(new Strength(0, "required"));
const STRONG_PREFERRED = dart.const(new Strength(1, "strongPreferred"));
const PREFERRED = dart.const(new Strength(2, "preferred"));
const STRONG_DEFAULT = dart.const(new Strength(3, "strongDefault"));
const NORMAL = dart.const(new Strength(4, "normal"));
const WEAK_DEFAULT = dart.const(new Strength(5, "weakDefault"));
const WEAKEST = dart.const(new Strength(6, "weakest"));
class Constraint extends core.Object {
Constraint(strength) {
this.strength = strength;
}
addConstraint() {
this.addToGraph();
exports.planner.incrementalAdd(this);
}
satisfy(mark) {
this.chooseMethod(dart.as(mark, core.int));
if (!dart.notNull(this.isSatisfied())) {
if (dart.equals(this.strength, REQUIRED)) {
core.print("Could not satisfy a required constraint!");
}
return null;
}
this.markInputs(dart.as(mark, core.int));
let out = this.output();
let overridden = out.determinedBy;
if (overridden != null) overridden.markUnsatisfied();
out.determinedBy = this;
if (!dart.notNull(exports.planner.addPropagate(this, dart.as(mark, core.int)))) core.print("Cycle encountered");
out.mark = dart.as(mark, core.int);
return overridden;
}
destroyConstraint() {
if (dart.notNull(this.isSatisfied())) exports.planner.incrementalRemove(this);
this.removeFromGraph();
}
isInput() {
return false;
}
}
dart.setSignature(Constraint, {
constructors: () => ({Constraint: [Constraint, [Strength]]}),
methods: () => ({
addConstraint: [dart.void, []],
satisfy: [Constraint, [dart.dynamic]],
destroyConstraint: [dart.void, []],
isInput: [core.bool, []]
})
});
class UnaryConstraint extends Constraint {
UnaryConstraint(myOutput, strength) {
this.myOutput = myOutput;
this.satisfied = false;
super.Constraint(strength);
this.addConstraint();
}
addToGraph() {
this.myOutput.addConstraint(this);
this.satisfied = false;
}
chooseMethod(mark) {
this.satisfied = this.myOutput.mark != mark && dart.notNull(Strength.stronger(this.strength, this.myOutput.walkStrength));
}
isSatisfied() {
return this.satisfied;
}
markInputs(mark) {}
output() {
return this.myOutput;
}
recalculate() {
this.myOutput.walkStrength = this.strength;
this.myOutput.stay = !dart.notNull(this.isInput());
if (dart.notNull(this.myOutput.stay)) this.execute();
}
markUnsatisfied() {
this.satisfied = false;
}
inputsKnown(mark) {
return true;
}
removeFromGraph() {
if (this.myOutput != null) this.myOutput.removeConstraint(this);
this.satisfied = false;
}
}
dart.setSignature(UnaryConstraint, {
constructors: () => ({UnaryConstraint: [UnaryConstraint, [Variable, Strength]]}),
methods: () => ({
addToGraph: [dart.void, []],
chooseMethod: [dart.void, [core.int]],
isSatisfied: [core.bool, []],
markInputs: [dart.void, [core.int]],
output: [Variable, []],
recalculate: [dart.void, []],
markUnsatisfied: [dart.void, []],
inputsKnown: [core.bool, [core.int]],
removeFromGraph: [dart.void, []]
})
});
class StayConstraint extends UnaryConstraint {
StayConstraint(v, str) {
super.UnaryConstraint(v, str);
}
execute() {}
}
dart.setSignature(StayConstraint, {
constructors: () => ({StayConstraint: [StayConstraint, [Variable, Strength]]}),
methods: () => ({execute: [dart.void, []]})
});
class EditConstraint extends UnaryConstraint {
EditConstraint(v, str) {
super.UnaryConstraint(v, str);
}
isInput() {
return true;
}
execute() {}
}
dart.setSignature(EditConstraint, {
constructors: () => ({EditConstraint: [EditConstraint, [Variable, Strength]]}),
methods: () => ({execute: [dart.void, []]})
});
const NONE = 1;
const FORWARD = 2;
const BACKWARD = 0;
class BinaryConstraint extends Constraint {
BinaryConstraint(v1, v2, strength) {
this.v1 = v1;
this.v2 = v2;
this.direction = NONE;
super.Constraint(strength);
this.addConstraint();
}
chooseMethod(mark) {
if (this.v1.mark == mark) {
this.direction = this.v2.mark != mark && dart.notNull(Strength.stronger(this.strength, this.v2.walkStrength)) ? FORWARD : NONE;
}
if (this.v2.mark == mark) {
this.direction = this.v1.mark != mark && dart.notNull(Strength.stronger(this.strength, this.v1.walkStrength)) ? BACKWARD : NONE;
}
if (dart.notNull(Strength.weaker(this.v1.walkStrength, this.v2.walkStrength))) {
this.direction = dart.notNull(Strength.stronger(this.strength, this.v1.walkStrength)) ? BACKWARD : NONE;
} else {
this.direction = dart.notNull(Strength.stronger(this.strength, this.v2.walkStrength)) ? FORWARD : BACKWARD;
}
}
addToGraph() {
this.v1.addConstraint(this);
this.v2.addConstraint(this);
this.direction = NONE;
}
isSatisfied() {
return this.direction != NONE;
}
markInputs(mark) {
this.input().mark = mark;
}
input() {
return this.direction == FORWARD ? this.v1 : this.v2;
}
output() {
return this.direction == FORWARD ? this.v2 : this.v1;
}
recalculate() {
let ihn = this.input(), out = this.output();
out.walkStrength = Strength.weakest(this.strength, ihn.walkStrength);
out.stay = ihn.stay;
if (dart.notNull(out.stay)) this.execute();
}
markUnsatisfied() {
this.direction = NONE;
}
inputsKnown(mark) {
let i = this.input();
return i.mark == mark || dart.notNull(i.stay) || i.determinedBy == null;
}
removeFromGraph() {
if (this.v1 != null) this.v1.removeConstraint(this);
if (this.v2 != null) this.v2.removeConstraint(this);
this.direction = NONE;
}
}
dart.setSignature(BinaryConstraint, {
constructors: () => ({BinaryConstraint: [BinaryConstraint, [Variable, Variable, Strength]]}),
methods: () => ({
chooseMethod: [dart.void, [core.int]],
addToGraph: [dart.void, []],
isSatisfied: [core.bool, []],
markInputs: [dart.void, [core.int]],
input: [Variable, []],
output: [Variable, []],
recalculate: [dart.void, []],
markUnsatisfied: [dart.void, []],
inputsKnown: [core.bool, [core.int]],
removeFromGraph: [dart.void, []]
})
});
class ScaleConstraint extends BinaryConstraint {
ScaleConstraint(src, scale, offset, dest, strength) {
this.scale = scale;
this.offset = offset;
super.BinaryConstraint(src, dest, strength);
}
addToGraph() {
super.addToGraph();
this.scale.addConstraint(this);
this.offset.addConstraint(this);
}
removeFromGraph() {
super.removeFromGraph();
if (this.scale != null) this.scale.removeConstraint(this);
if (this.offset != null) this.offset.removeConstraint(this);
}
markInputs(mark) {
super.markInputs(mark);
this.scale.mark = this.offset.mark = mark;
}
execute() {
if (this.direction == FORWARD) {
this.v2.value = dart.notNull(this.v1.value) * dart.notNull(this.scale.value) + dart.notNull(this.offset.value);
} else {
this.v1.value = ((dart.notNull(this.v2.value) - dart.notNull(this.offset.value)) / dart.notNull(this.scale.value))[dartx.truncate]();
}
}
recalculate() {
let ihn = this.input(), out = this.output();
out.walkStrength = Strength.weakest(this.strength, ihn.walkStrength);
out.stay = dart.notNull(ihn.stay) && dart.notNull(this.scale.stay) && dart.notNull(this.offset.stay);
if (dart.notNull(out.stay)) this.execute();
}
}
dart.setSignature(ScaleConstraint, {
constructors: () => ({ScaleConstraint: [ScaleConstraint, [Variable, Variable, Variable, Variable, Strength]]}),
methods: () => ({execute: [dart.void, []]})
});
class EqualityConstraint extends BinaryConstraint {
EqualityConstraint(v1, v2, strength) {
super.BinaryConstraint(v1, v2, strength);
}
execute() {
this.output().value = this.input().value;
}
}
dart.setSignature(EqualityConstraint, {
constructors: () => ({EqualityConstraint: [EqualityConstraint, [Variable, Variable, Strength]]}),
methods: () => ({execute: [dart.void, []]})
});
class Variable extends core.Object {
Variable(name, value) {
this.constraints = dart.list([], Constraint);
this.name = name;
this.value = value;
this.determinedBy = null;
this.mark = 0;
this.walkStrength = WEAKEST;
this.stay = true;
}
addConstraint(c) {
this.constraints[dartx.add](c);
}
removeConstraint(c) {
this.constraints[dartx.remove](c);
if (dart.equals(this.determinedBy, c)) this.determinedBy = null;
}
}
dart.setSignature(Variable, {
constructors: () => ({Variable: [Variable, [core.String, core.int]]}),
methods: () => ({
addConstraint: [dart.void, [Constraint]],
removeConstraint: [dart.void, [Constraint]]
})
});
class Planner extends core.Object {
Planner() {
this.currentMark = 0;
}
incrementalAdd(c) {
let mark = this.newMark();
for (let overridden = c.satisfy(mark); overridden != null; overridden = overridden.satisfy(mark))
;
}
incrementalRemove(c) {
let out = c.output();
c.markUnsatisfied();
c.removeFromGraph();
let unsatisfied = this.removePropagateFrom(out);
let strength = REQUIRED;
do {
for (let i = 0; i < dart.notNull(unsatisfied[dartx.length]); i++) {
let u = unsatisfied[dartx.get](i);
if (dart.equals(u.strength, strength)) this.incrementalAdd(u);
}
strength = strength.nextWeaker();
} while (!dart.equals(strength, WEAKEST));
}
newMark() {
return this.currentMark = dart.notNull(this.currentMark) + 1;
}
makePlan(sources) {
let mark = this.newMark();
let plan = new Plan();
let todo = sources;
while (dart.notNull(todo[dartx.length]) > 0) {
let c = todo[dartx.removeLast]();
if (c.output().mark != mark && dart.notNull(c.inputsKnown(mark))) {
plan.addConstraint(c);
c.output().mark = mark;
this.addConstraintsConsumingTo(c.output(), todo);
}
}
return plan;
}
extractPlanFromConstraints(constraints) {
let sources = dart.list([], Constraint);
for (let i = 0; i < dart.notNull(constraints[dartx.length]); i++) {
let c = constraints[dartx.get](i);
if (dart.notNull(c.isInput()) && dart.notNull(c.isSatisfied())) sources[dartx.add](c);
}
return this.makePlan(sources);
}
addPropagate(c, mark) {
let todo = dart.list([c], Constraint);
while (dart.notNull(todo[dartx.length]) > 0) {
let d = todo[dartx.removeLast]();
if (d.output().mark == mark) {
this.incrementalRemove(c);
return false;
}
d.recalculate();
this.addConstraintsConsumingTo(d.output(), todo);
}
return true;
}
removePropagateFrom(out) {
out.determinedBy = null;
out.walkStrength = WEAKEST;
out.stay = true;
let unsatisfied = dart.list([], Constraint);
let todo = dart.list([out], Variable);
while (dart.notNull(todo[dartx.length]) > 0) {
let v = todo[dartx.removeLast]();
for (let i = 0; i < dart.notNull(v.constraints[dartx.length]); i++) {
let c = v.constraints[dartx.get](i);
if (!dart.notNull(c.isSatisfied())) unsatisfied[dartx.add](c);
}
let determining = v.determinedBy;
for (let i = 0; i < dart.notNull(v.constraints[dartx.length]); i++) {
let next = v.constraints[dartx.get](i);
if (!dart.equals(next, determining) && dart.notNull(next.isSatisfied())) {
next.recalculate();
todo[dartx.add](next.output());
}
}
}
return unsatisfied;
}
addConstraintsConsumingTo(v, coll) {
let determining = v.determinedBy;
for (let i = 0; i < dart.notNull(v.constraints[dartx.length]); i++) {
let c = v.constraints[dartx.get](i);
if (!dart.equals(c, determining) && dart.notNull(c.isSatisfied())) coll[dartx.add](c);
}
}
}
dart.setSignature(Planner, {
methods: () => ({
incrementalAdd: [dart.void, [Constraint]],
incrementalRemove: [dart.void, [Constraint]],
newMark: [core.int, []],
makePlan: [Plan, [core.List$(Constraint)]],
extractPlanFromConstraints: [Plan, [core.List$(Constraint)]],
addPropagate: [core.bool, [Constraint, core.int]],
removePropagateFrom: [core.List$(Constraint), [Variable]],
addConstraintsConsumingTo: [dart.void, [Variable, core.List$(Constraint)]]
})
});
class Plan extends core.Object {
Plan() {
this.list = dart.list([], Constraint);
}
addConstraint(c) {
this.list[dartx.add](c);
}
size() {
return this.list[dartx.length];
}
execute() {
for (let i = 0; i < dart.notNull(this.list[dartx.length]); i++) {
this.list[dartx.get](i).execute();
}
}
}
dart.setSignature(Plan, {
methods: () => ({
addConstraint: [dart.void, [Constraint]],
size: [core.int, []],
execute: [dart.void, []]
})
});
function chainTest(n) {
exports.planner = new Planner();
let prev = null, first = null, last = null;
for (let i = 0; i <= dart.notNull(n); i++) {
let v = new Variable("v", 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);
let edit = new EditConstraint(first, PREFERRED);
let plan = exports.planner.extractPlanFromConstraints(dart.list([edit], Constraint));
for (let i = 0; i < 100; i++) {
first.value = i;
plan.execute();
if (last.value != i) {
core.print("Chain test failed:");
core.print(`Expected last value to be ${i} but it was ${last.value}.`);
}
}
}
dart.fn(chainTest, dart.void, [core.int]);
function projectionTest(n) {
exports.planner = new Planner();
let scale = new Variable("scale", 10);
let offset = new Variable("offset", 1000);
let src = null, dst = null;
let dests = dart.list([], Variable);
for (let i = 0; i < dart.notNull(n); i++) {
src = new Variable("src", i);
dst = new Variable("dst", i);
dests[dartx.add](dst);
new StayConstraint(src, NORMAL);
new ScaleConstraint(src, scale, offset, dst, REQUIRED);
}
change(src, 17);
if (dst.value != 1170) core.print("Projection 1 failed");
change(dst, 1050);
if (src.value != 5) core.print("Projection 2 failed");
change(scale, 5);
for (let i = 0; i < dart.notNull(n) - 1; i++) {
if (dests[dartx.get](i).value != i * 5 + 1000) core.print("Projection 3 failed");
}
change(offset, 2000);
for (let i = 0; i < dart.notNull(n) - 1; i++) {
if (dests[dartx.get](i).value != i * 5 + 2000) core.print("Projection 4 failed");
}
}
dart.fn(projectionTest, dart.void, [core.int]);
function change(v, newValue) {
let edit = new EditConstraint(v, PREFERRED);
let plan = exports.planner.extractPlanFromConstraints(dart.list([edit], EditConstraint));
for (let i = 0; i < 10; i++) {
v.value = newValue;
plan.execute();
}
edit.destroyConstraint();
}
dart.fn(change, dart.void, [Variable, core.int]);
exports.planner = null;
// Exports:
exports.main = main;
exports.DeltaBlue = DeltaBlue;
exports.Strength = Strength;
exports.REQUIRED = REQUIRED;
exports.STRONG_PREFERRED = STRONG_PREFERRED;
exports.PREFERRED = PREFERRED;
exports.STRONG_DEFAULT = STRONG_DEFAULT;
exports.NORMAL = NORMAL;
exports.WEAK_DEFAULT = WEAK_DEFAULT;
exports.WEAKEST = WEAKEST;
exports.Constraint = Constraint;
exports.UnaryConstraint = UnaryConstraint;
exports.StayConstraint = StayConstraint;
exports.EditConstraint = EditConstraint;
exports.NONE = NONE;
exports.FORWARD = FORWARD;
exports.BACKWARD = BACKWARD;
exports.BinaryConstraint = BinaryConstraint;
exports.ScaleConstraint = ScaleConstraint;
exports.EqualityConstraint = EqualityConstraint;
exports.Variable = Variable;
exports.Planner = Planner;
exports.Plan = Plan;
exports.chainTest = chainTest;
exports.projectionTest = projectionTest;
exports.change = change;
});