From: Tim Vieira Date: Fri, 5 Jul 2013 22:16:21 +0000 (-0400) Subject: `dict=` create something like associative list -- this lets us use it in our X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=01692b5d9d79e536cf29a7821a62b9b002ae3319;p=dyna2 `dict=` create something like associative list -- this lets us use it in our dyna programs. doctests strip colors tweak to solution print out: print 'Solution empty' instead of a "Solution" heading. proper BC rule retraction. --- diff --git a/src/Dyna/Backend/Python/aggregator.py b/src/Dyna/Backend/Python/aggregator.py index d1cbe33..664a60d 100644 --- a/src/Dyna/Backend/Python/aggregator.py +++ b/src/Dyna/Backend/Python/aggregator.py @@ -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): diff --git a/src/Dyna/Backend/Python/dyna-doctest.py b/src/Dyna/Backend/Python/dyna-doctest.py index fcc3a6c..0d7a16f 100755 --- a/src/Dyna/Backend/Python/dyna-doctest.py +++ b/src/Dyna/Backend/Python/dyna-doctest.py @@ -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: diff --git a/src/Dyna/Backend/Python/interpreter.py b/src/Dyna/Backend/Python/interpreter.py index 98a54a4..b70f666 100644 --- a/src/Dyna/Backend/Python/interpreter.py +++ b/src/Dyna/Backend/Python/interpreter.py @@ -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: diff --git a/src/Dyna/Backend/Python/repl.py b/src/Dyna/Backend/Python/repl.py index efe7b28..d3a3e09 100644 --- a/src/Dyna/Backend/Python/repl.py +++ b/src/Dyna/Backend/Python/repl.py @@ -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) diff --git a/src/Dyna/Backend/Python/stdlib.py b/src/Dyna/Backend/Python/stdlib.py index 336a5a5..21c4a76 100644 --- a/src/Dyna/Backend/Python/stdlib.py +++ b/src/Dyna/Backend/Python/stdlib.py @@ -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): diff --git a/test/misc/retract-bc.dynadoc b/test/misc/retract-bc.dynadoc index a1053ca..f6ba303 100644 --- a/test/misc/retract-bc.dynadoc +++ b/test/misc/retract-bc.dynadoc @@ -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