From c931fc9641f172f8f7926099fa7b40bc442143b7 Mon Sep 17 00:00:00 2001 From: timv Date: Mon, 3 Jun 2013 11:45:17 -0400 Subject: [PATCH] Queries return variable assignments :- query rewrite(X,Y) (1, {'Y': 'ate', 'X': 'V'}) (1, {'Y': 'caviar', 'X': 'N'}) (1, {'Y': 'spoon', 'X': 'N'}) (1, {'Y': 'the', 'X': 'Det'}) (1, {'Y': 'with', 'X': 'P'}) (1, {'Y': 'a', 'X': 'Det'}) (1, {'Y': 'Papa', 'X': 'NP'}) Added `dict=` (name might changed) and aggregator which stores user variable assignments. [This is what is used for answering queries like the one above.qq] --- src/Dyna/Backend/Python/defn.py | 72 +++++++++++++++----------- src/Dyna/Backend/Python/interpreter.py | 62 ++++++++++++++-------- 2 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/Dyna/Backend/Python/defn.py b/src/Dyna/Backend/Python/defn.py index f326702..8362854 100644 --- a/src/Dyna/Backend/Python/defn.py +++ b/src/Dyna/Backend/Python/defn.py @@ -19,25 +19,18 @@ class Aggregator(object): class BAggregator(Counter, Aggregator): - def __init__(self, name): + def __init__(self, name, folder): + self.folder = folder Aggregator.__init__(self, name) Counter.__init__(self) + def fold(self): + return self.folder(self) def inc(self, val, ruleix, variables): self[val] += 1 def dec(self, val, ruleix, variables): self[val] -= 1 - def fold(self): - return self def fromkeys(self, *_): - assert False, 'bah.' - - -class MultisetAggregator(BAggregator): - def __init__(self, name, folder): - self.folder = folder - BAggregator.__init__(self, name) - def fold(self): - return self.folder(self) + assert False, "This method should never be called." class LastEquals(BAggregator): @@ -46,23 +39,32 @@ class LastEquals(BAggregator): def dec(self, val, ruleix, variables): self[ruleix, val] -= 1 def fold(self): - return max(x for x, cnt in self.items() if cnt > 0)[1] + return max(ruleix for ruleix, cnt in self.iteritems() if cnt > 0)[1] -class SetEquals(Aggregator): - def __init__(self, name): - self.set = set([]) - Aggregator.__init__(self, name) +def user_vars(variables): + "Post process the variables past to emit (which passes them to aggregator)." + # remove the 'u' prefix on user variables 'uX' + + # Note: We also ignore user variables with an underscore prefix + + return tuple((name[1:], val) for name, val in variables.items() if name.startswith('u') and not name.startswith('u_')) + + +class DictEquals(BAggregator): + def inc(self, val, ruleix, variables): - self.set.add(val) - def dec(self, val, ruleix, variables): - self.set.remove(val) - def fold(self): - return self.set - def clear(self): - self.set.clear() + # I think we only want user variables -- XXX: are we guaranteed to have + # all of the user variables? + vs = user_vars(variables) + self[val, vs] += 1 + def dec(self, val, ruleix, variables): + vs = user_vars(variables) + self[val, vs] -= 1 + def fold(self): + return list((x[0], dict(x[1])) for x, cnt in self.iteritems() if cnt > 0) def majority_equals(a): @@ -109,6 +111,15 @@ def b_or_equals(a): if len(s): return reduce(operator.or_, s) +def set_equals(a): + s = {x for x, m in a.iteritems() if m > 0} + if len(s): + return s + +def bag_equals(a): + return Counter(a) + + # map names to functions defs = { 'max=': max_equals, @@ -121,6 +132,8 @@ defs = { '|=': b_or_equals, ':-': or_equals, 'majority=': majority_equals, + 'set=': set_equals, + 'bag=': bag_equals, } @@ -131,13 +144,10 @@ def aggregator(name): return None if name == ':=': - return LastEquals(name) - - elif name == 'bag=': - return BAggregator(name) + return LastEquals(name, folder=None) - elif name == 'set=': - return SetEquals(name) + elif name == 'dict=': + return DictEquals(name, folder=None) else: - return MultisetAggregator(name, defs[name]) + return BAggregator(name, defs[name]) diff --git a/src/Dyna/Backend/Python/interpreter.py b/src/Dyna/Backend/Python/interpreter.py index c429896..1d552e5 100644 --- a/src/Dyna/Backend/Python/interpreter.py +++ b/src/Dyna/Backend/Python/interpreter.py @@ -5,15 +5,48 @@ MISC ==== -TODO: create an Interpreter object to hold what is now global state. + - TODO: create an Interpreter object to hold what is now global state. -FIXME: set= is wrong .. needs to keep counts like bag= + - FIXME: timv: I think that set= is wrong .. needs to keep counts like bag= + - TODO: sorted order of Chart seems to have changed. Check that this changed order + makes sense -This has an absurd parse: + - "initializers" aren't just initializers, they are the fully-naive bottom-up + inference rules. + + - XXX: we should probably fuse update handlers instead of dispatching to each + one independently. + + - TODO: deleting a rule: (1) remove update handlers (2) run initializers in + delete mode (3) remove initializers. + + - TODO: hooks from introspection, eval, and prioritization. + + - TODO: Term's should only be aggregated with ``=`` or ``:=``. We should + disallow ``a += &b.`` + + - TODO: doc tests for Dyna code! + + + +PARSER +====== + + - Singled quoted strings: + + x += f('result = 5'). - x += f('result = 5'). + - Nested expressions: + + out(0) dict= _VALUE is (rewrite(X,Y) + rewrite(X,Y,Z)), _VALUE. + + FATAL: Encountered error in input program: + Parser error + /tmp/tmp.dyna:1:14: error: expected: "." + rewrite(X,Y) + rewrite(X,Y,Z) + ^ What is null? @@ -38,23 +71,6 @@ Warnings/lint checking the LHS of a rule and it's not quoted (i.e. not some new piece of structure). -=== - - - "initializers" aren't just initializers, they are the fully-naive bottom-up - inference rules. - - - XXX: we should probably fuse update handlers instead of dispatching to each - one independently. - - - TODO: deleting a rule: (1) remove update handlers (2) run initializers in - delete mode (3) remove initializers. - - - TODO: hooks from introspection, eval, and prioritization. - - - TODO: Term's should only be aggregated with ``=`` or ``:=``. We should - disallow ``a += &b.`` - - REPL ==== @@ -511,7 +527,7 @@ class REPL(cmd.Cmd, object): @property def prompt(self): - return 'in(%s) :- ' % self.lineno + return ':- ' #% self.lineno def do_exit(self, _): readline.write_history_file(self.hist) @@ -596,7 +612,7 @@ class REPL(cmd.Cmd, object): print "Queries don't end with a dot." return - query = 'out(%s) bag= _VALUE is %s, &result(&(%s), _VALUE).' % (self.lineno, line, line) + query = 'out(%s) dict= _VALUE is %s, _VALUE.' % (self.lineno, line) print blue % query -- 2.50.1