| OLD | NEW |
| (Empty) |
| 1 var DeltaBlue; | |
| 2 (function(DeltaBlue) { | |
| 3 'use strict'; | |
| 4 // Function main: () → dynamic | |
| 5 function main() { | |
| 6 new DeltaBlue().report(); | |
| 7 } | |
| 8 class DeltaBlue extends BenchmarkBase.BenchmarkBase { | |
| 9 DeltaBlue() { | |
| 10 super.BenchmarkBase("DeltaBlue"); | |
| 11 } | |
| 12 run() { | |
| 13 chainTest(100); | |
| 14 projectionTest(100); | |
| 15 } | |
| 16 } | |
| 17 class Strength extends dart.Object { | |
| 18 Strength(value, name) { | |
| 19 this.value = value; | |
| 20 this.name = name; | |
| 21 } | |
| 22 nextWeaker() { | |
| 23 return /* Unimplemented const */new List.from([STRONG_PREFERRED, PREFERRED
, STRONG_DEFAULT, NORMAL, WEAK_DEFAULT, WEAKEST]).get(this.value); | |
| 24 } | |
| 25 static stronger(s1, s2) { | |
| 26 return s1.value < s2.value; | |
| 27 } | |
| 28 static weaker(s1, s2) { | |
| 29 return s1.value > s2.value; | |
| 30 } | |
| 31 static weakest(s1, s2) { | |
| 32 return weaker(s1, s2) ? s1 : s2; | |
| 33 } | |
| 34 static strongest(s1, s2) { | |
| 35 return stronger(s1, s2) ? s1 : s2; | |
| 36 } | |
| 37 } | |
| 38 let REQUIRED = new Strength(0, "required"); | |
| 39 let STRONG_PREFERRED = new Strength(1, "strongPreferred"); | |
| 40 let PREFERRED = new Strength(2, "preferred"); | |
| 41 let STRONG_DEFAULT = new Strength(3, "strongDefault"); | |
| 42 let NORMAL = new Strength(4, "normal"); | |
| 43 let WEAK_DEFAULT = new Strength(5, "weakDefault"); | |
| 44 let WEAKEST = new Strength(6, "weakest"); | |
| 45 class Constraint extends dart.Object { | |
| 46 Constraint(strength) { | |
| 47 this.strength = strength; | |
| 48 } | |
| 49 addConstraint() { | |
| 50 this.addToGraph(); | |
| 51 DeltaBlue.planner.incrementalAdd(this); | |
| 52 } | |
| 53 satisfy(mark) { | |
| 54 this.chooseMethod(dart.as(mark, core.int)); | |
| 55 if (!dart.notNull(this.isSatisfied())) { | |
| 56 if (dart.equals(this.strength, REQUIRED)) { | |
| 57 core.print("Could not satisfy a required constraint!"); | |
| 58 } | |
| 59 return null; | |
| 60 } | |
| 61 this.markInputs(dart.as(mark, core.int)); | |
| 62 let out = this.output(); | |
| 63 let overridden = out.determinedBy; | |
| 64 if (overridden !== null) | |
| 65 overridden.markUnsatisfied(); | |
| 66 out.determinedBy = this; | |
| 67 if (!dart.notNull(DeltaBlue.planner.addPropagate(this, dart.as(mark, core.
int)))) | |
| 68 core.print("Cycle encountered"); | |
| 69 out.mark = dart.as(mark, core.int); | |
| 70 return overridden; | |
| 71 } | |
| 72 destroyConstraint() { | |
| 73 if (this.isSatisfied()) | |
| 74 DeltaBlue.planner.incrementalRemove(this); | |
| 75 this.removeFromGraph(); | |
| 76 } | |
| 77 isInput() { | |
| 78 return false; | |
| 79 } | |
| 80 } | |
| 81 class UnaryConstraint extends Constraint { | |
| 82 UnaryConstraint(myOutput, strength) { | |
| 83 this.myOutput = myOutput; | |
| 84 this.satisfied = false; | |
| 85 super.Constraint(strength); | |
| 86 this.addConstraint(); | |
| 87 } | |
| 88 addToGraph() { | |
| 89 this.myOutput.addConstraint(this); | |
| 90 this.satisfied = false; | |
| 91 } | |
| 92 chooseMethod(mark) { | |
| 93 this.satisfied = dart.notNull(this.myOutput.mark !== mark) && dart.notNull
(Strength.stronger(this.strength, this.myOutput.walkStrength)); | |
| 94 } | |
| 95 isSatisfied() { | |
| 96 return this.satisfied; | |
| 97 } | |
| 98 markInputs(mark) {} | |
| 99 output() { | |
| 100 return this.myOutput; | |
| 101 } | |
| 102 recalculate() { | |
| 103 this.myOutput.walkStrength = this.strength; | |
| 104 this.myOutput.stay = !dart.notNull(this.isInput()); | |
| 105 if (this.myOutput.stay) | |
| 106 this.execute(); | |
| 107 } | |
| 108 markUnsatisfied() { | |
| 109 this.satisfied = false; | |
| 110 } | |
| 111 inputsKnown(mark) { | |
| 112 return true; | |
| 113 } | |
| 114 removeFromGraph() { | |
| 115 if (this.myOutput !== null) | |
| 116 this.myOutput.removeConstraint(this); | |
| 117 this.satisfied = false; | |
| 118 } | |
| 119 } | |
| 120 class StayConstraint extends UnaryConstraint { | |
| 121 StayConstraint(v, str) { | |
| 122 super.UnaryConstraint(v, str); | |
| 123 } | |
| 124 execute() {} | |
| 125 } | |
| 126 class EditConstraint extends UnaryConstraint { | |
| 127 EditConstraint(v, str) { | |
| 128 super.UnaryConstraint(v, str); | |
| 129 } | |
| 130 isInput() { | |
| 131 return true; | |
| 132 } | |
| 133 execute() {} | |
| 134 } | |
| 135 let NONE = 1; | |
| 136 let FORWARD = 2; | |
| 137 let BACKWARD = 0; | |
| 138 class BinaryConstraint extends Constraint { | |
| 139 BinaryConstraint(v1, v2, strength) { | |
| 140 this.v1 = v1; | |
| 141 this.v2 = v2; | |
| 142 this.direction = NONE; | |
| 143 super.Constraint(strength); | |
| 144 this.addConstraint(); | |
| 145 } | |
| 146 chooseMethod(mark) { | |
| 147 if (this.v1.mark === mark) { | |
| 148 this.direction = dart.notNull(this.v2.mark !== mark) && dart.notNull(Str
ength.stronger(this.strength, this.v2.walkStrength)) ? FORWARD : NONE; | |
| 149 } | |
| 150 if (this.v2.mark === mark) { | |
| 151 this.direction = dart.notNull(this.v1.mark !== mark) && dart.notNull(Str
ength.stronger(this.strength, this.v1.walkStrength)) ? BACKWARD : NONE; | |
| 152 } | |
| 153 if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) { | |
| 154 this.direction = Strength.stronger(this.strength, this.v1.walkStrength)
? BACKWARD : NONE; | |
| 155 } else { | |
| 156 this.direction = Strength.stronger(this.strength, this.v2.walkStrength)
? FORWARD : BACKWARD; | |
| 157 } | |
| 158 } | |
| 159 addToGraph() { | |
| 160 this.v1.addConstraint(this); | |
| 161 this.v2.addConstraint(this); | |
| 162 this.direction = NONE; | |
| 163 } | |
| 164 isSatisfied() { | |
| 165 return this.direction !== NONE; | |
| 166 } | |
| 167 markInputs(mark) { | |
| 168 this.input().mark = mark; | |
| 169 } | |
| 170 input() { | |
| 171 return this.direction === FORWARD ? this.v1 : this.v2; | |
| 172 } | |
| 173 output() { | |
| 174 return this.direction === FORWARD ? this.v2 : this.v1; | |
| 175 } | |
| 176 recalculate() { | |
| 177 let ihn = this.input(), out = this.output(); | |
| 178 out.walkStrength = Strength.weakest(this.strength, ihn.walkStrength); | |
| 179 out.stay = ihn.stay; | |
| 180 if (out.stay) | |
| 181 this.execute(); | |
| 182 } | |
| 183 markUnsatisfied() { | |
| 184 this.direction = NONE; | |
| 185 } | |
| 186 inputsKnown(mark) { | |
| 187 let i = this.input(); | |
| 188 return dart.notNull(dart.notNull(i.mark === mark) || dart.notNull(i.stay))
|| dart.notNull(i.determinedBy === null); | |
| 189 } | |
| 190 removeFromGraph() { | |
| 191 if (this.v1 !== null) | |
| 192 this.v1.removeConstraint(this); | |
| 193 if (this.v2 !== null) | |
| 194 this.v2.removeConstraint(this); | |
| 195 this.direction = NONE; | |
| 196 } | |
| 197 } | |
| 198 class ScaleConstraint extends BinaryConstraint { | |
| 199 ScaleConstraint(src, scale, offset, dest, strength) { | |
| 200 this.scale = scale; | |
| 201 this.offset = offset; | |
| 202 super.BinaryConstraint(src, dest, strength); | |
| 203 } | |
| 204 addToGraph() { | |
| 205 super.addToGraph(); | |
| 206 this.scale.addConstraint(this); | |
| 207 this.offset.addConstraint(this); | |
| 208 } | |
| 209 removeFromGraph() { | |
| 210 super.removeFromGraph(); | |
| 211 if (this.scale !== null) | |
| 212 this.scale.removeConstraint(this); | |
| 213 if (this.offset !== null) | |
| 214 this.offset.removeConstraint(this); | |
| 215 } | |
| 216 markInputs(mark) { | |
| 217 super.markInputs(mark); | |
| 218 this.scale.mark = this.offset.mark = mark; | |
| 219 } | |
| 220 execute() { | |
| 221 if (this.direction === FORWARD) { | |
| 222 this.v2.value = this.v1.value * this.scale.value + this.offset.value; | |
| 223 } else { | |
| 224 this.v1.value = ((this.v2.value - this.offset.value) / this.scale.value)
.truncate(); | |
| 225 } | |
| 226 } | |
| 227 recalculate() { | |
| 228 let ihn = this.input(), out = this.output(); | |
| 229 out.walkStrength = Strength.weakest(this.strength, ihn.walkStrength); | |
| 230 out.stay = dart.notNull(dart.notNull(ihn.stay) && dart.notNull(this.scale.
stay)) && dart.notNull(this.offset.stay); | |
| 231 if (out.stay) | |
| 232 this.execute(); | |
| 233 } | |
| 234 } | |
| 235 class EqualityConstraint extends BinaryConstraint { | |
| 236 EqualityConstraint(v1, v2, strength) { | |
| 237 super.BinaryConstraint(v1, v2, strength); | |
| 238 } | |
| 239 execute() { | |
| 240 this.output().value = this.input().value; | |
| 241 } | |
| 242 } | |
| 243 class Variable extends dart.Object { | |
| 244 Variable(name, value) { | |
| 245 this.constraints = new List.from([]); | |
| 246 this.name = name; | |
| 247 this.value = value; | |
| 248 this.determinedBy = null; | |
| 249 this.mark = 0; | |
| 250 this.walkStrength = WEAKEST; | |
| 251 this.stay = true; | |
| 252 } | |
| 253 addConstraint(c) { | |
| 254 this.constraints.add(c); | |
| 255 } | |
| 256 removeConstraint(c) { | |
| 257 this.constraints.remove(c); | |
| 258 if (dart.equals(this.determinedBy, c)) | |
| 259 this.determinedBy = null; | |
| 260 } | |
| 261 } | |
| 262 class Planner extends dart.Object { | |
| 263 Planner() { | |
| 264 this.currentMark = 0; | |
| 265 } | |
| 266 incrementalAdd(c) { | |
| 267 let mark = this.newMark(); | |
| 268 for (let overridden = c.satisfy(mark); overridden !== null; overridden = o
verridden.satisfy(mark)) | |
| 269 ; | |
| 270 } | |
| 271 incrementalRemove(c) { | |
| 272 let out = c.output(); | |
| 273 c.markUnsatisfied(); | |
| 274 c.removeFromGraph(); | |
| 275 let unsatisfied = this.removePropagateFrom(out); | |
| 276 let strength = REQUIRED; | |
| 277 do { | |
| 278 for (let i = 0; i < unsatisfied.length; i++) { | |
| 279 let u = unsatisfied.get(i); | |
| 280 if (dart.equals(u.strength, strength)) | |
| 281 this.incrementalAdd(u); | |
| 282 } | |
| 283 strength = strength.nextWeaker(); | |
| 284 } while (!dart.equals(strength, WEAKEST)); | |
| 285 } | |
| 286 newMark() { | |
| 287 return ++this.currentMark; | |
| 288 } | |
| 289 makePlan(sources) { | |
| 290 let mark = this.newMark(); | |
| 291 let plan = new Plan(); | |
| 292 let todo = sources; | |
| 293 while (todo.length > 0) { | |
| 294 let c = todo.removeLast(); | |
| 295 if (dart.notNull(c.output().mark !== mark) && dart.notNull(c.inputsKnown
(mark))) { | |
| 296 plan.addConstraint(c); | |
| 297 c.output().mark = mark; | |
| 298 this.addConstraintsConsumingTo(c.output(), todo); | |
| 299 } | |
| 300 } | |
| 301 return plan; | |
| 302 } | |
| 303 extractPlanFromConstraints(constraints) { | |
| 304 let sources = new List.from([]); | |
| 305 for (let i = 0; i < constraints.length; i++) { | |
| 306 let c = constraints.get(i); | |
| 307 if (dart.notNull(c.isInput()) && dart.notNull(c.isSatisfied())) | |
| 308 sources.add(c); | |
| 309 } | |
| 310 return this.makePlan(sources); | |
| 311 } | |
| 312 addPropagate(c, mark) { | |
| 313 let todo = new List.from([c]); | |
| 314 while (todo.length > 0) { | |
| 315 let d = todo.removeLast(); | |
| 316 if (d.output().mark === mark) { | |
| 317 this.incrementalRemove(c); | |
| 318 return false; | |
| 319 } | |
| 320 d.recalculate(); | |
| 321 this.addConstraintsConsumingTo(d.output(), todo); | |
| 322 } | |
| 323 return true; | |
| 324 } | |
| 325 removePropagateFrom(out) { | |
| 326 out.determinedBy = null; | |
| 327 out.walkStrength = WEAKEST; | |
| 328 out.stay = true; | |
| 329 let unsatisfied = new List.from([]); | |
| 330 let todo = new List.from([out]); | |
| 331 while (todo.length > 0) { | |
| 332 let v = todo.removeLast(); | |
| 333 for (let i = 0; i < v.constraints.length; i++) { | |
| 334 let c = v.constraints.get(i); | |
| 335 if (!dart.notNull(c.isSatisfied())) | |
| 336 unsatisfied.add(c); | |
| 337 } | |
| 338 let determining = v.determinedBy; | |
| 339 for (let i = 0; i < v.constraints.length; i++) { | |
| 340 let next = v.constraints.get(i); | |
| 341 if (dart.notNull(!dart.equals(next, determining)) && dart.notNull(next
.isSatisfied())) { | |
| 342 next.recalculate(); | |
| 343 todo.add(next.output()); | |
| 344 } | |
| 345 } | |
| 346 } | |
| 347 return unsatisfied; | |
| 348 } | |
| 349 addConstraintsConsumingTo(v, coll) { | |
| 350 let determining = v.determinedBy; | |
| 351 for (let i = 0; i < v.constraints.length; i++) { | |
| 352 let c = v.constraints.get(i); | |
| 353 if (dart.notNull(!dart.equals(c, determining)) && dart.notNull(c.isSatis
fied())) | |
| 354 coll.add(c); | |
| 355 } | |
| 356 } | |
| 357 } | |
| 358 class Plan extends dart.Object { | |
| 359 Plan() { | |
| 360 this.list = new List.from([]); | |
| 361 } | |
| 362 addConstraint(c) { | |
| 363 this.list.add(c); | |
| 364 } | |
| 365 size() { | |
| 366 return this.list.length; | |
| 367 } | |
| 368 execute() { | |
| 369 for (let i = 0; i < this.list.length; i++) { | |
| 370 this.list.get(i).execute(); | |
| 371 } | |
| 372 } | |
| 373 } | |
| 374 // Function chainTest: (int) → void | |
| 375 function chainTest(n) { | |
| 376 DeltaBlue.planner = new Planner(); | |
| 377 let prev = null, first = null, last = null; | |
| 378 for (let i = 0; i <= n; i++) { | |
| 379 let v = new Variable("v", 0); | |
| 380 if (prev !== null) | |
| 381 new EqualityConstraint(prev, v, REQUIRED); | |
| 382 if (i === 0) | |
| 383 first = v; | |
| 384 if (i === n) | |
| 385 last = v; | |
| 386 prev = v; | |
| 387 } | |
| 388 new StayConstraint(last, STRONG_DEFAULT); | |
| 389 let edit = new EditConstraint(first, PREFERRED); | |
| 390 let plan = DeltaBlue.planner.extractPlanFromConstraints(new List.from([edit]
)); | |
| 391 for (let i = 0; i < 100; i++) { | |
| 392 first.value = i; | |
| 393 plan.execute(); | |
| 394 if (last.value !== i) { | |
| 395 core.print("Chain test failed:"); | |
| 396 core.print(`Expected last value to be ${i} but it was ${last.value}.`); | |
| 397 } | |
| 398 } | |
| 399 } | |
| 400 // Function projectionTest: (int) → void | |
| 401 function projectionTest(n) { | |
| 402 DeltaBlue.planner = new Planner(); | |
| 403 let scale = new Variable("scale", 10); | |
| 404 let offset = new Variable("offset", 1000); | |
| 405 let src = null, dst = null; | |
| 406 let dests = new List.from([]); | |
| 407 for (let i = 0; i < n; i++) { | |
| 408 src = new Variable("src", i); | |
| 409 dst = new Variable("dst", i); | |
| 410 dests.add(dst); | |
| 411 new StayConstraint(src, NORMAL); | |
| 412 new ScaleConstraint(src, scale, offset, dst, REQUIRED); | |
| 413 } | |
| 414 change(src, 17); | |
| 415 if (dst.value !== 1170) | |
| 416 core.print("Projection 1 failed"); | |
| 417 change(dst, 1050); | |
| 418 if (src.value !== 5) | |
| 419 core.print("Projection 2 failed"); | |
| 420 change(scale, 5); | |
| 421 for (let i = 0; i < n - 1; i++) { | |
| 422 if (dests.get(i).value !== i * 5 + 1000) | |
| 423 core.print("Projection 3 failed"); | |
| 424 } | |
| 425 change(offset, 2000); | |
| 426 for (let i = 0; i < n - 1; i++) { | |
| 427 if (dests.get(i).value !== i * 5 + 2000) | |
| 428 core.print("Projection 4 failed"); | |
| 429 } | |
| 430 } | |
| 431 // Function change: (Variable, int) → void | |
| 432 function change(v, newValue) { | |
| 433 let edit = new EditConstraint(v, PREFERRED); | |
| 434 let plan = DeltaBlue.planner.extractPlanFromConstraints(new List.from([edit]
)); | |
| 435 for (let i = 0; i < 10; i++) { | |
| 436 v.value = newValue; | |
| 437 plan.execute(); | |
| 438 } | |
| 439 edit.destroyConstraint(); | |
| 440 } | |
| 441 DeltaBlue.planner = null; | |
| 442 // Exports: | |
| 443 DeltaBlue.main = main; | |
| 444 DeltaBlue.DeltaBlue = DeltaBlue; | |
| 445 DeltaBlue.Strength = Strength; | |
| 446 DeltaBlue.REQUIRED = REQUIRED; | |
| 447 DeltaBlue.STRONG_PREFERRED = STRONG_PREFERRED; | |
| 448 DeltaBlue.PREFERRED = PREFERRED; | |
| 449 DeltaBlue.STRONG_DEFAULT = STRONG_DEFAULT; | |
| 450 DeltaBlue.NORMAL = NORMAL; | |
| 451 DeltaBlue.WEAK_DEFAULT = WEAK_DEFAULT; | |
| 452 DeltaBlue.WEAKEST = WEAKEST; | |
| 453 DeltaBlue.Constraint = Constraint; | |
| 454 DeltaBlue.UnaryConstraint = UnaryConstraint; | |
| 455 DeltaBlue.StayConstraint = StayConstraint; | |
| 456 DeltaBlue.EditConstraint = EditConstraint; | |
| 457 DeltaBlue.NONE = NONE; | |
| 458 DeltaBlue.FORWARD = FORWARD; | |
| 459 DeltaBlue.BACKWARD = BACKWARD; | |
| 460 DeltaBlue.BinaryConstraint = BinaryConstraint; | |
| 461 DeltaBlue.ScaleConstraint = ScaleConstraint; | |
| 462 DeltaBlue.EqualityConstraint = EqualityConstraint; | |
| 463 DeltaBlue.Variable = Variable; | |
| 464 DeltaBlue.Planner = Planner; | |
| 465 DeltaBlue.Plan = Plan; | |
| 466 DeltaBlue.chainTest = chainTest; | |
| 467 DeltaBlue.projectionTest = projectionTest; | |
| 468 DeltaBlue.change = change; | |
| 469 })(DeltaBlue || (DeltaBlue = {})); | |
| OLD | NEW |