def test_compile(*filenames): ''' Compile rules -> programs for the virtual machine. ''' if not filenames: filenames = find_theories() for stem_rules in filenames: programs = ['# {filename}'.format(filename=stem_rules)] assert stem_rules[-len('.theory'):] == '.theory', stem_rules sequents = load_theory(stem_rules)['rules'] for sequent in sequents: for cost, seq, plan in compile_full(sequent): programs += [ '', '# using {}'.format(sequent), '# infer '.format(seq), '# cost = '.format(cost), ] plan.program(programs) for event in get_events(sequent): for cost, seq, plan in compile_given(sequent, event): programs += [ '', '# given {}'.format(event), '# using {}'.format(sequent), '# infer {}'.format(seq), '# cost {}'.format(cost), ] plan.program(programs) print '\n'.join(programs)
def test_compile(*filenames): """ Compile rules -> programs for the virtual machine. """ if not filenames: filenames = find_theories() for stem_rules in filenames: programs = ["# {filename}".format(filename=stem_rules)] assert stem_rules[-len(".theory") :] == ".theory", stem_rules sequents = load_theory(stem_rules)["rules"] for sequent in sequents: for cost, seq, plan in compile_full(sequent): programs += ["", "# using {}".format(sequent), "# infer ".format(seq), "# cost = ".format(cost)] plan.program(programs) for event in get_events(sequent): for cost, seq, plan in compile_given(sequent, event): programs += [ "", "# given {}".format(event), "# using {}".format(sequent), "# infer {}".format(seq), "# cost {}".format(cost), ] plan.program(programs) print "\n".join(programs)
def test_compile(*filenames): ''' Compile rules -> C++ ''' for stem_rules in filenames: assert stem_rules[-6:] == '.rules', stem_rules sequents = parser.parse_rules(stem_rules) for sequent in sequents: for cost, strategy in compile_full(sequent): print '\n'.join(strategy.cpp_lines()) for event in get_events(sequent): for cost, strategy in compile_given(sequent, event): print '\n'.join(strategy.cpp_lines())
def extract_tasks(infile, outfile=None): """Extract tasks from facts and rules, but do not compile to programs.""" theory = load_theory(infile) with writer(outfile) as write: facts = theory['facts'] for sequent in theory['rules']: facts += extensional.derive_facts(sequent) facts.sort() write('\n'.join(map(str, facts))) for sequent in theory['rules']: write(sequent.ascii()) for normal in sorted(compiler.normalize(sequent)): write(normal.ascii(indent=4)) for event in sorted(compiler.get_events(sequent)): write(' Given: {}'.format(event)) for normal in sorted(compiler.normalize_given(sequent, event)): write(normal.ascii(indent=8))
def _test_sequent(*args): sequent = Sequent(*args) print '-' * 78 print 'Compiling full search: {0}'.format(sequent) compiles = compile_full(sequent) print_compiles(compiles) full_cost = add_costs(c for (c, _, _) in compiles) incremental_cost = None for event in get_events(sequent): print 'Compiling incremental search given: {0}'.format(event) compiles = compile_given(sequent, event) print_compiles(compiles) if event.args: cost = add_costs(c for (c, _, _) in compiles) if incremental_cost: incremental_cost = add_costs([incremental_cost, cost]) else: incremental_cost = cost print '# full cost =', full_cost, 'incremental cost =', incremental_cost
def measure_sequent(sequent): print '-' * 78 print 'Compiling full search: {0}'.format(sequent) compiles = compile_full(sequent) print_compiles(compiles) full_cost = add_costs(c for (c, _, _) in compiles) incremental_cost = None for event in get_events(sequent): print 'Compiling incremental search given: {0}'.format(event) compiles = compile_given(sequent, event) print_compiles(compiles) if event.args: cost = add_costs(c for (c, _, _) in compiles) if incremental_cost: incremental_cost = add_costs([incremental_cost, cost]) else: incremental_cost = cost else: pass # event is only triggered once, so ignore cost print '# full cost =', full_cost, 'incremental cost =', incremental_cost
def write_event_tasks(code, sequents): code( ''' $bar // event tasks ''', bar=bar, ).newline() event_tasks = {} for sequent in sequents: for event in compiler.get_events(sequent): name = '<variable>' if event.is_var() else event.name tasks = event_tasks.setdefault(name, []) strategies = compiler.compile_given(sequent, event) strategies.sort(key=lambda (cost, _): cost) costs = [cost for cost, _ in strategies] cost = log_sum_exp(*costs) tasks.append((event, cost, strategies)) def get_group(name): special = { 'LESS': 'PositiveOrder', 'NLESS': 'NegativeOrder', '<variable>': 'Exists', } return special.get(name, signature.get_arity(name)) group_tasks = {} for name, tasks in event_tasks.iteritems(): groupname = get_group(name) group_tasks.setdefault(groupname, {})[name] = tasks # TODO sort groups # event_tasks = event_tasks.items() # event_tasks.sort(key=lambda (name, tasks): (len(tasks), len(name), name)) group_tasks = list(group_tasks.iteritems()) group_tasks.sort() for groupname, group in group_tasks: group = list(group.iteritems()) group.sort() body = Code() for eventname, tasks in group: subbody = Code() nargs = signature.get_nargs(signature.get_arity(group[0][0])) args = [[], ['arg'], ['lhs', 'rhs']][nargs] for arg in args: subbody('const Ob $arg = task.$arg;', arg=arg) if signature.is_fun(eventname): subbody( ''' const Ob val = $eventname.find($args); ''', eventname=eventname, args=', '.join(args)) for event, _, strategies in tasks: subsubbody = Code() diagonal = (nargs == 2 and event.args[0] == event.args[1]) if diagonal: subsubbody( ''' const Ob $local __attribute__((unused)) = $arg; ''', local=event.args[0], arg=args[0], ) else: for local, arg in zip(event.args, args): subsubbody( ''' const Ob $local __attribute__((unused)) = $arg; ''', local=local, arg=arg, ) if event.is_fun(): subsubbody('const Ob $arg = val;', arg=event.var.name) elif event.is_var(): subsubbody('const Ob $arg = task.ob;', arg=event.name) subcost = 0 for cost, strategy in strategies: subsubbody.newline() strategy.cpp(subsubbody) subcost += cost if diagonal: subbody( ''' if (lhs == rhs) { // cost = $cost $subsubbody } ''', cost=cost, subsubbody=wrapindent(subsubbody), ) else: subbody( ''' { // cost = $cost $subsubbody } ''', cost=cost, subsubbody=wrapindent(subsubbody), ) if eventname in ['LESS', 'NLESS', '<variable>']: body(str(subbody)).newline() else: body( ''' if (task.fun == & $eventname) { $subbody } ''', eventname=eventname, subbody=wrapindent(subbody), ).newline() code( ''' void execute (const ${groupname}Task & task) { $body } ''', groupname=groupname, body=wrapindent(body), ).newline() nontrivial_arities = [groupname for groupname, _ in group_tasks] for arity in signature.FUNCTION_ARITIES: if arity not in nontrivial_arities: code( ''' void execute (const ${arity}Task &) {} ''', arity=arity, ).newline()
def write_event_programs(programs, sequents): event_tasks = {} for sequent in sequents: for event in compiler.get_events(sequent): name = 'Variable' if event.is_var() else event.name plans = sorted(compiler.compile_given(sequent, event)) cost = add_costs(c for (c, _, _) in plans) tasks = event_tasks.setdefault(name, []) tasks.append((cost, event, sequent, plans)) group_tasks = {} for name, tasks in event_tasks.iteritems(): groupname = signature.get_arity(name) group_tasks.setdefault(groupname, {})[name] = sorted(tasks) group_tasks = sorted(group_tasks.iteritems()) group_id = 0 for groupname, group in group_tasks: group = sorted(group.iteritems()) arity = signature.get_arity(group[0][0]) for eventname, tasks in group: total_cost = add_costs(c for (c, _, _, _) in tasks) programs += [ '', '# ' + '-' * 76, '# plans {}.*: total cost = {:0.1f}'.format( group_id, total_cost), '# given {}'.format(eventname), ] plan_id = 0 for _, event, sequent, plans in tasks: diagonal = ( len(event.args) == 2 and event.args[0] == event.args[1]) if diagonal: lhs = event.args[0] assert lhs.arity == 'Variable' rhs = Expression.make(lhs.name + '_') event = Expression.make(event.name, lhs, rhs) if arity == 'Variable': given = 'GIVEN_EXISTS {var}'.format(var=event.name) elif arity == 'UnaryRelation': given = 'GIVEN_UNARY_RELATION {rel} {key}'.format( rel=event.name, key=event.args[0]) elif arity == 'BinaryRelation': given = 'GIVEN_BINARY_RELATION {rel} {lhs} {rhs}'.format( rel=event.name, lhs=event.args[0], rhs=event.args[1]) elif arity == 'NullaryFunction': given = 'GIVEN_NULLARY_FUNCTION {fun} {val}'\ .format( fun=event.name, val=event.var.name) elif arity == 'InjectiveFunction': given = 'GIVEN_INJECTIVE_FUNCTION {fun} {key} {val}'\ .format( fun=event.name, key=event.args[0], val=event.var.name) elif arity == 'BinaryFunction': given = 'GIVEN_BINARY_FUNCTION {fun} {lhs} {rhs} {val}'\ .format( fun=event.name, lhs=event.args[0], rhs=event.args[1], val=event.var.name) elif arity == 'SymmetricFunction': given = 'GIVEN_SYMMETRIC_FUNCTION {fun} {lhs} {rhs} {val}'\ .format( fun=event.name, lhs=event.args[0], rhs=event.args[1], val=event.var.name) else: raise ValueError('invalid arity: {}'.format(arity)) header = [given] if diagonal: header.append('IF_EQUAL {lhs} {rhs}'.format( lhs=event.args[0], rhs=event.args[1])) for cost, seq, plan in plans: programs += [ '', '# plan {}.{}: cost = {:0.1f}'.format( group_id, plan_id, cost), '# using {}'.format(sequent), '# infer {}'.format(seq), ] programs += header plan.program(programs) plan_id += 1 group_id += 1