of `argm`.
BUGFIX: hash and eq for list wasn't correct.
% single source shortest path with optimal path extraction.
-path(start) min= 0.
-path(B) min= path(A) + edge(A,B).
-goal min= path(end).
+path(start) argmin= [0, start].
+path(B) argmin= [path(A) + edge(A,B), A].
+goal argmin= [path(end), end].
% expensive path
edge("a","b") := 1.
start := "a".
end := "d".
-% use argmin to determine backpointers
-b(V) argmin= [path(U) + edge(U,V), U].
-
% extract cheapest path by following backpointers from each vertex.
bestpath(start) := [start].
-bestpath(V) := U is b(V), [V | bestpath(U)].
+bestpath(V) := U is $key(&path(V)), [V | bestpath(U)] for V != start.
% the optimal path is the one from the `end`.
optimalpath = reverse(bestpath(end)).
b([X,Y,Z]) := [X,b(Y),b(Z)].
% CKY parser
-phrase(X,I,K) max= phrase(Y,I,J) * phrase(Z,J,K) * p(X,Y,Z).
-phrase(X,I,K) max= phrase(Y,I,K) * p(X,Y).
-phrase(X,I,I+1) max= 1 for [I,X] in enumerate(sentence).
+phrase(X,I,K) argmax= [phrase(Y,I,J) * phrase(Z,J,K) * p(X,Y,Z), [[Y,I,J], [Z,J,K]]].
+phrase(X,I,K) argmax= [phrase(Y,I,K) * p(X,Y), [[Y,I,K]]].
+phrase(X,I,I+1) argmax= [1, X] for [I,X] in enumerate(sentence).
% backpointers
-bk(X,I,K) argmax= [phrase(Y,I,J) * phrase(Z,J,K) * p(X,Y,Z), [[Y,I,J], [Z,J,K]]].
-bk(X,I,K) argmax= [phrase(Y,I,K) * p(X,Y), [[Y,I,K]]].
-bk(X,I,I+1) argmax= [1, X] for [I,X] in enumerate(sentence).
+bk(X,I,K) = $key(&phrase(X,I,K)).
% extract path from backpointers
path(X,I,K) := W is bk(X,I,K), W.
def clear(self):
pass
+NoAggregator = Aggregator()
class BAggregator(Counter, Aggregator):
# def __init__(self):
if len(s):
return min(s)
-
-class argmax_equals(max_equals):
+class maxwithkey_equals(max_equals):
def fold(self):
m = max_equals.fold(self)
- if m:
+ 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")
- return m.aslist[1]
+ self.key = m.aslist[1]
+ return m.aslist[0]
-class argmin_equals(min_equals):
+class minwithkey_equals(min_equals):
def fold(self):
m = min_equals.fold(self)
- if m:
+ 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")
- return m.aslist[1]
+ self.key = m.aslist[1]
+ return m.aslist[0]
class plus_equals(BAggregator):
'set=': set_equals,
'bag=': bag_equals,
'mean=': mean_equals,
- 'argmax=': argmax_equals,
- 'argmin=': argmin_equals,
+ 'argmax=': maxwithkey_equals,
+ 'argmin=': minwithkey_equals,
}
-def aggregator(name):
+def aggregator(name, term):
"Create aggregator by ``name``."
if name is None:
from collections import defaultdict
-from defn import aggregator
+from aggregator import aggregator
from term import Term
from utils import _repr
self.ix = [defaultdict(set) for _ in xrange(arity)]
self.agg_name = agg_name
- def new_aggregator(self):
- return aggregator(self.agg_name)
+ def new_aggregator(self, term):
+ return aggregator(self.agg_name, term)
def __repr__(self):
rows = [term for term in self.intern.values() if term.value is not None]
return self.intern[args]
except KeyError:
self.intern[args] = term = Term(self.name, args)
- term.aggregator = self.new_aggregator()
+ term.aggregator = self.new_aggregator(term)
# index new term
for i, x in enumerate(args):
self.ix[i][x].add(term)
from term import Term, Cons, Nil
from chart import Chart
-from defn import aggregator
from utils import ip, red, green, blue, magenta, yellow, parse_attrs, \
ddict, dynac, read_anf, strip_comments, _repr
if nullary:
print >> out
for x in others:
-
if x.startswith('$rule/'):
continue
-
y = str(self.chart[x]) # skip empty chart
if y:
print >> out, y
if i >= 5:
print >> out, ' %s more ...' % (len(I[r][etype]) - i)
break
- print >> out, ' when `%s` = %s' % (item, _repr(value))
- print >> out, ' %s' % (e)
+ print >> out, ' `%s`: %s' % (item, e)
print >> out
# errors pertaining to rules
if was == now:
continue
+
+ # aggregator with special key
+ if hasattr(item.aggregator, 'key'):
+ key = self.build('$key/1', item)
+ if key.aggregator is None:
+ from aggregator import aggregator
+ key.aggregator = aggregator('=', key)
+ self.delete_emit(key, key.value, None, None)
+ self.emit(key, item.aggregator.key, None, None, delete=False)
+
+
was_error = False
if item in error: # clear error
was_error = True
import re
from collections import defaultdict
-import debug, defn
+import debug
from draw_circuit import infer_edges
from utils import yellow, green, cyan, red, _repr
def format(self):
rule = self.rule
#src = rule.src.replace('\n',' ').strip()
- #user_vars = dict(defn.user_vars(self.vs.items()))
+ #user_vars = dict(user_vars(self.vs.items()))
graph = self.graph
side = [self.get_function(x) for x in graph.outputs if x != rule.anf.result and x != rule.anf.head]
from errors import notimplemented
from utils import _repr
-from defn import Aggregator
+from aggregator import NoAggregator
# TODO: codegen should output a derived Term instance for each functor
return self.fn == other.fn and self.args == other.args
def __cmp__(self, other):
-# if self is other:
-# return 0
if other is None:
return 1
if not isinstance(other, Term):
return 1
-# if self == other:
-# return 0
return cmp((self.fn, self.args), (other.fn, other.args))
def __repr__(self):
self.head = head
self.tail = tail
Term.__init__(self, 'cons/2', (head, tail))
- self.aggregator = Aggregator()
+ self.aggregator = NoAggregator
self.aslist = [self.head] + self.tail.aslist
def __repr__(self):
else:
yield a, (None,), a
+ def __eq__(self, other):
+ try:
+ return self.aslist == other.aslist
+ except AttributeError:
+ return False
+
+ def __hash__(self):
+ return hash(tuple(self.aslist))
+
def __cmp__(self, other):
try:
return cmp(self.aslist, other.aslist)
class _Nil(Term):
def __init__(self):
Term.__init__(self, 'nil/0', ())
- self.aggregator = Aggregator()
+ self.aggregator = NoAggregator
self.aslist = []
def __repr__(self):
return '[]'