#!/usr/bin/env python
-import os, sys, imp, traceback
+import re, os, sys, imp, traceback
from collections import defaultdict
from hashlib import sha1
from path import path
tmp.rmtree()
tmp.makedirs_p()
+ # coarsening of the program shows which rules might depend on each other
+ # (an over estimate -- high recall, low precision).
+ self.coarse_deps = defaultdict(set)
+ self.rule_by_head = defaultdict(list)
+
def new_fn(self, fn, agg):
if self.agg_name[fn] is None:
self.agg_name[fn] = agg
if self.uninitialized_rules:
self.run_uninitialized()
-
if self.agenda:
self.run_agenda(changed)
# changes to aggregators.
emittiers = []
t_emit = lambda item, val, ruleix, variables: \
- emittiers.append((item, val, ruleix, variables, delete))
+ emittiers.append((item, val, ruleix, variables, delete))
error = []
rule.init(emit=_emit)
except (ZeroDivisionError, TypeError, KeyboardInterrupt, RuntimeError, OverflowError) as e:
- # TODO: should put stuff in error table, like everything else.
e.exception_frame = rule_error_context()
e.traceback = traceback.format_exc()
-
self.error[rule] = e
-
failed.append(rule)
else:
rule.initialized = True
# Adding/removing rules
def add_rule(self, index, init=None, query=None, head_fn=None, anf=None):
-
+ assert anf is not None
assert index not in self.rules
+ for (x, label, ys) in anf.unifs:
+ if x == anf.head:
+ assert label == '&'
+ fa = '%s/%d' % (ys[0], len(ys) - 1)
+ if head_fn is not None:
+ assert head_fn == fa
+ head_fn = fa
+ break
+ else:
+ assert False, 'did not find head'
+ assert head_fn is not None
+
+
span = hide_ugly_filename(parse_attrs(init or query)['Span'])
dyna_src = strip_comments(parse_attrs(init or query)['rule'])
rule.anf = anf
rule.head_fn = head_fn
+ self.update_coarse(rule)
+
if init:
rule.init = init
init.rule = rule
assert False, "Can't add rule with out an initializer or query handler."
# XXX: all rules should eventually have ANF tacked on, but until then...
- if anf is not None:
- agg, head, evals, unifs, result = anf[2:]
+ #if anf is not None:
+ if True:
args = (index,
dyna_src,
- todyna([head, agg, result, evals, unifs]),
+ todyna([anf.head, anf.agg, anf.result, anf.evals, anf.unifs]),
init,
query)
rule.item = self.build(fn, *args)
self.emit(rule.item, true, ruleix=None, variables=None, delete=False)
+ def update_coarse(self, rule):
+ self.rule_by_head[rule.head_fn].append(rule)
+ for (_, label, ys) in rule.anf.evals:
+ [(label, _evalix)] = re.findall('^(.*)@(\d+)$', label) # remove evaluation index
+ self.coarse_deps[rule.head_fn].add('%s/%d' % (label, len(ys)))
+
+ def recompute_coarse(self):
+ self.rule_by_head.clear()
+ self.coarse_deps.clear()
+ for rule in self.rules.values():
+ self.update_coarse(rule)
+
def retract_rule(self, idx):
"Retract rule and all of it's edges."
self.agenda[head] = self.time_step
self.time_step += 1
+ self.recompute_coarse()
+ # todo: need coarse deps transitive closure
+
return self.run_agenda()
def new_updater(self, fn, ruleix, handler):