]> hydra-www.ietfng.org Git - dyna2/commitdiff
`dict=` create something like associative list -- this lets us use it in our
authorTim Vieira <tim.f.vieira@gmail.com>
Fri, 5 Jul 2013 22:16:21 +0000 (18:16 -0400)
committerTim Vieira <tim.f.vieira@gmail.com>
Fri, 5 Jul 2013 22:16:21 +0000 (18:16 -0400)
dyna programs.

doctests strip colors

tweak to solution print out: print 'Solution empty' instead of a "Solution"
heading.

proper BC rule retraction.

src/Dyna/Backend/Python/aggregator.py
src/Dyna/Backend/Python/dyna-doctest.py
src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/repl.py
src/Dyna/Backend/Python/stdlib.py
test/misc/retract-bc.dynadoc

index d1cbe33166a74b4f29a87e58d4c6f438d4472f92..664a60da51335377f3160ec41f61ce1b6b48ce46 100644 (file)
@@ -100,10 +100,10 @@ class Equals(BAggregator):
 
 
 
-from collections import namedtuple
-class Result(namedtuple('Result', 'value variables')):
-    def __repr__(self):
-        return 'Result(value=%s, variables=%s)' % (_repr(self.value), drepr(dict(self.variables)))
+#from collections import namedtuple
+#class Result(namedtuple('Result', 'value variables')):
+#    def __repr__(self):
+#        return 'Result(value=%s, variables=%s)' % (_repr(self.value), drepr(dict(self.variables)))
 
 
 class DictEquals(BAggregator):
@@ -118,7 +118,8 @@ class DictEquals(BAggregator):
         self[val, vs] -= 1
 
     def fold(self):
-        return tuple(Result(v, b) for (v, b), cnt in self.iteritems() if cnt > 0)
+        from stdlib import todyna
+        return todyna([b + (('$val', v),) for (v, b), cnt in self.iteritems() if cnt > 0])
 
 
 class majority_equals(BAggregator):
index fcc3a6c23736c6c025aefa158230950bdc13ddb0..0d7a16fc29e847a81c62a9e3774c816b464871b2 100755 (executable)
@@ -23,17 +23,21 @@ def extract(code):
         yield '\n'.join(cmd).strip(), '\n'.join(expect).strip()
 
 
+def clean(x):
+    return re.sub('\033\[\d+m', '', strip_comments(x)).strip()
+
+
 def run(code):
     interp = Interpreter()
     repl = REPL(interp)
     errors = []
     for cmd, expect in extract(code):
-        if not strip_comments(cmd).strip():
+        if not clean(cmd):
             print
             continue
         print yellow % '> %s' % cmd
 
-        if strip_comments(cmd) == '*resume*':
+        if clean(cmd) == '*resume*':
             repl.cmdloop()
             continue
 
@@ -42,18 +46,21 @@ def run(code):
             repl.onecmd(cmd)
         finally:
             sys.stdout = sys.__stdout__
-        got = x.getvalue().strip()
-        expect = expect.strip()
 
-        if strip_comments(expect) == '*ignore*':
+        got = clean(x.getvalue())
+        expect = clean(got)
+
+        if clean(expect) == '*ignore*':
             continue
 
-        if strip_comments(expect) != strip_comments(got):
+        if expect != got:
             print green % expect
             print red % got
             errors.append([cmd, expect, got])
         else:
-            print x.getvalue().rstrip()
+            print
+            print got
+
         print
 
     if not errors:
index 98a54a4a653ac3dabdd7f9bde0f04b0aa211b80f..b70f666972ec87a4b73ed87d95c89980622e24d0 100644 (file)
@@ -123,9 +123,10 @@ from config import dotdynadir
 from errors import crash_handler, DynaInitializerException, AggregatorError, DynaCompilerError
 from stdlib import todyna
 
+
 class Rule(object):
-    def __init__(self, idx):
-        self.idx = idx
+    def __init__(self, index):
+        self.index = index
         self.init = None
         self.updaters = []
         self.query = None
@@ -136,7 +137,7 @@ class Rule(object):
     def src(self):
         return strip_comments(parse_attrs(self.init or self.query)['rule'])
     def __repr__(self):
-        return 'Rule(%s, %r)' % (self.idx, self.src)
+        return 'Rule(%s, %r)' % (self.index, self.src)
 
 
 # TODO: yuck, hopefully temporary measure to support pickling the Interpreter's
@@ -217,27 +218,36 @@ class Interpreter(object):
     def dump_charts(self, out=None):
         if out is None:
             out = sys.stdout
-        print >> out
-        print >> out, 'Solution'
-        print >> out, '========'
         fns = self.chart.keys()
         fns.sort()
         fns = [x for x in fns if x not in self._gbc]  # don't show backchained items
         nullary = [x for x in fns if x.endswith('/0')]
         others = [x for x in fns if not x.endswith('/0')]
+
         # show nullary charts first
-        for x in nullary:
-            y = str(self.chart[x])   # skip empty chart
-            if y:
-                print >> out, y
+        nullary = [str(self.chart[x]) for x in nullary]
+        charts = [str(self.chart[x]) for x in others if not x.startswith('$rule/')]
+
+        nullary = filter(None, nullary)
+        charts = filter(None, charts)
+
+        if nullary or charts:
+            print >> out
+            print >> out, 'Solution'
+            print >> out, '========'
+        else:
+            print >> out, 'Solution empty.'
+
         if nullary:
+            for line in nullary:
+                print >> out, line
             print >> out
-        for x in others:
-            if x.startswith('$rule/'):
-                continue
-            y = str(self.chart[x])   # skip empty chart
-            if y:
-                print >> out, y
+        else:
+            print >> out
+
+        for line in charts:
+            print >> out, line
+
         self.dump_errors(out)
 
     def dump_errors(self, out=None):
@@ -321,17 +331,9 @@ class Interpreter(object):
 
         return self.chart[fn].insert(args)
 
-#    def retract_item(self, item):
-#        """
-#        For the moment we only correctly retract leaves. If you retract a
-#        non-leaf item, you run the risk of it being rederived. In the case of
-#        cyclic programs the derivation might be the same or different.
-#        """
-#        self.emit(item, item.value, None, sys.maxint, delete=True)
-#        return self.go()
-
     def retract_rule(self, idx):
         "Retract rule and all of it's edges."
+
         try:
             rule = self.rules.pop(idx)
         except KeyError:
@@ -357,8 +359,13 @@ class Interpreter(object):
             self._gbc[rule.head_fn].remove(rule.query)
             # blast the memo entries for items it helped derive
             if rule.head_fn in self.chart:
-                for x in self.chart.pop(rule.head_fn).intern.itervalues():
-                    self.delete_emit(x, x.value, None, None)
+                for head in self.chart[rule.head_fn].intern.itervalues():
+
+                    def _emit(item, val, ruleix, variables):
+                        item.aggregator.dec(val, ruleix, variables)
+
+                    rule.query(*head.args, emit=_emit)
+                    self.agenda[head] = time()
 
         return self.go()
 
@@ -399,8 +406,7 @@ class Interpreter(object):
                 continue
 
             if hasattr(now, 'fn') and now.fn == 'with_key/2':
-                val, key = now.args
-                now = val
+                now, key = now.args
                 dkey = self.build('$key/1', item)
                 self.delete_emit(dkey, dkey.value, None, None)
                 self.emit(dkey, key, None, None, delete=False)
@@ -408,7 +414,6 @@ class Interpreter(object):
             if was == now:
                 continue
 
-
             was_error = False
             if item in error:    # clear error
                 was_error = True
@@ -492,31 +497,19 @@ class Interpreter(object):
         rule.query = handler
         handler.rule = rule
         rule.head_fn = fn
+        rule.index = ruleix
 
     def new_initializer(self, ruleix, init):
         rule = self.rules[ruleix]
         assert rule.init is None
         rule.init = init
         init.rule = rule
+        rule.index = ruleix
 
     def delete_emit(self, item, val, ruleix, variables):
         self.emit(item, val, ruleix, variables, delete=True)
 
     def emit(self, item, val, ruleix, variables, delete): #, aggregator_to_inherit=None):
-
-#        if item.fn == 'cons/2':
-#            assert isinstance(val, Term) \
-#                and val.fn == 'cons/2' \
-#                and len(val.aslist) == len(item.aslist)
-#            # recurse.
-#            for x, v in zip(item.aslist, val.aslist):
-#                self.emit(x, v, ruleix, variables, delete,
-#                          aggregator_to_inherit=self.rules[ruleix].anf.agg)
-#            return
-#        assert item.fn != 'cons/2' and item.fn != 'nil/0'
-#        if item.aggregator is None:
-#            self.new_fn(item.fn, aggregator_to_inherit)
-
         if delete:
             item.aggregator.dec(val, ruleix, variables)
         else:
index efe7b286696b61cf5a013834666dd2290a6fef74..d3a3e092ca756890a28cbb8879adc1761a4ee3a5 100644 (file)
@@ -11,6 +11,7 @@ to help.
 
 import os, cmd, readline
 from utils import dynac, ip, lexer, subst, drepr, _repr, get_module
+from stdlib import topython
 from errors import DynaCompilerError, DynaInitializerException
 from config import dotdynadir
 from errors import show_traceback
@@ -176,7 +177,9 @@ class REPL(cmd.Cmd, object):
 
             try:
                 [(_, _, results)] = self.interp.chart['$query/0'][:,]
-                return results
+
+                return [dict(r) for r in topython(results)]
+
             except ValueError:
                 return []
 
@@ -207,8 +210,9 @@ class REPL(cmd.Cmd, object):
         if len(results) == 0:
             print 'No results.'
             return
-        for val, bindings in sorted(results):
-            print _repr(val), 'where', drepr(dict(bindings))
+        results = [(b.pop('$val'), b) for b in results]
+        for val, b in sorted(results):
+            print _repr(val), 'where', drepr(b)
         print
 
     def do_query(self, q):
@@ -245,8 +249,8 @@ class REPL(cmd.Cmd, object):
             print 'No results.'
             return
         print
-        for term, result in sorted((subst(q, dict(result.variables)), result) for result in results):
-            print term, '=', _repr(result.value)
+        for term, result in sorted((subst(q, result), result) for result in results):
+            print term, '=', _repr(result['$val'])
         print
 
     def default(self, line, show_changed=True):
@@ -559,13 +563,17 @@ class REPL(cmd.Cmd, object):
 
             try:
                 [(_, _, results)] = self.interp.chart['$trace/0'][:,]
+
+                results = topython(results)
+                results = [dict(r)['$val'] for r in results]
+
             except ValueError:
                 print 'no items matching `%s`.' % q
                 return
 
             from post.trace import Tracer
             tracer = Tracer(self.interp)
-            for item, _ in results:
+            for item in results:
                 print
                 tracer(item)
 
index 336a5a5a5c19d1db82a2dfb5c1866ac0ecb74944..21c4a76de8aa9d9189cc0e630c5c8ea8718b82b3 100644 (file)
@@ -29,18 +29,22 @@ def pycall(name, *args):
 
 def topython(x):
     if isinstance(x, Cons) or x is Nil:
-        return x.aslist
+        return [topython(y) for y in x.aslist]
     return x
 
-
 def todynalist(x):    # TODO: get rid of this.
     return todyna(x)
 
 def todyna(x):
+
     if isinstance(x, (set, Counter)):
         x = list(x)
         x.sort()
         return todyna(x)
+
+    elif isinstance(x, dict):
+        return todyna(x.items())
+
     elif isinstance(x, (list, tuple)):
         c = Nil
         for y in reversed(x):
index a1053cabc7cbe330eacd69233f76fa5f0c827610..f6ba303fd597a1d224c69c8a00255731ca64dea7 100644 (file)
@@ -6,16 +6,23 @@
 | b := f(4).
 | c := f(5).
 
- *ignore*
-
-> sol
-
-Solution
-========
+Changes
+=======
 a = 3.
 b = 5.
 c = 8.
 
+> rules
+
+Rules
+=====
+  0: f(X) := f(X-1) + f(X-2) for X > 1.
+  1: f(1) := 1.
+  2: f(0) := 1.
+  3: a := f(3).
+  4: b := f(4).
+  5: c := f(5).
+
 > retract_rule 0
 
 Changes
@@ -23,3 +30,20 @@ Changes
 a = null.
 b = null.
 c = null.
+f(2) = null.
+f(3) = null.
+f(4) = null.
+f(5) = null.
+
+> sol
+
+Solution empty.
+
+> :- backchain g/2.
+| g(X,Y) dict= X*Y.
+| h(1,2). h(2,3).
+| f(X,Y) = h(X,Y), g(X,Y).
+
+> query g(1,2)
+> rules
+> retract_rule 6
\ No newline at end of file