def diff(y, x): """Return the symbolic derivative, dy/dx, as an Expr. However, you probably want to simplify the results with simp. >>> diff(x * x, x) ((x * 1) + (x * 1)) >>> simp(diff(x * x, x)) (2 * x) """ if y == x: return ONE elif not y.args: return ZERO else: u, op, v = y.args[0], y.op, y.args[-1] if op == '+': return diff(u, x) + diff(v, x) elif op == '-' and len(args) == 1: return -diff(u, x) elif op == '-': return diff(u, x) - diff(v, x) elif op == '*': return u * diff(v, x) + v * diff(u, x) elif op == '/': return (v * diff(u, x) - u * diff(v, x)) / (v * v) elif op == '**' and utils_lpw.isnumber(x.op): return (v * u**(v - 1) * diff(u, x)) elif op == '**': return (v * u**(v - 1) * diff(u, x) + u**v * Expr('log')(u) * diff(v, x)) elif op == 'log': return diff(u, x) / u else: raise ValueError("Unknown op: %s in diff(%s, %s)" % (op, y, x))
def expr(s): """Create an Expr representing a logic expression by parsing the input string. Symbols and numbers are automatically converted to Exprs. In addition you can use alternative spellings of these operators: 'x ==> y' parses as (x >> y) # Implication 'x <== y' parses as (x << y) # Reverse implication 'x <=> y' parses as (x % y) # Logical equivalence 'x =/= y' parses as (x ^ y) # Logical disequality (xor) But BE CAREFUL; precedence of implication is wrong. expr('P & Q ==> R & S') is ((P & (Q >> R)) & S); so you must use expr('(P & Q) ==> (R & S)'). >>> expr('P <=> Q(1)') (P <=> Q(1)) >>> expr('P & Q | ~R(x, F(x))') ((P & Q) | ~R(x, F(x))) """ if isinstance(s, Expr): return s if utils_lpw.isnumber(s): return Expr(s) ## Replace the alternative spellings of operators with canonical spellings s = s.replace('==>', '>>').replace('<==', '<<') s = s.replace('<=>', '%').replace('=/=', '^') ## Replace a symbol or number, such as 'P' with 'Expr("P")' s = re.sub(r'([a-zA-Z0-9_.]+)', r'Expr("\1")', s) ## Now eval the string. (A security hole; do not use with an adversary.) return eval(s, {'Expr': Expr})
def __init__(self, op, *args): "Op is a string or number; args are Exprs (or are coerced to Exprs)." assert isinstance(op, str) or (utils_lpw.isnumber(op) and not args) self.op = utils_lpw.num_or_str(op) self.args = map(expr, args) ## Coerce args to Exprs