def test_simple_8(): assert O(sqrt(-x)) == O(sqrt(x)) assert O(x**2 * sqrt(x)) == O(x**(S(5) / 2)) assert O(x**3 * sqrt(-(-x)**3)) == O(x**(S(9) / 2)) assert O(x**(S(3) / 2) * sqrt((-x)**3)) == O(x**3) assert O(x * (-2 * x)**(I / 2)) == O(x * (-x)**(I / 2))
def test_ln_args(): assert O(log(x)) + O(log(2 * x)) == O(log(x)) assert O(log(x)) + O(log(x**3)) == O(log(x)) assert O(log(x * y)) + O(log(x) + log(y)) == O(log(x * y))
def test_order_leadterm(): assert O(x**2)._eval_as_leading_term(x) == O(x**2)
def test_ignore_order_terms(): eq = exp(x).series(x,0,3) + sin(y+x**3) - 1 assert cse(eq) == ([], [sin(x**3 + y) + x + x**2/2 + O(x**3)])
def test_simple_7(): assert 1 + O(1) == O(1) assert 2 + O(1) == O(1) assert x + O(1) == O(1) assert 1 / x + O(1) == 1 / x + O(1)
def test_issue_9192(): assert O(1) * O(1) == O(1) assert O(1)**O(1) == O(1)
def test_issue_15539(): assert O(1 / x**2 + 1 / x**4, (x, -oo)) == O(1 / x**2, (x, -oo)) assert O(1 / x**4 + exp(x), (x, -oo)) == O(1 / x**4, (x, -oo)) assert O(1 / x**4 + exp(-x), (x, -oo)) == O(exp(-x), (x, -oo)) assert O(1 / x, (x, oo)).subs(x, -x) == O(-1 / x, (x, -oo))
def test_erf_series(): assert erf(x).series(x, 0, 7) == 2*x/sqrt(pi) - \ 2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7)
def test_piecewise_series(): from sympy import sin, cos, O p1 = Piecewise((sin(x), x < 0), (cos(x), x > 0)) p2 = Piecewise((x + O(x**2), x < 0), (1 + O(x**2), x > 0)) assert p1.nseries(x, n=2) == p2
def _eval_nseries(self, x, x0, n): from sympy import powsimp, collect def geto(e): "Returns the O(..) symbol, or None if there is none." if e.is_Order: return e if e.is_Add: for x in e.args: if x.is_Order: return x def getn(e): """ Returns the order of the expression "e". The order is determined either from the O(...) term. If there is no O(...) term, it returns None. Example: >>> getn(1+x+O(x**2)) 2 >>> getn(1+x) >>> """ o = geto(e) if o is None: return None else: o = o.expr if o.is_Symbol: return Integer(1) if o.is_Pow: return o.args[1] n, d = o.as_numer_denom() if isinstance(d, log): # i.e. o = x**2/log(x) if n.is_Symbol: return Integer(1) if n.is_Pow: return n.args[1] raise NotImplementedError() base, exp = self.args if exp.is_Integer: if exp > 0: # positive integer powers are easy to expand, e.g.: # sin(x)**4 = (x-x**3/3+...)**4 = ... return (base.nseries(x, x0, n) ** exp).expand() elif exp == -1: # this is also easy to expand using the formula: # 1/(1 + x) = 1 + x + x**2 + x**3 ... # so we need to rewrite base to the form "1+x" from sympy import log if base.has(log(x)): # we need to handle the log(x) singularity: assert x0 == 0 y = Symbol("y", dummy=True) p = self.subs(log(x), -1/y) if not p.has(x): p = p.nseries(y, x0, n) p = p.subs(y, -1/log(x)) return p base = base.nseries(x, x0, n) if base.has(log(x)): # we need to handle the log(x) singularity: assert x0 == 0 y = Symbol("y", dummy=True) self0 = 1/base p = self0.subs(log(x), -1/y) if not p.has(x): p = p.nseries(y, x0, n) p = p.subs(y, -1/log(x)) return p prefactor = base.as_leading_term(x) # express "rest" as: rest = 1 + k*x**l + ... + O(x**n) rest = powsimp(((base-prefactor)/prefactor).expand(),\ deep=True, combine='exp') if rest == 0: # if prefactor == w**4 + x**2*w**4 + 2*x*w**4, we need to # factor the w**4 out using collect: return 1/collect(prefactor, x) if rest.is_Order: return ((1+rest)/prefactor).expand() n2 = getn(rest) if n2 is not None: n = n2 term2 = collect(rest.as_leading_term(x), x) k, l = Wild("k"), Wild("l") r = term2.match(k*x**l) k, l = r[k], r[l] if l.is_Integer and l>0: l = int(l) elif l.is_number and l>0: l = float(l) else: raise NotImplementedError() s = 1 m = 1 while l * m < n: s += ((-rest)**m).expand() m += 1 r = (s/prefactor).expand() if n2 is None: # Append O(...) because it is not included in "r" from sympy import O r += O(x**n) return powsimp(r, deep=True, combine='exp') else: # negative powers are rewritten to the cases above, for example: # sin(x)**(-4) = 1/( sin(x)**4) = ... # and expand the denominator: denominator = (base**(-exp)).nseries(x, x0, n) if 1/denominator == self: return self # now we have a type 1/f(x), that we know how to expand return (1/denominator).nseries(x, x0, n) if exp.has(x): import sympy return sympy.exp(exp*sympy.log(base)).nseries(x, x0, n) if base == x: return powsimp(self, deep=True, combine='exp') order = C.Order(x**n, x) x = order.symbols[0] e = self.exp b = self.base ln = C.log exp = C.exp if e.has(x): return exp(e * ln(b)).nseries(x, x0, n) if b==x: return self b0 = b.limit(x,0) if b0 is S.Zero or b0.is_unbounded: lt = b.as_leading_term(x) o = order * lt**(1-e) bs = b.nseries(x, x0, n-e) if bs.is_Add: bs = bs.removeO() if bs.is_Add: # bs -> lt + rest -> lt * (1 + (bs/lt - 1)) return (lt**e * ((bs/lt).expand()**e).nseries(x, x0, n-e)).expand() + order return bs**e+order o2 = order * (b0**-e) # b -> b0 + (b-b0) -> b0 * (1 + (b/b0-1)) z = (b/b0-1) #r = self._compute_oseries3(z, o2, self.taylor_term) x = o2.symbols[0] ln = C.log o = C.Order(z, x) if o is S.Zero: r = (1+z) else: if o.expr.is_number: e2 = ln(o2.expr*x)/ln(x) else: e2 = ln(o2.expr)/ln(o.expr) n = e2.limit(x,0) + 1 if n.is_unbounded: # requested accuracy gives infinite series, # order is probably nonpolynomial e.g. O(exp(-1/x), x). r = (1+z) else: try: n = int(n) except TypeError: #well, the n is something more complicated (like 1+log(2)) n = int(n.evalf()) + 1 assert n>=0,`n` l = [] g = None for i in xrange(n+2): g = self.taylor_term(i, z, g) g = g.nseries(x, x0, n) l.append(g) r = Add(*l) return r * b0**e + order
def test_fresnel(): assert fresnels(0) == 0 assert fresnels(oo) == S.Half assert fresnels(-oo) == -S.Half assert fresnels(z) == fresnels(z) assert fresnels(-z) == -fresnels(z) assert fresnels(I * z) == -I * fresnels(z) assert fresnels(-I * z) == I * fresnels(z) assert conjugate(fresnels(z)) == fresnels(conjugate(z)) assert fresnels(z).diff(z) == sin(pi * z**2 / 2) assert fresnels(z).rewrite(erf) == (S.One + I) / 4 * (erf( (S.One + I) / 2 * sqrt(pi) * z) - I * erf( (S.One - I) / 2 * sqrt(pi) * z)) assert fresnels(z).rewrite(hyper) == \ pi*z**3/6 * hyper([S(3)/4], [S(3)/2, S(7)/4], -pi**2*z**4/16) assert fresnels(z).series(z, n=15) == \ pi*z**3/6 - pi**3*z**7/336 + pi**5*z**11/42240 + O(z**15) assert fresnels(w).is_real is True assert fresnels(z).as_real_imag() == \ ((fresnels(re(z) - I*re(z)*Abs(im(z))/Abs(re(z)))/2 + fresnels(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))/2, I*(fresnels(re(z) - I*re(z)*Abs(im(z))/Abs(re(z))) - fresnels(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))) * re(z)*Abs(im(z))/(2*im(z)*Abs(re(z))))) assert fresnels(2 + 3 * I).as_real_imag() == ( fresnels(2 + 3 * I) / 2 + fresnels(2 - 3 * I) / 2, I * (fresnels(2 - 3 * I) - fresnels(2 + 3 * I)) / 2) assert expand_func(integrate(fresnels(z), z)) == \ z*fresnels(z) + cos(pi*z**2/2)/pi assert fresnels(z).rewrite(meijerg) == sqrt(2)*pi*z**(S(9)/4) * \ meijerg(((), (1,)), ((S(3)/4,), (S(1)/4, 0)), -pi**2*z**4/16)/(2*(-z)**(S(3)/4)*(z**2)**(S(3)/4)) assert fresnelc(0) == 0 assert fresnelc(oo) == S.Half assert fresnelc(-oo) == -S.Half assert fresnelc(z) == fresnelc(z) assert fresnelc(-z) == -fresnelc(z) assert fresnelc(I * z) == I * fresnelc(z) assert fresnelc(-I * z) == -I * fresnelc(z) assert conjugate(fresnelc(z)) == fresnelc(conjugate(z)) assert fresnelc(z).diff(z) == cos(pi * z**2 / 2) assert fresnelc(z).rewrite(erf) == (S.One - I) / 4 * (erf( (S.One + I) / 2 * sqrt(pi) * z) + I * erf( (S.One - I) / 2 * sqrt(pi) * z)) assert fresnelc(z).rewrite(hyper) == \ z * hyper([S.One/4], [S.One/2, S(5)/4], -pi**2*z**4/16) assert fresnelc(z).series(z, n=15) == \ z - pi**2*z**5/40 + pi**4*z**9/3456 - pi**6*z**13/599040 + O(z**15) assert fresnelc(w).is_real is True assert fresnelc(z).as_real_imag() == \ ((fresnelc(re(z) - I*re(z)*Abs(im(z))/Abs(re(z)))/2 + fresnelc(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))/2, I*(fresnelc(re(z) - I*re(z)*Abs(im(z))/Abs(re(z))) - fresnelc(re(z) + I*re(z)*Abs(im(z))/Abs(re(z)))) * re(z)*Abs(im(z))/(2*im(z)*Abs(re(z))))) assert fresnelc(2 + 3 * I).as_real_imag() == ( fresnelc(2 - 3 * I) / 2 + fresnelc(2 + 3 * I) / 2, I * (fresnelc(2 - 3 * I) - fresnelc(2 + 3 * I)) / 2) assert expand_func(integrate(fresnelc(z), z)) == \ z*fresnelc(z) - sin(pi*z**2/2)/pi assert fresnelc(z).rewrite(meijerg) == sqrt(2)*pi*z**(S(3)/4) * \ meijerg(((), (1,)), ((S(1)/4,), (S(3)/4, 0)), -pi**2*z**4/16)/(2*(-z)**(S(1)/4)*(z**2)**(S(1)/4)) from sympy.utilities.randtest import test_numerically test_numerically(re(fresnels(z)), fresnels(z).as_real_imag()[0], z) test_numerically(im(fresnels(z)), fresnels(z).as_real_imag()[1], z) test_numerically(fresnels(z), fresnels(z).rewrite(hyper), z) test_numerically(fresnels(z), fresnels(z).rewrite(meijerg), z) test_numerically(re(fresnelc(z)), fresnelc(z).as_real_imag()[0], z) test_numerically(im(fresnelc(z)), fresnelc(z).as_real_imag()[1], z) test_numerically(fresnelc(z), fresnelc(z).rewrite(hyper), z) test_numerically(fresnelc(z), fresnelc(z).rewrite(meijerg), z)
def test_issue_1756(): x = Symbol('x') f = Function('f') assert 1 / O(1) != O(1) assert 1 / O(x) != O(1 / x) assert 1 / O(f(x)) != O(1 / x)
def test_issue_1180(): a, b = symbols('a b') assert O(a + b, a, b) + O(1, a, b) == O(1, a, b)
def test_factorial_series(): n = Symbol('n', integer=True) assert factorial(n).series(n, 0, 3) == \ 1 - n*EulerGamma + n**2*(EulerGamma**2/2 + pi**2/12) + O(n**3)
def test_issue_6753(): assert (1 + x**2)**10000 * O(x) == O(x)
def test_nan(): assert O(nan) is nan assert not O(x).contains(nan)
def test_order_at_some_point(): assert Order(x, (x, 1)) == Order(1, (x, 1)) assert Order(2 * x - 2, (x, 1)) == Order(x - 1, (x, 1)) assert Order(-x + 1, (x, 1)) == Order(x - 1, (x, 1)) assert Order(x - 1, (x, 1))**2 == Order((x - 1)**2, (x, 1)) assert Order(x - 2, (x, 2)) - O(x - 2, (x, 2)) == Order(x - 2, (x, 2))
def test_O1(): assert O(1, x) * x == O(x) assert O(1, y) * x == O(1, y)
def test_performance_of_adding_order(): l = list(x**i for i in range(1000)) l.append(O(x**1001)) assert Add(*l).subs(x, 1) == O(1)
def test_diff(): assert O(x**2).diff(x) == O(x)
def test_caching_bug(): #needs to be a first test, so that all caches are clean #cache it O(w) #and test that this won't raise an exception O(w**(-1 / x / log(3) * log(5)), w)
def test_getO(): assert (x).getO() is None assert (x).removeO() == x assert (O(x)).getO() == O(x) assert (O(x)).removeO() == 0 assert (z + O(x) + O(y)).getO() == O(x) + O(y) assert (z + O(x) + O(y)).removeO() == z raises(NotImplementedError, lambda: (O(x) + O(y)).getn())
def _eval_nseries(self, x, n, logx): # NOTE! This function is an important part of the gruntz algorithm # for computing limits. It has to return a generalized power # series with coefficients in C(log, log(x)). In more detail: # It has to return an expression # c_0*x**e_0 + c_1*x**e_1 + ... (finitely many terms) # where e_i are numbers (not necessarily integers) and c_i are # expressions involving only numbers, the log function, and log(x). from sympy import powsimp, collect, exp, log, O, ceiling b, e = self.args if e.is_Integer: if e > 0: # positive integer powers are easy to expand, e.g.: # sin(x)**4 = (x-x**3/3+...)**4 = ... return expand_multinomial(self.func( b._eval_nseries(x, n=n, logx=logx), e), deep=False) elif e is S.NegativeOne: # this is also easy to expand using the formula: # 1/(1 + x) = 1 - x + x**2 - x**3 ... # so we need to rewrite base to the form "1+x" nuse = n cf = 1 try: ord = b.as_leading_term(x) cf = C.Order(ord, x).getn() if cf: nuse = n + 2 * cf else: cf = 1 except NotImplementedError: pass b_orig = b b = b_orig._eval_nseries(x, n=nuse, logx=logx) prefactor = b.as_leading_term(x) while prefactor.is_Order: nuse += 1 b = b_orig._eval_nseries(x, n=nuse, logx=logx) prefactor = b.as_leading_term(x) # express "rest" as: rest = 1 + k*x**l + ... + O(x**n) rest = expand_mul((b - prefactor) / prefactor) if rest == 0: # if prefactor == w**4 + x**2*w**4 + 2*x*w**4, we need to # factor the w**4 out using collect: return 1 / collect(prefactor, x) if rest.is_Order: return 1 / prefactor + rest / prefactor + O(x**n, x) n2 = rest.getn() if n2 is not None: # remove the O - powering this is slow if logx is not None: rest = rest.removeO() k, l = rest.leadterm(x) if l.is_Rational and l > 0: pass elif l.is_number and l > 0: l = l.evalf() else: raise NotImplementedError() if cf < 0: cf = S.One / abs(cf) terms = [1 / prefactor] for m in xrange(1, ceiling(n / l * cf)): new_term = terms[-1] * (-rest) if new_term.is_Pow: new_term = new_term._eval_expand_multinomial( deep=False) else: new_term = expand_mul(new_term, deep=False) terms.append(new_term) terms.append(O(x**n, x)) # Append O(...), we know the order. if n2 is None or logx is not None: terms.append(O(x**n)) return powsimp(Add(*terms), deep=True, combine='exp') else: # negative powers are rewritten to the cases above, for # example: # sin(x)**(-4) = 1/( sin(x)**4) = ... # and expand the denominator: nuse, denominator = n, O(1) while denominator.is_Order: denominator = (b**(-e))._eval_nseries(x, n=nuse, logx=logx) nuse += 1 if 1 / denominator == self: return self # now we have a type 1/f(x), that we know how to expand return (1 / denominator)._eval_nseries(x, n=n, logx=logx) if e.has(Symbol): return exp(e * log(b))._eval_nseries(x, n=n, logx=logx) # see if the base is as simple as possible bx = b while bx.is_Pow and bx.exp.is_Rational: bx = bx.base if bx == x: return self # work for b(x)**e where e is not an Integer and does not contain x # and hopefully has no other symbols def e2int(e): """return the integer value (if possible) of e and a flag indicating whether it is bounded or not.""" n = e.limit(x, 0) unbounded = n.is_unbounded if not unbounded: # XXX was int or floor intended? int used to behave like floor # so int(-Rational(1, 2)) returned -1 rather than int's 0 try: n = int(n) except TypeError: #well, the n is something more complicated (like 1+log(2)) try: n = int(n.evalf()) + 1 # XXX why is 1 being added? except TypeError: pass # hope that base allows this to be resolved n = _sympify(n) return n, unbounded order = O(x**n, x) ei, unbounded = e2int(e) b0 = b.limit(x, 0) if unbounded and (b0 is S.One or b0.has(Symbol)): # XXX what order if b0 is S.One: resid = (b - 1) if resid.is_positive: return S.Infinity elif resid.is_negative: return S.Zero raise ValueError('cannot determine sign of %s' % resid) return b0**ei if (b0 is S.Zero or b0.is_unbounded): if unbounded is not False: return b0**e # XXX what order if not ei.is_number: # if not, how will we proceed? raise ValueError('expecting numerical exponent but got %s' % ei) nuse = n - ei if e.is_real and e.is_positive: lt = b.as_leading_term(x) # Try to correct nuse (= m) guess from: # (lt + rest + O(x**m))**e = # lt**e*(1 + rest/lt + O(x**m)/lt)**e = # lt**e + ... + O(x**m)*lt**(e - 1) = ... + O(x**n) try: cf = C.Order(lt, x).getn() nuse = ceiling(n - cf * (e - 1)) except NotImplementedError: pass bs = b._eval_nseries(x, n=nuse, logx=logx) terms = bs.removeO() if terms.is_Add: bs = terms lt = terms.as_leading_term(x) # bs -> lt + rest -> lt*(1 + (bs/lt - 1)) return ((self.func(lt, e) * self.func( (bs / lt).expand(), e).nseries( x, n=nuse, logx=logx)).expand() + order) if bs.is_Add: from sympy import O # So, bs + O() == terms c = Dummy('c') res = [] for arg in bs.args: if arg.is_Order: arg = c * arg.expr res.append(arg) bs = Add(*res) rv = (bs**e).series(x).subs(c, O(1)) rv += order return rv rv = bs**e if terms != bs: rv += order return rv # either b0 is bounded but neither 1 nor 0 or e is unbounded # b -> b0 + (b-b0) -> b0 * (1 + (b/b0-1)) o2 = order * (b0**-e) z = (b / b0 - 1) o = O(z, x) #r = self._compute_oseries3(z, o2, self.taylor_term) if o is S.Zero or o2 is S.Zero: unbounded = True else: if o.expr.is_number: e2 = log(o2.expr * x) / log(x) else: e2 = log(o2.expr) / log(o.expr) n, unbounded = e2int(e2) if unbounded: # requested accuracy gives infinite series, # order is probably non-polynomial e.g. O(exp(-1/x), x). r = 1 + z else: l = [] g = None for i in xrange(n + 2): g = self._taylor_term(i, z, g) g = g.nseries(x, n=n, logx=logx) l.append(g) r = Add(*l) return expand_mul(r * b0**e) + order
def test_leading_term(): from sympy import digamma assert O(1 / digamma(1 / x)) == O(1 / log(x))
def test_simple_8(): assert O(sqrt(-x)) == O(sqrt(x)) assert O(x**2 * sqrt(x)) == O(x**Rational(5, 2)) assert O(x**3 * sqrt(-((-x)**3))) == O(x**Rational(9, 2)) assert O(x**Rational(3, 2) * sqrt((-x)**3)) == O(x**3) assert O(x * (-2 * x)**(I / 2)) == O(x * (-x)**(I / 2))
def test_eval(): assert Order(x).subs(Order(x), 1) == 1 assert Order(x).subs(x, y) == Order(y) assert Order(x).subs(y, x) == Order(x) assert Order(x).subs(x, x + y) == Order(x + y, (x, -y)) assert (O(1)**x).is_Pow
def test_leading_order2(): assert set((2 + pi + x**2).extract_leading_order(x)) == set( ((pi, O(1, x)), (S(2), O(1, x)))) assert set((2 * x + pi * x + x**2).extract_leading_order(x)) == set( ((2 * x, O(x)), (x * pi, O(x))))
def test_issue_4279(): a, b = symbols('a b') assert O(a, a, b) + O(1, a, b) == O(1, a, b) assert O(b, a, b) + O(1, a, b) == O(1, a, b) assert O(a + b, a, b) + O(1, a, b) == O(1, a, b) assert O(1, a, b) + O(a, a, b) == O(1, a, b) assert O(1, a, b) + O(b, a, b) == O(1, a, b) assert O(1, a, b) + O(a + b, a, b) == O(1, a, b)
def test_order_symbols(): e = x * y * sin(x) * Integral(x, (x, 1, 2)) assert O(e) == O(x**2 * y, x, y) assert O(e, x) == O(x**2)
def test_issue_3654(): assert (1 + x**2)**10000 * O(x) == O(x)