def eq_comm(u, v, eq=None): """ Goal for commutative equality >>> from logpy import run, var, fact >>> from logpy.assoccomm import eq_comm as eq >>> from logpy.assoccomm import commutative, associative >>> 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', 2, x, 1))) (3,) """ eq = eq or eq_comm op = var() utail = var() vtail = var() if isvar(u) and isvar(v): return (core.eq, u, v) raise EarlyGoalError() uop, uargs = op_args(u) vop, vargs = op_args(v) if not uop and not vop: return (core.eq, u, v) if vop and not uop: uop, uargs = vop, vargs v, u = u, v return (conde, ((core.eq, u, v),), ((commutative, uop), (buildo, uop, vtail, v), (permuteq, uargs, vtail, eq)))
def eq_comm(u, v, eq=None): """ Goal for commutative equality >>> from logpy import run, var, fact >>> from logpy.assoccomm import eq_comm as eq >>> from logpy.assoccomm import commutative, associative >>> 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', 2, x, 1))) (3,) """ eq = eq or eq_comm op = var() utail = var() vtail = var() if isvar(u) and isvar(v): return (core.eq, u, v) raise EarlyGoalError() if isinstance(v, tuple) and not isinstance(u, tuple): u, v = v, u return (conde, ((core.eq, u, v),), ((heado, op, u), (commutative, op), (tailo, utail, u), (conso, op, vtail, v), (seteq, utail, vtail, eq)))
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 >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> e1 = ('add', 1, 2, 3) >>> e2 = ('add', 1, x) >>> run(0, x, eq(e1, e2)) (('add', 2, 3), ('add', 3, 2)) """ try: uop, uargs = op_args(u) vop, vargs = op_args(v) except ValueError: return (eq, u, v) if uop and not vop and not isvar(v): return fail if vop and not uop and not isvar(u): return fail if uop and vop and not uop == vop: return fail if uop and not (uop,) in associative.facts: return (eq, u, v) if vop and not (vop,) in associative.facts: return (eq, u, v) if uop and vop: u, v = (u, v) if len(uargs) >= len(vargs) else (v, u) n = min(map(len, (uargs, vargs))) # length of shorter tail else: n = None if vop and not uop: u, v = v, u w = var() return (lall, (eq_assoc, u, w, eq_assoccomm, n), (eq_comm, v, w, eq_assoccomm))
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 >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> e1 = ('add', 1, 2, 3) >>> e2 = ('add', 1, x) >>> run(0, x, eq(e1, e2)) (('add', 2, 3), ('add', 3, 2)) """ for typ, fn in seq_registry: if isinstance(u, typ): u = fn(u) if isinstance(v, typ): v = fn(v) if isinstance(u, tuple) and not isinstance(v, tuple) and not isvar(v): return fail if isinstance(v, tuple) and not isinstance(u, tuple) and not isvar(u): return fail if isinstance(u, tuple) and isinstance(v, tuple) and not u[0] == v[0]: return fail if isinstance(u, tuple) and not (u[0],) in associative.facts: return (eq, u, v) if isinstance(v, tuple) and not (v[0],) in associative.facts: return (eq, u, v) if isinstance(u, tuple) and isinstance(v, tuple): u, v = (u, v) if len(u) >= len(v) else (v, u) n = len(v)-1 # length of shorter tail else: n = None if isinstance(v, tuple) and not isinstance(u, tuple): u, v = v, u w = var() return lall((eq_assoc, u, w, eq_assoccomm, n), (eq_comm, v, w, eq_assoccomm))
def op_args(x): """ Break apart x into an operation and tuple of args """ if isvar(x): return None, None try: return operator(x), arguments(x) except NotImplementedError: return None, None
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 >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> e1 = ('add', 1, 2, 3) >>> e2 = ('add', 1, x) >>> run(0, x, eq(e1, e2)) (('add', 2, 3), ('add', 3, 2)) """ if isinstance(u, tuple) and not isinstance(v, tuple) and not isvar(v): return fail if isinstance(v, tuple) and not isinstance(u, tuple) and not isvar(u): return fail if isinstance(u, tuple) and isinstance(v, tuple) and not u[0] == v[0]: return fail if isinstance(u, tuple) and not (u[0],) in associative.facts: return (eq, u, v) if isinstance(v, tuple) and not (v[0],) in associative.facts: return (eq, u, v) if isinstance(u, tuple) and isinstance(v, tuple): u, v = (u, v) if len(u) >= len(v) else (v, u) n = len(v)-1 # length of shorter tail else: n = None if isinstance(v, tuple) and not isinstance(u, tuple): u, v = v, u w = var() return lall((eq_assoc, u, w, eq_assoccomm, n), (eq_comm, v, w, eq_assoccomm))
def op_args(x, registry=op_registry): """ Break apart x into an operation and tuple of args """ if isvar(x): return None, None if hasattr(x, '_as_logpy') and not isinstance(x, type): return x._as_logpy() for d in registry: if d['objvalid'](x): return d['op'](x), d['args'](x) return None, None
def goal(x, y, z): if not isvar(x) and not isvar(y): return eq(op(x, y), z) if not isvar(y) and not isvar(z) and revop: return eq(x, revop(z, y)) if not isvar(x) and not isvar(z) and revop: return eq(y, revop(z, x)) raise EarlyGoalError()
def buildo(op, args, obj): """ obj is composed of op on args Example: in add(1,2,3) ``add`` is the op and (1,2,3) are the args Checks op_regsitry for functions to define op/arg relationships """ if not isvar(obj): oop, oargs = op_args(obj) return lall((eq, op, oop), (eq, args, oargs)) else: try: return eq(obj, build(op, args)) except TypeError: raise EarlyGoalError() raise EarlyGoalError()
def check_prime(x): if lc.isvar(x): return lc.condeseq([(lc.eq, x, p)] for p in map(prime, it.count(1))) else: return lc.success if isprime(x) else lc.fail
def primo(x): """ x is a prime number """ if isvar(x): return condeseq([(eq, x, p)] for p in it.imap(prime, it.count(1))) else: return success if isprime(x) else fail
def gt(x, y): """ x > y """ if not isvar(x) and not isvar(y): return eq(x > y, True) else: raise EarlyGoalError()
def _primo(x): if isvar(x): return lambda s: (assoc(s, x, p) for p in it.imap(prime, it.count(1))) else: return success if isprime(x) else fail
def test_isvar(): assert not isvar(3) assert isvar(var(3))