def eval_expr_listo(exprs: Union[List, Var], env, value, depth=0, maxdepth=3): """ Evaluate a list of expressions. Not the same as evaluating the List AST """ if depth >= maxdepth: # logger.debug("Depth {} reached, which is the maximum depth".format(depth)) return fail uuid = str(uuid4())[:4] head_expr = var("head_expr_" + uuid) tail_expr = var("tail_expr_" + uuid) head_value = var("head_value_" + uuid) tail_value = var("tail_value_" + uuid) # fmt: off return conde(( typeo(exprs, list), typeo(value, list), # Either empty list or filled list conde( (eq(exprs, []), eq(value, [])), ( conso(head_expr, tail_expr, exprs), eval_expro(head_expr, env, head_value, depth + 1, maxdepth), # TODO: how to do depth in lists? typeo(tail_expr, list), typeo(tail_value, list), eval_expr_listo(tail_expr, env, tail_value, depth + 1, maxdepth), conso(head_value, tail_value, value)))))
def seq_apply_anyo_sub_goal(s): nonlocal i_any, null_type l_in_rf, l_out_rf = reify((l_in, l_out), s) i_car, i_cdr = var(), var() o_car, o_cdr = var(), var() conde_branches = [] if i_any or (isvar(l_in_rf) and isvar(l_out_rf)): # Consider terminating the sequences when we've had at least # one successful goal or when both sequences are logic variables. conde_branches.append([eq(l_in_rf, null_type), eq(l_in_rf, l_out_rf)]) # Extract the CAR and CDR of each argument sequence; this is how we # iterate through elements of the two sequences. cons_parts_branch = [ goaleval(conso(i_car, i_cdr, l_in_rf)), goaleval(conso(o_car, o_cdr, l_out_rf)), ] conde_branches.append(cons_parts_branch) conde_relation_branches = [] relation_branch = None if not skip_cars: relation_branch = [ # This case tries the relation continues on. relation(i_car, o_car), # In this conde clause, we can tell future calls to # seq_apply_anyo that we've had at least one successful # application of the relation (otherwise, this clause # would fail due to the above goal). _seq_apply_anyo(relation, i_cdr, o_cdr, True, null_type), ] conde_relation_branches.append(relation_branch) base_branch = [ # This is the "base" case; it is used when, for example, # the given relation isn't satisfied. eq(i_car, o_car), _seq_apply_anyo(relation, i_cdr, o_cdr, i_any, null_type), ] conde_relation_branches.append(base_branch) cons_parts_branch.append(conde(*conde_relation_branches)) g = conde(*conde_branches) g = goaleval(g) yield from g(s)
def test_nullo_itero(): x, y, z = var(), var(), var() q_lv, a_lv = var(), var() assert run(0, q_lv, conso(1, q_lv, [1]), nullo(q_lv)) assert run(0, q_lv, nullo(q_lv), conso(1, q_lv, [1])) assert not run(0, q_lv, nullo(q_lv, [], ())) assert run(0, [a_lv, q_lv], nullo(q_lv, a_lv, default_ConsNull=tuple)) == ([(), ()], ) assert run(0, [a_lv, q_lv], nullo(a_lv, [], q_lv)) == ([[], []], ) assert ([], ) == run(0, q_lv, nullo(q_lv, [])) assert ([], ) == run(0, q_lv, nullo([], q_lv)) assert (None, ) == run(0, q_lv, nullo(None, q_lv)) assert (tuple(), ) == run(0, q_lv, nullo(tuple(), q_lv)) assert (q_lv, ) == run(0, q_lv, nullo(tuple(), tuple())) assert ([], ) == run(0, q_lv, nullo(var(), q_lv)) assert ([], ) == run(0, q_lv, nullo(q_lv, var())) assert ([], ) == run(0, q_lv, nullo(q_lv, q_lv)) assert isvar(run(0, y, nullo([]))[0]) assert isvar(run(0, y, nullo(None))[0]) assert run(0, y, nullo(y))[0] == [] assert run(0, y, conso(var(), y, [1]), nullo(y))[0] == [] assert run(0, y, conso(var(), y, (1, )), nullo(y))[0] == () assert run(1, y, conso(1, x, y), itero(y))[0] == [1] assert run(1, y, conso(1, x, y), conso(2, z, x), itero(y))[0] == [1, 2] # Make sure that the remaining results end in logic variables res_2 = run(2, y, conso(1, x, y), conso(2, z, x), itero(y))[1] assert res_2[:2] == [1, 2] assert isvar(res_2[-1])
def test_nullo_itero(): assert isvar(run(0, y, nullo([]))[0]) assert isvar(run(0, y, nullo(None))[0]) assert run(0, y, nullo(y))[0] is None assert run(0, y, (conso, var(), y, [1]), nullo(y))[0] == [] assert run(0, y, (conso, var(), y, (1, )), nullo(y))[0] == () assert run(1, y, conso(1, x, y), itero(y))[0] == [1] assert run(1, y, conso(1, x, y), conso(2, z, x), itero(y))[0] == [1, 2] # Make sure that the remaining results end in logic variables res_2 = run(2, y, conso(1, x, y), conso(2, z, x), itero(y))[1] assert res_2[:2] == [1, 2] assert isvar(res_2[-1])
def test_nullo_itero(): assert isvar(run(0, y, nullo([]))[0]) assert isvar(run(0, y, nullo(None))[0]) assert run(0, y, nullo(y))[0] is None assert run(0, y, (conso, var(), y, [1]), nullo(y))[0] == [] assert run(0, y, (conso, var(), y, (1,)), nullo(y))[0] == () assert run(1, y, conso(1, x, y), itero(y))[0] == [1] assert run(1, y, conso(1, x, y), conso(2, z, x), itero(y))[0] == [1, 2] # Make sure that the remaining results end in logic variables res_2 = run(2, y, conso(1, x, y), conso(2, z, x), itero(y))[1] assert res_2[:2] == [1, 2] assert isvar(res_2[-1])
def test_heado(): x, y, z = var(), var(), var() assert (x, 1) in results(heado(x, (1, 2, 3)))[0].items() assert (x, 1) in results(heado(1, (x, 2, 3)))[0].items() assert results(heado(x, ())) == () assert run(0, x, heado(x, z), conso(1, y, z)) == (1, )
def eval_stmto(stmt, env, new_env, depth=0, maxdepth=3): logger.info("Evaluating stmt {} to new env {} using old env {}".format( ast_dump_if_possible(stmt), ast_dump_if_possible(new_env), ast_dump_if_possible(env), )) if depth >= maxdepth: return fail uuid = str(uuid4())[:4] # fmt: off goals = conde( ( eq( stmt, ast.Assign(targets=var('assign_targets_' + uuid), value=var("assign_value_" + uuid))), # TODO: Allow for multiple assigns: a, b, = ... heado(ast.Name(id=var('assign_lhs_' + uuid), ctx=ast.Store()), var('assign_targets_' + uuid)), eval_expro(var("assign_value_" + uuid), env, var("assign_rhs_" + uuid)), conso([var("assign_lhs_" + uuid), var("assign_rhs_" + uuid)], env, new_env), # new_env = [lhs, rhs] + env ), # Expression statements don't change the environment ( eq(stmt, ast.Expr(value=var("exprbody" + uuid))), # Expressions eq(env, new_env)), ) # fmt: on return goals
def test_tailo(): x, y, z = var(), var(), var() assert (x, (2, 3)) in results(tailo(x, (1, 2, 3)))[0].items() assert (x, ()) in results(tailo(x, (1, )))[0].items() assert results(tailo(x, ())) == () assert run(0, y, tailo(y, z), conso(x, (1, 2), z)) == ((1, 2), )
def buildo(op, args, obj): if not isvar(obj): if not isvar(args): args = etuplize(args, shallow=True) oop, oargs = operator(obj), arguments(obj) return lallgreedy(eq(op, oop), eq(args, oargs)) elif isvar(args) or isvar(op): return conso(op, args, obj) else: return eq(obj, term(op, args))
def test_conso(): x, y, z = var(), var(), var() assert not results(conso(x, y, ())) assert results(conso(1, (2, 3), (1, 2, 3))) assert results(conso(x, (2, 3), (1, 2, 3))) == ({x: 1}, ) assert results(conso(1, (2, 3), x)) == ({x: (1, 2, 3)}, ) assert results(conso(x, y, (1, 2, 3))) == ({x: 1, y: (2, 3)}, ) assert results(conso(x, (2, 3), y)) == ({y: (x, 2, 3)}, ) assert run(0, x, conso(x, y, z), eq(z, (1, 2, 3))) == (1, ) # Confirm that custom types are preserved. class mytuple(tuple): def __add__(self, other): return type(self)(super(mytuple, self).__add__(other)) assert type(results(conso(x, mytuple((2, 3)), y))[0][y]) == mytuple
def test_conso(): assert not results(conso(x, y, ())) assert results(conso(1, (2, 3), (1, 2, 3))) assert results(conso(x, (2, 3), (1, 2, 3))) == ({x: 1}, ) assert results(conso(1, (2, 3), x)) == ({x: (1, 2, 3)}, ) assert results(conso(x, y, (1, 2, 3))) == ({x: 1, y: (2, 3)}, ) assert results(conso(x, (2, 3), y)) == ({y: (x, 2, 3)}, ) # Confirm that custom types are preserved. class mytuple(tuple): def __add__(self, other): return type(self)(super(mytuple, self).__add__(other)) assert type(results(conso(x, mytuple((2, 3)), y))[0][y]) == mytuple