From 5399bb23440b63535b332f87b30d8a34874be42c Mon Sep 17 00:00:00 2001 From: Tim Vieira Date: Wed, 10 Jul 2013 15:10:24 -0400 Subject: [PATCH] (Issue #46) `:-` now implicit aggregator for facts. `|=` no longer available. --- src/Dyna/Backend/Python/Backend.hs | 2 +- src/Dyna/Backend/Python/aggregator.py | 83 +++++---------------------- src/Dyna/Backend/Python/repl.py | 4 +- src/Dyna/ParserHS/Parser.hs | 6 +- src/Dyna/ParserHS/Selftest.hs | 16 +++--- test/repl/aggregator-conflict.dynadoc | 2 +- 6 files changed, 29 insertions(+), 84 deletions(-) diff --git a/src/Dyna/Backend/Python/Backend.hs b/src/Dyna/Backend/Python/Backend.hs index 9bef418..74419af 100644 --- a/src/Dyna/Backend/Python/Backend.hs +++ b/src/Dyna/Backend/Python/Backend.hs @@ -51,7 +51,7 @@ aggrs :: S.Set String aggrs = S.fromList [ "max=" , "min=" , "+=" , "*=" - , "&=" , "|=" + , "&=" , ":-" , "=" , "majority=" , "mean=" diff --git a/src/Dyna/Backend/Python/aggregator.py b/src/Dyna/Backend/Python/aggregator.py index fd3f76b..ee99ab3 100644 --- a/src/Dyna/Backend/Python/aggregator.py +++ b/src/Dyna/Backend/Python/aggregator.py @@ -10,17 +10,6 @@ from collections import Counter from utils import drepr, _repr, user_vars from errors import AggregatorError -""" -class Aggregator(object): - def fold(self): - raise NotImplementedError - def inc(self, val, ruleix, variables): - raise NotImplementedError - def dec(self, val, ruleix, variables): - raise NotImplementedError - def clear(self): - raise NotImplementedError -""" class NoAggregatorError(Exception): """ @@ -39,8 +28,10 @@ class Aggregator(object): def clear(self): pass + NoAggregator = Aggregator() + class BAggregator(Counter, Aggregator): # def __init__(self): # super(BAggregator, self).__init__() @@ -52,19 +43,6 @@ class BAggregator(Counter, Aggregator): assert False, "This method should never be called." -#class PlusEquals(object): -# __slots__ = 'pos', 'neg' -# def __init__(self): -# self.pos = 0 -# self.neg = 0 -# def inc(self, val, ruleix, variables): -# self.pos += val -# def dec(self, val, ruleix, variables): -# self.neg += val -# def fold(self): -# return self.pos - self.neg - - class ColonEquals(BAggregator): def inc(self, val, ruleix, _variables): self[ruleix, val] += 1 @@ -99,13 +77,6 @@ class Equals(BAggregator): raise AggregatorError('`=` got conflicting values %s' % (vs,)) - -#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): def inc(self, val, _ruleix, variables): @@ -128,6 +99,7 @@ class majority_equals(BAggregator): if c > 0: return k + class mean_equals(BAggregator): def fold(self): # TODO: support negative multiplicity or throw an error @@ -136,38 +108,20 @@ class mean_equals(BAggregator): n = sum(m for _, m in self.iteritems() if m > 0) return reduce(operator.add, s) / n + class max_equals(BAggregator): def fold(self): s = [k for k, m in self.iteritems() if m > 0] if len(s): return max(s) + class min_equals(BAggregator): def fold(self): s = [k for k, m in self.iteritems() if m > 0] if len(s): return min(s) -#class maxwithkey_equals(max_equals): -# def fold(self): -# m = max_equals.fold(self) -# self.key = None -# if m is not None: -# if not hasattr(m, 'aslist') or len(m.aslist) != 2: -# raise AggregatorError("argmax expects a pair of values") -# self.key = m.aslist[1] -# return m.aslist[0] - -#class minwithkey_equals(min_equals): -# def fold(self): -# m = min_equals.fold(self) -# self.key = None -# if m is not None: -# if not hasattr(m, 'aslist') or len(m.aslist) != 2: -# raise AggregatorError("argmin expects a pair of values") -# self.key = m.aslist[1] -# return m.aslist[0] - class plus_equals(BAggregator): def fold(self): @@ -175,25 +129,15 @@ class plus_equals(BAggregator): if len(s): return reduce(operator.add, s) + class times_equals(BAggregator): def fold(self): s = [k**m for k, m in self.iteritems() if m != 0] if len(s): return reduce(operator.mul, s) -#class and_equals(BAggregator): -# def fold(self): -# s = [k for k, m in self.iteritems() if m > 0] -# if len(s): -# return reduce(lambda x,y: x and y, s) -#class or_equals(BAggregator): -# def fold(self): -# s = [k for k, m in self.iteritems() if m > 0] -# if len(s): -# return reduce(lambda x,y: x or y, s) - -class boolean_or_equals(BAggregator): +class or_equals(BAggregator): def fold(self): s = [x for x, m in self.iteritems() if m > 0] if len(s): @@ -203,7 +147,8 @@ class boolean_or_equals(BAggregator): return reduce(lambda x,y: x or y, s) -class boolean_and_equals(BAggregator): + +class and_equals(BAggregator): def fold(self): s = [x for x, m in self.iteritems() if m > 0] if len(s): @@ -212,6 +157,7 @@ class boolean_and_equals(BAggregator): raise TypeError('%s is not Boolean.' % _repr(val)) return reduce(lambda x,y: x and y, s) + class set_equals(BAggregator): def fold(self): from stdlib import todyna @@ -219,6 +165,7 @@ class set_equals(BAggregator): if len(s): return todyna(s) + class bag_equals(BAggregator): def fold(self): from stdlib import todyna @@ -231,17 +178,15 @@ defs = { 'min=': min_equals, '+=': plus_equals, '*=': times_equals, - '&=': boolean_and_equals, - '|=': boolean_or_equals, - ':-': boolean_or_equals, + '&=': and_equals, + ':-': or_equals, 'majority=': majority_equals, 'set=': set_equals, 'bag=': bag_equals, 'mean=': mean_equals, -# 'argmax=': maxwithkey_equals, -# 'argmin=': minwithkey_equals, } + def aggregator(name, term): "Create aggregator by ``name``." diff --git a/src/Dyna/Backend/Python/repl.py b/src/Dyna/Backend/Python/repl.py index c3c19df..bd661d8 100644 --- a/src/Dyna/Backend/Python/repl.py +++ b/src/Dyna/Backend/Python/repl.py @@ -465,9 +465,9 @@ class REPL(cmd.Cmd, object): | └─ c = true | - └─ |= true + └─ :- true - c |= &true. + c :- &true. The trace shows which rules fired and contributed to the value we diff --git a/src/Dyna/ParserHS/Parser.hs b/src/Dyna/ParserHS/Parser.hs index 167a6d9..290ac21 100644 --- a/src/Dyna/ParserHS/Parser.hs +++ b/src/Dyna/ParserHS/Parser.hs @@ -465,7 +465,7 @@ rule = token $ do h@(_ :~ hs) <- term choice [ do (_ :~ ds) <- try (spanned (char '.') <* lookAhead whiteSpace) - return (Rule h "|=" (TFunctor "true" [] :~ ds) :~ (hs <> ds)) + return (Rule h ":-" (TFunctor "true" [] :~ ds) :~ (hs <> ds)) , do aggr <- token $ join $ asks dlc_aggrs body <- tfexpr @@ -537,7 +537,7 @@ pragmaBody :: forall m . (DeltaParsing m, LookAheadParsing m, MonadReader DLCfg m) => m Pragma pragmaBody = token $ choice - [ + [ symbol "backchain" *> parseBackchain , symbol "dispos_def" *> parseDisposDefl -- set default dispositions , symbol "dispos" *> parseDisposition -- in-place dispositions @@ -607,7 +607,7 @@ pragmaBody = token $ choice return $ POperAdd fx (fromIntegral prec) sym parseOperDel = POperDel <$> afx - + fixity = choice [ symbol "pre" *> pure (PFPre, pfx) , symbol "post" *> pure (PFPost, pfx) , symbol "in" *> ((,) <$> (PFIn <$> assoc) <*> pure ifx) diff --git a/src/Dyna/ParserHS/Selftest.hs b/src/Dyna/ParserHS/Selftest.hs index 3cf8515..35b8b2b 100644 --- a/src/Dyna/ParserHS/Selftest.hs +++ b/src/Dyna/ParserHS/Selftest.hs @@ -163,13 +163,13 @@ case_list = e @=? (term s) e = TFunctor "cons" [ _tNumeric (Left 1) :~ Span (Columns 1 1) (Columns 2 2) s , TFunctor "cons" - [ TFunctor "+" + [ TFunctor "+" [ _tNumeric (Left 2) :~ Span (Columns 3 3) (Columns 4 4) s , _tNumeric (Left 3) :~ Span (Columns 5 5) (Columns 6 6) s ] :~ Span (Columns 3 3) (Columns 6 6) s - , TFunctor "nil" [] :~ Span (Columns 7 7) (Columns 7 7) s - ] + , TFunctor "nil" [] :~ Span (Columns 7 7) (Columns 7 7) s + ] :~ Span (Columns 3 3) (Columns 7 7) s ] :~ Span (Columns 0 0) (Columns 7 7) s @@ -181,13 +181,13 @@ case_list_bar = e @=? (term s) e = TFunctor "cons" [ _tNumeric (Left 1) :~ Span (Columns 1 1) (Columns 2 2) s , TFunctor "cons" - [ TFunctor "+" + [ TFunctor "+" [ _tNumeric (Left 2) :~ Span (Columns 3 3) (Columns 4 4) s , _tNumeric (Left 3) :~ Span (Columns 5 5) (Columns 6 6) s ] :~ Span (Columns 3 3) (Columns 6 6) s - , TVar "X" :~ Span (Columns 7 7) (Columns 8 8) s - ] + , TVar "X" :~ Span (Columns 7 7) (Columns 8 8) s + ] :~ Span (Columns 3 3) (Columns 8 8) s ] :~ Span (Columns 0 0) (Columns 8 8) s @@ -274,7 +274,7 @@ case_ruleFact = e @=? (progrule sr) where e = Rule (TFunctor "goal" [] :~ Span (Columns 0 0) (Columns 4 4) sr) - "|=" + ":-" (TFunctor "true" [] :~ Span (Columns 4 4) (Columns 5 5) sr) :~ ts ts = Span (Columns 0 0) (Columns 5 5) sr @@ -509,7 +509,7 @@ arbPragma = oneof arbAtom = elements [ "f", "+" ] prop_pragma_roundtrip :: Property -prop_pragma_roundtrip = +prop_pragma_roundtrip = forAll arbPragma (\p -> p == unsafeParse (testPragma defDLC) (BU.fromString (flip PP.displayS "" $ PP.renderCompact diff --git a/test/repl/aggregator-conflict.dynadoc b/test/repl/aggregator-conflict.dynadoc index f5dd087..9fd31c5 100644 --- a/test/repl/aggregator-conflict.dynadoc +++ b/test/repl/aggregator-conflict.dynadoc @@ -9,7 +9,7 @@ a = 1. DynaCompilerError: Encountered error in input program: Conflicting aggregators; rule - uses '|=' for a/0 but I had been lead to expect '+='. + uses ':-' for a/0 but I had been lead to expect '+='. Everything was syntactically valid, but we could not see it through. -- 2.50.1