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)))))
예제 #2
0
def logicBased():
    x = var()
    print(run(1, x, eq(x, 5)))
    z = var()
    print(run(1, x, eq(x, z), eq(z, 3)))

    print(run(1, x, eq((1, 2), (1, x))))

    print(run(2, x, membero(x, (1, 2, 3)), membero(x, (2, 3, 4))))

    z = var('test')
    print(z)

    a, b, c = vars(3)
    print(a)
    print(b)
    print(c)

    parent = Relation()
    facts(parent, ("Homer", "Bart"), ("Homer", "Lias"), ("Abe", "Homer"))
    print(run(2, x, parent("Homer", x)))

    y = var()
    print(run(1, x, parent(x, y), parent(y, 'Bart')))

    def grandparent(x, z):
        y = var()
        return conde((parent(x, y), parent(y, z)))

    print(run(1, x, grandparent(x, 'Bart')))
    menu()  #calls the menu function (a menu loop)
예제 #3
0
def test_seq_apply_anyo_types():
    """Make sure that `applyo` preserves the types between its arguments."""
    q_lv = var()
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), [1], q_lv))
    assert res[0] == [1]
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), (1, ), q_lv))
    assert res[0] == (1, )
    res = run(
        1, q_lv,
        seq_apply_anyo(lambda x, y: eq(x, y), etuple(1, ), q_lv,
                       skip_op=False))
    assert res[0] == etuple(1, )
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), q_lv, (1, )))
    assert res[0] == (1, )
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), q_lv, [1]))
    assert res[0] == [1]
    res = run(
        1, q_lv,
        seq_apply_anyo(lambda x, y: eq(x, y), q_lv, etuple(1), skip_op=False))
    assert res[0] == etuple(1)
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), [1, 2], [1, 2]))
    assert len(res) == 1
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), [1, 2], [1, 3]))
    assert len(res) == 0
    res = run(1, q_lv, seq_apply_anyo(lambda x, y: eq(x, y), [1, 2], (1, 2)))
    assert len(res) == 0
    res = run(
        0, q_lv,
        seq_apply_anyo(lambda x, y: eq(y, etuple(mul, 2, x)),
                       etuple(add, 1, 2),
                       q_lv,
                       skip_op=True))
    assert len(res) == 3
    assert all(r[0] == add for r in res)
예제 #4
0
def walk(pos, path, end_pos):
    if eq(path, []):
        eq(pos, end_pos)
        return success
    else:
        x = var()
        return conde(edges(pos, path[0], x), walk(x, path[1:], end_pos))
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
예제 #6
0
        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)
예제 #7
0
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))
예제 #8
0
def test_distributions():
    res = run(0, var('q'), eq(var('q'), mt(1)),
              constant_neq(var('q'), np.array(1.)))

    assert not res

    res = run(0, var('q'), eq(var('q'), mt(2)),
              constant_neq(var('q'), np.array(1.)))

    assert res
예제 #9
0
    def mul_trans(in_expr, out_expr):
        """Equate `2 * x` with `5 * x` in a Theano `scan`.

        I.e. from left-to-right, replace `2 * x[t-1]` with `5 * x[t-1]`.
        """
        arg_lv = var()
        inputs_lv, info_lv = var(), var()
        in_scan_lv = mt.Scan(inputs_lv, [mt.mul(2, arg_lv)], info_lv)
        out_scan_lv = mt.Scan(inputs_lv, [mt.mul(5, arg_lv)], info_lv)

        return lall(eq(in_expr, in_scan_lv), eq(out_expr, out_scan_lv))
예제 #10
0
 def distributes(in_lv, out_lv):
     return lall(
         # lhs == A * (x + b)
         eq(etuple(mt.dot, var("A"), etuple(mt.add, var("x"), var("b"))),
            etuplize(in_lv)),
         # rhs == A * x + A * b
         eq(
             etuple(mt.add, etuple(mt.dot, var("A"), var("x")),
                    etuple(mt.dot, var("A"), var("b"))),
             out_lv,
         ),
     )
예제 #11
0
def eval_expro(expr, env, value, depth=0, maxdepth=3):
    # logger.debug("Evaluating expr {} to {} with env {}".format(expr, value, env))
    uuid = str(uuid4())[:4]
    if isinstance(expr, ast.AST):
        logger.info("Found AST for expr -> {}".format(
            ast_dump_if_possible(expr)))
    if isinstance(value, ast.AST):
        logger.info("Found AST for value -> {}".format(
            ast_dump_if_possible(value)))

    if depth >= maxdepth:
        return fail
    # fmt: off
    return conde(
        (eq(expr, ast.Name(id=var('name_' + uuid), ctx=ast.Load())),
         lookupo(var('name_' + uuid), env, value)),
        # (lany(
        #     typeo(value, int),
        #     typeo(value, str),
        #  ),
        #  eq(expr, ast.Constant(value=value)),),
        (eq(expr, ast.Str(s=var('str_e_' + uuid))), typeo(
            value, str), eq(var('str_e_' + uuid), value)),
        (eq(expr, ast.Num(n=value)), membero(value, [_ for _ in range(5)])),
        (eq(
            expr,
            ast.BinOp(left=var('e1_' + uuid),
                      op=var('op_e_' + uuid),
                      right=var('e2_' + uuid))), typeo(var('v1_' + uuid), int),
         typeo(var('v2_' + uuid), int),
         eval_expro(var('e1_' + uuid), env, var('v1_' + uuid), depth + 1,
                    maxdepth),
         eval_expro(var('e2_' + uuid), env, var('v2_' + uuid), depth + 1,
                    maxdepth),
         eval_opo(var('op_e_' + uuid), var('op_v_' + uuid), var('v1_' + uuid),
                  var('v2_' + uuid), value),
         binopo(var('v1_' + uuid),
                var('v2_' + uuid),
                value,
                op=var('op_v_' + uuid))),

        # Lists
        (eq(expr, ast.List(elts=var("list_elements_" + uuid), ctx=ast.Load())),
         eval_expr_listo(var("list_elements_" + uuid), env, value, depth,
                         maxdepth)),

        # Functions
        (eq(expr, ast.Lambda(body=var('body_' + uuid),
                             args=[])), typeo(value, FunctionType),
         eval_expro(var('body_' + uuid), env, var('body_v_' + uuid), depth + 1,
                    maxdepth), eq(lambda: var('body_v_' + uuid), value)),
        (eq(expr, ast.Call(func=var('func_' + uuid), args=[], keywords=[])),
         typeo(var('func_v_' + uuid), FunctionType),
         eval_expro(var('func_' + uuid), env, var('func_v_' + uuid), depth + 1,
                    maxdepth), applyo(var('func_v_' + uuid), [], value)),
    )
예제 #12
0
def test_walko_misc():
    q_lv = var(prefix="q")

    expr = etuple(add, etuple(mul, 2, 1), etuple(add, 1, 1))
    res = run(0, q_lv, walko(eq, expr, expr))
    # TODO: Remove duplicates
    assert len(res) == 162

    expr2 = etuple(add, etuple(mul, 2, 1), etuple(add, 2, 1))
    res = run(0, q_lv, walko(eq, expr, expr2))
    assert len(res) == 0

    def one_to_threeo(x, y):
        return conde([eq(x, 1), eq(y, 3)])

    res = run(
        1,
        q_lv,
        walko(
            one_to_threeo,
            [1, [1, 2, 4], 2, [[4, 1, 1]], 1],
            q_lv,
        ),
    )
    assert res == ([3, [3, 2, 4], 2, [[4, 3, 3]], 3], )

    assert run(2, q_lv, walko(eq, q_lv, q_lv, null_type=ExpressionTuple)) == (
        q_lv,
        etuple(),
    )

    res = run(
        1,
        q_lv,
        walko(
            one_to_threeo,
            etuple(
                add,
                1,
                etuple(mul, etuple(add, 1, 2), 1),
                etuple(add, etuple(add, 1, 2), 2),
            ),
            q_lv,
            # Only descend into `add` terms
            rator_goal=lambda x, y: lall(eq(x, add), eq(y, add)),
        ),
    )

    assert res == (etuple(add, 3, etuple(mul, etuple(add, 1, 2), 1),
                          etuple(add, etuple(add, 3, 2), 2)), )
예제 #13
0
def non_obs_graph_applyo(relation, a, b):
    """Construct a goal that applies a relation to all nodes above an observed random variable.

    This is useful if you don't want to apply relations to an observed random
    variable, but you do want to apply them to every term above one and
    ultimately reproduce the entire graph (observed RV included).

    Parameters
    ----------
    relation: function
      A binary relation/goal constructor function
    a: lvar or meta graph
      The left-hand side of the relation.
    b: lvar or meta graph
      The right-hand side of the relation

    """
    obs_lv, obs_rv_lv = var(), var()
    rv_op_lv, rv_args_lv, obs_rv_lv = var(), var(), var()
    new_rv_args_lv, new_obs_rv_lv = var(), var()
    return lall(
        # Indicate the observed term (i.e. observation and RV)
        eq(a, mt.observed(obs_lv, obs_rv_lv)),
        # Deconstruct the observed random variable
        (buildo, rv_op_lv, rv_args_lv, obs_rv_lv),
        # Apply relation to the RV's inputs
        seq_apply_anyo(
            partial(tt_graph_applyo, relation), rv_args_lv, new_rv_args_lv, skip_op=False
        ),
        # Reconstruct the random variable
        (buildo, rv_op_lv, new_rv_args_lv, new_obs_rv_lv),
        # Reconstruct the observation
        (buildo, mt.observed, etuple(obs_lv, new_obs_rv_lv), b),
    )
예제 #14
0
def test_constant_neq():
    q_lv = var()

    res = run(0, q_lv, eq(q_lv, mt(1)), constant_neq(q_lv, np.array(1.0)))
    assert not res

    # TODO: If `constant_neq` was a true constraint, this would work.
    # res = run(0, q_lv, constant_neq(q_lv, np.array(1.0)), eq(q_lv, mt(1)))
    # assert not res

    # TODO: If `constant_neq` was a true constraint, this would work.
    # res = run(0, q_lv, constant_neq(q_lv, np.array(1.0)), eq(q_lv, mt(2)))
    # assert res == (mt(2),)

    res = run(0, q_lv, eq(q_lv, mt(2)), constant_neq(q_lv, np.array(1.0)))
    assert res == (mt(2), )
예제 #15
0
def test_disequality_basic():

    a_lv, b_lv = var(), var()

    ks = ConstrainedState()
    de = DisequalityStore({a_lv: {1}})
    ks.constraints[DisequalityStore] = de

    assert unify(a_lv, 1, ks) is False

    ks = unify(a_lv, b_lv, ks)
    assert unify(b_lv, 1, ks) is False

    res = list(lconj(neq({}, 1))({}))
    assert len(res) == 1

    res = list(lconj(neq(1, {}))({}))
    assert len(res) == 1

    res = list(lconj(neq({}, {}))({}))
    assert len(res) == 0

    res = list(lconj(neq(a_lv, 1))({}))
    assert len(res) == 1
    assert isinstance(res[0], ConstrainedState)
    assert res[0].constraints[DisequalityStore].lvar_constraints[a_lv] == {1}

    res = list(lconj(neq(1, a_lv))({}))
    assert len(res) == 1
    assert isinstance(res[0], ConstrainedState)
    assert res[0].constraints[DisequalityStore].lvar_constraints[a_lv] == {1}

    res = list(lconj(neq(a_lv, 1), neq(a_lv, 2), neq(a_lv, 1))({}))
    assert len(res) == 1
    assert isinstance(res[0], ConstrainedState)
    assert res[0].constraints[DisequalityStore].lvar_constraints[a_lv] == {1, 2}

    res = list(lconj(neq(a_lv, 1), eq(a_lv, 2))({}))
    assert len(res) == 1
    assert isinstance(res[0], ConstrainedState)
    # The constrained variable is already ground and satisfies the constraint,
    # so it should've been removed from the store
    assert a_lv not in res[0].constraints[DisequalityStore].lvar_constraints
    assert res[0][a_lv] == 2

    res = list(lconj(eq(a_lv, 1), neq(a_lv, 1))({}))
    assert res == []
예제 #16
0
def single_math_reduceo(expanded_term, reduced_term):
    """Construct a goal for some simple math reductions."""
    x_lv = var()
    return lall(
        isinstanceo(x_lv, Real),
        isinstanceo(x_lv, ExpressionTuple),
        conde(
            [
                eq(expanded_term, etuple(add, x_lv, x_lv)),
                eq(reduced_term, etuple(mul, 2, x_lv)),
            ],
            [
                eq(expanded_term, etuple(log, etuple(exp, x_lv))),
                eq(reduced_term, x_lv)
            ],
        ),
    )
예제 #17
0
def math_reduceo(in_expr, out_expr):
    """Create a relation for a couple math-based identities."""
    x_lv = var()
    x_lv.token = f'x{x_lv.token}'

    return (lall,
            conde([
                eq(in_expr, etuple(add, x_lv, x_lv)),
                eq(out_expr, etuple(mul, 2, x_lv))
            ], [
                eq(in_expr, etuple(log, etuple(exp, x_lv))),
                eq(out_expr, x_lv)
            ]),
            conde([(isinstanceo, [in_expr,
                                  (float, int, ExpressionTuple)], True)],
                  [(isinstanceo, [out_expr,
                                  (float, int, ExpressionTuple)], True)]))
예제 #18
0
def eval_opo(op, value, v1, v2, v):
    # Extra args for future use
    # fmt: off
    return conde(
        (eq(op, ast.Add()), eq(value, add)),
        (eq(op, ast.Sub()), eq(value, sub)),
        (eq(op, ast.Mult()), eq(value, mul)),
        (
            eq(op, ast.Mod()),
            neq(v2, 0),  # Prevent division by zero
            eq(value, mod)),
    )
예제 #19
0
    def binopo_goal(S: ConstrainedState):
        nonlocal x, y, v, op

        uuid = str(uuid4())[:4]
        t = var("type_" + uuid)
        x_rf, y_rf, v_rf, op_rf = reify((x, y, v, op), S)
        isground_all = [
            isground(reified_value, S)
            for reified_value in [x_rf, y_rf, v_rf, op_rf]
        ]
        if not all(isground_all):
            # We can only fix one LV at a time
            if len([uv for uv in isground_all if uv is False]) == 1:
                # TODO: Revop the other vars
                if not isground(v_rf, S):
                    try:
                        g = lall(
                            isinstanceo(x_rf, t),
                            isinstanceo(y_rf, t),
                            isinstanceo(v_rf, t),
                            eq(op_rf(x_rf, y_rf), v_rf),
                        )
                    except Exception as e:
                        logger.debug(
                            "Got exception during binop with args {}: {}".
                            format([x_rf, y_rf, v_rf, op_rf], e))
                        return
                    yield from g(S)
        else:
            # TODO: Why isnt this covered by the `typeo` goal?
            try:
                g = lall(
                    isinstanceo(x_rf, t),
                    isinstanceo(y_rf, t),
                    isinstanceo(v_rf, t),
                    eq(op_rf(x_rf, y_rf), v_rf),
                )
            except Exception as e:
                logger.debug(
                    "Got exception during ungrounded binop with args {}: {}".
                    format([x_rf, y_rf, v_rf, op_rf], e))
                return
            yield from g(S)
예제 #20
0
def test_kanren_basic():
    A_at = at.matrix("A")
    x_at = at.vector("x")

    y_at = at.dot(A_at, x_at)

    q = var()
    res = list(run(None, q, eq(y_at, etuple(_dot, q, x_at))))

    assert res == [A_at]
예제 #21
0
def test_kanren():
    # x, a, b = tt.dvectors('xab')
    #
    # with variables(x, a, b):
    #     assert b == run(1, x, eq(a + b, a + x))[0]
    #     assert b == run(1, x, eq(a * b, a * x))[0]

    a, b = mt.dvectors('ab')
    assert b == run(1, var('x'), eq(mt.add(a, b), mt.add(a, var('x'))))[0]
    assert b == run(1, var('x'), eq(mt.mul(a, b), mt.mul(a, var('x'))))[0]

    a_tt = tt.vector('a')
    R_tt = tt.matrix('R')
    F_t_tt = tt.matrix('F')
    V_tt = tt.matrix('V')
    beta_rv = MvNormalRV(a_tt, R_tt, name='\\beta')
    E_y_rv = F_t_tt.dot(beta_rv)
    Y_rv = MvNormalRV(E_y_rv, V_tt, name='y')

    beta_name_lv = var('beta_name')
    beta_size_lv = var('beta_size')
    beta_rng_lv = var('beta_rng')
    a_lv = var('a')
    R_lv = var('R')
    beta_prior_mt = mt.MvNormalRV(a_lv,
                                  R_lv,
                                  beta_size_lv,
                                  beta_rng_lv,
                                  name=beta_name_lv)

    y_name_lv = var('y_name')
    y_size_lv = var('y_size')
    y_rng_lv = var('y_rng')
    F_t_lv = var('f')
    V_lv = var('V')
    E_y_mt = mt.dot(F_t_lv, beta_prior_mt)

    Y_mt = mt.MvNormalRV(E_y_mt, V_lv, y_size_lv, y_rng_lv, name=y_name_lv)

    with variables(Y_mt):
        res, = run(0, Y_mt, (eq, Y_rv, Y_mt))
    assert res.reify() == Y_rv
예제 #22
0
def test_commutativity_tfp():

    with tf.Graph().as_default():
        mu_tf = tf.compat.v1.placeholder(tf.float32,
                                         name="mu",
                                         shape=tf.TensorShape([None]))
        tau_tf = tf.compat.v1.placeholder(tf.float32,
                                          name="tau",
                                          shape=tf.TensorShape([None]))

        normal_tfp = tfd.normal.Normal(mu_tf, tau_tf)

        value_tf = tf.compat.v1.placeholder(tf.float32,
                                            name="value",
                                            shape=tf.TensorShape([None]))

        normal_log_lik = normal_tfp.log_prob(value_tf)

    normal_log_lik_opt = normalize_tf_graph(normal_log_lik)

    with enable_lvar_defaults("names", "node_attrs"):
        tfp_normal_pattern_mt = mt_normal_log_prob(var(), var(), var())

    normal_log_lik_mt = mt(normal_log_lik)
    normal_log_lik_opt_mt = mt(normal_log_lik_opt)

    # Our pattern is the form of an unnormalized TFP normal PDF.
    assert run(0, True, eq(normal_log_lik_mt,
                           tfp_normal_pattern_mt)) == (True, )
    # Our pattern should *not* match the Grappler-optimized graph, because
    # Grappler will reorder terms (e.g. the log + constant
    # variance/normalization term)
    assert run(0, True, eq(normal_log_lik_opt_mt, tfp_normal_pattern_mt)) == ()

    # XXX: `eq_comm` is, unfortunately, order sensitive!  LHS should be ground.
    assert run(0, True, eq_comm(normal_log_lik_mt,
                                tfp_normal_pattern_mt)) == (True, )
    assert run(0, True, eq_comm(normal_log_lik_opt_mt,
                                tfp_normal_pattern_mt)) == (True, )
예제 #23
0
 def distributes(in_lv, out_lv):
     A_lv, x_lv, y_lv, z_lv = vars(4)
     return lall(
         # lhs == A * (x + y + z)
         eq_assoccomm(
             etuple(_dot, A_lv,
                    etuple(at.add, x_lv, etuple(at.add, y_lv, z_lv))),
             in_lv,
         ),
         # This relation does nothing but provide us with a means of
         # generating associative-commutative matches in the `kanren`
         # output.
         eq((A_lv, x_lv, y_lv, z_lv), out_lv),
     )
예제 #24
0
    def reduceo_goal(s):

        nonlocal in_term, out_term

        in_term_rf, out_term_rf = reify((in_term, out_term), s)

        # The result of reducing the input graph once
        term_rdcd = var()

        # Are we working "backward" and (potentially) "expanding" a graph
        # (e.g. when the relation is a reduction rule)?
        is_expanding = isvar(in_term_rf)

        # One application of the relation assigned to `term_rdcd`
        single_apply_g = (relation, in_term, term_rdcd)

        # Assign/equate (unify, really) the result of a single application to
        # the "output" term.
        single_res_g = eq(term_rdcd, out_term)

        # Recurse into applications of the relation (well, produce a goal that
        # will do that)
        another_apply_g = reduceo(relation, term_rdcd, out_term)

        # We want the fixed-point value to show up in the stream output
        # *first*, but that requires some checks.
        if is_expanding:
            # When an un-reduced term is a logic variable (e.g. we're
            # "expanding"), we can't go depth first.
            # We need to draw the association between (i.e. unify) the reduced
            # and expanded terms ASAP, in order to produce finite
            # expanded graphs first and yield results.
            #
            # In other words, there's no fixed-point to produce in this
            # situation.  Instead, for example, we have to produce an infinite
            # stream of terms that have `out_term` as a fixed point.
            # g = conde([single_res_g, single_apply_g],
            #           [another_apply_g, single_apply_g])
            g = lall(conde([single_res_g], [another_apply_g]), single_apply_g)
        else:
            # Run the recursion step first, so that we get the fixed-point as
            # the first result
            g = lall(single_apply_g, conde([another_apply_g], [single_res_g]))

        g = goaleval(g)
        yield from g(s)
예제 #25
0
    def typeo_goal(S: ConstrainedState):
        nonlocal v, t

        v_rf, t_rf = reify((v, t), S)
        isground_all = [
            isground(reified_value, S) for reified_value in [v_rf, t_rf]
        ]
        if not all(isground_all):
            if not isground(t_rf, S):
                g = eq(type(v_rf), t_rf)
                yield from g(S)
            # TODO: What if v_rf is not yet grounded?
            else:
                # g = applyo(isinstance, v_rf, t_rf)
                yield S
        else:
            if type(v_rf) == t_rf:
                yield S
예제 #26
0
def test_map_anyo_types():
    """Make sure that `map_anyo` preserves the types between its arguments."""
    q_lv = var()
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), [1], q_lv))
    assert res[0] == [1]
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), (1, ), q_lv))
    assert res[0] == (1, )
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), q_lv, (1, )))
    assert res[0] == (1, )
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), q_lv, [1]))
    assert res[0] == [1]
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), [1, 2], [1, 2]))
    assert len(res) == 1
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), [1, 2], [1, 3]))
    assert len(res) == 0
    res = run(1, q_lv, map_anyo(lambda x, y: eq(x, y), [1, 2], (1, 2)))
    assert len(res) == 0
예제 #27
0
#project 2-Author: Luke Landon-
import kanren
from kanren import run, eq, membero, var, conde, Relation, facts
import random
x = kanren.var()
print(run(1, x, eq(x, 5)))
#asks for a number x such that x is equal to z and z is equal to 3
z = kanren.var()
print(run(1, x, eq(x, z), eq(z, 3)))
#asks for a number x such that 1,2 equals 1,x
print(run(1, x, eq((1, 2), (1, x))))
#uses membero twice to ask for 2 values of x such that x is a member of 1,2,3 and that x is a member of 2,3.4
print(run(2, x, membero(x, (1, 2, 3)), membero(x, (2, 3, 4))))
#creates a logic variable
z = kanren.var('test')
print(z)
#creates multiple logic variables at once
a, b, c = var('a'), var('b'), var('c')
print(a)
print(b)
print(c)
#creates a parent relationship and uses it to state facts about who is related to who
parent = Relation()
facts(parent, ("Homer", "Bart"), ("Homer", "Lisa"), ("Abe", "Homer"))
print(run(1, x, parent(x, "Bart")))
print(run(2, x, parent("Homer", x)))
#uses intermediate variables for complex queries
y = var()
print(run(1, x, parent(x, y), parent(y, 'Bart')))

예제 #28
0
 def one_to_threeo(x, y):
     return conde([eq(x, 1), eq(y, 3)])
예제 #29
0
 def blah(x, y):
     return conde([eq(x, 1), eq(y, "a")], [eq(x, 3), eq(y, "b")])
예제 #30
0
 def test_bin(a, b):
     return conde([eq(a, 1), eq(b, 2)])