def test_user_query(): add_rules(""" fff(X) = 1. """) user_query('fff(1)')
def test_quicksort_optimize(): from dyna.syntax.normalizer import add_rules add_rules(""" quicksort([X|Xs],Ys) :- partition(Xs,X,Left,Right), quicksort(Left,Ls), quicksort(Right,Rs), append(Ls,[X|Rs],Ys). quicksort([],[]). partition([X|Xs],Y,[X|Ls],Rs) :- X <= Y, partition(Xs,Y,Ls,Rs). partition([X|Xs],Y,Ls,[X|Rs]) :- X > Y, partition(Xs,Y,Ls,Rs). partition([],Y,[],[]). """) #dyna_system._optimize_term(('partition', 4)) dyna_system._optimize_term(('quicksort', 2)) dyna_system.run_agenda() qs = dyna_system.call_term('quicksort', 2) frame = Frame() frame[0] = Term.fromlist([3, 1, 2]) rr = saturate(qs, frame) assert rr == Terminal(1)
def test_counting_custom_int(): # this test doesn't work as it can't get an iterator over the X variable at # the start. The backchaining that is required would construct an infinite # iterator, and the current backchaining rules are preventing this from # going all the way to the base case. It also wouldn't know that the base # case is as that is value dependent. # # This is basically that it won't run the - -> + mode via backwards chaining # as it can't know when it would stop. So I guess the safety thing in this # case is just that we could forward chain this operation, but then it # doesn't allow for it to stop once it has observed enough values? (if it # could even prove that) # # This should end up getting marked as mode plannable, but this requires # that there is an infinite recursion which means that it likely doesn't # terminate. from dyna.syntax.normalizer import add_rules add_rules(""" positive_int(1). positive_int(X+1) :- X >= 1, positive_int(X). % parser bug, the last expression is not unified with True when with :-, and thus the X>=1 can't be the last expression count_positive_int(Y) += positive_int(X), X < Y, 1. """) count_call = dyna_system.call_term('count_positive_int', 1) frame = Frame() frame[0] = 1 rr = saturate(count_call, frame) assert rr == Terminal(1)
def test_compiler8_structure(): return from dyna.syntax.normalizer import add_rules add_rules(""" """)
def add_rules(self, line): line = str(line) line += f' %% repl line {self.lineno}' try: #rules_or_cmds = self.interp.parse(line) add_rules(line) except DynaParserException as e: print(type(e).__name__ + ':') print(e) print('new rule(s) were not added to program.') print() return ([], {})
def test_aggregator_saturates(): from dyna.syntax.normalizer import add_rules add_rules(""" agg_saturates |= true for range(X, 0, 1000000000000000000000). % big number so it should stop the loop early """) a = dyna_system.call_term('agg_saturates', 0) frame = Frame() rr = saturate(a, frame) assert rr == Terminal(1) assert interpreter.ret_variable.getValue(frame) == True
def test_type_information_passing(): from dyna.syntax.normalizer import add_rules add_rules(""" type_r1(&foo(X, Y)). type_r2(&bar(Q, R)). type_z :- type_r1(X), type_r2(X). """) z = dyna_system.call_term('type_z', 0) frame = Frame() rr = saturate(z, frame) assert rr == Terminal(0)
def test_geometric_series(): from dyna.syntax.normalizer import add_rules add_rules(""" geometric += 1. geometric += geometric / 2. """) dyna_system.memoize_term(('geometric', 0), 'null') dyna_system.run_agenda() geo = dyna_system.call_term('geometric', 0) frame = Frame() rr = saturate(geo, frame) assert interpreter.ret_variable.getValue(frame) == 2.0
def test_safety_planning1(): from dyna.syntax.normalizer import add_rules add_rules(""" poly(X, [], 0). poly(X, [A|As], F) :- poly(X, As, Q), F is X*Q + A. factorial(0, 1). factorial(N, F) :- F is N*Q, factorial(N-1, Q). goal_delayed :- X > 7. % these delayed constraints can't be processed sp_fib(X) = 0. """) # check what mode we could enumerate these variables. sp = dyna_system.safety_planner call_poly = dyna_system.call_term('poly', 3) out_mode, has_delayed, is_finite = sp( call_poly, variables_named(0, 1, 2, interpreter.ret_variable), (False, True, True, False)) assert out_mode == (False, True, True, True ) # the variable X should still be unbound assert has_delayed assert not is_finite call_fact = dyna_system.call_term('factorial', 2) out_fact, has_delayed, is_finite = sp( call_fact, variables_named(0, 1, interpreter.ret_variable), (True, False, False)) assert out_fact == (True, True, True) assert not has_delayed assert not is_finite call_goal_delayed = dyna_system.call_term('goal_delayed', 0) out_delayed, has_delayed, is_finite = sp(call_goal_delayed, (), ()) assert out_delayed == () assert has_delayed assert is_finite
def test_watching_terms(): counter = 0 def cb(msg): nonlocal counter assert msg.key == (123, 456) print(msg) counter += 1 w = dyna_system.watch_term_changes(('test_term_watch', 1), cb) from dyna.syntax.normalizer import add_rules dyna_system.run_agenda() add_rules(""" test_term_watch(123) = 456. """) dyna_system.run_agenda() assert counter == 1
def test_even_odd_parser(): from dyna.syntax.normalizer import add_rules c = """ even_list_p([]). even_list_p([X,Y|Z]) :- even_list_p(Z). odd_list_p([X|Y]) :- even_list_p(Y). even_odd_list_p(X) :- even_list_p(X), odd_list_p(X). """ for l in c.split('\n'): add_rules(l) #dyna_system._optimize_term(('even_odd_list_p', 1)) dyna_system.optimize_system() dyna_system.run_agenda() call = dyna_system.call_term('even_odd_list_p', 1) frame = Frame() rr = saturate(call, frame) assert rr == Terminal(0)
def test_memo_defaults(): from dyna.syntax.normalizer import add_rules add_rules(""" fib_defaulting(X) += fib_defaulting(X - 1) + fib_defaulting(X - 2) for X > 1, X < 6. fib_defaulting(0) += 0. fib_defaulting(1) += 1. fib_defaulting(X) += 1. % make this use a default with adding a value """) def check(): w = dyna_system.call_term('fib_defaulting', 1) frame = Frame() frame[0] = 5 rr = simplify(w, frame) assert rr == Terminal(1) assert interpreter.ret_variable.getValue(frame) == 20 check()
def test_colon_equals(): from dyna.syntax.normalizer import add_rules add_rules(""" colon_e(X) := 0. colon_e(1) := 1. colon_e(Y) := 2 for Y > 7, Y < 10. """) def c(x): colon_e = dyna_system.call_term('colon_e', 1) frame = Frame() frame[0] = x rr = saturate(colon_e, frame) assert rr == Terminal(1) return interpreter.ret_variable.getValue(frame) assert c(1) == 1 assert c(0) == 0 assert c(5) == 0 assert c(8) == 2
def do_load(self, line: Path): "Load rules from a dyna source file." line = str(line) with open(line.strip()) as f: add_rules(f.read())