]> hydra-www.ietfng.org Git - dyna2/commitdiff
trace available at repl supports viewing derivations each item matching query
authorTim Vieira <tim.f.vieira@gmail.com>
Sun, 30 Jun 2013 04:49:45 +0000 (00:49 -0400)
committerTim Vieira <tim.f.vieira@gmail.com>
Sun, 30 Jun 2013 04:49:45 +0000 (00:49 -0400)
    :- a :- b.
    :- b:- c.
    :- c.
    =============
    a := true
    b := true
    c := true
    :- trace a

    a = true
    |
    └─ :- true
       # a :- b.
       # a :- b. where {}
       head:   &a
       result: b=true
       |
       └─ b = true
          |
          └─ :- true
             # b:- c.
             # b:- c. where {}
             head:   &b
             result: c=true
             |
             └─ c = true
                |
                └─ |= true
                   # c.
                   # c. where {}
                   head:   &c
                   result: &true

src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/post/trace.py
src/Dyna/Backend/Python/repl.py
test/repl/equals-errors.doctest [new file with mode: 0644]

index ee04af91e151e233cb8843915e785b199affdc84..dace1f1aca07ee3cd13d9068f51b8742715f0e92 100644 (file)
@@ -260,7 +260,7 @@ class Interpreter(object):
                 assert c.agg_name is None
                 c.agg_name = agg
                 for item in c.intern.itervalues():
-                    assert c.aggregator is None
+                    assert item.aggregator is None
                     item.aggregator = c.new_aggregator()
 
         assert self.agg_name[fn] == agg, (fn, self.agg_name[fn], agg)
index fe7a590e0b13c444567e4c542e8e28417e868126..2bcdcfcb06ab992a580c1c12aee46914de43fbf8 100644 (file)
@@ -2,7 +2,8 @@
 """
 Examine solution as an outline of computation.
 
-TODO: backchained stuff
+TODO: shared substructure.
+
 """
 
 import re
@@ -24,15 +25,28 @@ class trace(object):
         self.interp = interp
 
     def main(self):
-        es = infer_edges(self.interp)
+        tracer = Tracer(self.interp)
+        for item in tracer.items:
+            print
+            print tracer(item)
+
+
+class Tracer(object):
 
+    def __init__(self, interp):
+        self.interp = interp
+        self.edges = infer_edges(self.interp)
         # group edges by head then ruleindex
-        groups = groupby(lambda x: x[0], es)
+        groups = groupby(lambda x: x[0], self.edges)
         for a in groups:
             groups[a] = groupby(lambda x: x[1], groups[a])
+        self.items = groups
 
-        for head in groups:
-            print '\n'.join(dig(head, set(), groups, self.interp))
+    def __call__(self, item):
+        if item not in self.items:
+            print
+            print 'no trace for', item
+        print '\n'.join(dig(item, set(), self.items, self.interp))
 
 
 def groupby(key, data):
@@ -42,7 +56,6 @@ def groupby(key, data):
     return dict(g)
 
 
-
 def dig(head, visited, groups, interp):
 
     if head in visited:
@@ -72,7 +85,6 @@ def dig(head, visited, groups, interp):
 
 
 def branch(xs):
-
     ys = []
     for i, x in enumerate(xs):
         first = i == 0
@@ -85,16 +97,12 @@ def branch(xs):
             h = '├─ '
         else:
             h = '├─ '
-
         if not x:
             continue
-
         ys.append(h + x[0])
-
         indent = '│  ' if not last else '   '
         for a in x[1:]:
             ys.append(indent + a)
-
     return ys
 
 
@@ -155,7 +163,7 @@ class Crux(object):
             if not g.incoming[x]:  # input variable
                 return self.values(x)
             if len(g.incoming[x]) > 1:
-                return 'UNIF ' + ' === '.join(self.get_function(e) + (red % '=%s' % self.values(e.head)) for e in g.incoming[x])
+                return 'UNIFICATION ' + ' === '.join(self.get_function(e) + (red % '=%s' % self.values(e.head)) for e in g.incoming[x])
             [e] = g.incoming[x]
 
             if e.label == '=':
index 0cd8c622690d86ae42a0e8437784a11af5622a9e..0083b62d3abb3706fe3b7ea8f650ae22af4fb261 100644 (file)
@@ -380,6 +380,37 @@ class REPL(cmd.Cmd, object):
             show_traceback()
             readline.write_history_file(self.hist)
 
+    def do_trace(self, q):
+
+        if q.endswith('.'):
+            print "Queries don't end with a dot."
+            return
+
+        self.interp.new_rules = set()
+
+        try:
+            query = "$trace dict= _ is %s, &(%s)." % (q,q)
+            self.default(query, show_changed=False)
+            try:
+                [(_, _, results)] = self.interp.chart['$trace/0'][:,]
+            except ValueError:
+                print 'no items matching `%s`.' % q
+                return
+
+            from post.trace import Tracer
+            tracer = Tracer(self.interp)
+            for item, _ in results:
+                print
+                tracer(item)
+
+        finally:
+            # cleanup:
+            # retract newly added rules.
+            for r in self.interp.new_rules:
+                self.interp.retract_rule(r)
+            # drop $out chart
+            del self.interp.chart['$trace/0']
+
 
     do_load.__doc__ = do_load.__doc__.format(load=', '.join(load.available))
     do_post.__doc__ = do_post.__doc__.format(post=', '.join(post.available))
diff --git a/test/repl/equals-errors.doctest b/test/repl/equals-errors.doctest
new file mode 100644 (file)
index 0000000..adaa7e8
--- /dev/null
@@ -0,0 +1,36 @@
+
+:- a = 2.
+=============
+a := 2
+
+
+% It's ok to assign 2 again.
+
+:- a = 2.
+
+
+% but you can't set it to a different value, such as 1.
+
+:- a = 1.
+=============
+a := $error
+
+:- sol
+
+Solution
+========
+a => $error.
+
+
+Errors
+======
+because a is "failed to aggregate item `a` because `=` got conflicting values [1, 2]":
+
+
+:- retract_rule 2
+
+:- sol
+
+Solution
+========
+a => 2.