]> hydra-www.ietfng.org Git - dyna2/commitdiff
Experiment version of `trace` now available.
authorTim Vieira <tim.f.vieira@gmail.com>
Thu, 27 Jun 2013 20:45:14 +0000 (16:45 -0400)
committerTim Vieira <tim.f.vieira@gmail.com>
Thu, 27 Jun 2013 20:45:14 +0000 (16:45 -0400)
    $ ./dyna
    :- a += 1.
    :- a += a/2.
    :- post trace()

src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/post/__init__.py
src/Dyna/Backend/Python/post/draw_circuit.py
src/Dyna/Backend/Python/post/trace.py [new file with mode: 0644]

index 5eb2aec3882e7aa3e7d846e18c6bd3179e4b3a81..1a0fb535d8b6a3234a09ec1e4fbb785046aa74bb 100644 (file)
@@ -4,6 +4,8 @@
 TODO
 ====
 
+ - TODO: @nwf remove comments from rule source
+
  - More info in crash handler. (stack trace, repl transcript, cmd-line args,
    version control info, and dyna source is enough)
 
@@ -139,10 +141,10 @@ USERS
 NOTES
 =====
 
- - TODO: `None` does not propagate, eventually it will because of the `?` prefix
+ - `None` does not propagate, eventually it will because of the `?` prefix
    operator.
 
- - TODO: Term values should only be aggregated with ``=`` or ``:=`` maybe even
+ - Term values should only be aggregated with ``=`` or ``:=`` maybe even
    ``set=``. We should disallow ``a += &b.``
 
      Equals aggregation only one value allowed, mult. >0 on single value. The
@@ -154,7 +156,7 @@ NOTES
      This might not be the case during computation -- this is the same as the
      error problem.
 
- - TODO: Numeric precision is an issue with BAggregators.
+ - Numeric precision is an issue with BAggregators.
 
      timv: Are we sure we have this bug?
 
index 68121c71c5ac6e62e278bddf10363a1f3c198d89..77c90852b1afa867abd20b50bfc2152539f4ee48 100644 (file)
@@ -3,7 +3,7 @@ from save import save
 from graph import graph
 from draw_circuit import draw_circuit
 from dump_solution import dump_solution
-
+from trace import trace
 
 def run(interp, line):
     [(name, args)] = _re.findall('([a-z][a-zA-Z_0-9]*)\((.*)\)$', line.strip())
index d249fc3f8ebf1e4c717b1c76f6d85cd98322bbac..e697a3e550a3fc77f93648cbaed2cbbfe9d9764c 100644 (file)
@@ -1,4 +1,7 @@
 # -*- coding: utf-8 -*-
+"""
+TODO: nwf remove comments from rule source
+"""
 
 import webbrowser
 from debug import Hypergraph
@@ -77,166 +80,4 @@ class draw_circuit(object):
 
             print >> f, '</body></html>'
 
-#        webbrowser.open(f.name)
-
-        # group edges by head then ruleindex
-        global groups
-        groups = groupby(lambda x: x[0], es)
-        for a in groups:
-            groups[a] = groupby(lambda x: x[1], groups[a])
-
-        for head in groups:
-            dig(head, set())
-
-
-from collections import defaultdict
-def groupby(key, data):
-    g = defaultdict(list)
-    for x in data:
-        g[key(x)].append(x)
-    return dict(g)
-
-
-groups = None
-
-
-
-def dig(head, visited, indent='', first=False, last=False):
-
-    if last and first:
-        xxx = '└─ '
-    elif last:
-        xxx = '└─ '
-    elif first:
-        xxx = '├─ '
-    else:
-        xxx = '├─ '
-
-    if head in visited:
-        print indent[:-4] + xxx + red % '*CYCLE*'
-        return
-
-    if head not in groups:
-        return
-    visited.add(head)
-
-    print indent[:-4] + xxx + '%s = %s' % (yellow % head, _repr(head.value))
-
-    if last:
-        indent = indent[:-4] + '     '
-    else:
-        indent = indent + '   '
-
-    for ruleix in groups[head]:
-
-        contrib = groups[head][ruleix]
-        for (i, (_, _, body, vs)) in enumerate(contrib):
-
-            rule = interp.rules[ruleix]
-
-            # TODO: nwf remove comments from rule source
-            crux = Crux(head, rule, body, dict(vs))
-
-            for line in crux.format():
-                print indent + line
-
-            print indent
-
-            for i, x in enumerate(body):
-                dig(x, visited, indent=indent + '  │ ', first=i==0, last=i==len(body)-1)
-
-            print indent[:-2]
-
-
-"""
-def branch(*xs):
-
-    for i, x in enumerate(xs):
-        first = i == 0
-        last = i == len(contrib)-1
-        if last and first:
-            xxx = '└─ '
-        elif last:
-            xxx = '└─ '
-        elif first:
-            xxx = '├─ '
-        else:
-            xxx = '├─ '
-"""
-
-
-
-class Crux(object):
-
-    def __init__(self, head, rule, body, vs):
-        self.head = head
-        self.rule = rule
-        self.body = body
-        self.vs = vs
-        self.graph = debug.circuit(rule.anf)
-
-    def values(self, x):
-        if x in self.vs:
-            return _repr(self.vs[x])
-        try:
-            return _repr(eval(x.replace('\\"', '"')))
-        except (SyntaxError, NameError):
-            return x
-
-    def format(self):
-        rule = self.rule
-        src = rule.src.replace('\n',' ').strip()
-        graph = self.graph
-        user_vars = dict(defn.user_vars(self.vs.items()))
-        side = ['  side:   ' + self.get_function(x) for x in graph.outputs if x != rule.anf.result and x != rule.anf.head]
-        return [('%s %s' % (red % rule.anf.agg, self.values(rule.anf.result))),
-                (green % ('  # %s' % src)),
-                (green % ('  # %s' % subst(src, user_vars))),
-                (green % ('  # %s' % drepr(user_vars))),
-                ('  head:   %s' % self.get_function(rule.anf.head)),
-                ('  result: %s' % self.get_function(rule.anf.result))] \
-                + side
-
-    def get_function(self, x):
-        """
-        String of symbolic representation of ``x``, a variable or function, in
-        this expresion graph.
-        """
-        g = self.graph
-        if isinstance(x, debug.Edge):
-            label = re.sub('@\d+$', '', x.label)
-            label = re.sub('^& ', '&', label)
-
-            if label == '=':
-                [b] = x.body
-                return self.get_function(b)
-
-            if not x.body:  # arity 0
-                return label
-
-            fn_args = [self.get_function(y) for y in x.body]
-            if not label.isalpha() and not label.startswith('& ') and len(fn_args) == 2:  # infix
-                [a,b] = fn_args
-                return '(%s %s %s)' % (a, label, b)
-            return '%s(%s)' % (label, ', '.join(fn_args))
-        else:
-            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])
-            [e] = g.incoming[x]
-
-            if e.label == '=':
-                return self.get_function(e)
-
-            if e.label.startswith('&'):
-                return self.get_function(e)
-
-            return self.get_function(e) + (red % '=%s' % self.values(x))
-
-
-import re
-from utils import yellow, green, red
-from defn import drepr
-from term import _repr
-import debug, defn
+        webbrowser.open(f.name)
diff --git a/src/Dyna/Backend/Python/post/trace.py b/src/Dyna/Backend/Python/post/trace.py
new file mode 100644 (file)
index 0000000..0fe076b
--- /dev/null
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+"""
+Examine solution as an outline of computation.
+"""
+
+import re
+from utils import yellow, green, red
+from defn import drepr
+from term import _repr
+import debug, defn
+
+import webbrowser
+from debug import Hypergraph
+from cStringIO import StringIO
+from utils import lexer, subst
+
+from draw_circuit import infer_edges
+from collections import defaultdict
+
+
+class trace(object):
+    """
+    Crude visualization of circuit pertaining to state of the interpreter.
+    """
+
+    def __init__(self, interp):
+        self.interp = interp
+
+    def main(self):
+        es = infer_edges(self.interp)
+
+        # group edges by head then ruleindex
+        groups = groupby(lambda x: x[0], es)
+        for a in groups:
+            groups[a] = groupby(lambda x: x[1], groups[a])
+
+        for head in groups:
+            print '\n'.join(dig(head, set(), groups, self.interp))
+
+
+def groupby(key, data):
+    g = defaultdict(list)
+    for x in data:
+        g[key(x)].append(x)
+    return dict(g)
+
+
+
+def dig(head, visited, groups, interp):
+
+    if head in visited:
+        return [red % '*CYCLE*']
+
+    if head not in groups:
+        return []
+
+    visited.add(head)
+
+    contribs = []
+
+    for ruleix in groups[head]:
+        for (_, _, body, vs) in groups[head][ruleix]:
+
+            crux = Crux(head, interp.rules[ruleix], body, dict(vs))
+            block = branch([dig(x, visited, groups, interp) for x in body])
+
+            if block:
+                contribs.append(crux.format() + [''] + block)
+            else:
+                contribs.append(crux.format())
+
+    return ['%s = %s' % (yellow % head, _repr(head.value))] \
+        + ['|'] \
+        + branch(contribs) + ['']
+
+
+def branch(xs):
+
+    ys = []
+    for i, x in enumerate(xs):
+        first = i == 0
+        last = i == len(xs)-1
+        if last and first:
+            h = '└─ '
+        elif last:
+            h = '└─ '
+        elif first:
+            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
+
+
+class Crux(object):
+
+    def __init__(self, head, rule, body, vs):
+        self.head = head
+        self.rule = rule
+        self.body = body
+        self.vs = vs
+        self.graph = debug.circuit(self.rule.anf)
+
+    def values(self, x):
+        if x in self.vs:
+            return _repr(self.vs[x])
+        try:
+            return _repr(eval(x.replace('\\"', '"')))
+        except (SyntaxError, NameError):
+            return x
+
+    def format(self):
+        rule = self.rule
+        src = rule.src.replace('\n',' ').strip()
+        graph = self.graph
+        user_vars = dict(defn.user_vars(self.vs.items()))
+        side = ['side:   ' + self.get_function(x) for x in graph.outputs if x != rule.anf.result and x != rule.anf.head]
+        return [('%s %s' % (red % rule.anf.agg, self.values(rule.anf.result))),
+                (green % ('# %s' % src)),
+                (green % ('# %s' % subst(src, user_vars))),
+                (green % ('# %s' % drepr(user_vars))),
+                ('head:   %s' % self.get_function(rule.anf.head)),
+                ('result: %s' % self.get_function(rule.anf.result))] \
+                + side
+
+    def get_function(self, x):
+        """
+        String of symbolic representation of ``x``, a variable or function, in
+        this expresion graph.
+        """
+        g = self.graph
+        if isinstance(x, debug.Edge):
+            label = re.sub('@\d+$', '', x.label)
+            label = re.sub('^& ', '&', label)
+
+            if label == '=':
+                [b] = x.body
+                return self.get_function(b)
+
+            if not x.body:  # arity 0
+                return label
+
+            fn_args = [self.get_function(y) for y in x.body]
+            if not label.isalpha() and not label.startswith('& ') and len(fn_args) == 2:  # infix
+                [a,b] = fn_args
+                return '(%s %s %s)' % (a, label, b)
+            return '%s(%s)' % (label, ', '.join(fn_args))
+
+        else:
+            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])
+            [e] = g.incoming[x]
+
+            if e.label == '=':
+                return self.get_function(e)
+
+            if e.label.startswith('&'):
+                return self.get_function(e)
+
+            return self.get_function(e) + (red % '=%s' % self.values(x))