def eq_assoc(u, v, eq=core.eq, n=None): """ Goal for associative equality >>> from logpy import run, var, fact >>> from logpy.assoccomm import eq_assoc as eq >>> fact(commutative, 'add') # declare that 'add' is commutative >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> run(0, x, eq(('add', 1, 2, 3), ('add', 1, x))) (('add', 2, 3),) """ op = var() if isinstance(u, tuple) and isinstance(v, tuple): return conde([(core.eq, u, v)], [(heado, op, u), (heado, op, v), (associative, op), lambda s: assocunify(u, v, s, eq, n)]) if isinstance(u, tuple) or isinstance(v, tuple): if isinstance(v, tuple): v, u = u, v return conde([(core.eq, u, v)], [(heado, op, u), (associative, op), lambda s: assocunify(u, v, s, eq, n)]) return (core.eq, u, v)
def eq_assoc(u, v, eq=core.eq, n=None): """ Goal for associative equality >>> from logpy import run, var, fact >>> from logpy.assoccomm import eq_assoc as eq >>> fact(commutative, 'add') # declare that 'add' is commutative >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> run(0, x, eq(('add', 1, 2, 3), ('add', 1, x))) (('add', 2, 3),) """ uop, uargs = op_args(u) vop, vargs = op_args(v) if uop and vop: return conde([(core.eq, u, v)], [(eq, uop, vop), (associative, uop), lambda s: assocunify(u, v, s, eq, n)]) if uop or vop: if vop: uop, vop = vop, uop uargs, vargs = vargs, uargs v, u = u, v return conde([(core.eq, u, v)], [(associative, uop), lambda s: assocunify(u, v, s, eq, n)]) return (core.eq, u, v)
def test_run(): x, y, z = map(var, "xyz") assert run(1, x, eq(x, 1)) == (1,) assert run(2, x, eq(x, 1)) == (1,) assert run(0, x, eq(x, 1)) == (1,) assert run(1, x, eq(x, (y, z)), eq(y, 3), eq(z, 4)) == ((3, 4),) assert set(run(2, x, conde([eq(x, 1)], [eq(x, 2)]))) == set((1, 2))
def eq_assoccomm(u, v): """ Associative/Commutative eq Works like logic.core.eq but supports associative/commutative expr trees tree-format: (op, *args) example: (add, 1, 2, 3) State that operations are associative or commutative with relations >>> from logpy.assoccomm import eq_assoccomm as eq >>> from logpy.assoccomm import commutative, associative >>> from logpy import fact, run, var >>> fact(commutative, 'add') # declare that 'add' is commutative >>> x = var >>> e1 = ('add', 1, 2, 3) >>> e2 = ('add', 1, x) >>> run(0, x, eq(e1, e2)) (('add', 2, 3), ('add', 3, 2)) """ op = var() return conde(((eq, u, v),), ((opo, u, op), (opo, v, op), (conde, ((commutative, op), (eq_comm, u, v)), ((associative, op), (eq_assoc, u, v)))))
def test_run(): x, y, z = map(var, 'xyz') assert run(1, x, eq(x, 1)) == (1, ) assert run(2, x, eq(x, 1)) == (1, ) assert run(0, x, eq(x, 1)) == (1, ) assert run(1, x, eq(x, (y, z)), eq(y, 3), eq(z, 4)) == ((3, 4), ) assert set(run(2, x, conde([eq(x, 1)], [eq(x, 2)]))) == set((1, 2))
def opo(x, op): """ Operation of a tuple op((add, 1, 2), x) --> {x: add} """ h = var() return conde(((heado, h, x), (operation, h), (eq, h, op)))
def eq_assoc(u, v, eq=core.eq): """ Goal for associative equality >>> from logpy import run, var >>> from logpy.assoccomm import eq_assoc as eq >>> fact(commutative, 'add') # declare that 'add' is commutative >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> run(0, eq(('add', 1, 2, 3), ('add', 1, x))) (('add', 2, 3),) """ op = var() return conde([(core.eq, u, v)], [(heado, op, u), (heado, op, v), (associative, op), lambda s: assocunify(u, v, s, eq)])
def unify_assoccomm(u, v, s, ordering=None): u = walk(u, s) v = walk(v, s) res = unify(u, v, s) if res is not False: yield res if isinstance(u, tuple) and isinstance(v, tuple): uop, u = u[0], u[1:] vop, v = v[0], v[1:] s = unify(uop, vop, s) if s is False: raise StopIteration() op = walk(uop, s) sm, lg = (u, v) if len(u) <= len(v) else (v, u) for part in kbins(range(len(lg)), len(sm), ordering): lg2 = makeops(op, partition(lg, part)) # TODO: we use logpy code within python within logpy # There must be a more elegant way for res in conde((eq_assoccomm, a, b) for a, b in zip(sm, lg2))(s): yield res
def grandparent(x, z): y = var() return conde((parent(x, y), parent(y, z)))
def test_conde(): x = var("x") assert results(conde([eq(x, 2)], [eq(x, 3)])) == ({x: 2}, {x: 3}) assert results(conde([eq(x, 2), eq(x, 3)])) == ()
def test_conde(): x = var('x') assert tuple(conde([eq(x, 2)], [eq(x, 3)])({})) == ({x: 2}, {x: 3}) assert tuple(conde([eq(x, 2), eq(x, 3)])({})) == ()
def test_conde(): x = var('x') assert results(conde([eq(x, 2)], [eq(x, 3)])) == ({x: 2}, {x: 3}) assert results(conde([eq(x, 2), eq(x, 3)])) == ()
def operation(op): """ Either an associative or commutative operation """ return conde([commutative(op)], [associative(op)])