num_iterations := 10.
is_iter(0).
-is_iter(I+1) |= true for is_iter(I) & I < num_iterations.
+is_iter(I+1) :- true for is_iter(I) & I < num_iterations.
% ---------------------------------------------------
% FORWARD-BACKWARD ALGORITHM (THE "E STEP" OF THE EM ALGORITHM)
% ---------------------------------------------------
-% At each iteration I = 0, 1, ... num_iterations,
+% At each iteration I = 0, 1, ... num_iterations,
% define a trellis graph on states of the form &state(Time,Tag),
% which expresses all ways of explaining the word sequence.
% The edge weights are defined from iteration I's probability model.
-edge(I,&state(Time-1,PrevTag),&state(Time,Tag))
+edge(I,&state(Time-1,PrevTag),&state(Time,Tag))
= p_transition(I,PrevTag,Tag) * p_emission(I,Tag,word(Time)).
start_state = &state(0,&start). % the initial tag at time 0 is called &start
end_state = &state(last_time+1,&stop). % the final tag is called &stop
-% Compute alphas and betas on that trellis graph, using
+% Compute alphas and betas on that trellis graph, using
% dynamic programming.
alpha(I,start_state) += 1 for is_iter(I).
% true path is one of the paths in the trellis.
prob(I,State) = alpha(I,State) * beta(I,State) / z(I).
-prob(I,PrevState,State)
+prob(I,PrevState,State)
= alpha(I,PrevState) * edge(I,PrevState,State) * beta(I,State) / z(I).
% ---------------------------------------------------
% COUNTING TRANSITIONS AND EMISSIONS
% ---------------------------------------------------
-% From the above, we can get the expected counts of specific
+% From the above, we can get the expected counts of specific
% transitions and emissions.
count_transition(I,PrevTag,Tag) += prob(I,&state(Time-1,PrevTag),&state(Time,Tag)).
count_emission(I,Tag,word(Time)) += prob(I,&state(Time,Tag)).
-% Smooth by adding lambda to all counts corresponding to parameters,
+% Smooth by adding lambda to all counts corresponding to parameters,
% even counts that are still 0 or null.
lambda := 0.0. % can be changed
count_transition(I,PrevTag,Tag) += lambda for (Param is p_transition(I,PrevTag,Tag)).
count_emission(I,Tag,Word) += lambda for (Param is p_emission(I,Tag,Word)).
-% Get the total smoothed count in each context. These will be the
+% Get the total smoothed count in each context. These will be the
% denominators of our smoothed probabiities.
count_transition_denom(I,PrevTag) += count_transition(I,PrevTag,Tag).
% Given the smoothed counts at time I, we define the new model at time I+1:
-p_transition(I+1,PrevTag,Tag)
- = count_transition(I,PrevTag,Tag) / count_transition_denom(I,PrevTag)
+p_transition(I+1,PrevTag,Tag)
+ = count_transition(I,PrevTag,Tag) / count_transition_denom(I,PrevTag)
for I < num_iterations.
-p_emission(I+1,Tag,Word)
+p_emission(I+1,Tag,Word)
:= count_emission(I,Tag,Word) / count_emission_denom(I,Tag)
for I < num_iterations.
% DRAW CONCLUSIONS FROM THE ESTIMATED MODEL
% ---------------------------------------------------
-% After the model is estimated, look at the computations for the final
+% After the model is estimated, look at the computations for the final
% iteration to find the most likely tag at each time step, and its probability.
besttagprob(Time) max= prob(num_iterations, &state(Time,Tag)) with_key Tag.
with_key [Tag | $key(bestpathprob(NextState))] for &state(_,Tag) = State.
bestpathprob = bestpathprob(start_state).
bestpath = $key(bestpathprob(start_state)).
-
-p
\ No newline at end of file
class Rule(object):
+
def __init__(self, index):
self.index = index
self.init = None
self.updaters = []
self.query = None
+
@property
def span(self):
- span = parse_attrs(self.init or self.query)['Span']
- return hide_ugly_filename(span)
+ if self.init or self.query:
+ span = parse_attrs(self.init or self.query)['Span']
+ return hide_ugly_filename(span)
+
@property
def src(self):
- return strip_comments(parse_attrs(self.init or self.query)['rule'])
+ if self.init or self.query:
+ return strip_comments(parse_attrs(self.init or self.query)['rule'])
+
def __repr__(self):
return 'Rule(%s, %r)' % (self.index, self.src)
break
print >> out, ' when `%s` = %s' % (item, _repr(value))
print >> out, ' %s' % (e)
- print >> out
+ print >> out
+
+ # TODO: include an undefined or unknown marker
+ # TODO: can highlight the expression which raise the error.
+ from post.trace import Crux
+
+ c = Crux(head=None,
+ rule=r,
+ body=None,
+ vs = dict(e.exception_frame))
+
+ for line in c.format():
+ print ' ', line
+
+ print >> out
print >> out
try:
handler(item, val, emit=t_emit)
except (TypeError, ZeroDivisionError, KeyboardInterrupt, OverflowError) as e:
+
+ import traceback
+
+ # Move to the frame where the exception occurred, which is often not the
+ # same frame where the exception was caught.
+ tb = sys.exc_info()[2]
+ if tb is not None:
+ while 1:
+ if not tb.tb_next:
+ break
+ tb = tb.tb_next
+ f = tb.tb_frame
+ else: # no exception occurred
+ f = sys._getframe()
+
+ # get the stack frames
+ stack = []
+ while f:
+ stack.append(f)
+ f = f.f_back
+ stack.reverse()
+
+ if 0:
+ print 'Traceback:'
+ print '=========='
+ print traceback.format_exc()
+
+ print 'Locals by frame:'
+ print '================'
+ for frame in stack:
+ print 'Frame %s in %s at line %s' % (frame.f_code.co_name,
+ frame.f_code.co_filename,
+ frame.f_lineno)
+ for key, value in frame.f_locals.iteritems():
+ print '%20s = %r' % (key, value)
+
+ print
+ print
+
+
+ e.exception_frame = stack[-1].f_locals.items()
error.append((e, handler))
+
if error:
self.error[item] = (val, error)
return
def _emit(*args):
emits.append(args)
- # TODO: this should be a transaction.
for k, v in env.agg_decl.items():
self.new_fn(k, v)
except (TypeError, ZeroDivisionError) as e:
raise DynaInitializerException(e, init)
- else:
+
+ finally:
+
+ # process emits
+ for e in emits:
+ self.emit(*e, delete=False)
+
for fn, r, h in env.updaters:
self.new_updater(fn, r, h)
for r, h in env.initializers:
# accept the new parser state
self.parser_state = env.parser_state
- # process emits
- for e in emits:
- self.emit(*e, delete=False)
# ------ $rule for fun and profit -------
interp = self
groups[a] = groupby(lambda x: x[1], groups[a])
self.items = groups
- def __call__(self, item):
+ def __call__(self, item, depth_limit=-1):
if item not in self.items:
print
print 'no trace for', item
- print '\n'.join(dig(item, set(), tuple(), self.items, self.interp))
+ print '\n'.join(dig(head = item,
+ visited = set(),
+ tail = tuple(),
+ groups = self.items,
+ interp = self.interp,
+ depth_limit = depth_limit))
def groupby(key, data):
return dict(g)
-def dig(head, visited, tail, groups, interp):
+def dig(head, visited, tail, groups, interp, depth_limit=-1):
+
+ print head, len(tail), depth_limit
+ if depth_limit >= 0 and len(tail) >= depth_limit:
+ return [yellow % '*max depth*']
if head in tail:
return ['%s = %s' % (yellow % head, _repr(head.value))] \
for (_, _, body, vs) in groups[head][ruleix]:
crux = Crux(head, interp.rules[ruleix], body, dict(vs))
- block = branch([dig(x, visited, tail + (head,), groups, interp) for x in body])
+ block = branch([dig(x, visited, tail + (head,), groups, interp, depth_limit) for x in body])
if block:
- contribs.append(crux.format() + ['|'] + block)
+ contribs.append(crux.fvalue() + [''] + crux.format() + ['|'] + block)
else:
- contribs.append(crux.format() + [''])
+ contribs.append(crux.fvalue() + [''] + crux.format() + [''])
return ['%s = %s' % (yellow % head, cyan % _repr(head.value))] \
+ ['|'] \
except (SyntaxError, NameError):
return x
+ def fvalue(self):
+ # show value and aggregator.. separate from format so we can use in
+ # error handling
+ return ['%s %s' % (green % self.rule.anf.agg, self.values(self.rule.anf.result))]
+
def format(self):
rule = self.rule
- #src = rule.src.replace('\n',' ').strip()
- #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]
else:
explode += '.'
- lines = ['%s %s' % (green % rule.anf.agg, self.values(rule.anf.result)),
- '',
- explode]
+ lines = [explode]
if side:
lines.append(side)
"""
g = self.graph
if isinstance(x, debug.Edge):
- label = re.sub('@\d+$', '', x.label)
- label = re.sub('^& ', '&', label)
+
+ # clean up edge name
+ label = re.sub('@\d+$', '', x.label) # remove evaluation index
+ label = re.sub('^& ', '&', label) # normalize prefix quote operator
if label == '=':
[b] = x.body
return x[1:] + (cyan % '=%s' % self.values(x))
return self.values(x)
+ # handle multiple values (can happen at unification nodes)
if len(g.incoming[x]) > 1:
return ' = '.join('(%s%s)' % (self.get_function(e), (cyan % '=%s' % self.values(e.head))) for e in g.incoming[x])
return self.get_function(e)
# handle lists
-
if e.label == '& nil':
return '[]'
return self.get_function(e)
return self.get_function(e) + (cyan % '=%s' % self.values(x))
+
+
+class Expr(object):
+ pass
+class Fn(Expr):
+ pass
+class Infix(Expr):
+ pass
+class Unif(Expr):
+ pass
to help.
"""
-import os, cmd, readline
+import re, os, cmd, readline
from utils import ip, lexer, subst, drepr, _repr, get_module
from stdlib import topython, todyna
from errors import DynaCompilerError, DynaInitializerException
print "Queries don't end with a dot."
return
+ depth_limit = -1
+ p = re.compile('--limit=(\d+)\\b')
+ x = p.findall(q)
+ if x:
+ q = p.sub('', q)
+ depth_limit = int(x[0])
+
+ self._trace(q, depth_limit=depth_limit)
+
+ def _trace(self, q, depth_limit=-1):
+
self.interp.new_rules = set()
try:
for item in results:
print
- tracer(todyna(item))
+ tracer(todyna(item), depth_limit=depth_limit)
finally:
# cleanup:
# TODO: this assertion should eventually hold.
# assert x is not True and x is not False, x
+
if x is True:
return 'true'
elif x is False: