From 4934848c225e3d8fb42bce2066f3d262c7558d67 Mon Sep 17 00:00:00 2001 From: Arthur Peters Date: Fri, 17 Feb 2017 13:02:00 -0600 Subject: [PATCH] Experiment with using an onIdle like combinator in my solver. This discovered a bug in the interpreter: issue #190. --- OrcExamples/objects/sudoku_solver.orc | 70 +++++++++++++++++-- .../test_data/functional_valid/onidle.orc | 24 +++++++ 2 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 OrcTests/test_data/functional_valid/onidle.orc diff --git a/OrcExamples/objects/sudoku_solver.orc b/OrcExamples/objects/sudoku_solver.orc index b66500750..20230c1b7 100644 --- a/OrcExamples/objects/sudoku_solver.orc +++ b/OrcExamples/objects/sudoku_solver.orc @@ -8,6 +8,17 @@ import class ConcurrentHashMap = "java.util.concurrent.ConcurrentHashMap" def Set() = ConcurrentHashMap.newKeySet() +-- Implement something similar to the onIdle combinator. +-- This is not the same since it does not prevent f from restarting while +-- g is running. +def onIdle[A](f :: lambda() :: A, g :: lambda() :: A) :: A = + {| + Vclock(IntegerTimeOrder) >> ( + Vawait(0) >> f() | + Vawait(1) >> g() + ) + |} + def seq(n) = def h(i) if (i <: n) = i : h(i+1) def h(_) = [] @@ -62,6 +73,9 @@ class Grid { acc + foldl(lambda(acc, x) = acc + get(x, y).toString() + ", ", "", seq(n)) + "\n", "", seq(n)) + "]" + + def shallowForce() = + upto(n) >x> upto(m) >y> get(x, y) >> stop ; signal } {- @@ -155,6 +169,17 @@ class SudokuCell { val number = value + 1 def toString() = number.toString() + + def remainingIfUnknown() = stop +} + +class UnknownSudokuCell extends SelectLastValue with SudokuCell { + val possibilities = collect(allNumbers) + + def force(x) = + Ift(remaining.contains(x)) >> valueCell.write(x) + + def remainingIfUnknown() = Ift(remaining.size() :> 1) >> iterableToList(remaining) } {- @@ -164,7 +189,7 @@ the class will go quiescent, so onIdle could be used to detect this case and app guessing or heuristics. -} -val solver = new Grid { +class SudokuSolver extends Grid { val n = N val m = N @@ -177,9 +202,7 @@ val solver = new Grid { else None() - def makeUnknown(myX, myY) = new (SelectLastValue with SudokuCell) { - val possibilities = collect(allNumbers) - + def makeUnknown(myX, myY) = new UnknownSudokuCell { val _ = {| ( allNumbers() >x> (x, myY) | @@ -203,9 +226,43 @@ val solver = new Grid { val v = getPuzzleCell(myX, myY) v >Some(n)> makeKnown(myX, myY, n) | v >None()> makeUnknown(myX, myY) -} + + def copy() = + val orig = this + val c = new Grid { + val n = N + val m = N + + def compute(x, y) = + onIdle({ + makeKnown(x, y, orig.get(x, y).value >x> x) + }, { + makeUnknown(x, y) + }) + } + c.shallowForce() >> + c +} + +-- This is initial work on handling the case where the simple propogation of values fails. +-- This is not completed. +def solve(solver :: lambda() :: SudokuSolver) = + val s = Cell() + onIdle({ s := solver() >> s?.toString() }, { + -- == Find a location with the smallest number of remaining possibilities + -- For now just pick an arbitrary location with multiple possibilities. + val (x, y, ps) = {| allNumbers() >x> allNumbers() >y> (x, y, s?.get(x, y).remainingIfUnknown()) |} + val _ = Println((x, y, ps)) + -- == Force that location to one value in each copy + --val s2 = s.copy() + --val s1 = s2.shallowForce() >> s + + -- == Recursively call this on the copies + -- == Publish the completed version + Error("Not Implemented") + }) -Println(solver.toString()) >> stop +Println(new SudokuSolver.toString()) >> stop {- OUTPUT: @@ -220,5 +277,4 @@ OUTPUT: 2, 4, 8, 9, 5, 7, 1, 3, 6, 7, 6, 3, 4, 1, 8, 2, 5, 9, ] -signal -} diff --git a/OrcTests/test_data/functional_valid/onidle.orc b/OrcTests/test_data/functional_valid/onidle.orc new file mode 100644 index 000000000..19d255bff --- /dev/null +++ b/OrcTests/test_data/functional_valid/onidle.orc @@ -0,0 +1,24 @@ +-- Run g if f becomes idle/quiescent but not halted. Kill the whole mess when either half publishes. +def ifIdle[A](f :: lambda() :: A, g :: lambda() :: A) :: A = + {| + Vclock(IntegerTimeOrder) >> ( + (Vawait(0) >> Some(f()) ; None() ) | + Vawait(1) >> Some(g()) + ) + |} >Some(x)> x + +val c = Channel() + +def test() = + --ifIdle({ c.get() }, { Println("get idle") }) | + --ifIdle({ stop }, { Println("FAIL: stop idle") }) | + ifIdle({ "Publish from left" }, { Println("FAIL: publication idle") }) | + stop + +def f(n) if (n :> 0) = + test() >x> Println(x) >> stop ; Println("============") >> f(n-1) + +f(1000) + +-- TODO: Once https://github.com/orc-lang/orc/issues/190 is fixed this should be made into a real regression test. +-- It's not a test at the moment because I really don't want to deal with a deadlock in the testing harness. \ No newline at end of file