def mrv(e, x): """Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e', and e rewritten in terms of these""" e = powsimp(e, deep=True, combine='exp') assert isinstance(e, Basic) if not e.has(x): return SubsSet(), e elif e == x: s = SubsSet() return s, s[x] elif e.is_Mul or e.is_Add: i, d = e.as_independent(x) # throw away x-independent terms if d.func != e.func: s, expr = mrv(d, x) return s, e.func(i, expr) a, b = d.as_two_terms() s1, e1 = mrv(a, x) s2, e2 = mrv(b, x) return mrv_max1(s1, s2, e.func(i, e1, e2), x) elif e.is_Pow: b, e = e.as_base_exp() if e.has(x): return mrv(exp(e * log(b)), x) else: s, expr = mrv(b, x) return s, expr**e elif e.func is log: s, expr = mrv(e.args[0], x) return s, log(expr) elif e.func is exp: # We know from the theory of this algorithm that exp(log(...)) may always # be simplified here, and doing so is vital for termination. if e.args[0].func is log: return mrv(e.args[0].args[0], x) if limitinf(e.args[0], x).is_unbounded: s1 = SubsSet() e1 = s1[e] s2, e2 = mrv(e.args[0], x) su = s1.union(s2)[0] su.rewrites[e1] = exp(e2) return mrv_max3(s1, e1, s2, exp(e2), su, e1, x) else: s, expr = mrv(e.args[0], x) return s, exp(expr) elif e.is_Function: l = [mrv(a, x) for a in e.args] l2 = [s for (s, _) in l if s != SubsSet()] if len(l2) != 1: # e.g. something like BesselJ(x, x) raise NotImplementedError("MRV set computation for functions in" " several variables not implemented.") s, ss = l2[0], SubsSet() args = [ss.do_subs(x[1]) for x in l] return s, e.func(*args) elif e.is_Derivative: raise NotImplementedError("MRV set computation for derviatives" " not implemented yet.") return mrv(e.args[0], x) raise NotImplementedError( "Don't know how to calculate the mrv of '%s'" % e)
def test_functions_basic(): assert oclcode(abs(i)) == "abs(i)" assert oclcode(abs(x)) == "fabs(x)" assert oclcode(log(x)) == "log(x)" assert oclcode(log(x, 2)) == "log2(x)" assert oclcode(log(x, 10)) == "log10(x)" assert oclcode(log(x, 3)) == "log(x)/log(3)"
def _generate_patterns(): """ Generates patterns for transcendental equations. This is lazily calculated (called) in the tsolve() function and stored in the patterns global variable. """ tmp1 = _f ** (_h-(_c*_g/_b)) tmp2 = (-_e*tmp1/_a)**(1/_d) global _patterns _patterns = [ (_a*(_b*_x+_c)**_d + _e , ((-(_e/_a))**(1/_d)-_c)/_b), (_b+_c*exp(_d*_x+_e) , (log(-_b/_c)-_e)/_d), (_a*_x+_b+_c*exp(_d*_x+_e) , -_b/_a-LambertW(_c*_d*exp(_e-_b*_d/_a)/_a)/_d), (_b+_c*_f**(_d*_x+_e) , (log(-_b/_c)-_e*log(_f))/_d/log(_f)), (_a*_x+_b+_c*_f**(_d*_x+_e) , -_b/_a-LambertW(_c*_d*_f**(_e-_b*_d/_a)*log(_f)/_a)/_d/log(_f)), (_b+_c*log(_d*_x+_e) , (exp(-_b/_c)-_e)/_d), (_a*_x+_b+_c*log(_d*_x+_e) , -_e/_d+_c/_a*LambertW(_a/_c/_d*exp(-_b/_c+_a*_e/_c/_d))), (_a*(_b*_x+_c)**_d + _e*_f**(_g*_x+_h) , -_c/_b-_d*LambertW(-tmp2*_g*log(_f)/_b/_d)/_g/log(_f)) ]
def test_2(): test = [ [(a + b*x)/x, x, S(2), b*x + a*log(x)], [x**S(5)/(a + b*x), x, S(2), a**S(4)*x/b**S(5) - S(1)/S(2)*a**S(3)*x**S(2)/b**S(4) + S(1)/S(3)*a**S(2)*x**S(3)/b**S(3) - S(1)/S(4)*a*x**S(4)/b**S(2) + S(1)/S(5)*x**S(5)/b - a**S(5)*log(a + b*x)/b**S(6)], [S(1)/(a + b*x)**S(2), x, S(1), ( - S(1))/(b*(a + b*x))], [S(1)/(x*(a + b*x)**S(3)), x, S(2), S(1)/S(2)/(a*(a + b*x)**S(2)) + S(1)/(a**S(2)*(a + b*x)) + log(x)/a**S(3) - log(a + b*x)/a**S(3)], [S(1)/(S(2) + S(2)*x), x, S(1), S(1)/S(2)*log(S(1) + x)], [S(1)/(x*(S(1) + b*x)), x, S(3), log(x) - log(S(1) + b*x)], [x**S(3)*sqrt(a + b*x), x, S(2), - S(2)/S(3)*a**S(3)*(a + b*x)**(S(3)/S(2))/b**S(4) + S(6)/S(5)*a**S(2)*(a + b*x)**(S(5)/S(2))/b**S(4) - S(6)/S(7)*a*(a + b*x)**(S(7)/S(2))/b**S(4) + S(2)/S(9)*(a + b*x)**(S(9)/S(2))/b**S(4)], [(a + b*x)**(S(3)/S(2)), x, S(1), S(2)/S(5)*(a + b*x)**(S(5)/S(2))/b], [x**S(4)/sqrt(a + b*x), x, S(2), - S(8)/S(3)*a**S(3)*(a + b*x)**(S(3)/S(2))/b**S(5) + S(12)/S(5)*a**S(2)*(a + b*x)**(S(5)/S(2))/b**S(5) - S(8)/S(7)*a*(a + b*x)**(S(7)/S(2))/b**S(5) + S(2)/S(9)*(a + b*x)**(S(9)/S(2))/b**S(5) + S(2)*a**S(4)*sqrt(a + b*x)/b**S(5)], [S(1)/sqrt(a + b*x), x, S(1), S(2)*sqrt(a + b*x)/b], [S(1)/(x*(a + b*x)**(S(3)/S(2))), x, S(3), - S(2)*arctanh(sqrt(a + b*x)/sqrt(a))/a**(S(3)/S(2)) + S(2)/(a*sqrt(a + b*x))], [S(1)/(x**S(2)*( - a + b*x)**(S(3)/S(2))), x, S(4), - S(3)*b*arctan(sqrt( - a + b*x)/sqrt(a))/a**(S(5)/S(2)) + ( - S(2))/(a*x*sqrt( - a + b*x)) - S(3)*sqrt( - a + b*x)/(a**S(2)*x)], [x**S(3)*(a + b*x)**(S(1)/S(3)), x, S(2), - S(3)/S(4)*a**S(3)*(a + b*x)**(S(4)/S(3))/b**S(4) + S(9)/S(7)*a**S(2)*(a + b*x)**(S(7)/S(3))/b**S(4) - S(9)/S(10)*a*(a + b*x)**(S(10)/S(3))/b**S(4) + S(3)/S(13)*(a + b*x)**(S(13)/S(3))/b**S(4)], [x**S(2)*(a + b*x)**(S(2)/S(3)), x, S(2), S(3)/S(5)*a**S(2)*(a + b*x)**(S(5)/S(3))/b**S(3) - S(3)/S(4)*a*(a + b*x)**(S(8)/S(3))/b**S(3) + S(3)/S(11)*(a + b*x)**(S(11)/S(3))/b**S(3)], [x**S(2)/(a + b*x)**(S(1)/S(3)), x, S(2), S(3)/S(2)*a**S(2)*(a + b*x)**(S(2)/S(3))/b**S(3) - S(6)/S(5)*a*(a + b*x)**(S(5)/S(3))/b**S(3) + S(3)/S(8)*(a + b*x)**(S(8)/S(3))/b**S(3)], [x**S(3)/( - a + b*x)**(S(1)/S(3)), x, S(2), S(3)/S(2)*a**S(3)*( - a + b*x)**(S(2)/S(3))/b**S(4) + S(9)/S(5)*a**S(2)*( - a + b*x)**(S(5)/S(3))/b**S(4) + S(9)/S(8)*a*( - a + b*x)**(S(8)/S(3))/b**S(4) + S(3)/S(11)*( - a + b*x)**(S(11)/S(3))/b**S(4)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True)
def test_log(): R, x = ring('x', QQ) p = 1 + x p1 = rs_log(p, x, 4)/x**2 assert p1 == S(1)/3*x - S(1)/2 + x**(-1) p = 1 + x +2*x**2/3 p1 = rs_log(p, x, 9) assert p1 == -17*x**8/648 + 13*x**7/189 - 11*x**6/162 - x**5/45 + \ 7*x**4/36 - x**3/3 + x**2/6 + x p2 = rs_series_inversion(p, x, 9) p3 = rs_log(p2, x, 9) assert p3 == -p1 R, x, y = ring('x, y', QQ) p = 1 + x + 2*y*x**2 p1 = rs_log(p, x, 6) assert p1 == (4*x**5*y**2 - 2*x**5*y - 2*x**4*y**2 + x**5/5 + 2*x**4*y - x**4/4 - 2*x**3*y + x**3/3 + 2*x**2*y - x**2/2 + x) # Constant term in series a = symbols('a') R, x, y = ring('x, y', EX) assert rs_log(x + a, x, 5) == -EX(1/(4*a**4))*x**4 + EX(1/(3*a**3))*x**3 \ - EX(1/(2*a**2))*x**2 + EX(1/a)*x + EX(log(a)) assert rs_log(x + x**2*y + a, x, 4) == -EX(a**(-2))*x**3*y + \ EX(1/(3*a**3))*x**3 + EX(1/a)*x**2*y - EX(1/(2*a**2))*x**2 + \ EX(1/a)*x + EX(log(a)) p = x + x**2 + 3 assert rs_log(p, x, 10).compose(x, 5) == EX(log(3) + S(19281291595)/9920232)
def dig(self): """ Number of decimal digits that are guaranteed to be preserved in text. When converting text -> float -> text, you are guaranteed that at least ``dig`` number of digits are preserved with respect to rounding or overflow. """ from sympy.functions import floor, log return floor(self.nmant * log(2)/log(10))
def compare(a,b,x): """Returns "<" if a<b, "=" for a==b, ">" for a>b""" c = limitinf(log(a)/log(b), x) if c == 0: return "<" elif c in [oo,-oo]: return ">" else: return "="
def decimal_dig(self): """ Number of digits needed to store & load without loss. Number of decimal digits needed to guarantee that two consecutive conversions (float -> text -> float) to be idempotent. This is useful when one do not want to loose precision due to rounding errors when storing a floating point value as text. """ from sympy.functions import ceiling, log return ceiling((self.nmant + 1) * log(2)/log(10) + 1)
def test_trigintegrate_mixed(): assert trigintegrate(sin(x)*sec(x), x) == -log(sin(x)**2 - 1)/2 assert trigintegrate(sin(x)*csc(x), x) == x assert trigintegrate(sin(x)*cot(x), x) == sin(x) assert trigintegrate(cos(x)*sec(x), x) == x assert trigintegrate(cos(x)*csc(x), x) == log(cos(x)**2 - 1)/2 assert trigintegrate(cos(x)*tan(x), x) == -cos(x) assert trigintegrate(cos(x)*cot(x), x) == log(cos(x) - 1)/2 \ - log(cos(x) + 1)/2 + cos(x)
def rs_log(p, x, prec): """ The Logarithm of ``p`` modulo ``O(x**prec)`` Notes ===== truncation of ``integral dx p**-1*d p/dx`` is used. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_log >>> R, x = ring('x', QQ) >>> rs_log(1 + x, x, 8) 1/7*x**7 - 1/6*x**6 + 1/5*x**5 - 1/4*x**4 + 1/3*x**3 - 1/2*x**2 + x >>> rs_log(x**QQ(3, 2) + 1, x, 5) 1/3*x**(9/2) - 1/2*x**3 + x**(3/2) """ if rs_is_puiseux(p, x): return rs_puiseux(rs_log, p, x, prec) R = p.ring if p == 1: return R.zero if _has_constant_term(p, x): const = 0 zm = R.zero_monom c = p[zm] if c == 1: pass else: c_expr = c.as_expr() if R.domain is EX: const = log(c_expr) elif isinstance(c, PolyElement): try: const = R(log(c_expr)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") else: try: const = R(log(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") dlog = p.diff(x) dlog = rs_mul(dlog, _series_inversion1(p, x, prec), x, prec - 1) return rs_integrate(dlog, x) + const else: raise NotImplementedError
def test_variable_moment(): E = Symbol('E') I = Symbol('I') b = Beam(4, E, 2*(4 - x)) b.apply_load(20, 4, -1) R, M = symbols('R, M') b.apply_load(R, 0, -1) b.apply_load(M, 0, -2) b.bc_deflection = [(0, 0)] b.bc_slope = [(0, 0)] b.solve_for_reaction_loads(R, M) assert b.slope().expand() == ((10*x*SingularityFunction(x, 0, 0) - 10*(x - 4)*SingularityFunction(x, 4, 0))/E).expand() assert b.deflection().expand() == ((5*x**2*SingularityFunction(x, 0, 0) - 10*Piecewise((0, Abs(x)/4 < 1), (16*meijerg(((3, 1), ()), ((), (2, 0)), x/4), True)) + 40*SingularityFunction(x, 4, 1))/E).expand() b = Beam(4, E - x, I) b.apply_load(20, 4, -1) R, M = symbols('R, M') b.apply_load(R, 0, -1) b.apply_load(M, 0, -2) b.bc_deflection = [(0, 0)] b.bc_slope = [(0, 0)] b.solve_for_reaction_loads(R, M) assert b.slope().expand() == ((-80*(-log(-E) + log(-E + x))*SingularityFunction(x, 0, 0) + 80*(-log(-E + 4) + log(-E + x))*SingularityFunction(x, 4, 0) + 20*(-E*log(-E) + E*log(-E + x) + x)*SingularityFunction(x, 0, 0) - 20*(-E*log(-E + 4) + E*log(-E + x) + x - 4)*SingularityFunction(x, 4, 0))/I).expand()
def test_rubi_integrate(): assert rubi_integrate(x, x) == x**2/2 assert rubi_integrate(x**a, x) == x**(a + S(1))/(a + S(1)) assert rubi_integrate(S(1)/x, x) == log(x) assert rubi_integrate(a*x, x) == a*(S(1)/S(2))*x**S(2) assert rubi_integrate(1/(x**2*(a + b*x)**2), x) == -b/(a**2*(a + b*x)) - 1/(a**2*x) - 2*b*log(x)/a**3 + 2*b*log(a + b*x)/a**3 assert rubi_integrate(x**6/(a + b*x)**2, x) == (-a**6/(b**7*(a + b*x)) - S(6)*a**5*log(a + b*x)/b**7 + 5*a**4*x/b**6 - S(2)*a**3*x**2/b**5 + a**2*x**3/b**4 - a*x**4/(S(2)*b**3) + x**5/(S(5)*b**2)) assert rubi_integrate(1/(x**2*(a + b*x)**2), x) == -b/(a**2*(a + b*x)) - 1/(a**2*x) - 2*b*log(x)/a**3 + 2*b*log(a + b*x)/a**3 assert rubi_integrate(a + S(1)/x, x) == a*x + log(x) assert rubi_integrate((a + b*x)**2/x**3, x) == -a**2/(2*x**2) - 2*a*b/x + b**2*log(x) assert rubi_integrate(a**3*x, x) == S(1)/S(2)*a**3*x**2 assert rubi_integrate((a + b*x)**3/x**3, x) == -a**3/(2*x**2) - 3*a**2*b/x + 3*a*b**2*log(x) + b**3*x assert rubi_integrate(x**3*(a + b*x), x) == a*x**4/4 + b*x**5/5 assert rubi_integrate((b*x)**m*(d*x + 2)**n, x) == 2**n*(b*x)**(m + 1)*hyper((-n, m + 1), (m + 2,), -d*x/2)/(b*(m + 1)) assert rubi_test(rubi_integrate(1/(1 + x**5), x), x, log(x + S(1))/S(5) + S(2)*Sum(-log((S(2)*x - S(2)*cos(pi*(S(2)*k/S(5) + S(-1)/5)))**S(2) - S(4)*sin(S(2)*pi*k/S(5) + S(3)*pi/S(10))**S(2) + S(4))*cos(pi*(S(2)*k/S(5) + S(-1)/5))/S(2) - (-S(2)*cos(pi*(S(2)*k/S(5) + S(-1)/5))**S(2) + S(2))*atan((-x/cos(pi*(S(2)*k/S(5) + S(-1)/5)) + S(1))/sqrt(-(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(-1))*(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(1))/cos(S(2)*pi*k/S(5) - pi/S(5))**S(2)))/(S(2)*sqrt(-(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(-1))*(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(1))/cos(S(2)*pi*k/S(5) - pi/S(5))**S(2))*cos(pi*(S(2)*k/S(5) + S(-1)/5))), (k, S(1), S(2)))/S(5), _numerical=True)
def test_bounded(): x, y = symbols('x,y') assert ask(Q.bounded(x)) == False assert ask(Q.bounded(x), Q.bounded(x)) == True assert ask(Q.bounded(x), Q.bounded(y)) == False assert ask(Q.bounded(x), Q.complex(x)) == False assert ask(Q.bounded(x+1)) == False assert ask(Q.bounded(x+1), Q.bounded(x)) == True assert ask(Q.bounded(x+y)) == None assert ask(Q.bounded(x+y), Q.bounded(x)) == False assert ask(Q.bounded(x+1), Q.bounded(x) & Q.bounded(y)) == True assert ask(Q.bounded(2*x)) == False assert ask(Q.bounded(2*x), Q.bounded(x)) == True assert ask(Q.bounded(x*y)) == None assert ask(Q.bounded(x*y), Q.bounded(x)) == False assert ask(Q.bounded(x*y), Q.bounded(x) & Q.bounded(y)) == True assert ask(Q.bounded(x**2)) == False assert ask(Q.bounded(2**x)) == False assert ask(Q.bounded(2**x), Q.bounded(x)) == True assert ask(Q.bounded(x**x)) == False assert ask(Q.bounded(Rational(1,2) ** x)) == None assert ask(Q.bounded(Rational(1,2) ** x), Q.positive(x)) == True assert ask(Q.bounded(Rational(1,2) ** x), Q.negative(x)) == False assert ask(Q.bounded(sqrt(x))) == False # sign function assert ask(Q.bounded(sign(x))) == True assert ask(Q.bounded(sign(x)), ~Q.bounded(x)) == True # exponential functions assert ask(Q.bounded(log(x))) == False assert ask(Q.bounded(log(x)), Q.bounded(x)) == True assert ask(Q.bounded(exp(x))) == False assert ask(Q.bounded(exp(x)), Q.bounded(x)) == True assert ask(Q.bounded(exp(2))) == True # trigonometric functions assert ask(Q.bounded(sin(x))) == True assert ask(Q.bounded(sin(x)), ~Q.bounded(x)) == True assert ask(Q.bounded(cos(x))) == True assert ask(Q.bounded(cos(x)), ~Q.bounded(x)) == True assert ask(Q.bounded(2*sin(x))) == True assert ask(Q.bounded(sin(x)**2)) == True assert ask(Q.bounded(cos(x)**2)) == True assert ask(Q.bounded(cos(x) + sin(x))) == True
def test_bounded(): x, y = symbols('xy') assert ask(x, Q.bounded) == False assert ask(x, Q.bounded, Assume(x, Q.bounded)) == True assert ask(x, Q.bounded, Assume(y, Q.bounded)) == False assert ask(x, Q.bounded, Assume(x, Q.complex)) == False assert ask(x+1, Q.bounded) == False assert ask(x+1, Q.bounded, Assume(x, Q.bounded)) == True assert ask(x+y, Q.bounded) == None assert ask(x+y, Q.bounded, Assume(x, Q.bounded)) == False assert ask(x+1, Q.bounded, Assume(x, Q.bounded) & \ Assume(y, Q.bounded)) == True assert ask(2*x, Q.bounded) == False assert ask(2*x, Q.bounded, Assume(x, Q.bounded)) == True assert ask(x*y, Q.bounded) == None assert ask(x*y, Q.bounded, Assume(x, Q.bounded)) == False assert ask(x*y, Q.bounded, Assume(x, Q.bounded) & \ Assume(y, Q.bounded)) == True assert ask(x**2, Q.bounded) == False assert ask(2**x, Q.bounded) == False assert ask(2**x, Q.bounded, Assume(x, Q.bounded)) == True assert ask(x**x, Q.bounded) == False assert ask(Rational(1,2) ** x, Q.bounded) == True assert ask(x ** Rational(1,2), Q.bounded) == False # sign function assert ask(sign(x), Q.bounded) == True assert ask(sign(x), Q.bounded, Assume(x, Q.bounded, False)) == True # exponential functions assert ask(log(x), Q.bounded) == False assert ask(log(x), Q.bounded, Assume(x, Q.bounded)) == True assert ask(exp(x), Q.bounded) == False assert ask(exp(x), Q.bounded, Assume(x, Q.bounded)) == True assert ask(exp(2), Q.bounded) == True # trigonometric functions assert ask(sin(x), Q.bounded) == True assert ask(sin(x), Q.bounded, Assume(x, Q.bounded, False)) == True assert ask(cos(x), Q.bounded) == True assert ask(cos(x), Q.bounded, Assume(x, Q.bounded, False)) == True assert ask(2*sin(x), Q.bounded) == True assert ask(sin(x)**2, Q.bounded) == True assert ask(cos(x)**2, Q.bounded) == True assert ask(cos(x) + sin(x), Q.bounded) == True
def mrv_leadterm(e, x, Omega=[]): """Returns (c0, e0) for e.""" if not e.has(x): return (e, S.Zero) Omega = [t for t in Omega if subexp(e, t)] if Omega == []: Omega = mrv(e, x) if not Omega: # e really does not depend on x after simplification series = calculate_series(e, x) c0, e0 = series.leadterm(x) assert e0 == 0 return c0, e0 if x in set(Omega): # move the whole omega up (exponentiate each term): Omega_up = set(moveup(Omega, x)) e_up = moveup([e], x)[0] # calculate the lead term mrv_leadterm_up = mrv_leadterm(e_up, x, Omega_up) # move the result (c0, e0) down return tuple(movedown(mrv_leadterm_up, x)) # # The positive dummy, w, is used here so log(w*2) etc. will expand; # a unique dummy is needed in this algorithm # # For limits of complex functions, the algorithm would have to be # improved, or just find limits of Re and Im components separately. # w = Dummy("w", real=True, positive=True) f, logw = rewrite(e, set(Omega), x, w) series = calculate_series(f, w) series = series.subs(log(w), logw) return series.leadterm(w)
def mrv_leadterm(e, x): """Returns (c0, e0) for e.""" Omega = SubsSet() if not e.has(x): return (e, S.Zero) if Omega == SubsSet(): Omega, exps = mrv(e, x) if not Omega: # e really does not depend on x after simplification series = calculate_series(e, x) c0, e0 = series.leadterm(x) assert e0 == 0 return c0, e0 if x in Omega: #move the whole omega up (exponentiate each term): Omega_up = moveup2(Omega, x) e_up = moveup([e], x)[0] exps_up = moveup([exps], x)[0] # NOTE: there is no need to move this down! e = e_up Omega = Omega_up exps = exps_up # # The positive dummy, w, is used here so log(w*2) etc. will expand; # a unique dummy is needed in this algorithm # # For limits of complex functions, the algorithm would have to be # improved, or just find limits of Re and Im components separately. # w = Dummy("w", real=True, positive=True, bounded=True) f, logw = rewrite(exps, Omega, x, w) series = calculate_series(f, w, logx=logw) series = series.subs(log(w), logw) # this should not be necessary return series.leadterm(w)
def compare(a, b, x): """Returns "<" if a<b, "=" for a == b, ">" for a>b""" # log(exp(...)) must always be simplified here for termination la, lb = log(a), log(b) if isinstance(a, Basic) and a.func is exp: la = a.args[0] if isinstance(b, Basic) and b.func is exp: lb = b.args[0] c = limitinf(la/lb, x) if c == 0: return "<" elif c.is_unbounded: return ">" else: return "="
def mrv(e, x): "Returns a python set of most rapidly varying (mrv) subexpressions of 'e'" assert isinstance(e, Basic) if not e.has(x): return set([]) elif e == x: return set([x]) elif e.is_Mul: a, b = e.as_two_terms() return mrv_max(mrv(a,x), mrv(b,x), x) elif e.is_Add: a, b = e.as_two_terms() return mrv_max(mrv(a,x), mrv(b,x), x) elif e.is_Pow: if e.exp.has(x): return mrv(exp(e.exp * log(e.base)), x) else: return mrv(e.base, x) elif e.func is log: return mrv(e.args[0], x) elif e.func is exp: if limitinf(e.args[0], x) in [oo,-oo]: return mrv_max(set([e]), mrv(e.args[0], x), x) else: return mrv(e.args[0], x) elif e.is_Function: if len(e.args) == 1: return mrv(e.args[0], x) #only functions of 1 argument currently implemented raise NotImplementedError("Functions with more arguments: '%s'" % e) raise NotImplementedError("Don't know how to calculate the mrv of '%s'" % e)
def test_catalan(): n = Symbol('n', integer=True) m = Symbol('n', integer=True, positive=True) catalans = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786] for i, c in enumerate(catalans): assert catalan(i) == c assert catalan(n).rewrite(factorial).subs(n, i) == c assert catalan(n).rewrite(Product).subs(n, i).doit() == c assert catalan(x) == catalan(x) assert catalan(2*x).rewrite(binomial) == binomial(4*x, 2*x)/(2*x + 1) assert catalan(Rational(1, 2)).rewrite(gamma) == 8/(3*pi) assert catalan(Rational(1, 2)).rewrite(factorial).rewrite(gamma) ==\ 8 / (3 * pi) assert catalan(3*x).rewrite(gamma) == 4**( 3*x)*gamma(3*x + Rational(1, 2))/(sqrt(pi)*gamma(3*x + 2)) assert catalan(x).rewrite(hyper) == hyper((-x + 1, -x), (2,), 1) assert catalan(n).rewrite(factorial) == factorial(2*n) / (factorial(n + 1) * factorial(n)) assert isinstance(catalan(n).rewrite(Product), catalan) assert isinstance(catalan(m).rewrite(Product), Product) assert diff(catalan(x), x) == (polygamma( 0, x + Rational(1, 2)) - polygamma(0, x + 2) + log(4))*catalan(x) assert catalan(x).evalf() == catalan(x) c = catalan(S.Half).evalf() assert str(c) == '0.848826363156775' c = catalan(I).evalf(3) assert str((re(c), im(c))) == '(0.398, -0.0209)'
def test_trigintegrate_odd(): assert trigintegrate(Rational(1), x) == x assert trigintegrate(x, x) is None assert trigintegrate(x**2, x) is None assert trigintegrate(sin(x), x) == -cos(x) assert trigintegrate(cos(x), x) == sin(x) assert trigintegrate(sin(3*x), x) == -cos(3*x)/3 assert trigintegrate(cos(3*x), x) == sin(3*x)/3 y = Symbol('y') assert trigintegrate(sin(y*x), x) == \ Piecewise((0, Eq(y, 0)), (-cos(y*x)/y, True)) assert trigintegrate(cos(y*x), x) == \ Piecewise((x, Eq(y, 0)), (sin(y*x)/y, True)) assert trigintegrate(sin(y*x)**2, x) == \ Piecewise((0, Eq(y, 0)), ((x*y/2 - sin(x*y)*cos(x*y)/2)/y, True)) assert trigintegrate(sin(y*x)*cos(y*x), x) == \ Piecewise((0, Eq(y, 0)), (sin(x*y)**2/(2*y), True)) assert trigintegrate(cos(y*x)**2, x) == \ Piecewise((x, Eq(y, 0)), ((x*y/2 + sin(x*y)*cos(x*y)/2)/y, True)) y = Symbol('y', positive=True) # TODO: remove conds='none' below. For this to work we would have to rule # out (e.g. by trying solve) the condition y = 0, incompatible with # y.is_positive being True. assert trigintegrate(sin(y*x), x, conds='none') == -cos(y*x)/y assert trigintegrate(cos(y*x), x, conds='none') == sin(y*x)/y assert trigintegrate(sin(x)*cos(x), x) == sin(x)**2/2 assert trigintegrate(sin(x)*cos(x)**2, x) == -cos(x)**3/3 assert trigintegrate(sin(x)**2*cos(x), x) == sin(x)**3/3 # check if it selects right function to substitute, # so the result is kept simple assert trigintegrate(sin(x)**7 * cos(x), x) == sin(x)**8/8 assert trigintegrate(sin(x) * cos(x)**7, x) == -cos(x)**8/8 assert trigintegrate(sin(x)**7 * cos(x)**3, x) == \ -sin(x)**10/10 + sin(x)**8/8 assert trigintegrate(sin(x)**3 * cos(x)**7, x) == \ cos(x)**10/10 - cos(x)**8/8 # both n, m are odd and -ve, and not necessarily equal assert trigintegrate(sin(x)**-1*cos(x)**-1, x) == \ -log(sin(x)**2 - 1)/2 + log(sin(x))
def test_ccode_math_macros(): assert ccode(z + exp(1)) == 'z + M_E' assert ccode(z + log2(exp(1))) == 'z + M_LOG2E' assert ccode(z + 1/log(2)) == 'z + M_LOG2E' assert ccode(z + log(2)) == 'z + M_LN2' assert ccode(z + log(10)) == 'z + M_LN10' assert ccode(z + pi) == 'z + M_PI' assert ccode(z + pi/2) == 'z + M_PI_2' assert ccode(z + pi/4) == 'z + M_PI_4' assert ccode(z + 1/pi) == 'z + M_1_PI' assert ccode(z + 2/pi) == 'z + M_2_PI' assert ccode(z + 2/sqrt(pi)) == 'z + M_2_SQRTPI' assert ccode(z + 2/Sqrt(pi)) == 'z + M_2_SQRTPI' assert ccode(z + sqrt(2)) == 'z + M_SQRT2' assert ccode(z + Sqrt(2)) == 'z + M_SQRT2' assert ccode(z + 1/sqrt(2)) == 'z + M_SQRT1_2' assert ccode(z + 1/Sqrt(2)) == 'z + M_SQRT1_2'
def test_C99CodePrinter__precision(): n = symbols('n', integer=True) f32_printer = C99CodePrinter(dict(type_aliases={real: float32})) f64_printer = C99CodePrinter(dict(type_aliases={real: float64})) f80_printer = C99CodePrinter(dict(type_aliases={real: float80})) assert f32_printer.doprint(sin(x+2.1)) == 'sinf(x + 2.1F)' assert f64_printer.doprint(sin(x+2.1)) == 'sin(x + 2.1000000000000001)' assert f80_printer.doprint(sin(x+Float('2.0'))) == 'sinl(x + 2.0L)' for printer, suffix in zip([f32_printer, f64_printer, f80_printer], ['f', '', 'l']): def check(expr, ref): assert printer.doprint(expr) == ref.format(s=suffix, S=suffix.upper()) check(Abs(n), 'abs(n)') check(Abs(x + 2.0), 'fabs{s}(x + 2.0{S})') check(sin(x + 4.0)**cos(x - 2.0), 'pow{s}(sin{s}(x + 4.0{S}), cos{s}(x - 2.0{S}))') check(exp(x*8.0), 'exp{s}(8.0{S}*x)') check(exp2(x), 'exp2{s}(x)') check(expm1(x*4.0), 'expm1{s}(4.0{S}*x)') check(Mod(n, 2), '((n) % (2))') check(Mod(2*n + 3, 3*n + 5), '((2*n + 3) % (3*n + 5))') check(Mod(x + 2.0, 3.0), 'fmod{s}(1.0{S}*x + 2.0{S}, 3.0{S})') check(Mod(x, 2.0*x + 3.0), 'fmod{s}(1.0{S}*x, 2.0{S}*x + 3.0{S})') check(log(x/2), 'log{s}((1.0{S}/2.0{S})*x)') check(log10(3*x/2), 'log10{s}((3.0{S}/2.0{S})*x)') check(log2(x*8.0), 'log2{s}(8.0{S}*x)') check(log1p(x), 'log1p{s}(x)') check(2**x, 'pow{s}(2, x)') check(2.0**x, 'pow{s}(2.0{S}, x)') check(x**3, 'pow{s}(x, 3)') check(x**4.0, 'pow{s}(x, 4.0{S})') check(sqrt(3+x), 'sqrt{s}(x + 3)') check(Cbrt(x-2.0), 'cbrt{s}(x - 2.0{S})') check(hypot(x, y), 'hypot{s}(x, y)') check(sin(3.*x + 2.), 'sin{s}(3.0{S}*x + 2.0{S})') check(cos(3.*x - 1.), 'cos{s}(3.0{S}*x - 1.0{S})') check(tan(4.*y + 2.), 'tan{s}(4.0{S}*y + 2.0{S})') check(asin(3.*x + 2.), 'asin{s}(3.0{S}*x + 2.0{S})') check(acos(3.*x + 2.), 'acos{s}(3.0{S}*x + 2.0{S})') check(atan(3.*x + 2.), 'atan{s}(3.0{S}*x + 2.0{S})') check(atan2(3.*x, 2.*y), 'atan2{s}(3.0{S}*x, 2.0{S}*y)') check(sinh(3.*x + 2.), 'sinh{s}(3.0{S}*x + 2.0{S})') check(cosh(3.*x - 1.), 'cosh{s}(3.0{S}*x - 1.0{S})') check(tanh(4.0*y + 2.), 'tanh{s}(4.0{S}*y + 2.0{S})') check(asinh(3.*x + 2.), 'asinh{s}(3.0{S}*x + 2.0{S})') check(acosh(3.*x + 2.), 'acosh{s}(3.0{S}*x + 2.0{S})') check(atanh(3.*x + 2.), 'atanh{s}(3.0{S}*x + 2.0{S})') check(erf(42.*x), 'erf{s}(42.0{S}*x)') check(erfc(42.*x), 'erfc{s}(42.0{S}*x)') check(gamma(x), 'tgamma{s}(x)') check(loggamma(x), 'lgamma{s}(x)') check(ceiling(x + 2.), "ceil{s}(x + 2.0{S})") check(floor(x + 2.), "floor{s}(x + 2.0{S})") check(fma(x, y, -z), 'fma{s}(x, y, -z)') check(Max(x, 8.0, x**4.0), 'fmax{s}(8.0{S}, fmax{s}(x, pow{s}(x, 4.0{S})))') check(Min(x, 2.0), 'fmin{s}(2.0{S}, x)')
def _generate_patterns(): """Generates patterns for transcendental equations. This is lazily calculated (called) in the tsolve() function and stored in the patterns global variable. """ tmp1 = f ** (h-(c*g/b)) tmp2 = (-e*tmp1/a)**(1/d) global patterns patterns = [ (a*(b*x+c)**d + e , ((-(e/a))**(1/d)-c)/b), ( b+c*exp(d*x+e) , (log(-b/c)-e)/d), (a*x+b+c*exp(d*x+e) , -b/a-LambertW(c*d*exp(e-b*d/a)/a)/d), ( b+c*f**(d*x+e) , (log(-b/c)-e*log(f))/d/log(f)), (a*x+b+c*f**(d*x+e) , -b/a-LambertW(c*d*f**(e-b*d/a)*log(f)/a)/d/log(f)), ( b+c*log(d*x+e) , (exp(-b/c)-e)/d), (a*x+b+c*log(d*x+e) , -e/d+c/a*LambertW(a/c/d*exp(-b/c+a*e/c/d))), (a*(b*x+c)**d + e*f**(g*x+h) , -c/b-d*LambertW(-tmp2*g*log(f)/b/d)/g/log(f)) ]
def __new__(cls, b, e, evaluate=True): from sympy.functions.elementary.exponential import exp_polar from sympy.functions import log # don't optimize "if e==0; return 1" here; it's better to handle that # in the calling routine so this doesn't get called b = _sympify(b) e = _sympify(e) if evaluate: if e is S.Zero: return S.One elif e is S.One: return b elif S.NaN in (b, e): if b is S.One: # already handled e == 0 above return S.One return S.NaN else: if e.func == log: if len(e.args) == 2: lbase = e.args[1] else: lbase = S.Exp1 if lbase == b: return e.args[0] if e is Mul and e.args[1].func == log: if len(e.args[1].args) == 2: lbase = e.args[1].args[1] else: lbase = S.Exp1 if lbase == b: return e.args[1].args[0] ** e.args[0] # recognize base as E if not e.is_Atom and b is not S.Exp1 and b.func is not exp_polar: from sympy import numer, denom, log, sign, im, factor_terms c, ex = factor_terms(e, sign=False).as_coeff_Mul() den = denom(ex) if den.func is log and den.args[0] == b: return S.Exp1**(c*numer(ex)) elif den.is_Add: s = sign(im(b)) if s.is_Number and s and den == \ log(-factor_terms(b, sign=False)) + s*S.ImaginaryUnit*S.Pi: return S.Exp1**(c*numer(ex)) obj = b._eval_power(e) if obj is not None: return obj obj = Expr.__new__(cls, b, e) obj.is_commutative = (b.is_commutative and e.is_commutative) return obj
def test_Function(): assert mcode(sin(x) ** cos(x)) == "sin(x).^cos(x)" assert mcode(sign(x)) == "sign(x)" assert mcode(exp(x)) == "exp(x)" assert mcode(log(x)) == "log(x)" assert mcode(factorial(x)) == "factorial(x)" assert mcode(floor(x)) == "floor(x)" assert mcode(atan2(y, x)) == "atan2(y, x)" assert mcode(beta(x, y)) == 'beta(x, y)' assert mcode(polylog(x, y)) == 'polylog(x, y)' assert mcode(harmonic(x)) == 'harmonic(x)' assert mcode(bernoulli(x)) == "bernoulli(x)" assert mcode(bernoulli(x, y)) == "bernoulli(x, y)"
def integrate(field=None): irreducibles = set() for poly in reducibles: for z in poly.atoms(Symbol): if z in V: break else: continue irreducibles |= set(root_factors(poly, z, domain=field)) log_coeffs, log_part = [], [] B = _symbols('B', len(irreducibles)) for i, poly in enumerate(irreducibles): if poly.has(*V): log_coeffs.append(B[i]) log_part.append(log_coeffs[-1] * log(poly)) coeffs = poly_coeffs + log_coeffs candidate = poly_part/poly_denom + Add(*log_part) h = together(F - derivation(candidate) / denom) numer = h.as_numer_denom()[0].expand() if not numer.is_Add: numer = [numer] equations = {} for term in numer.args: coeff, dependent = term.as_independent(*V) if dependent in equations: equations[dependent] += coeff else: equations[dependent] = coeff solution = solve(equations.values(), *coeffs) if solution is not None: return (solution, candidate, coeffs) else: return None
def ispow2(d, log2=False): if not d.is_Pow: return False e = d.exp if e.is_Rational and e.q == 2 or symbolic and denom(e) == 2: return True if log2: q = 1 if e.is_Rational: q = e.q elif symbolic: d = denom(e) if d.is_Integer: q = d if q != 1 and log(q, 2).is_Integer: return True return False
def test_catalan(): assert catalan(1) == 1 assert catalan(2) == 2 assert catalan(3) == 5 assert catalan(4) == 14 assert catalan(x) == catalan(x) assert catalan(2*x).rewrite(binomial) == binomial(4*x, 2*x)/(2*x + 1) assert catalan(Rational(1, 2)).rewrite(gamma) == 8/(3*pi) assert catalan(3*x).rewrite(gamma) == 4**( 3*x)*gamma(3*x + Rational(1, 2))/(sqrt(pi)*gamma(3*x + 2)) assert catalan(x).rewrite(hyper) == hyper((-x + 1, -x), (2,), 1) assert diff(catalan(x), x) == (polygamma( 0, x + Rational(1, 2)) - polygamma(0, x + 2) + log(4))*catalan(x) c = catalan(0.5).evalf() assert str(c) == '0.848826363156775'
def mrv_leadterm(e, x, Omega=[]): """Returns (c0, e0) for e.""" if not e.has(x): return (e, Rational(0)) Omega = [t for t in Omega if subexp(e,t)] if Omega == []: Omega = mrv(e,x) if x in set(Omega): #move the whole omega up (exponentiate each term): Omega_up = set(moveup(Omega,x)) e_up = moveup([e],x)[0] #calculate the lead term mrv_leadterm_up = mrv_leadterm(e_up, x, Omega_up) #move the result (c0, e0) down return tuple(movedown(mrv_leadterm_up, x)) wsym = Symbol("w", dummy=True) f, logw=rewrite(e, set(Omega), x, wsym) series = calculate_series(f, wsym) series=series.subs(log(wsym), logw) return calculate_leadterm(series, wsym)
def test_1(): test = [ [ - S(3)/S(2), x, S(1), - S(3)/S(2)*x], [Pi, x, S(1), Pi*x], [a, x, S(1), a*x], [x**m, x, S(1), x**(S(1) + m)/(S(1) + m)], [x**S(100), x, S(1), S(1)/S(101)*x**S(101)], [x**(S(5)/S(2)), x, S(1), S(2)/S(7)*x**(S(7)/S(2))], [x**(S(5)/S(3)), x, S(1), S(3)/S(8)*x**(S(8)/S(3))], [S(1)/x**(S(1)/S(3)), x, S(1), S(3)/S(2)*x**(S(2)/S(3))], [x**S(3)*(a + b*x), x, S(2), S(1)/S(4)*a*x**S(4) + S(1)/S(5)*b*x**S(5)], [(a + b*x)**S(2)/x**S(2), x, S(2), - a**S(2)/x + b**S(2)*x + S(2)*a*b*log(x)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True)
def test_rubi_integrate(): from sympy.integrals.rubi.rubi import rubi_integrate assert rubi_integrate(x, x) == x**2 / 2 assert rubi_integrate(x**2, x) == x**3 / 3 assert rubi_integrate(x**3, x) == x**4 / 4 assert rubi_integrate(x**a, x) == x**(a + S(1)) / (a + S(1)) assert rubi_integrate(S(1) / x, x) == log(x) assert rubi_integrate(a * x, x) == a * (S(1) / S(2)) * x**S(2) assert rubi_integrate( 1 / (x**2 * (a + b * x)**2), x) == -b / (a**2 * (a + b * x)) - 1 / ( a**2 * x) - 2 * b * log(x) / a**3 + 2 * b * log(a + b * x) / a**3 assert rubi_integrate( x**6 / (a + b * x)**2, x) == (-a**6 / (b**7 * (a + b * x)) - S(6) * a**5 * log(a + b * x) / b**7 + 5 * a**4 * x / b**6 - S(2) * a**3 * x**2 / b**5 + a**2 * x**3 / b**4 - a * x**4 / (S(2) * b**3) + x**5 / (S(5) * b**2)) assert rubi_integrate( 1 / (x**2 * (a + b * x)**2), x) == -b / (a**2 * (a + b * x)) - 1 / ( a**2 * x) - 2 * b * log(x) / a**3 + 2 * b * log(a + b * x) / a**3 assert rubi_integrate(a + S(1) / x, x) == a * x + log(x) assert rubi_integrate( (a + b * x)**2 / x**3, x) == -a**2 / (2 * x**2) - 2 * a * b / x + b**2 * log(x) assert rubi_integrate(a**3 * x, x) == S(1) / S(2) * a**3 * x**2 assert rubi_integrate((a + b * x)**3 / x**3, x) == -a**3 / ( 2 * x**2) - 3 * a**2 * b / x + 3 * a * b**2 * log(x) + b**3 * x assert rubi_integrate(x**3 * (a + b * x), x) == a * x**4 / 4 + b * x**5 / 5 assert rubi_integrate( (b * x)**m * (d * x + 2)**n, x) == 2**n * (b * x)**(m + 1) * hyper( (-n, m + 1), (m + 2, ), -d * x / 2) / (b * (m + 1)) assert rubi_test( rubi_integrate(1 / (1 + x**5), x), x, log(x + S(1)) / S(5) + S(2) * Sum( -log((S(2) * x - S(2) * cos(pi * (S(2) * k / S(5) + S(-1) / 5)))**S(2) - S(4) * sin(S(2) * pi * k / S(5) + S(3) * pi / S(10))**S(2) + S(4)) * cos(pi * (S(2) * k / S(5) + S(-1) / 5)) / S(2) - (-S(2) * cos(pi * (S(2) * k / S(5) + S(-1) / 5))**S(2) + S(2)) * atan((-x / cos(pi * (S(2) * k / S(5) + S(-1) / 5)) + S(1)) / sqrt(-(cos(S(2) * pi * k / S(5) - pi / S(5)) + S(-1)) * (cos(S(2) * pi * k / S(5) - pi / S(5)) + S(1)) / cos(S(2) * pi * k / S(5) - pi / S(5))**S(2))) / (S(2) * sqrt(-(cos(S(2) * pi * k / S(5) - pi / S(5)) + S(-1)) * (cos(S(2) * pi * k / S(5) - pi / S(5)) + S(1)) / cos(S(2) * pi * k / S(5) - pi / S(5))**S(2)) * cos(pi * (S(2) * k / S(5) + S(-1) / 5))), (k, S(1), S(2))) / S(5), _numerical=True)
def _expr_small_minus(cls, z): return log(S.Half + sqrt(1 + z) / 2)
def test_harmonic_rational(): ne = S(6) no = S(5) pe = S(8) po = S(9) qe = S(10) qo = S(13) Heee = harmonic(ne + pe / qe) Aeee = (-log(10) + 2 * (Rational(-1, 4) + sqrt(5) / 4) * log(sqrt(-sqrt(5) / 8 + Rational(5, 8))) + 2 * (-sqrt(5) / 4 - Rational(1, 4)) * log(sqrt(sqrt(5) / 8 + Rational(5, 8))) + pi * sqrt(2 * sqrt(5) / 5 + 1) / 2 + Rational(13944145, 4720968)) Heeo = harmonic(ne + pe / qo) Aeeo = (-log(26) + 2 * log(sin(pi * Rational(3, 13))) * cos(pi * Rational(4, 13)) + 2 * log(sin(pi * Rational(2, 13))) * cos(pi * Rational(32, 13)) + 2 * log(sin(pi * Rational(5, 13))) * cos(pi * Rational(80, 13)) - 2 * log(sin(pi * Rational(6, 13))) * cos(pi * Rational(5, 13)) - 2 * log(sin(pi * Rational(4, 13))) * cos(pi / 13) + pi * cot(pi * Rational(5, 13)) / 2 - 2 * log(sin(pi / 13)) * cos(pi * Rational(3, 13)) + Rational(2422020029, 702257080)) Heoe = harmonic(ne + po / qe) Aeoe = ( -log(20) + 2 * (Rational(1, 4) + sqrt(5) / 4) * log(Rational(-1, 4) + sqrt(5) / 4) + 2 * (Rational(-1, 4) + sqrt(5) / 4) * log(sqrt(-sqrt(5) / 8 + Rational(5, 8))) + 2 * (-sqrt(5) / 4 - Rational(1, 4)) * log(sqrt(sqrt(5) / 8 + Rational(5, 8))) + 2 * (-sqrt(5) / 4 + Rational(1, 4)) * log(Rational(1, 4) + sqrt(5) / 4) + Rational(11818877030, 4286604231) + pi * sqrt(2 * sqrt(5) + 5) / 2) Heoo = harmonic(ne + po / qo) Aeoo = (-log(26) + 2 * log(sin(pi * Rational(3, 13))) * cos(pi * Rational(54, 13)) + 2 * log(sin(pi * Rational(4, 13))) * cos(pi * Rational(6, 13)) + 2 * log(sin(pi * Rational(6, 13))) * cos(pi * Rational(108, 13)) - 2 * log(sin(pi * Rational(5, 13))) * cos(pi / 13) - 2 * log(sin(pi / 13)) * cos(pi * Rational(5, 13)) + pi * cot(pi * Rational(4, 13)) / 2 - 2 * log(sin(pi * Rational(2, 13))) * cos(pi * Rational(3, 13)) + Rational(11669332571, 3628714320)) Hoee = harmonic(no + pe / qe) Aoee = (-log(10) + 2 * (Rational(-1, 4) + sqrt(5) / 4) * log(sqrt(-sqrt(5) / 8 + Rational(5, 8))) + 2 * (-sqrt(5) / 4 - Rational(1, 4)) * log(sqrt(sqrt(5) / 8 + Rational(5, 8))) + pi * sqrt(2 * sqrt(5) / 5 + 1) / 2 + Rational(779405, 277704)) Hoeo = harmonic(no + pe / qo) Aoeo = (-log(26) + 2 * log(sin(pi * Rational(3, 13))) * cos(pi * Rational(4, 13)) + 2 * log(sin(pi * Rational(2, 13))) * cos(pi * Rational(32, 13)) + 2 * log(sin(pi * Rational(5, 13))) * cos(pi * Rational(80, 13)) - 2 * log(sin(pi * Rational(6, 13))) * cos(pi * Rational(5, 13)) - 2 * log(sin(pi * Rational(4, 13))) * cos(pi / 13) + pi * cot(pi * Rational(5, 13)) / 2 - 2 * log(sin(pi / 13)) * cos(pi * Rational(3, 13)) + Rational(53857323, 16331560)) Hooe = harmonic(no + po / qe) Aooe = ( -log(20) + 2 * (Rational(1, 4) + sqrt(5) / 4) * log(Rational(-1, 4) + sqrt(5) / 4) + 2 * (Rational(-1, 4) + sqrt(5) / 4) * log(sqrt(-sqrt(5) / 8 + Rational(5, 8))) + 2 * (-sqrt(5) / 4 - Rational(1, 4)) * log(sqrt(sqrt(5) / 8 + Rational(5, 8))) + 2 * (-sqrt(5) / 4 + Rational(1, 4)) * log(Rational(1, 4) + sqrt(5) / 4) + Rational(486853480, 186374097) + pi * sqrt(2 * sqrt(5) + 5) / 2) Hooo = harmonic(no + po / qo) Aooo = (-log(26) + 2 * log(sin(pi * Rational(3, 13))) * cos(pi * Rational(54, 13)) + 2 * log(sin(pi * Rational(4, 13))) * cos(pi * Rational(6, 13)) + 2 * log(sin(pi * Rational(6, 13))) * cos(pi * Rational(108, 13)) - 2 * log(sin(pi * Rational(5, 13))) * cos(pi / 13) - 2 * log(sin(pi / 13)) * cos(pi * Rational(5, 13)) + pi * cot(pi * Rational(4, 13)) / 2 - 2 * log(sin(pi * Rational(2, 13))) * cos(3 * pi / 13) + Rational(383693479, 125128080)) H = [Heee, Heeo, Heoe, Heoo, Hoee, Hoeo, Hooe, Hooo] A = [Aeee, Aeeo, Aeoe, Aeoo, Aoee, Aoeo, Aooe, Aooo] for h, a in zip(H, A): e = expand_func(h).doit() assert cancel(e / a) == 1 assert abs(h.n() - a.n()) < 1e-12
def test_C99CodePrinter__precision(): n = symbols('n', integer=True) p = symbols('p', integer=True, positive=True) f32_printer = C99CodePrinter(dict(type_aliases={real: float32})) f64_printer = C99CodePrinter(dict(type_aliases={real: float64})) f80_printer = C99CodePrinter(dict(type_aliases={real: float80})) assert f32_printer.doprint(sin(x + 2.1)) == 'sinf(x + 2.1F)' assert f64_printer.doprint(sin(x + 2.1)) == 'sin(x + 2.1000000000000001)' assert f80_printer.doprint(sin(x + Float('2.0'))) == 'sinl(x + 2.0L)' for printer, suffix in zip([f32_printer, f64_printer, f80_printer], ['f', '', 'l']): def check(expr, ref): assert printer.doprint(expr) == ref.format(s=suffix, S=suffix.upper()) check(Abs(n), 'abs(n)') check(Abs(x + 2.0), 'fabs{s}(x + 2.0{S})') check( sin(x + 4.0)**cos(x - 2.0), 'pow{s}(sin{s}(x + 4.0{S}), cos{s}(x - 2.0{S}))') check(exp(x * 8.0), 'exp{s}(8.0{S}*x)') check(exp2(x), 'exp2{s}(x)') check(expm1(x * 4.0), 'expm1{s}(4.0{S}*x)') check(Mod(p, 2), 'p % 2') check(Mod(2 * p + 3, 3 * p + 5, evaluate=False), '(2*p + 3) % (3*p + 5)') check(Mod(x + 2.0, 3.0), 'fmod{s}(1.0{S}*x + 2.0{S}, 3.0{S})') check(Mod(x, 2.0 * x + 3.0), 'fmod{s}(1.0{S}*x, 2.0{S}*x + 3.0{S})') check(log(x / 2), 'log{s}((1.0{S}/2.0{S})*x)') check(log10(3 * x / 2), 'log10{s}((3.0{S}/2.0{S})*x)') check(log2(x * 8.0), 'log2{s}(8.0{S}*x)') check(log1p(x), 'log1p{s}(x)') check(2**x, 'pow{s}(2, x)') check(2.0**x, 'pow{s}(2.0{S}, x)') check(x**3, 'pow{s}(x, 3)') check(x**4.0, 'pow{s}(x, 4.0{S})') check(sqrt(3 + x), 'sqrt{s}(x + 3)') check(Cbrt(x - 2.0), 'cbrt{s}(x - 2.0{S})') check(hypot(x, y), 'hypot{s}(x, y)') check(sin(3. * x + 2.), 'sin{s}(3.0{S}*x + 2.0{S})') check(cos(3. * x - 1.), 'cos{s}(3.0{S}*x - 1.0{S})') check(tan(4. * y + 2.), 'tan{s}(4.0{S}*y + 2.0{S})') check(asin(3. * x + 2.), 'asin{s}(3.0{S}*x + 2.0{S})') check(acos(3. * x + 2.), 'acos{s}(3.0{S}*x + 2.0{S})') check(atan(3. * x + 2.), 'atan{s}(3.0{S}*x + 2.0{S})') check(atan2(3. * x, 2. * y), 'atan2{s}(3.0{S}*x, 2.0{S}*y)') check(sinh(3. * x + 2.), 'sinh{s}(3.0{S}*x + 2.0{S})') check(cosh(3. * x - 1.), 'cosh{s}(3.0{S}*x - 1.0{S})') check(tanh(4.0 * y + 2.), 'tanh{s}(4.0{S}*y + 2.0{S})') check(asinh(3. * x + 2.), 'asinh{s}(3.0{S}*x + 2.0{S})') check(acosh(3. * x + 2.), 'acosh{s}(3.0{S}*x + 2.0{S})') check(atanh(3. * x + 2.), 'atanh{s}(3.0{S}*x + 2.0{S})') check(erf(42. * x), 'erf{s}(42.0{S}*x)') check(erfc(42. * x), 'erfc{s}(42.0{S}*x)') check(gamma(x), 'tgamma{s}(x)') check(loggamma(x), 'lgamma{s}(x)') check(ceiling(x + 2.), "ceil{s}(x + 2.0{S})") check(floor(x + 2.), "floor{s}(x + 2.0{S})") check(fma(x, y, -z), 'fma{s}(x, y, -z)') check(Max(x, 8.0, x**4.0), 'fmax{s}(8.0{S}, fmax{s}(x, pow{s}(x, 4.0{S})))') check(Min(x, 2.0), 'fmin{s}(2.0{S}, x)')
def _expr_big_minus(cls, x, n): return log(1 + x) + 2 * n * pi * I
def _integrate(field=None): irreducibles = set() for poly in reducibles: for z in poly.atoms(Symbol): if z in V: break else: continue irreducibles |= set(root_factors(poly, z, filter=field)) log_coeffs, log_part = [], [] B = _symbols('B', len(irreducibles)) for i, poly in enumerate(irreducibles): if poly.has(*V): log_coeffs.append(B[i]) log_part.append(log_coeffs[-1] * log(poly)) coeffs = poly_coeffs + log_coeffs # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancelation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part / poly_denom + Add(*log_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(coeffs, ground) ring = PolyRing(V, coeff_ring) numer = ring.from_expr(raw_numer) solution = solve_lin_sys(numer.coeffs(), coeff_ring) if solution is None: return None else: solution = [(k.as_expr(), v.as_expr()) for k, v in solution.items()] return candidate.subs(solution).subs( list(zip(coeffs, [S.Zero] * len(coeffs))))
def integrand_simplification(rubi): pattern1 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda a: ZeroQ(a))) rule1 = ReplacementRule(pattern1, lambda p, b, u, a, x, n : Int(u*(b*x**n)**p, x)) rubi.add(rule1) pattern2 = Pattern(Integral((a_ + x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda n, j: ZeroQ(j - S(2)*n)), CustomConstraint(lambda a: ZeroQ(a))) rule2 = ReplacementRule(pattern2, lambda j, b, p, u, a, x, n, c : Int(u*(b*x**n + c*x**(S(2)*n))**p, x)) rubi.add(rule2) pattern3 = Pattern(Integral((x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda n, j: ZeroQ(j - S(2)*n)), CustomConstraint(lambda b: ZeroQ(b))) rule3 = ReplacementRule(pattern3, lambda j, b, p, u, a, x, n, c : Int(u*(a + c*x**(S(2)*n))**p, x)) rubi.add(rule3) pattern4 = Pattern(Integral((x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda n, j: ZeroQ(j - S(2)*n)), CustomConstraint(lambda c: ZeroQ(c))) rule4 = ReplacementRule(pattern4, lambda j, b, p, u, a, x, n, c : Int(u*(a + b*x**n)**p, x)) rubi.add(rule4) pattern5 = Pattern(Integral((v_*WC('a', S(1)) + v_*WC('b', S(1)) + WC('w', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda x, v: NFreeQ(v, x))) rule5 = ReplacementRule(pattern5, lambda p, b, v, u, a, x, w : Int(u*(v*(a + b) + w)**p, x)) rubi.add(rule5) pattern6 = Pattern(Integral(Pm_**p_*WC('u', S(1)), x_), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda x, Pm: PolyQ(Pm, x)), CustomConstraint(lambda p: Not(RationalQ(p))), CustomConstraint(lambda p: RationalQ(p))) rule6 = ReplacementRule(pattern6, lambda u, x, p, Pm : Int(Pm**p*u, x)) rubi.add(rule6) pattern7 = Pattern(Integral(a_, x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a, x: FreeQ(a, x))) rule7 = ReplacementRule(pattern7, lambda a, x : a*x) rubi.add(rule7) pattern8 = Pattern(Integral(a_*(b_ + x_*WC('c', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda a, c, b, x: FreeQ(List(a, b, c), x))) rule8 = ReplacementRule(pattern8, lambda a, c, b, x : a*(b + c*x)**S(2)/(S(2)*c)) rubi.add(rule8) pattern9 = Pattern(Integral(-u_, x_)) rule9 = ReplacementRule(pattern9, lambda u, x : I*Int(u, x)) rubi.add(rule9) pattern10 = Pattern(Integral(u_*Complex(S(0), a_), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: EqQ(a**S(2), S(1)))) rule10 = ReplacementRule(pattern10, lambda u, a, x : Int(u, x)*Complex(I, a)) rubi.add(rule10) pattern11 = Pattern(Integral(a_*u_, x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a, x: FreeQ(a, x))) rule11 = ReplacementRule(pattern11, lambda u, a, x : a*Int(u, x)) rubi.add(rule11) pattern12 = Pattern(Integral(u_, x_), CustomConstraint(lambda u: SumQ(u))) rule12 = ReplacementRule(pattern12, lambda u, x : IntSum(u, x)) rubi.add(rule12) pattern13 = Pattern(Integral(v_**WC('m', S(1))*(b_*v_)**n_*WC('u', S(1)), x_), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda m: IntegerQ(m))) rule13 = ReplacementRule(pattern13, lambda b, v, u, m, x, n : b**(-m)*Int(u*(b*v)**(m + n), x)) rubi.add(rule13) pattern14 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda m: Not(IntegerQ(m))), CustomConstraint(lambda n: PositiveIntegerQ(n + S(1)/2)), CustomConstraint(lambda m, n: IntegerQ(m + n))) rule14 = ReplacementRule(pattern14, lambda b, v, u, m, a, x, n : a**(m + S(1)/2)*b**(n + S(-1)/2)*sqrt(b*v)*Int(u*v**(m + n), x)/sqrt(a*v)) rubi.add(rule14) pattern15 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda m: Not(IntegerQ(m))), CustomConstraint(lambda n: NegativeIntegerQ(n + S(-1)/2)), CustomConstraint(lambda m, n: IntegerQ(m + n))) rule15 = ReplacementRule(pattern15, lambda b, v, u, m, a, x, n : a**(m + S(-1)/2)*b**(n + S(1)/2)*sqrt(a*v)*Int(u*v**(m + n), x)/sqrt(b*v)) rubi.add(rule15) pattern16 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda m: Not(IntegerQ(m))), CustomConstraint(lambda n: Not(IntegerQ(n))), CustomConstraint(lambda m, n: IntegerQ(m + n))) rule16 = ReplacementRule(pattern16, lambda b, v, u, m, a, x, n : a**(m + n)*(a*v)**(-n)*(b*v)**n*Int(u*v**(m + n), x)) rubi.add(rule16) pattern17 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda m: Not(IntegerQ(m))), CustomConstraint(lambda n: Not(IntegerQ(n))), CustomConstraint(lambda m, n: Not(IntegerQ(m + n)))) rule17 = ReplacementRule(pattern17, lambda b, v, u, m, a, x, n : a**(-IntPart(n))*b**IntPart(n)*(a*v)**(-FracPart(n))*(b*v)**FracPart(n)*Int(u*(a*v)**(m + n), x)) rubi.add(rule17) pattern18 = Pattern(Integral((a_ + v_*WC('b', S(1)))**WC('m', S(1))*(c_ + v_*WC('d', S(1)))**WC('n', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda a, c, b, d: ZeroQ(-a*d + b*c)), CustomConstraint(lambda m: IntegerQ(m)), CustomConstraint(lambda b, a, x, d, n, c: Not(IntegerQ(n)) | SimplerQ(c + d*x, a + b*x))) rule18 = ReplacementRule(pattern18, lambda b, v, u, m, a, x, d, n, c : (b/d)**m*Int(u*(c + d*v)**(m + n), x)) rubi.add(rule18) pattern19 = Pattern(Integral((a_ + v_*WC('b', S(1)))**m_*(c_ + v_*WC('d', S(1)))**n_*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda a, c, b, d: ZeroQ(-a*d + b*c)), CustomConstraint(lambda b, d: PositiveQ(b/d)), CustomConstraint(lambda m, n: Not(IntegerQ(m) | IntegerQ(n)))) rule19 = ReplacementRule(pattern19, lambda b, v, u, m, a, x, d, n, c : (b/d)**m*Int(u*(c + d*v)**(m + n), x)) rubi.add(rule19) pattern20 = Pattern(Integral((a_ + v_*WC('b', S(1)))**m_*(c_ + v_*WC('d', S(1)))**n_*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda a, c, b, d: ZeroQ(-a*d + b*c)), CustomConstraint(lambda m, n, b, d: Not(IntegerQ(m) | IntegerQ(n) | PositiveQ(b/d)))) rule20 = ReplacementRule(pattern20, lambda b, v, u, m, a, x, d, n, c : (a + b*v)**m*(c + d*v)**(-m)*Int(u*(c + d*v)**(m + n), x)) rubi.add(rule20) pattern21 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_**S(2)*WC('c', S(1)) + v_*WC('b', S(1)))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda m: RationalQ(m)), CustomConstraint(lambda m: LessEqual(m, S(-1)))) rule21 = ReplacementRule(pattern21, lambda b, v, u, m, a, x, c : Int(u*(a*v)**(m + S(1))*(b + c*v), x)/a) rubi.add(rule21) pattern22 = Pattern(Integral((a_ + v_*WC('b', S(1)))**m_*(v_**S(2)*WC('C', S(1)) + v_*WC('B', S(1)) + WC('A', S(0)))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda C, x: FreeQ(C, x)), CustomConstraint(lambda b, A, B, a, C: ZeroQ(A*b**S(2) - B*a*b + C*a**S(2))), CustomConstraint(lambda m: RationalQ(m)), CustomConstraint(lambda m: LessEqual(m, S(-1)))) rule22 = ReplacementRule(pattern22, lambda b, v, u, A, B, m, a, x, C : Int(u*(a + b*v)**(m + S(1))*Simp(B*b - C*a + C*b*v, x), x)/b**S(2)) rubi.add(rule22) pattern23 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('m', S(1))*(c_ + x_**WC('q', S(1))*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda n, q: ZeroQ(n + q)), CustomConstraint(lambda p: IntegerQ(p)), CustomConstraint(lambda a, c, b, d: ZeroQ(a*c - b*d)), CustomConstraint(lambda m, n: Not(IntegerQ(m) & NegQ(n)))) rule23 = ReplacementRule(pattern23, lambda q, p, b, u, m, a, x, d, n, c : (d/a)**p*Int(u*x**(-n*p)*(a + b*x**n)**(m + p), x)) rubi.add(rule23) pattern24 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('m', S(1))*(c_ + x_**j_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda n, j: ZeroQ(j - S(2)*n)), CustomConstraint(lambda m, p: ZeroQ(m + p)), CustomConstraint(lambda a, c, b, d: ZeroQ(a**S(2)*d + b**S(2)*c)), CustomConstraint(lambda a: PositiveQ(a)), CustomConstraint(lambda d: NegativeQ(d))) rule24 = ReplacementRule(pattern24, lambda p, b, j, u, m, a, x, d, n, c : (-b**S(2)/d)**m*Int(u*(a - b*x**n)**(-m), x)) rubi.add(rule24) pattern25 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda a, c, b: ZeroQ(-S(4)*a*c + b**S(2))), CustomConstraint(lambda p: IntegerQ(p))) rule25 = ReplacementRule(pattern25, lambda p, b, u, a, x, c : Int(S(2)**(-S(2)*p)*c**(-p)*u*(b + S(2)*c*x)**(S(2)*p), x)) rubi.add(rule25) pattern26 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda n, n2: ZeroQ(-S(2)*n + n2)), CustomConstraint(lambda a, c, b: ZeroQ(-S(4)*a*c + b**S(2))), CustomConstraint(lambda p: IntegerQ(p))) rule26 = ReplacementRule(pattern26, lambda n2, p, b, u, a, x, n, c : c**(-p)*Int(u*(b/S(2) + c*x**n)**(S(2)*p), x)) rubi.add(rule26) pattern27 = Pattern(Integral((d_ + x_*WC('e', S(1)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda e, x: FreeQ(e, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda e, c, b, d: ZeroQ(-b*e + S(2)*c*d))) rule27 = ReplacementRule(pattern27, lambda p, b, a, x, d, e, c : d*Subst(Int(x**p, x), x, a + b*x + c*x**S(2))/b) rubi.add(rule27) pattern28 = Pattern(Integral((x_**WC('p', S(1))*WC('a', S(1)) + x_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda q, x: FreeQ(q, x)), CustomConstraint(lambda m: IntegerQ(m)), CustomConstraint(lambda q, p: PosQ(-p + q))) rule28 = ReplacementRule(pattern28, lambda q, p, b, u, m, a, x : Int(u*x**(m*p)*(a + b*x**(-p + q))**m, x)) rubi.add(rule28) pattern29 = Pattern(Integral((x_**WC('p', S(1))*WC('a', S(1)) + x_**WC('q', S(1))*WC('b', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**WC('m', S(1))*WC('u', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda q, x: FreeQ(q, x)), CustomConstraint(lambda r, x: FreeQ(r, x)), CustomConstraint(lambda m: IntegerQ(m)), CustomConstraint(lambda q, p: PosQ(-p + q)), CustomConstraint(lambda r, p: PosQ(-p + r))) rule29 = ReplacementRule(pattern29, lambda q, r, p, b, u, m, a, x, c : Int(u*x**(m*p)*(a + b*x**(-p + q) + c*x**(-p + r))**m, x)) rubi.add(rule29) pattern30 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda m, n: ZeroQ(m - n + S(1)))) rule30 = ReplacementRule(pattern30, lambda b, m, a, x, n : log(RemoveContent(a + b*x**n, x))/(b*n)) rubi.add(rule30) pattern31 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda m, n: ZeroQ(m - n + S(1))), CustomConstraint(lambda p: NonzeroQ(p + S(1)))) rule31 = ReplacementRule(pattern31, lambda p, b, m, a, x, n : (a + b*x**n)**(p + S(1))/(b*n*(p + S(1)))) rubi.add(rule31) pattern32 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**p_*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**p_, x_), CustomConstraint(lambda a1, x: FreeQ(a1, x)), CustomConstraint(lambda b1, x: FreeQ(b1, x)), CustomConstraint(lambda a2, x: FreeQ(a2, x)), CustomConstraint(lambda b2, x: FreeQ(b2, x)), CustomConstraint(lambda m, x: FreeQ(m, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda b2, b1, a1, a2: ZeroQ(a1*b2 + a2*b1)), CustomConstraint(lambda m, n: ZeroQ(m - S(2)*n + S(1))), CustomConstraint(lambda p: NonzeroQ(p + S(1)))) rule32 = ReplacementRule(pattern32, lambda p, a1, b2, m, x, a2, n, b1 : (a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*b1*b2*n*(p + S(1)))) rubi.add(rule32) ''' pattern33 = Pattern(Integral(Qm_*(Pm_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda x, Pm: PolyQ(Pm, x)), CustomConstraint(lambda Qm, x: PolyQ(Qm, x)), ) def With33(p, b, a, x, n, Qm, Pm): m = Expon(Pm, x) if Equal(Expon(Qm, x), m + S(-1)) & ZeroQ(-Qm*m*Coeff(Pm, x, m) + Coeff(Qm, x, m + S(-1))*D(Pm, x)): return Coeff(Qm, x, m + S(-1))*Subst(Int((a + b*x**n)**p, x), x, Pm)/(m*Coeff(Pm, x, m)) print("Unable to Integrate") rule33 = ReplacementRule(pattern33, lambda p, b, a, x, n, Qm, Pm : With33(p, b, a, x, n, Qm, Pm)) rubi.add(rule33) pattern34 = Pattern(Integral(Qm_*(Pm_**WC('n', S(1))*WC('b', S(1)) + Pm_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, x: FreeQ(n, x)), CustomConstraint(lambda p, x: FreeQ(p, x)), CustomConstraint(lambda n, n2: ZeroQ(-S(2)*n + n2)), CustomConstraint(lambda x, Pm: PolyQ(Pm, x)), CustomConstraint(lambda Qm, x: PolyQ(Qm, x)), ) def With34(n2, p, b, a, x, n, Qm, c, Pm): m = Expon(Pm, x) if Equal(Expon(Qm, x), m + S(-1)) & ZeroQ(-Qm*m*Coeff(Pm, x, m) + Coeff(Qm, x, m + S(-1))*D(Pm, x)): return Coeff(Qm, x, m + S(-1))*Subst(Int((a + b*x**n + c*x**(S(2)*n))**p, x), x, Pm)/(m*Coeff(Pm, x, m)) print("Unable to Integrate") rule34 = ReplacementRule(pattern34, lambda n2, p, b, a, x, n, Qm, c, Pm : With34(n2, p, b, a, x, n, Qm, c, Pm)) rubi.add(rule34) pattern35 = Pattern(Integral(Pq_**m_*Qr_**p_*WC('u', S(1)), x_), CustomConstraint(lambda m: PositiveIntegerQ(m)), CustomConstraint(lambda p: NegativeIntegerQ(p)), CustomConstraint(lambda Pq, x: PolyQ(Pq, x)), CustomConstraint(lambda Qr, x: PolyQ(Qr, x)), ) def With35(Qr, p, u, Pq, m, x): gcd = PolyGCD(Pq, Qr, x) if NonzeroQ(gcd + S(-1)): return Int(gcd**(m + p)*u*PolynomialQuotient(Pq, gcd, x)**m*PolynomialQuotient(Qr, gcd, x)**p, x) print("Unable to Integrate") rule35 = ReplacementRule(pattern35, lambda Qr, p, u, Pq, m, x : With35(Qr, p, u, Pq, m, x)) rubi.add(rule35) pattern36 = Pattern(Integral(Pq_*Qr_**p_*WC('u', S(1)), x_), CustomConstraint(lambda p: NegativeIntegerQ(p)), CustomConstraint(lambda Pq, x: PolyQ(Pq, x)), CustomConstraint(lambda Qr, x: PolyQ(Qr, x)), ) def With36(Qr, p, u, Pq, x): gcd = PolyGCD(Pq, Qr, x) if NonzeroQ(gcd + S(-1)): return Int(gcd**(p + S(1))*u*PolynomialQuotient(Pq, gcd, x)*PolynomialQuotient(Qr, gcd, x)**p, x) print("Unable to Integrate") rule36 = ReplacementRule(pattern36, lambda Qr, p, u, Pq, x : With36(Qr, p, u, Pq, x)) rubi.add(rule36) ''' return rubi
def test_rs_series(): x, a, b, c = symbols('x, a, b, c') assert rs_series(a, a, 5).as_expr() == a assert rs_series(sin(a), a, 5).as_expr() == (sin(a).series(a, 0, 5)).removeO() assert rs_series(sin(a) + cos(a), a, 5).as_expr() == ((sin(a) + cos(a)).series(a, 0, 5)).removeO() assert rs_series(sin(a) * cos(a), a, 5).as_expr() == ((sin(a) * cos(a)).series(a, 0, 5)).removeO() p = (sin(a) - a) * (cos(a**2) + a**4 / 2) assert expand(rs_series(p, a, 10).as_expr()) == expand( p.series(a, 0, 10).removeO()) p = sin(a**2 / 2 + a / 3) + cos(a / 5) * sin(a / 2)**3 assert expand(rs_series(p, a, 5).as_expr()) == expand( p.series(a, 0, 5).removeO()) p = sin(x**2 + a) * (cos(x**3 - 1) - a - a**2) assert expand(rs_series(p, a, 5).as_expr()) == expand( p.series(a, 0, 5).removeO()) p = sin(a**2 - a / 3 + 2)**5 * exp(a**3 - a / 2) assert expand(rs_series(p, a, 10).as_expr()) == expand( p.series(a, 0, 10).removeO()) p = sin(a + b + c) assert expand(rs_series(p, a, 5).as_expr()) == expand( p.series(a, 0, 5).removeO()) p = tan(sin(a**2 + 4) + b + c) assert expand(rs_series(p, a, 6).as_expr()) == expand( p.series(a, 0, 6).removeO()) p = a**QQ(2, 5) + a**QQ(2, 3) + a r = rs_series(tan(p), a, 2) assert r.as_expr() == a**QQ(9,5) + a**QQ(26,15) + a**QQ(22,15) + a**QQ(6,5)/3 + \ a + a**QQ(2,3) + a**QQ(2,5) r = rs_series(exp(p), a, 1) assert r.as_expr() == a**QQ(4, 5) / 2 + a**QQ(2, 3) + a**QQ(2, 5) + 1 r = rs_series(sin(p), a, 2) assert r.as_expr() == -a**QQ(9,5)/2 - a**QQ(26,15)/2 - a**QQ(22,15)/2 - \ a**QQ(6,5)/6 + a + a**QQ(2,3) + a**QQ(2,5) r = rs_series(cos(p), a, 2) assert r.as_expr() == a**QQ(28,15)/6 - a**QQ(5,3) + a**QQ(8,5)/24 - a**QQ(7,5) - \ a**QQ(4,3)/2 - a**QQ(16,15) - a**QQ(4,5)/2 + 1 assert rs_series(sin(a) / 7, a, 5).as_expr() == (sin(a) / 7).series(a, 0, 5).removeO() assert rs_series(log(1 + x), x, 5).as_expr() == -x**4/4 + x**3/3 - \ x**2/2 + x assert rs_series(log(1 + 4*x), x, 5).as_expr() == -64*x**4 + 64*x**3/3 - \ 8*x**2 + 4*x assert rs_series(log(1 + x + x**2), x, 10).as_expr() == -2*x**9/9 + \ x**8/8 + x**7/7 - x**6/3 + x**5/5 + x**4/4 - 2*x**3/3 + \ x**2/2 + x assert rs_series(log(1 + x*a**2), x, 7).as_expr() == -x**6*a**12/6 + \ x**5*a**10/5 - x**4*a**8/4 + x**3*a**6/3 - \ x**2*a**4/2 + x*a**2
def _diff_wrt_parameter(self, idx): # Differentiation wrt a parameter can only be done in very special # cases. In particular, if we want to differentiate with respect to # `a`, all other gamma factors have to reduce to rational functions. # # Let MT denote mellin transform. Suppose T(-s) is the gamma factor # appearing in the definition of G. Then # # MT(log(z)G(z)) = d/ds T(s) = d/da T(s) + ... # # Thus d/da G(z) = log(z)G(z) - ... # The ... can be evaluated as a G function under the above conditions, # the formula being most easily derived by using # # d Gamma(s + n) Gamma(s + n) / 1 1 1 \ # -- ------------ = ------------ | - + ---- + ... + --------- | # ds Gamma(s) Gamma(s) \ s s + 1 s + n - 1 / # # which follows from the difference equation of the digamma function. # (There is a similar equation for -n instead of +n). # We first figure out how to pair the parameters. an = list(self.an) ap = list(self.aother) bm = list(self.bm) bq = list(self.bother) if idx < len(an): an.pop(idx) else: idx -= len(an) if idx < len(ap): ap.pop(idx) else: idx -= len(ap) if idx < len(bm): bm.pop(idx) else: bq.pop(idx - len(bm)) pairs1 = [] pairs2 = [] for l1, l2, pairs in [(an, bq, pairs1), (ap, bm, pairs2)]: while l1: x = l1.pop() found = None for i, y in enumerate(l2): if not Mod((x - y).simplify(), 1): found = i break if found is None: raise NotImplementedError('Derivative not expressible ' 'as G-function?') y = l2[i] l2.pop(i) pairs.append((x, y)) # Now build the result. res = log(self.argument) * self for a, b in pairs1: sign = 1 n = a - b base = b if n < 0: sign = -1 n = b - a base = a for k in range(n): res -= sign * meijerg(self.an + (base + k + 1, ), self.aother, self.bm, self.bother + (base + k + 0, ), self.argument) for a, b in pairs2: sign = 1 n = b - a base = a if n < 0: sign = -1 n = a - b base = b for k in range(n): res -= sign * meijerg( self.an, self.aother + (base + k + 1, ), self.bm + (base + k + 0, ), self.bother, self.argument) return res
def _integrate(field=None): irreducibles = set() atans = set() pairs = set() for poly in reducibles: for z in poly.free_symbols: if z in V: break # should this be: `irreducibles |= \ else: # set(root_factors(poly, z, filter=field))` continue # and the line below deleted? # | # V irreducibles |= set(root_factors(poly, z, filter=field)) log_part, atan_part = [], [] for poly in list(irreducibles): m = collect(poly, I, evaluate=False) y = m.get(I, S.Zero) if y: x = m.get(S.One, S.Zero) if x.has(I) or y.has(I): continue # nontrivial x + I*y pairs.add((x, y)) irreducibles.remove(poly) while pairs: x, y = pairs.pop() if (x, -y) in pairs: pairs.remove((x, -y)) # Choosing b with no minus sign if y.could_extract_minus_sign(): y = -y irreducibles.add(x * x + y * y) atans.add(atan(x / y)) else: irreducibles.add(x + I * y) B = _symbols('B', len(irreducibles)) C = _symbols('C', len(atans)) # Note: the ordering matters here for poly, b in reversed(list(zip(ordered(irreducibles), B))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) for poly, c in reversed(list(zip(ordered(atans), C))): if poly.has(*V): poly_coeffs.append(c) atan_part.append(c * poly) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancellation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part / poly_denom + Add(*log_part) + Add(*atan_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) try: numer = ring.from_expr(raw_numer) except ValueError: raise PolynomialError solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.subs(solution).subs( list(zip(poly_coeffs, [S.Zero] * len(poly_coeffs))))
def _expr_small(cls, x): return log(1 - x)
def _denest_pow(eq): """ Denest powers. This is a helper function for powdenest that performs the actual transformation. """ from sympy.simplify.simplify import logcombine b, e = eq.as_base_exp() if b.is_Pow or isinstance(b.func, exp) and e != 1: new = b._eval_power(e) if new is not None: eq = new b, e = new.as_base_exp() # denest exp with log terms in exponent if b is S.Exp1 and e.is_Mul: logs = [] other = [] for ei in e.args: if any(isinstance(ai, log) for ai in Add.make_args(ei)): logs.append(ei) else: other.append(ei) logs = logcombine(Mul(*logs)) return Pow(exp(logs), Mul(*other)) _, be = b.as_base_exp() if be is S.One and not (b.is_Mul or b.is_Rational and b.q != 1 or b.is_positive): return eq # denest eq which is either pos**e or Pow**e or Mul**e or # Mul(b1**e1, b2**e2) # handle polar numbers specially polars, nonpolars = [], [] for bb in Mul.make_args(b): if bb.is_polar: polars.append(bb.as_base_exp()) else: nonpolars.append(bb) if len(polars) == 1 and not polars[0][0].is_Mul: return Pow(polars[0][0], polars[0][1] * e) * powdenest( Mul(*nonpolars)**e) elif polars: return Mul(*[powdenest(bb**(ee*e)) for (bb, ee) in polars]) \ *powdenest(Mul(*nonpolars)**e) if b.is_Integer: # use log to see if there is a power here logb = expand_log(log(b)) if logb.is_Mul: c, logb = logb.args e *= c base = logb.args[0] return Pow(base, e) # if b is not a Mul or any factor is an atom then there is nothing to do if not b.is_Mul or any(s.is_Atom for s in Mul.make_args(b)): return eq # let log handle the case of the base of the argument being a Mul, e.g. # sqrt(x**(2*i)*y**(6*i)) -> x**i*y**(3**i) if x and y are positive; we # will take the log, expand it, and then factor out the common powers that # now appear as coefficient. We do this manually since terms_gcd pulls out # fractions, terms_gcd(x+x*y/2) -> x*(y + 2)/2 and we don't want the 1/2; # gcd won't pull out numerators from a fraction: gcd(3*x, 9*x/2) -> x but # we want 3*x. Neither work with noncommutatives. def nc_gcd(aa, bb): a, b = [i.as_coeff_Mul() for i in [aa, bb]] c = gcd(a[0], b[0]).as_numer_denom()[0] g = Mul(*(a[1].args_cnc(cset=True)[0] & b[1].args_cnc(cset=True)[0])) return _keep_coeff(c, g) glogb = expand_log(log(b)) if glogb.is_Add: args = glogb.args g = reduce(nc_gcd, args) if g != 1: cg, rg = g.as_coeff_Mul() glogb = _keep_coeff(cg, rg * Add(*[a / g for a in args])) # now put the log back together again if isinstance(glogb, log) or not glogb.is_Mul: if glogb.args[0].is_Pow or isinstance(glogb.args[0], exp): glogb = _denest_pow(glogb.args[0]) if (abs(glogb.exp) < 1) == True: return Pow(glogb.base, glogb.exp * e) return eq # the log(b) was a Mul so join any adds with logcombine add = [] other = [] for a in glogb.args: if a.is_Add: add.append(a) else: other.append(a) return Pow(exp(logcombine(Mul(*add))), e * Mul(*other))
def f(rv): if not (rv.is_Add or rv.is_Mul): return rv def gooda(a): # bool to tell whether the leading ``a`` in ``a*log(x)`` # could appear as log(x**a) return (a is not S.NegativeOne and # -1 *could* go, but we disallow (a.is_real or force and a.is_real is not False)) def goodlog(l): # bool to tell whether log ``l``'s argument can combine with others a = l.args[0] return a.is_positive or force and a.is_nonpositive is not False other = [] logs = [] log1 = defaultdict(list) for a in Add.make_args(rv): if a.func is log and goodlog(a): log1[()].append(([], a)) elif not a.is_Mul: other.append(a) else: ot = [] co = [] lo = [] for ai in a.args: if ai.is_Rational and ai < 0: ot.append(S.NegativeOne) co.append(-ai) elif ai.func is log and goodlog(ai): lo.append(ai) elif gooda(ai): co.append(ai) else: ot.append(ai) if len(lo) > 1: logs.append((ot, co, lo)) elif lo: log1[tuple(ot)].append((co, lo[0])) else: other.append(a) # if there is only one log at each coefficient and none have # an exponent to place inside the log then there is nothing to do if not logs and all( len(log1[k]) == 1 and log1[k][0] == [] for k in log1): return rv # collapse multi-logs as far as possible in a canonical way # TODO: see if x*log(a)+x*log(a)*log(b) -> x*log(a)*(1+log(b))? # -- in this case, it's unambiguous, but if it were were a log(c) in # each term then it's arbitrary whether they are grouped by log(a) or # by log(c). So for now, just leave this alone; it's probably better to # let the user decide for o, e, l in logs: l = list(ordered(l)) e = log(l.pop(0).args[0]**Mul(*e)) while l: li = l.pop(0) e = log(li.args[0]**e) c, l = Mul(*o), e if l.func is log: # it should be, but check to be sure log1[(c, )].append(([], l)) else: other.append(c * l) # logs that have the same coefficient can multiply for k in list(log1.keys()): log1[Mul(*k)] = log( logcombine(Mul(*[l.args[0]**Mul(*c) for c, l in log1.pop(k)]), force=force)) # logs that have oppositely signed coefficients can divide for k in ordered(list(log1.keys())): if not k in log1: # already popped as -k continue if -k in log1: # figure out which has the minus sign; the one with # more op counts should be the one num, den = k, -k if num.count_ops() > den.count_ops(): num, den = den, num other.append( num * log(log1.pop(num).args[0] / log1.pop(den).args[0])) else: other.append(k * log1.pop(k)) return Add(*other)
def _invert_real(f, g_ys, symbol): """Helper function for _invert.""" if f == symbol: return (f, g_ys) n = Dummy('n', real=True) if hasattr(f, 'inverse') and not isinstance(f, ( TrigonometricFunction, HyperbolicFunction, )): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_real(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, Abs): pos = Interval(0, S.Infinity) neg = Interval(S.NegativeInfinity, 0) return _invert_real( f.args[0], Union( imageset(Lambda(n, n), g_ys).intersect(pos), imageset(Lambda(n, -n), g_ys).intersect(neg)), symbol) if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g is not S.Zero: return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g is not S.One: return _invert_real(h, imageset(Lambda(n, n / g), g_ys), symbol) if f.is_Pow: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if not expo_has_sym: res = imageset(Lambda(n, real_root(n, expo)), g_ys) if expo.is_rational: numer, denom = expo.as_numer_denom() if numer == S.One or numer == -S.One: return _invert_real(base, res, symbol) else: if numer % 2 == 0: n = Dummy('n') neg_res = imageset(Lambda(n, -n), res) return _invert_real(base, res + neg_res, symbol) else: return _invert_real(base, res, symbol) else: if not base.is_positive: raise ValueError("x**w where w is irrational is not " "defined for negative x") return _invert_real(base, res, symbol) if not base_has_sym: return _invert_real(expo, imageset(Lambda(n, log(n) / log(base)), g_ys), symbol) if isinstance(f, TrigonometricFunction): if isinstance(g_ys, FiniteSet): def inv(trig): if isinstance(f, (sin, csc)): F = asin if isinstance(f, sin) else acsc return (lambda a: n * pi + (-1)**n * F(a), ) if isinstance(f, (cos, sec)): F = acos if isinstance(f, cos) else asec return ( lambda a: 2 * n * pi + F(a), lambda a: 2 * n * pi - F(a), ) if isinstance(f, (tan, cot)): return (lambda a: n * pi + f.inverse()(a), ) n = Dummy('n', integer=True) invs = S.EmptySet for L in inv(f): invs += Union( *[imageset(Lambda(n, L(g)), S.Integers) for g in g_ys]) return _invert_real(f.args[0], invs, symbol) return (f, g_ys)
def _expr_small(cls, z): return log(S.Half + sqrt(1 - z) / 2)
def _expr_small_minus(cls, z): return log(S(1) / 2 + sqrt(1 + z) / 2)
def _(expr, assumptions): """ * Real**Integer -> Real * Positive**Real -> Real * Real**(Integer/Even) -> Real if base is nonnegative * Real**(Integer/Odd) -> Real * Imaginary**(Integer/Even) -> Real * Imaginary**(Integer/Odd) -> not Real * Imaginary**Real -> ? since Real could be 0 (giving real) or 1 (giving imaginary) * b**Imaginary -> Real if log(b) is imaginary and b != 0 and exponent != integer multiple of I*pi/log(b) * Real**Real -> ? e.g. sqrt(-1) is imaginary and sqrt(2) is not """ if expr.is_number: return _RealPredicate_number(expr, assumptions) if expr.base == E: return ask( Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions ) if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E): if ask(Q.imaginary(expr.base.exp), assumptions): if ask(Q.imaginary(expr.exp), assumptions): return True # If the i = (exp's arg)/(I*pi) is an integer or half-integer # multiple of I*pi then 2*i will be an integer. In addition, # exp(i*I*pi) = (-1)**i so the overall realness of the expr # can be determined by replacing exp(i*I*pi) with (-1)**i. i = expr.base.exp/I/pi if ask(Q.integer(2*i), assumptions): return ask(Q.real(((-1)**i)**expr.exp), assumptions) return if ask(Q.imaginary(expr.base), assumptions): if ask(Q.integer(expr.exp), assumptions): odd = ask(Q.odd(expr.exp), assumptions) if odd is not None: return not odd return if ask(Q.imaginary(expr.exp), assumptions): imlog = ask(Q.imaginary(log(expr.base)), assumptions) if imlog is not None: # I**i -> real, log(I) is imag; # (2*I)**i -> complex, log(2*I) is not imag return imlog if ask(Q.real(expr.base), assumptions): if ask(Q.real(expr.exp), assumptions): if expr.exp.is_Rational and \ ask(Q.even(expr.exp.q), assumptions): return ask(Q.positive(expr.base), assumptions) elif ask(Q.integer(expr.exp), assumptions): return True elif ask(Q.positive(expr.base), assumptions): return True elif ask(Q.negative(expr.base), assumptions): return False
def mrv(e, x): """Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e', and e rewritten in terms of these""" e = powsimp(e, deep=True, combine='exp') if not isinstance(e, Basic): raise TypeError("e should be an instance of Basic") if not e.has(x): return SubsSet(), e elif e == x: s = SubsSet() return s, s[x] elif e.is_Mul or e.is_Add: i, d = e.as_independent(x) # throw away x-independent terms if d.func != e.func: s, expr = mrv(d, x) return s, e.func(i, expr) a, b = d.as_two_terms() s1, e1 = mrv(a, x) s2, e2 = mrv(b, x) return mrv_max1(s1, s2, e.func(i, e1, e2), x) elif e.is_Pow: b, e = e.as_base_exp() if b == 1: return SubsSet(), b if e.has(x): return mrv(exp(e * log(b)), x) else: s, expr = mrv(b, x) return s, expr**e elif isinstance(e, log): s, expr = mrv(e.args[0], x) return s, log(expr) elif isinstance(e, exp): # We know from the theory of this algorithm that exp(log(...)) may always # be simplified here, and doing so is vital for termination. if isinstance(e.args[0], log): return mrv(e.args[0].args[0], x) # if a product has an infinite factor the result will be # infinite if there is no zero, otherwise NaN; here, we # consider the result infinite if any factor is infinite li = limitinf(e.args[0], x) if any(_.is_infinite for _ in Mul.make_args(li)): s1 = SubsSet() e1 = s1[e] s2, e2 = mrv(e.args[0], x) su = s1.union(s2)[0] su.rewrites[e1] = exp(e2) return mrv_max3(s1, e1, s2, exp(e2), su, e1, x) else: s, expr = mrv(e.args[0], x) return s, exp(expr) elif e.is_Function: l = [mrv(a, x) for a in e.args] l2 = [s for (s, _) in l if s != SubsSet()] if len(l2) != 1: # e.g. something like BesselJ(x, x) raise NotImplementedError("MRV set computation for functions in" " several variables not implemented.") s, ss = l2[0], SubsSet() args = [ss.do_subs(x[1]) for x in l] return s, e.func(*args) elif e.is_Derivative: raise NotImplementedError("MRV set computation for derviatives" " not implemented yet.") return mrv(e.args[0], x) raise NotImplementedError("Don't know how to calculate the mrv of '%s'" % e)
#init_printing() print numpy.arccos(-1) print math.acos(-1) print acos(-1) print acos(0) print acos(0) print acos(S.One/2) x,y,z = symbols('x,y,z') alpha,beta,gamma = symbols('alpha,beta,gamma') print x+1 print log(alpha ** beta) + gamma print sin(x)**2 + cos(x)**2 print simplify(sin(x)**2 + cos(x)**2) mu,sigma = symbols('mu,sigma') bell = exp(-(x-mu)**2 / 2*sigma**2) print bell.diff(x) print bell.diff(sigma) print bell.diff(x).diff(x).diff(x) print simplify(bell.diff(x).diff(x).diff(x)) print (x**2).diff(x) print sin(x).diff(x) print (x**2+x*y+y**2).diff(x) print (x**2+x*y+y**2).diff(y)
def _expr_big(cls, z, n): if n.is_even: return (n - S(1)/2)*pi*I + log(sqrt(z)/2) + I*asin(1/sqrt(z)) else: return (n - S(1)/2)*pi*I + log(sqrt(z)/2) - I*asin(1/sqrt(z))
def test_harmonic_rational(): ne = S(6) no = S(5) pe = S(8) po = S(9) qe = S(10) qo = S(13) Heee = harmonic(ne + pe/qe) Aeee = (-log(10) + 2*(-1/S(4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + 5/S(8))) + 2*(-sqrt(5)/4 - 1/S(4))*log(sqrt(sqrt(5)/8 + 5/S(8))) + pi*(1/S(4) + sqrt(5)/4)/(2*sqrt(-sqrt(5)/8 + 5/S(8))) + 13944145/S(4720968)) Heeo = harmonic(ne + pe/qo) Aeeo = (-log(26) + 2*log(sin(3*pi/13))*cos(4*pi/13) + 2*log(sin(2*pi/13))*cos(32*pi/13) + 2*log(sin(5*pi/13))*cos(80*pi/13) - 2*log(sin(6*pi/13))*cos(5*pi/13) - 2*log(sin(4*pi/13))*cos(pi/13) + pi*cot(5*pi/13)/2 - 2*log(sin(pi/13))*cos(3*pi/13) + 2422020029/S(702257080)) Heoe = harmonic(ne + po/qe) Aeoe = (-log(20) + 2*(1/S(4) + sqrt(5)/4)*log(-1/S(4) + sqrt(5)/4) + 2*(-1/S(4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + 5/S(8))) + 2*(-sqrt(5)/4 - 1/S(4))*log(sqrt(sqrt(5)/8 + 5/S(8))) + 2*(-sqrt(5)/4 + 1/S(4))*log(1/S(4) + sqrt(5)/4) + 11818877030/S(4286604231) + pi*(sqrt(5)/8 + 5/S(8))/sqrt(-sqrt(5)/8 + 5/S(8))) Heoo = harmonic(ne + po/qo) Aeoo = (-log(26) + 2*log(sin(3*pi/13))*cos(54*pi/13) + 2*log(sin(4*pi/13))*cos(6*pi/13) + 2*log(sin(6*pi/13))*cos(108*pi/13) - 2*log(sin(5*pi/13))*cos(pi/13) - 2*log(sin(pi/13))*cos(5*pi/13) + pi*cot(4*pi/13)/2 - 2*log(sin(2*pi/13))*cos(3*pi/13) + 11669332571/S(3628714320)) Hoee = harmonic(no + pe/qe) Aoee = (-log(10) + 2*(-1/S(4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + 5/S(8))) + 2*(-sqrt(5)/4 - 1/S(4))*log(sqrt(sqrt(5)/8 + 5/S(8))) + pi*(1/S(4) + sqrt(5)/4)/(2*sqrt(-sqrt(5)/8 + 5/S(8))) + 779405/S(277704)) Hoeo = harmonic(no + pe/qo) Aoeo = (-log(26) + 2*log(sin(3*pi/13))*cos(4*pi/13) + 2*log(sin(2*pi/13))*cos(32*pi/13) + 2*log(sin(5*pi/13))*cos(80*pi/13) - 2*log(sin(6*pi/13))*cos(5*pi/13) - 2*log(sin(4*pi/13))*cos(pi/13) + pi*cot(5*pi/13)/2 - 2*log(sin(pi/13))*cos(3*pi/13) + 53857323/S(16331560)) Hooe = harmonic(no + po/qe) Aooe = (-log(20) + 2*(1/S(4) + sqrt(5)/4)*log(-1/S(4) + sqrt(5)/4) + 2*(-1/S(4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + 5/S(8))) + 2*(-sqrt(5)/4 - 1/S(4))*log(sqrt(sqrt(5)/8 + 5/S(8))) + 2*(-sqrt(5)/4 + 1/S(4))*log(1/S(4) + sqrt(5)/4) + 486853480/S(186374097) + pi*(sqrt(5)/8 + 5/S(8))/sqrt(-sqrt(5)/8 + 5/S(8))) Hooo = harmonic(no + po/qo) Aooo = (-log(26) + 2*log(sin(3*pi/13))*cos(54*pi/13) + 2*log(sin(4*pi/13))*cos(6*pi/13) + 2*log(sin(6*pi/13))*cos(108*pi/13) - 2*log(sin(5*pi/13))*cos(pi/13) - 2*log(sin(pi/13))*cos(5*pi/13) + pi*cot(4*pi/13)/2 - 2*log(sin(2*pi/13))*cos(3*pi/13) + 383693479/S(125128080)) H = [Heee, Heeo, Heoe, Heoo, Hoee, Hoeo, Hooe, Hooo] A = [Aeee, Aeeo, Aeoe, Aeoo, Aoee, Aoeo, Aooe, Aooo] for h, a in zip(H, A): e = expand_func(h).doit() assert cancel(e/a) == 1 assert abs(h.n() - a.n()) < 1e-12
def _expr_big_minus(cls, z, n): if n.is_even: return pi * I * n + log(S(1) / 2 + sqrt(1 + z) / 2) else: return pi * I * n + log(sqrt(1 + z) / 2 - S(1) / 2)
def test_1(): ''' Tests for Rubi Algebraic 1.2 rules. Parsed from Maple syntax All tests: http://www.apmaths.uwo.ca/~arich/IntegrationProblems/MapleSyntaxFiles/MapleSyntaxFiles.html Note: Some tests are commented since they depend rules other than Algebraic1.2. ''' test = [ [(a + b*x)**S(2)*(e + f*x)*sqrt(c + d*x)/x, x, S(5), S(2)/S(7)*f*(a + b*x)**S(2)*(c + d*x)**(S(3)/S(2))/d + S(2)/S(105)*(c + d*x)**(S(3)/S(2))*(S(2)*(S(10)*a**S(2)*d**S(2)*f - b**S(2)*c*(S(7)*d*e - S(4)*c*f) + S(7)*a*b*d*(S(5)*d*e - S(2)*c*f)) + S(3)*b*d*(S(7)*b*d*e - S(4)*b*c*f + S(4)*a*d*f)*x)/d**S(3) - S(2)*a**S(2)*e*arctanh(sqrt(c + d*x)/sqrt(c))*sqrt(c) + S(2)*a**S(2)*e*sqrt(c + d*x)], [(a + b*x)*(e + f*x)*sqrt(c + d*x)/x, x, S(4), - S(2)/S(15)*(c + d*x)**(S(3)/S(2))*(S(2)*b*c*f - S(5)*d*(b*e + a*f) - S(3)*b*d*f*x)/d**S(2) - S(2)*a*e*arctanh(sqrt(c + d*x)/sqrt(c))*sqrt(c) + S(2)*a*e*sqrt(c + d*x)], [(c + d*x)**S(2)*(e + f*x)*sqrt(a + b*x)/x, x, S(5), S(2)/S(7)*f*(a + b*x)**(S(3)/S(2))*(c + d*x)**S(2)/b + S(2)/S(105)*(a + b*x)**(S(3)/S(2))*(S(2)*(S(4)*a**S(2)*d**S(2)*f - S(7)*a*b*d*(d*e + S(2)*c*f) + S(5)*b**S(2)*c*(S(7)*d*e + S(2)*c*f)) + S(3)*b*d*(S(7)*b*d*e + S(4)*b*c*f - S(4)*a*d*f)*x)/b**S(3) - S(2)*c**S(2)*e*arctanh(sqrt(a + b*x)/sqrt(a))*sqrt(a) + S(2)*c**S(2)*e*sqrt(a + b*x)], [(c + d*x)*(e + f*x)*sqrt(a + b*x)/x, x, S(4), - S(2)/S(15)*(a + b*x)**(S(3)/S(2))*(S(2)*a*d*f - S(5)*b*(d*e + c*f) - S(3)*b*d*f*x)/b**S(2) - S(2)*c*e*arctanh(sqrt(a + b*x)/sqrt(a))*sqrt(a) + S(2)*c*e*sqrt(a + b*x)], [x**S(4)*(e + f*x)**n/((a + b*x)*(c + d*x)), x, S(8), e**S(2)*(e + f*x)**(S(1) + n)/(b*d*f**S(3)*(S(1) + n)) + (b*c + a*d)*e*(e + f*x)**(S(1) + n)/(b**S(2)*d**S(2)*f**S(2)*(S(1) + n)) + (b**S(2)*c**S(2) + a*b*c*d + a**S(2)*d**S(2))*(e + f*x)**(S(1) + n)/(b**S(3)*d**S(3)*f*(S(1) + n)) - S(2)*e*(e + f*x)**(S(2) + n)/(b*d*f**S(3)*(S(2) + n)) - (b*c + a*d)*(e + f*x)**(S(2) + n)/(b**S(2)*d**S(2)*f**S(2)*(S(2) + n)) + (e + f*x)**(S(3) + n)/(b*d*f**S(3)*(S(3) + n)) - a**S(4)*(e + f*x)**(S(1) + n)*hypergeom([S(1), S(1) + n], [S(2) + n], b*(e + f*x)/(b*e - a*f))/(b**S(3)*(b*c - a*d)*(b*e - a*f)*(S(1) + n)) + c**S(4)*(e + f*x)**(S(1) + n)*hypergeom([S(1), S(1) + n], [S(2) + n], d*(e + f*x)/(d*e - c*f))/(d**S(3)*(b*c - a*d)*(d*e - c*f)*(S(1) + n))], [(a + b*x)*(c + d*x)*(e + f*x)*(g + h*x), x, S(2), a*c*e*g*x + S(1)/S(2)*(b*c*e*g + a*(d*e*g + c*f*g + c*e*h))*x**S(2) + S(1)/S(3)*(b*(d*e*g + c*f*g + c*e*h) + a*(d*f*g + d*e*h + c*f*h))*x**S(3) + S(1)/S(4)*(a*d*f*h + b*(d*f*g + d*e*h + c*f*h))*x**S(4) + S(1)/S(5)*b*d*f*h*x**S(5)], [(a + b*x)*(c + d*x)*(e + f*x)/(g + h*x), x, S(2), (b*(d*g - c*h)*(f*g - e*h) - a*h*(d*f*g - d*e*h - c*f*h))*x/h**S(3) + S(1)/S(2)*(a*d*f*h - b*(d*f*g - d*e*h - c*f*h))*x**S(2)/h**S(2) + S(1)/S(3)*b*d*f*x**S(3)/h - (b*g - a*h)*(d*g - c*h)*(f*g - e*h)*log(g + h*x)/h**S(4)], [(a + b*x)**m*(c + d*x)*(e + f*x)*(g + h*x), x, S(2), (b*c - a*d)*(b*e - a*f)*(b*g - a*h)*(a + b*x)**(S(1) + m)/(b**S(4)*(S(1) + m)) + (S(3)*a**S(2)*d*f*h + b**S(2)*(d*e*g + c*f*g + c*e*h) - S(2)*a*b*(d*f*g + d*e*h + c*f*h))*(a + b*x)**(S(2) + m)/(b**S(4)*(S(2) + m)) - (S(3)*a*d*f*h - b*(d*f*g + d*e*h + c*f*h))*(a + b*x)**(S(3) + m)/(b**S(4)*(S(3) + m)) + d*f*h*(a + b*x)**(S(4) + m)/(b**S(4)*(S(4) + m))], [(c + d*x)**( - S(4) - m)*(e + f*x)**m*(g + h*x), x, S(3), - (d*g - c*h)*(c + d*x)**( - S(3) - m)*(e + f*x)**(S(1) + m)/(d*(d*e - c*f)*(S(3) + m)) + (c*f*h*(S(1) + m) + d*(S(2)*f*g - e*h*(S(3) + m)))*(c + d*x)**( - S(2) - m)*(e + f*x)**(S(1) + m)/(d*(d*e - c*f)**S(2)*(S(2) + m)*(S(3) + m)) - f*(c*f*h*(S(1) + m) + d*(S(2)*f*g - e*h*(S(3) + m)))*(c + d*x)**( - S(1) - m)*(e + f*x)**(S(1) + m)/(d*(d*e - c*f)**S(3)*(S(1) + m)*(S(2) + m)*(S(3) + m))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True)
def _invert_real(f, g_ys, symbol): """ Helper function for invert_real """ if not f.has(symbol): raise ValueError("Inverse of constant function doesn't exist") if f is symbol: return (f, g_ys) n = Dummy('n') if hasattr(f, 'inverse') and not isinstance(f, C.TrigonometricFunction): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_real(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, Abs): return _invert_real(f.args[0], Union(g_ys, imageset(Lambda(n, -n), g_ys)), symbol) if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g != S.Zero: return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g != S.One: return _invert_real(h, imageset(Lambda(n, n / g), g_ys), symbol) if f.is_Pow: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if not expo_has_sym: res = imageset(Lambda(n, Pow(n, 1 / expo)), g_ys) if expo.is_rational: numer, denom = expo.as_numer_denom() if numer == S.One or numer == -S.One: return _invert_real(base, res, symbol) else: if numer % 2 == 0: n = Dummy('n') neg_res = imageset(Lambda(n, -n), res) return _invert_real(base, res + neg_res, symbol) else: return _invert_real(base, res, symbol) else: if not base.is_positive: raise ValueError("x**w where w is irrational is not" "defined for negative x") return _invert_real(base, res, symbol) if not base_has_sym: return _invert_real(expo, imageset(Lambda(n, log(n) / log(base)), g_ys), symbol) if isinstance(f, tan) or isinstance(f, cot): n = Dummy('n') if isinstance(g_ys, FiniteSet): tan_cot_invs = Union(*[ imageset(Lambda(n, n * pi + f.inverse()(g_y)), S.Integers) for g_y in g_ys ]) return _invert_real(f.args[0], tan_cot_invs, symbol) return (f, g_ys)
def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3, degree_offset=0, unnecessary_permutations=None, _try_heurisch=None): """ Compute indefinite integral using heuristic Risch algorithm. This is a heuristic approach to indefinite integration in finite terms using the extended heuristic (parallel) Risch algorithm, based on Manuel Bronstein's "Poor Man's Integrator". The algorithm supports various classes of functions including transcendental elementary or special functions like Airy, Bessel, Whittaker and Lambert. Note that this algorithm is not a decision procedure. If it isn't able to compute the antiderivative for a given function, then this is not a proof that such a functions does not exist. One should use recursive Risch algorithm in such case. It's an open question if this algorithm can be made a full decision procedure. This is an internal integrator procedure. You should use toplevel 'integrate' function in most cases, as this procedure needs some preprocessing steps and otherwise may fail. Specification ============= heurisch(f, x, rewrite=False, hints=None) where f : expression x : symbol rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh' hints -> a list of functions that may appear in anti-derivate - hints = None --> no suggestions at all - hints = [ ] --> try to figure out - hints = [f1, ..., fn] --> we know better Examples ======== >>> from sympy import tan >>> from sympy.integrals.heurisch import heurisch >>> from sympy.abc import x, y >>> heurisch(y*tan(x), x) y*log(tan(x)**2 + 1)/2 See Manuel Bronstein's "Poor Man's Integrator": [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html For more information on the implemented algorithm refer to: [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration Method and its Implementation in Maple, Proceedings of ISSAC'89, ACM Press, 212-217. [3] J. H. Davenport, On the Parallel Risch Algorithm (I), Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157. [4] J. H. Davenport, On the Parallel Risch Algorithm (III): Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6. [5] J. H. Davenport, B. M. Trager, On the Parallel Risch Algorithm (II), ACM Transactions on Mathematical Software 11 (1985), 356-362. See Also ======== sympy.integrals.integrals.Integral.doit sympy.integrals.integrals.Integral sympy.integrals.heurisch.components """ f = sympify(f) # There are some functions that Heurisch cannot currently handle, # so do not even try. # Set _try_heurisch=True to skip this check if _try_heurisch is not True: if f.has(Abs, re, im, sign, Heaviside, DiracDelta, floor, ceiling, arg): return if x not in f.free_symbols: return f * x if not f.is_Add: indep, f = f.as_independent(x) else: indep = S.One rewritables = { (sin, cos, cot): tan, (sinh, cosh, coth): tanh, } if rewrite: for candidates, rule in rewritables.items(): f = f.rewrite(candidates, rule) else: for candidates in rewritables.keys(): if f.has(*candidates): break else: rewrite = True terms = components(f, x) if hints is not None: if not hints: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) c = Wild('c', exclude=[x]) for g in set(terms): # using copy of terms if g.is_Function: if isinstance(g, li): M = g.args[0].match(a * x**b) if M is not None: terms.add( x * (li(M[a] * x**M[b]) - (M[a] * x**M[b])**(-1 / M[b]) * Ei( (M[b] + 1) * log(M[a] * x**M[b]) / M[b]))) #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) ) elif isinstance(g, exp): M = g.args[0].match(a * x**2) if M is not None: if M[a].is_positive: terms.add(erfi(sqrt(M[a]) * x)) else: # M[a].is_negative or unknown terms.add(erf(sqrt(-M[a]) * x)) M = g.args[0].match(a * x**2 + b * x + c) if M is not None: if M[a].is_positive: terms.add( sqrt(pi / 4 * (-M[a])) * exp(M[c] - M[b]**2 / (4 * M[a])) * erfi( sqrt(M[a]) * x + M[b] / (2 * sqrt(M[a])))) elif M[a].is_negative: terms.add( sqrt(pi / 4 * (-M[a])) * exp(M[c] - M[b]**2 / (4 * M[a])) * erf( sqrt(-M[a]) * x - M[b] / (2 * sqrt(-M[a])))) M = g.args[0].match(a * log(x)**2) if M is not None: if M[a].is_positive: terms.add( erfi( sqrt(M[a]) * log(x) + 1 / (2 * sqrt(M[a])))) if M[a].is_negative: terms.add( erf( sqrt(-M[a]) * log(x) - 1 / (2 * sqrt(-M[a])))) elif g.is_Pow: if g.exp.is_Rational and g.exp.q == 2: M = g.base.match(a * x**2 + b) if M is not None and M[b].is_positive: if M[a].is_positive: terms.add(asinh(sqrt(M[a] / M[b]) * x)) elif M[a].is_negative: terms.add(asin(sqrt(-M[a] / M[b]) * x)) M = g.base.match(a * x**2 - b) if M is not None and M[b].is_positive: if M[a].is_positive: terms.add(acosh(sqrt(M[a] / M[b]) * x)) elif M[a].is_negative: terms.add((-M[b] / 2 * sqrt(-M[a]) * atan( sqrt(-M[a]) * x / sqrt(M[a] * x**2 - M[b])) )) else: terms |= set(hints) dcache = DiffCache(x) for g in set(terms): # using copy of terms terms |= components(dcache.get_diff(g), x) # TODO: caching is significant factor for why permutations work at all. Change this. V = _symbols('x', len(terms)) # sort mapping expressions from largest to smallest (last is always x). mapping = list( reversed( list( zip(*ordered( # [(a[0].as_independent(x)[1], a) for a in zip(terms, V)])))[1])) # rev_mapping = {v: k for k, v in mapping} # if mappings is None: # # optimizing the number of permutations of mapping # assert mapping[-1][0] == x # if not, find it and correct this comment unnecessary_permutations = [mapping.pop(-1)] mappings = permutations(mapping) else: unnecessary_permutations = unnecessary_permutations or [] def _substitute(expr): return expr.subs(mapping) for mapping in mappings: mapping = list(mapping) mapping = mapping + unnecessary_permutations diffs = [_substitute(dcache.get_diff(g)) for g in terms] denoms = [g.as_numer_denom()[1] for g in diffs] if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V): denom = reduce(lambda p, q: lcm(p, q, *V), denoms) break else: if not rewrite: result = heurisch( f, x, rewrite=True, hints=hints, unnecessary_permutations=unnecessary_permutations) if result is not None: return indep * result return None numers = [cancel(denom * g) for g in diffs] def _derivation(h): return Add(*[d * h.diff(v) for d, v in zip(numers, V)]) def _deflation(p): for y in V: if not p.has(y): continue if _derivation(p) is not S.Zero: c, q = p.as_poly(y).primitive() return _deflation(c) * gcd(q, q.diff(y)).as_expr() return p def _splitter(p): for y in V: if not p.has(y): continue if _derivation(y) is not S.Zero: c, q = p.as_poly(y).primitive() q = q.as_expr() h = gcd(q, _derivation(q), y) s = quo(h, gcd(q, q.diff(y), y), y) c_split = _splitter(c) if s.as_poly(y).degree() == 0: return (c_split[0], q * c_split[1]) q_split = _splitter(cancel(q / s)) return (c_split[0] * q_split[0] * s, c_split[1] * q_split[1]) return (S.One, p) special = {} for term in terms: if term.is_Function: if isinstance(term, tan): special[1 + _substitute(term)**2] = False elif isinstance(term, tanh): special[1 + _substitute(term)] = False special[1 - _substitute(term)] = False elif isinstance(term, LambertW): special[_substitute(term)] = True F = _substitute(f) P, Q = F.as_numer_denom() u_split = _splitter(denom) v_split = _splitter(Q) polys = set(list(v_split) + [u_split[0]] + list(special.keys())) s = u_split[0] * Mul(*[k for k, v in special.items() if v]) polified = [p.as_poly(*V) for p in [s, P, Q]] if None in polified: return None #--- definitions for _integrate a, b, c = [p.total_degree() for p in polified] poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr() def _exponent(g): if g.is_Pow: if g.exp.is_Rational and g.exp.q != 1: if g.exp.p > 0: return g.exp.p + g.exp.q - 1 else: return abs(g.exp.p + g.exp.q) else: return 1 elif not g.is_Atom and g.args: return max([_exponent(h) for h in g.args]) else: return 1 A, B = _exponent(f), a + max(b, c) if A > 1 and B > 1: monoms = tuple(ordered(itermonomials(V, A + B - 1 + degree_offset))) else: monoms = tuple(ordered(itermonomials(V, A + B + degree_offset))) poly_coeffs = _symbols('A', len(monoms)) poly_part = Add( *[poly_coeffs[i] * monomial for i, monomial in enumerate(monoms)]) reducibles = set() for poly in polys: if poly.has(*V): try: factorization = factor(poly, greedy=True) except PolynomialError: factorization = poly if factorization.is_Mul: factors = factorization.args else: factors = (factorization, ) for fact in factors: if fact.is_Pow: reducibles.add(fact.base) else: reducibles.add(fact) def _integrate(field=None): irreducibles = set() atans = set() pairs = set() for poly in reducibles: for z in poly.free_symbols: if z in V: break # should this be: `irreducibles |= \ else: # set(root_factors(poly, z, filter=field))` continue # and the line below deleted? # | # V irreducibles |= set(root_factors(poly, z, filter=field)) log_part, atan_part = [], [] for poly in list(irreducibles): m = collect(poly, I, evaluate=False) y = m.get(I, S.Zero) if y: x = m.get(S.One, S.Zero) if x.has(I) or y.has(I): continue # nontrivial x + I*y pairs.add((x, y)) irreducibles.remove(poly) while pairs: x, y = pairs.pop() if (x, -y) in pairs: pairs.remove((x, -y)) # Choosing b with no minus sign if y.could_extract_minus_sign(): y = -y irreducibles.add(x * x + y * y) atans.add(atan(x / y)) else: irreducibles.add(x + I * y) B = _symbols('B', len(irreducibles)) C = _symbols('C', len(atans)) # Note: the ordering matters here for poly, b in reversed(list(zip(ordered(irreducibles), B))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) for poly, c in reversed(list(zip(ordered(atans), C))): if poly.has(*V): poly_coeffs.append(c) atan_part.append(c * poly) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancellation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part / poly_denom + Add(*log_part) + Add(*atan_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) try: numer = ring.from_expr(raw_numer) except ValueError: raise PolynomialError solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.subs(solution).subs( list(zip(poly_coeffs, [S.Zero] * len(poly_coeffs)))) if not (F.free_symbols - set(V)): solution = _integrate('Q') if solution is None: solution = _integrate() else: solution = _integrate() if solution is not None: antideriv = solution.subs(rev_mapping) antideriv = cancel(antideriv).expand(force=True) if antideriv.is_Add: antideriv = antideriv.as_independent(x)[1] return indep * antideriv else: if retries >= 0: result = heurisch( f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations) if result is not None: return indep * result return None
def heurisch(f, x, **kwargs): """Compute indefinite integral using heuristic Risch algorithm. This is a heuristic approach to indefinite integration in finite terms using the extended heuristic (parallel) Risch algorithm, based on Manuel Bronstein's "Poor Man's Integrator". The algorithm supports various classes of functions including transcendental elementary or special functions like Airy, Bessel, Whittaker and Lambert. Note that this algorithm is not a decision procedure. If it isn't able to compute the antiderivative for a given function, then this is not a proof that such a functions does not exist. One should use recursive Risch algorithm in such case. It's an open question if this algorithm can be made a full decision procedure. This is an internal integrator procedure. You should use toplevel 'integrate' function in most cases, as this procedure needs some preprocessing steps and otherwise may fail. Specification ============ heurisch(f, x, rewrite=False, hints=None) where f : expression x : symbol rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh' hints -> a list of functions that may appear in anti-derivate - hints = None --> no suggestions at all - hints = [ ] --> try to figure out - hints = [f1, ..., fn] --> we know better Examples ======== >>> from sympy import tan >>> from sympy.integrals.risch import heurisch >>> from sympy.abc import x, y >>> heurisch(y*tan(x), x) y*log(tan(x)**2 + 1)/2 See Manuel Bronstein's "Poor Man's Integrator": [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html For more information on the implemented algorithm refer to: [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration Method and its Implementation in Maple, Proceedings of ISSAC'89, ACM Press, 212-217. [3] J. H. Davenport, On the Parallel Risch Algorithm (I), Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157. [4] J. H. Davenport, On the Parallel Risch Algorithm (III): Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6. [5] J. H. Davenport, B. M. Trager, On the Parallel Risch Algorithm (II), ACM Transactions on Mathematical Software 11 (1985), 356-362. """ f = sympify(f) if not f.is_Add: indep, f = f.as_independent(x) else: indep = S.One if not f.has(x): return indep * f * x rewritables = { (sin, cos, cot): tan, (sinh, cosh, coth): tanh, } rewrite = kwargs.pop('rewrite', False) if rewrite: for candidates, rule in rewritables.iteritems(): f = f.rewrite(candidates, rule) else: for candidates in rewritables.iterkeys(): if f.has(*candidates): break else: rewrite = True terms = components(f, x) hints = kwargs.get('hints', None) if hints is not None: if not hints: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) c = Wild('c', exclude=[x]) for g in set(terms): if g.is_Function: if g.func is exp: M = g.args[0].match(a * x**2) if M is not None: terms.add(erf(sqrt(-M[a]) * x)) M = g.args[0].match(a * x**2 + b * x + c) if M is not None: if M[a].is_positive: terms.add(sqrt(pi/4*(-M[a]))*exp(M[c]-M[b]**2/(4*M[a]))* \ erf(-sqrt(-M[a])*x + M[b]/(2*sqrt(-M[a])))) elif M[a].is_negative: terms.add(sqrt(pi/4*(-M[a]))*exp(M[c]-M[b]**2/(4*M[a]))* \ erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a])))) M = g.args[0].match(a * log(x)**2) if M is not None: if M[a].is_positive: terms.add(-I * erf(I * (sqrt(M[a]) * log(x) + 1 / (2 * sqrt(M[a]))))) if M[a].is_negative: terms.add( erf( sqrt(-M[a]) * log(x) - 1 / (2 * sqrt(-M[a])))) elif g.is_Pow: if g.exp.is_Rational and g.exp.q == 2: M = g.base.match(a * x**2 + b) if M is not None and M[b].is_positive: if M[a].is_positive: terms.add(asinh(sqrt(M[a] / M[b]) * x)) elif M[a].is_negative: terms.add(asin(sqrt(-M[a] / M[b]) * x)) M = g.base.match(a * x**2 - b) if M is not None and M[b].is_positive: if M[a].is_positive: terms.add(acosh(sqrt(M[a] / M[b]) * x)) elif M[a].is_negative: terms.add((-M[b]/2*sqrt(-M[a])*\ atan(sqrt(-M[a])*x/sqrt(M[a]*x**2-M[b])))) else: terms |= set(hints) for g in set(terms): terms |= components(cancel(g.diff(x)), x) V = _symbols('x', len(terms)) mapping = dict(zip(terms, V)) rev_mapping = {} for k, v in mapping.iteritems(): rev_mapping[v] = k def substitute(expr): return expr.subs(mapping) diffs = [substitute(cancel(g.diff(x))) for g in terms] denoms = [g.as_numer_denom()[1] for g in diffs] try: denom = reduce(lambda p, q: lcm(p, q, *V), denoms) except PolynomialError: # lcm can fail with this. See issue 1418. return None numers = [cancel(denom * g) for g in diffs] def derivation(h): return Add(*[d * h.diff(v) for d, v in zip(numers, V)]) def deflation(p): for y in V: if not p.has(y): continue if derivation(p) is not S.Zero: c, q = p.as_poly(y).primitive() return deflation(c) * gcd(q, q.diff(y)).as_expr() else: return p def splitter(p): for y in V: if not p.has(y): continue if derivation(y) is not S.Zero: c, q = p.as_poly(y).primitive() q = q.as_expr() h = gcd(q, derivation(q), y) s = quo(h, gcd(q, q.diff(y), y), y) c_split = splitter(c) if s.as_poly(y).degree() == 0: return (c_split[0], q * c_split[1]) q_split = splitter(cancel(q / s)) return (c_split[0] * q_split[0] * s, c_split[1] * q_split[1]) else: return (S.One, p) special = {} for term in terms: if term.is_Function: if term.func is tan: special[1 + substitute(term)**2] = False elif term.func is tanh: special[1 + substitute(term)] = False special[1 - substitute(term)] = False elif term.func is C.LambertW: special[substitute(term)] = True F = substitute(f) P, Q = F.as_numer_denom() u_split = splitter(denom) v_split = splitter(Q) polys = list(v_split) + [u_split[0]] + special.keys() s = u_split[0] * Mul(*[k for k, v in special.iteritems() if v]) polified = [p.as_poly(*V) for p in [s, P, Q]] if None in polified: return a, b, c = [p.total_degree() for p in polified] poly_denom = (s * v_split[0] * deflation(v_split[1])).as_expr() def exponent(g): if g.is_Pow: if g.exp.is_Rational and g.exp.q != 1: if g.exp.p > 0: return g.exp.p + g.exp.q - 1 else: return abs(g.exp.p + g.exp.q) else: return 1 elif not g.is_Atom: return max([exponent(h) for h in g.args]) else: return 1 A, B = exponent(f), a + max(b, c) if A > 1 and B > 1: monoms = monomials(V, A + B - 1) else: monoms = monomials(V, A + B) poly_coeffs = _symbols('A', len(monoms)) poly_part = Add( *[poly_coeffs[i] * monomial for i, monomial in enumerate(monoms)]) reducibles = set() for poly in polys: if poly.has(*V): try: factorization = factor(poly, greedy=True) except PolynomialError: factorization = poly factorization = poly if factorization.is_Mul: reducibles |= set(factorization.args) else: reducibles.add(factorization) def integrate(field=None): irreducibles = set() for poly in reducibles: for z in poly.atoms(Symbol): if z in V: break else: continue irreducibles |= set(root_factors(poly, z, filter=field)) log_coeffs, log_part = [], [] B = _symbols('B', len(irreducibles)) for i, poly in enumerate(irreducibles): if poly.has(*V): log_coeffs.append(B[i]) log_part.append(log_coeffs[-1] * log(poly)) coeffs = poly_coeffs + log_coeffs candidate = poly_part / poly_denom + Add(*log_part) h = F - derivation(candidate) / denom numer = h.as_numer_denom()[0].expand(force=True) equations = {} for term in Add.make_args(numer): coeff, dependent = term.as_independent(*V) if dependent in equations: equations[dependent] += coeff else: equations[dependent] = coeff solution = solve(equations.values(), *coeffs) if solution is not None: return (solution, candidate, coeffs) else: return None if not (F.atoms(Symbol) - set(V)): result = integrate('Q') if result is None: result = integrate() else: result = integrate() if result is not None: (solution, candidate, coeffs) = result antideriv = candidate.subs(solution) for coeff in coeffs: if coeff not in solution: antideriv = antideriv.subs(coeff, S.Zero) antideriv = antideriv.subs(rev_mapping) antideriv = cancel(antideriv).expand(force=True) if antideriv.is_Add: antideriv = antideriv.as_independent(x)[1] return indep * antideriv else: if not rewrite: result = heurisch(f, x, rewrite=True, **kwargs) if result is not None: return indep * result return None
def _expr_small_minus(cls, x): return log(1 + x)
def _expr_small(cls, z): return log(S(1) / 2 + sqrt(1 - z) / 2)
def _expr_big(cls, x, n): return log(x - 1) + (2 * n - 1) * pi * I
def __init__(self): self.s,self.t,self.x,self.y,self.z = symbols('s,t,x,y,z') self.stack = [] self.defs = {} self.mode = 0 self.hist = [('',[])] # Innehåller en lista med (kommandorad, stack) self.lastx = '' self.clear = True self.op0 = { 's': lambda : self.s, 't': lambda : self.t, 'x': lambda : self.x, 'y': lambda : self.y, 'z': lambda : self.z, 'oo': lambda : S('oo'), 'inf': lambda : S('oo'), 'infinity': lambda : S('oo'), '?': lambda : self.help(), 'help': lambda : self.help(), 'hist': lambda : self.history(), 'history': lambda : self.history(), 'sketch': lambda : self.sketch(), } self.op1 = { 'radians': lambda x : pi/180*x, 'sin': lambda x : sin(x), 'cos': lambda x : cos(x), 'tan': lambda x : tan(x), 'sq': lambda x : x ** 2, 'sqrt': lambda x : sqrt(x), 'ln': lambda x : ln(x), 'exp': lambda x : exp(x), 'log': lambda x : log(x), 'simplify': lambda x : simplify(x), 'polynom': lambda x : self.polynom(x), 'inv': lambda x : 1/x, 'chs': lambda x : -x, 'center': lambda x : x.center, 'radius': lambda x : x.radius, 'expand': lambda x : x.expand(), 'factor': lambda x : x.factor(), 'incircle': lambda x : x.incircle, 'circumcircle': lambda x : x.circumcircle, 'xdiff': lambda x : x.diff(self.x), 'ydiff': lambda x : x.diff(self.y), 'xint': lambda x : x.integrate(self.x), 'xsolve': lambda x : solve(x,self.x), 'xapart': lambda x : apart(x,self.x), 'xtogether': lambda x : together(x,self.x), 'N': lambda x : N(x), 'info': lambda x : [x.__class__.__name__, [m for m in dir(x) if m[0]!= '_']], } self.op2 = { '+': lambda x,y : y+x, '-': lambda x,y : y-x, '*': lambda x,y : y*x, '/': lambda x,y : y/x, '**': lambda x,y : y**x, 'item': lambda x,y : y[x], 'point': lambda x,y : Point(y,x), 'line': lambda x,y : Line(y,x), 'circle': lambda x,y : Circle(y,x), 'tangent_lines': lambda x,y : y.tangent_lines(x), 'intersection': lambda x,y : intersection(x,y), 'perpendicular_line': lambda x,y : y.perpendicular_line(x), 'diff': lambda x,y : y.diff(x), 'int': lambda x,y : y.integrate(x), 'solve': lambda x,y : solve(y,x), 'apart': lambda x,y : apart(y,x), 'together': lambda x,y : together(y,x), 'xeval': lambda x,y : y.subs(self.x,x), } self.op3 = { 'triangle': lambda x,y,z : Triangle(x,y,z), 'limit': lambda x,y,z : limit(z,y,x), # limit(sin(x)/x,x,0) <=> x sin x / x 0 limit 'eval': lambda x,y,z : z.subs(y,x), } self.op4 = { 'sum': lambda x,y,z,t : Sum(t,(z,y,x)).doit() # Sum(1/x**2,(x,1,oo)).doit() <=> 1 x x * / x 1 oo sum } self.lastx = ''