(self, x=None, x0=0, n=6, dir="+", logx=None)
Series expansion of "self" around ``x = x0`` yielding either terms of
        the series one by one (the lazy series given when n=None), else
        all the terms at once when n != None.

        Note: when n != None, if an O() term is returned then the x in the
        in it and the entire expression represents x - x0, the displacement
        from x0. (If there is no O() term then the series was exact and x has
        it's normal meaning.) This is currently necessary since sympy's O()
        can only represent terms at x0=0. So instead of::

          cos(x).series(x0=1, n=2) --> (1 - x)*sin(1) + cos(1) + O((x - 1)**2)

        which graphically looks like this::

               |
              .|.         . .
             . | \      .     .
            ---+----------------------
               |   . .          . .
               |    \
              x=0

        the following is returned instead::

        -x*sin(1) + cos(1) + O(x**2)

        whose graph is this::

               \ |
              . .|        . .
             .   \      .     .
            -----+\------------------.
                 | . .          . .
                 |  \
                x=0

        which is identical to ``cos(x + 1).series(n=2)``.

        Usage:
            Returns the series expansion of "self" around the point ``x = x0``
            with respect to ``x`` up to O(x**n) (default n is 6).

            If ``x=None`` and ``self`` is univariate, the univariate symbol will
            be supplied, otherwise an error will be raised.

            >>> from sympy import cos, exp
            >>> from sympy.abc import x, y
            >>> cos(x).series()
            1 - x**2/2 + x**4/24 + O(x**6)
            >>> cos(x).series(n=4)
            1 - x**2/2 + O(x**4)
            >>> e = cos(x + exp(y))
            >>> e.series(y, n=2)
            cos(x + 1) - y*sin(x + 1) + O(y**2)
            >>> e.series(x, n=2)
            cos(exp(y)) - x*sin(exp(y)) + O(x**2)

            If ``n=None`` then a generator of the series terms will be returned.

            >>> term=cos(x).series(n=None)
            >>> [next(term) for i in range(2)]
            [1, -x**2/2]

            For ``dir=+`` (default) the series is calculated from the right and
            for ``dir=-`` the series from the left. For smooth functions this
            flag will not alter the results.

            >>> abs(x).series(dir="+")
            x
            >>> abs(x).series(dir="-")
            -x
Series expansion of "self" around ``x = x0`` yielding either terms of
        the series one by one (the lazy series given when n=None), else
        all the terms at once when n != None.
Series expansion of self around x = x0 yielding either terms of the series one by one ( the lazy series given when n = None ) else all the terms at once when n ! = None .
def series(self, x=None, x0=0, n=6, dir="+", logx=None):
        """
        Series expansion of "self" around ``x = x0`` yielding either terms of
        the series one by one (the lazy series given when n=None), else
        all the terms at once when n != None.

        Note: when n != None, if an O() term is returned then the x in the
        in it and the entire expression represents x - x0, the displacement
        from x0. (If there is no O() term then the series was exact and x has
        it's normal meaning.) This is currently necessary since sympy's O()
        can only represent terms at x0=0. So instead of::

          cos(x).series(x0=1, n=2) --> (1 - x)*sin(1) + cos(1) + O((x - 1)**2)

        which graphically looks like this::

               |
              .|.         . .
             . | \      .     .
            ---+----------------------
               |   . .          . .
               |    \
              x=0

        the following is returned instead::

        -x*sin(1) + cos(1) + O(x**2)

        whose graph is this::

               \ |
              . .|        . .
             .   \      .     .
            -----+\------------------.
                 | . .          . .
                 |  \
                x=0

        which is identical to ``cos(x + 1).series(n=2)``.

        Usage:
            Returns the series expansion of "self" around the point ``x = x0``
            with respect to ``x`` up to O(x**n) (default n is 6).

            If ``x=None`` and ``self`` is univariate, the univariate symbol will
            be supplied, otherwise an error will be raised.

            >>> from sympy import cos, exp
            >>> from sympy.abc import x, y
            >>> cos(x).series()
            1 - x**2/2 + x**4/24 + O(x**6)
            >>> cos(x).series(n=4)
            1 - x**2/2 + O(x**4)
            >>> e = cos(x + exp(y))
            >>> e.series(y, n=2)
            cos(x + 1) - y*sin(x + 1) + O(y**2)
            >>> e.series(x, n=2)
            cos(exp(y)) - x*sin(exp(y)) + O(x**2)

            If ``n=None`` then a generator of the series terms will be returned.

            >>> term=cos(x).series(n=None)
            >>> [next(term) for i in range(2)]
            [1, -x**2/2]

            For ``dir=+`` (default) the series is calculated from the right and
            for ``dir=-`` the series from the left. For smooth functions this
            flag will not alter the results.

            >>> abs(x).series(dir="+")
            x
            >>> abs(x).series(dir="-")
            -x

        """
        from sympy import collect
        if x is None:
            syms = self.atoms(C.Symbol)
            if len(syms) > 1:
                raise ValueError('x must be given for multivariate functions.')
            x = syms.pop()

        if not self.has(x):
            if n is None:
                return (s for s in [self])
            else:
                return self

        if len(dir) != 1 or dir not in '+-':
            raise ValueError("Dir must be '+' or '-'")

        if x0 in [S.Infinity, S.NegativeInfinity]:
            dir = {S.Infinity: '+', S.NegativeInfinity: '-'}[x0]
            s = self.subs(x, 1/x).series(x, n=n, dir=dir)
            if n is None:
                return (si.subs(x, 1/x) for si in s)
            return s.subs(x, 1/x)

        # use rep to shift origin to x0 and change sign (if dir is negative)
        # and undo the process with rep2
        if x0 or dir == '-':
            if dir == '-':
                rep = -x + x0
                rep2 = -x
                rep2b = x0
            else:
                rep = x + x0
                rep2 = x
                rep2b = -x0
            s = self.subs(x, rep).series(x, x0=0, n=n, dir='+', logx=logx)
            if n is None:  # lseries...
                return (si.subs(x, rep2 + rep2b) for si in s)
            # nseries...
            o = s.getO() or S.Zero
            s = s.removeO()
            if o and x0:
                rep2b = 0  # when O() can handle x0 != 0 this can be removed
            return s.subs(x, rep2 + rep2b) + o

        # from here on it's x0=0 and dir='+' handling

        if x.is_positive is x.is_negative is None:
            # replace x with an x that has a positive assumption
            xpos = C.Dummy('x', positive=True, bounded=True)
            rv = self.subs(x, xpos).series(xpos, x0, n, dir, logx=logx)
            if n is None:
                return (s.subs(xpos, x) for s in rv)
            else:
                return rv.subs(xpos, x)

        if n is not None:  # nseries handling
            s1 = self._eval_nseries(x, n=n, logx=logx)
            o = s1.getO() or S.Zero
            if o:
                # make sure the requested order is returned
                ngot = o.getn()
                if ngot > n:
                    # leave o in its current form (e.g. with x*log(x)) so
                    # it eats terms properly, then replace it below
                    if n != 0:
                        s1 += o.subs(x, x**C.Rational(n, ngot))
                    else:
                        s1 += C.Order(1, x)
                elif ngot < n:
                    # increase the requested number of terms to get the desired
                    # number keep increasing (up to 9) until the received order
                    # is different than the original order and then predict how
                    # many additional terms are needed
                    for more in range(1, 9):
                        s1 = self._eval_nseries(x, n=n + more, logx=logx)
                        newn = s1.getn()
                        if newn != ngot:
                            ndo = n + (n - ngot)*more/(newn - ngot)
                            s1 = self._eval_nseries(x, n=ndo, logx=logx)
                            while s1.getn() < n:
                                s1 = self._eval_nseries(x, n=ndo, logx=logx)
                                ndo += 1
                            break
                    else:
                        raise ValueError('Could not calculate %s terms for %s'
                                         % (str(n), self))
                    s1 += C.Order(x**n, x)
                o = s1.getO()
                s1 = s1.removeO()
            else:
                o = C.Order(x**n, x)
                if (s1 + o).removeO() == s1:
                    o = S.Zero

            try:
                return collect(s1, x) + o
            except NotImplementedError:
                return s1 + o

        else:  # lseries handling
            def yield_lseries(s):
                """Return terms of lseries one at a time."""
                for si in s:
                    if not si.is_Add:
                        yield si
                        continue
                    # yield terms 1 at a time if possible
                    # by increasing order until all the
                    # terms have been returned
                    yielded = 0
                    o = C.Order(si, x)*x
                    ndid = 0
                    ndo = len(si.args)
                    while 1:
                        do = (si - yielded + o).removeO()
                        o *= x
                        if not do or do.is_Order:
                            continue
                        if do.is_Add:
                            ndid += len(do.args)
                        else:
                            ndid += 1
                        yield do
                        if ndid == ndo:
                            break
                        yielded += do

            return yield_lseries(self.removeO()._eval_lseries(x, logx=logx))
def series ( self , x = None , x0 = 0 , n = 6 , dir = "+" , logx = None ) : from sympy import collect if x is None : syms = self . atoms ( C . Symbol ) if len ( syms ) > 1 : raise ValueError ( 'x must be given for multivariate functions.' ) x = syms . pop ( ) if not self . has ( x ) : if n is None : return ( s for s in [ self ] ) else : return self if len ( dir ) != 1 or dir not in '+-' : raise ValueError ( "Dir must be '+' or '-'" ) if x0 in [ S . Infinity , S . NegativeInfinity ] : dir = { S . Infinity : '+' , S . NegativeInfinity : '-' } [ x0 ] s = self . subs ( x , 1 / x ) . series ( x , n = n , dir = dir ) if n is None : return ( si . subs ( x , 1 / x ) for si in s ) return s . subs ( x , 1 / x ) # use rep to shift origin to x0 and change sign (if dir is negative) # and undo the process with rep2 if x0 or dir == '-' : if dir == '-' : rep = - x + x0 rep2 = - x rep2b = x0 else : rep = x + x0 rep2 = x rep2b = - x0 s = self . subs ( x , rep ) . series ( x , x0 = 0 , n = n , dir = '+' , logx = logx ) if n is None : # lseries... return ( si . subs ( x , rep2 + rep2b ) for si in s ) # nseries... o = s . getO ( ) or S . Zero s = s . removeO ( ) if o and x0 : rep2b = 0 # when O() can handle x0 != 0 this can be removed return s . subs ( x , rep2 + rep2b ) + o # from here on it's x0=0 and dir='+' handling if x . is_positive is x . is_negative is None : # replace x with an x that has a positive assumption xpos = C . Dummy ( 'x' , positive = True , bounded = True ) rv = self . subs ( x , xpos ) . series ( xpos , x0 , n , dir , logx = logx ) if n is None : return ( s . subs ( xpos , x ) for s in rv ) else : return rv . subs ( xpos , x ) if n is not None : # nseries handling s1 = self . _eval_nseries ( x , n = n , logx = logx ) o = s1 . getO ( ) or S . Zero if o : # make sure the requested order is returned ngot = o . getn ( ) if ngot > n : # leave o in its current form (e.g. with x*log(x)) so # it eats terms properly, then replace it below if n != 0 : s1 += o . subs ( x , x ** C . Rational ( n , ngot ) ) else : s1 += C . Order ( 1 , x ) elif ngot < n : # increase the requested number of terms to get the desired # number keep increasing (up to 9) until the received order # is different than the original order and then predict how # many additional terms are needed for more in range ( 1 , 9 ) : s1 = self . _eval_nseries ( x , n = n + more , logx = logx ) newn = s1 . getn ( ) if newn != ngot : ndo = n + ( n - ngot ) * more / ( newn - ngot ) s1 = self . _eval_nseries ( x , n = ndo , logx = logx ) while s1 . getn ( ) < n : s1 = self . _eval_nseries ( x , n = ndo , logx = logx ) ndo += 1 break else : raise ValueError ( 'Could not calculate %s terms for %s' % ( str ( n ) , self ) ) s1 += C . Order ( x ** n , x ) o = s1 . getO ( ) s1 = s1 . removeO ( ) else : o = C . Order ( x ** n , x ) if ( s1 + o ) . removeO ( ) == s1 : o = S . Zero try : return collect ( s1 , x ) + o except NotImplementedError : return s1 + o else : # lseries handling def yield_lseries ( s ) : """Return terms of lseries one at a time.""" for si in s : if not si . is_Add : yield si continue # yield terms 1 at a time if possible # by increasing order until all the # terms have been returned yielded = 0 o = C . Order ( si , x ) * x ndid = 0 ndo = len ( si . args ) while 1 : do = ( si - yielded + o ) . removeO ( ) o *= x if not do or do . is_Order : continue if do . is_Add : ndid += len ( do . args ) else : ndid += 1 yield do if ndid == ndo : break yielded += do return yield_lseries ( self . removeO ( ) . _eval_lseries ( x , logx = logx ) )