Ticket #10956: trac_10956_add_pseudo_differential_operators.patch

File trac_10956_add_pseudo_differential_operators.patch, 23.6 KB (added by tkluck, 10 years ago)
  • new file sage/rings/pseudo_diff_op_algebra.py

    # HG changeset patch
    # User Timo Kluck <tkluck@infty.nl>
    # Date 1300381819 -3600
    # Node ID 47d8268f4c5a3b80534cdbd782a5c88a2b5741d4
    # Parent  ed12a27d452047988f18aa9a1f71272105efce92
    Trac 10956: Add support for pseudo-differential operators.
    
    diff -r ed12a27d4520 -r 47d8268f4c5a sage/rings/pseudo_diff_op_algebra.py
    - +  
     1r"""
     2Pseudo-differential operators
     3
     4An implementation of pseudo-differential operators. These are
     5formal expansions of the form $\sum_n=-N^\infty u_{-n}(x) \partial_x^{-n}$.
     6Multiplication is such that $[\partial_x, u(x)] =\frac{\partial u}{\partial x}$.
     7
     8AUTHORS:
     9
     10    - Timo Kluck (2010-11-15): initial version
     11
     12EXAMPLES::
     13
     14We first create a pseudo-differential operator algebra with coefficients in the symbolic ring::
     15    sage: x=var('x')
     16    sage: from sage.rings.pseudo_diff_op_algebra import *
     17    sage: A.<d> = PseudoDiffOpAlgebra(SR,x); A
     18    Algebra of pseudo-differential operators over Symbolic Ring acting on x
     19   
     20The formal inverse of d behaves as it should::
     21    sage: d^-1 * d
     22    1
     23    sage: d * d^-1
     24    1
     25
     26And we have the usual commutation relation::
     27    sage: u=function('u',x)
     28    sage: bracket(d,u)     # long time
     29    D[0](u)(x)
     30
     31This illustrates associativity of the product::
     32    sage: d*(d^-1 * (u * d^-3)) # long time
     33    (u(x))d^(-3) + O(d^-9)
     34
     35Note that [d^3, u] is not the same as [d, [d, [d, u]]]::
     36    sage: bracket(d,bracket(d,bracket(d,u))) # long time
     37    D[0, 0, 0](u)(x)
     38    sage: bracket(d^3,u)  # long time
     39    (3*D[0](u)(x))d^(2) + (3*D[0, 0](u)(x))d + D[0, 0, 0](u)(x)   
     40
     41.. WARNING::
     42
     43    This algebra is only interesting when used over the symbolic ring, because
     44    multiplication involves differentation. However, in the current
     45    implementation, this can be very slow. The reason for this is that we use
     46    LaurentSeriesRing, which checks whether any coefficient vanishes after
     47    every operation. For symbolic expressions, checking for vanishing spawns a
     48    Maxima process and this can be very slow.
     49"""
     50
     51#*****************************************************************************
     52#       Copyright (C) 2010-2011 William Stein <wstein@gmail.com>
     53#                     2010-2011 Timo Kluck <tkluck@infty.nl>
     54#
     55#  Distributed under the terms of the GNU General Public License (GPL)
     56#                  http://www.gnu.org/licenses/
     57#*****************************************************************************
     58
     59from sage.misc.latex import latex
     60from sage.rings.integer import Integer
     61from sage.rings.ring import Algebra
     62from sage.structure.element import AlgebraElement
     63from sage.rings.laurent_series_ring import LaurentSeriesRing
     64from sage.rings.infinity import Infinity
     65from sage.rings.arith import binomial
     66from sage.calculus.functional import diff
     67
     68def bracket(a,b):
     69    r"""
     70    Returns the commutator bracket between two elements.
     71    Equivalent to a*b - b*a.
     72    """
     73    return a*b - b*a
     74
     75class PseudoDiffOpAlgebra(Algebra):
     76    r"""
     77    An algebra of pseudo-differential operators.
     78   
     79    Pseudo-differential operators  are formal expansions of the form
     80    $\sum_n=-N^\infty u_{-n}(x) \partial_x^{-n}$. Multiplication is such that
     81    $[\partial_x, u(x)] =\frac{\partial u}{\partial x}$.
     82   
     83    EXAMPLES::
     84        sage: x=var('x')
     85        sage: from sage.rings.pseudo_diff_op_algebra import *
     86        sage: A.<d> = PseudoDiffOpAlgebra(SR,x)
     87        sage: d^-1 * d
     88        1
     89        sage: d * d^-1
     90        1
     91        sage: u=function('u',x)
     92        sage: bracket(d,u) # long time
     93        D[0](u)(x)
     94        sage: d*(d^-1 * (u * d^-3)) # long time
     95        (u(x))d^(-3) + O(d^-9)
     96
     97    AUTHORS:
     98        Timo Kluck (2010-11-15)   
     99    """
     100   
     101    def __init__(self,base,variable,prec=10,*kwds, **args):
     102        r"""
     103        Initializes an algebra of pseudo-differential operators.
     104       
     105        INPUT:
     106       
     107        -   ``base`` - the ring of coefficients
     108       
     109        -   ``variable`` - the variable with respect to which the operators
     110            should differentiate
     111           
     112        -   ``prec`` - the default order up to which to evaluate expansions, default is 10
     113       
     114        -   ``names`` - the name of the generator variable
     115       
     116        EXAMPLES::
     117       
     118            sage: x=var('x')
     119            sage: from sage.rings.pseudo_diff_op_algebra import *
     120            sage: A.<d> = PseudoDiffOpAlgebra(SR,x); A
     121            Algebra of pseudo-differential operators over Symbolic Ring acting on x
     122
     123        AUTHORS:
     124            Timo Kluck (2010-11-15)   
     125        """
     126        Algebra.__init__(self,base,*kwds,**args)
     127        self._var = variable
     128        self._prec = prec
     129        self.__symbolAlgebra = LaurentSeriesRing(base,'z_inverse')
     130       
     131    def prec(self):
     132        r"""
     133        Returns the default order up to which to evaluate expansions
     134       
     135        EXAMPLES::
     136        We first create a pseudo-differential operator algebra with coefficients in the symbolic ring::
     137            sage: x=var('x')
     138            sage: from sage.rings.pseudo_diff_op_algebra import *
     139            sage: A.<d> = PseudoDiffOpAlgebra(SR,x,20); A
     140            Algebra of pseudo-differential operators over Symbolic Ring acting on x
     141
     142        This illustrates associativity of the product, but now with precision equal to 20::
     143            sage: d*(d^-1 * (u * d^-3)) # long time
     144            (u(x))d^(-3) + O(d^-19)
     145
     146        AUTHORS:
     147            Timo Kluck (2010-11-15)   
     148        """
     149        return self._prec
     150       
     151    def var(self):
     152        r"""
     153        Returns the variable upon which the differential operators act.
     154
     155        AUTHORS:
     156            Timo Kluck (2010-11-15)   
     157        """
     158       
     159    def _repr_(self):
     160        r"""
     161        Prints out an algebra of pseudo-differential operators.
     162       
     163        EXAMPLES::
     164       
     165            sage: x=var('x')
     166            sage: from sage.rings.pseudo_diff_op_algebra import *
     167            sage: A.<d> = PseudoDiffOpAlgebra(SR,x); A
     168            Algebra of pseudo-differential operators over Symbolic Ring acting on x
     169
     170        AUTHORS:
     171            Timo Kluck (2010-11-15)   
     172        """
     173        return "Algebra of pseudo-differential operators over %s acting on %s" % (str(self.__symbolAlgebra.base_ring()), str(self._var))
     174       
     175    def _latex_(self):
     176        r"""
     177        Returns a latex representation.
     178       
     179        EXAMPLES::
     180       
     181            sage: x=var('x')
     182            sage: from sage.rings.pseudo_diff_op_algebra import *
     183            sage: A.<d> = PseudoDiffOpAlgebra(SR,x); latex(A)
     184            \texttt{Algebra of pseudo-differential operators over } \text{SR} \texttt{ acting on } x
     185
     186        AUTHORS:
     187            Timo Kluck (2010-11-15)   
     188        """
     189        return r"\texttt{Algebra of pseudo-differential operators over } %s \texttt{ acting on } %s" % (latex(self.__symbolAlgebra.base_ring()), latex(self._var))
     190   
     191           
     192    def _coerce_map_from_(self, S):
     193        r"""
     194        A coerce map exists iff a coerce map to the symbol algebra exists.
     195       
     196        Note that the symbol algebra is not an accessible property, because the
     197        implementation with z_inverse as a generator is a bit messy. This means
     198        that if the user wants to construct a pseudo-differential operator, s/he
     199        cannot do that by constructing a symbol and coerceing it. However, the
     200        generator is accessible via gen(0), so the user will only need coercion
     201        from the base ring to PseudoDiffOpAlgebra. Coercion via the symbol
     202        ring provides this.
     203
     204        AUTHORS:
     205            Timo Kluck (2010-11-15)   
     206        """
     207        return self.__symbolAlgebra.has_coerce_map_from(S)
     208
     209    def _element_constructor_(self, x):
     210        r"""
     211        Returns a pseudo-differential operator with symbol x
     212       
     213        INPUT:
     214       
     215        -    ``x`` - the symbol of x as an element of the symbol algebra
     216       
     217        OUTPUT:
     218       
     219        An instance of PseudoDiffOpAlgebra_element with symbol equal to x
     220
     221        AUTHORS:
     222            Timo Kluck (2010-11-15)   
     223        """       
     224       
     225        x = self.__symbolAlgebra(x)
     226        return PseudoDiffOpAlgebraElement(self, x)
     227
     228    def is_commutative(self):
     229        r"""
     230        Returns False, since for example $[\partial, u] = u^\prime \neq 0$.
     231
     232        AUTHORS:
     233            Timo Kluck (2010-11-15)   
     234        """
     235        return False
     236   
     237    def gen(self, n):
     238        r"""
     239        Returns a generator for the algebra. There is only one generator.
     240       
     241        EXAMPLES::
     242            sage: from sage.rings.pseudo_diff_op_algebra import *
     243            sage: A.<d> = PseudoDiffOpAlgebra(SR,x)
     244            sage: A.gen(0)
     245            d
     246
     247        AUTHORS:
     248            Timo Kluck (2010-11-15)   
     249        """
     250       
     251        if(n!=0):
     252            raise IndexError, "Generator n not defined."
     253        z_inverse = self.__symbolAlgebra.gen(0)
     254        return PseudoDiffOpAlgebraElement(parent=self,symbol=1/z_inverse,is_gen=True)
     255       
     256    def ngens(self):
     257        r"""
     258        Returns 1; the only generator is $\partial_{\mathrm{var}}$.
     259
     260        AUTHORS:
     261            Timo Kluck (2010-11-15)   
     262        """
     263        return 1
     264
     265
     266class PseudoDiffOpAlgebraElement(AlgebraElement):
     267    r"""
     268    A pseudo-differential operator.
     269   
     270    Pseudo-differential operators  are formal expansions of the form
     271    $\sum_n=-N^\infty u_{-n}(x) \partial_x^{-n}$. Multiplication is such that
     272    $[\partial_x, u(x)] =\frac{\partial u}{\partial x}$.
     273   
     274    EXAMPLES::
     275        sage: x=var('x')
     276        sage: from sage.rings.pseudo_diff_op_algebra import *
     277        sage: A.<d> = PseudoDiffOpAlgebra(SR,x)
     278        sage: type(d)
     279        <class 'sage.rings.pseudo_diff_op_algebra.PseudoDiffOpAlgebraElement'>
     280        sage: d^-1 * d
     281        1
     282        sage: d * d^-1
     283        1
     284        sage: u=function('u',x)
     285        sage: bracket(d,u)  # long time
     286        D[0](u)(x)
     287        sage: d*(d^-1 * (u * d^-3))  # long time
     288        (u(x))d^(-3) + O(d^-9)
     289       
     290    AUTHORS:
     291   
     292        Timo Kluck (2010-11-15)   
     293    """
     294    def __init__(self, parent, symbol,is_gen=False):
     295        r"""
     296        Initializes a pseudo-differential operator with symbol ``symbol``
     297       
     298        INPUT:
     299       
     300        -    ``symbol`` - the symbol of x as an element of the symbol algebra
     301       
     302        -   ``is_gen`` - whether this symbol is equal to z_inverse^(-1) (for
     303            internal use only!)
     304           
     305        AUTHORS:
     306       
     307            Timo Kluck (2010-11-15)   
     308        """
     309
     310        AlgebraElement.__init__(self,parent)
     311        self._symbol = symbol
     312        self._is_gen = is_gen
     313       
     314    def _add_(left, right):
     315        r"""
     316        Adds two pseudo-differential operators. This is just addition of the
     317        symbols.
     318
     319        AUTHORS:
     320       
     321            Timo Kluck (2010-11-15)   
     322        """
     323       
     324        new_symbol = left._symbol + right._symbol
     325        return PseudoDiffOpAlgebraElement(left.parent(), new_symbol)
     326       
     327    def _sub_(left, right):
     328        r"""
     329        Substracts two pseudo-differential operators. This is just addition of the
     330        symbols.
     331
     332        AUTHORS:
     333            Timo Kluck (2010-11-15)   
     334        """
     335
     336        new_symbol = left._symbol - right._symbol
     337        return PseudoDiffOpAlgebraElement(left.parent(), new_symbol)
     338   
     339   
     340    def _mul_(left, right):
     341        r"""
     342        Multiply two pseudo-differential operators.
     343       
     344        Multiplication is such that $[\partial_x, u(x)] =\frac{\partial u}{\partial x}$,
     345        and such that $\partial_x^{-1} \cdot \partial_x = 1$. More precisely,
     346        we define multiplication by the formula
     347        \[
     348        a \partial_x^n * b \partial_x^m = \sum_{k=0}^{\infty} \choose{n}{k} a \frac{\partial b}{\partial x} \partial_x^{m+m-k}
     349        \]
     350       
     351        EXAMPLES::
     352            sage: x=var('x')
     353            sage: from sage.rings.pseudo_diff_op_algebra import *
     354            sage: A.<d> = PseudoDiffOpAlgebra(SR,x)
     355            sage: type(d)
     356            <class 'sage.rings.pseudo_diff_op_algebra.PseudoDiffOpAlgebraElement'>
     357            sage: d^-1 * d
     358            1
     359            sage: d * d^-1
     360            1
     361            sage: u=function('u',x)
     362            sage: bracket(d,u)   # long time
     363            D[0](u)(x)
     364            sage: d*(d^-1 * (u * d^-3))   # long time
     365            (u(x))d^(-3) + O(d^-9)
     366
     367        AUTHORS:
     368       
     369            Timo Kluck (2010-11-15)   
     370        """
     371        # some shortcuts
     372        #if(left.is_zero() or right.is_zero()):
     373        #    return PseudoDiffOpAlgebraElement(left.parent(), left._symbol.parent()(0))
     374        #if(right.is_gen()):
     375        #    return PseudoDiffOpAlgebraElement(left.parent(), left._symbol>>1)
     376        #if(right.is_monomial() and left.exponents()==[0]):
     377        #    return PseudoDiffOpAlgebraElement(left.parent(), left._symbol*right._symbol)
     378           
     379       
     380        z_inverse = left._symbol.parent().gen(0)
     381       
     382        new_prec = (left._symbol * right._symbol).prec()
     383        if(not new_prec < Infinity):
     384            new_prec=left.parent().prec()
     385        new_symbol=left._symbol.parent()(0)
     386        for a,n in zip(left.coefficients(), left.exponents()):
     387            for b,m in zip(right.coefficients(), right.exponents()):
     388                k=0
     389                while(k-m-n < new_prec):
     390                    new_symbol += binomial(n,k) * a * diff(b, left.parent().var(), k) * z_inverse**(k-m-n)
     391                    k+=1
     392                if binomial(n,k)!=0 and diff(b,left.parent().var(),k)!=0:
     393                    new_symbol = new_symbol.add_bigoh(new_prec)
     394                         
     395           
     396        return PseudoDiffOpAlgebraElement(left.parent(), new_symbol)
     397
     398    def __pow__(self, exponent):
     399        r"""
     400        Raises a pseudo-differential operator to an integer power.
     401       
     402        .. NOTE::
     403       
     404            Raising any operator but $\partial_x$ to a negative power raises a
     405            value error. I am not sure if that is mathematically right.
     406
     407        AUTHORS:
     408       
     409            Timo Kluck (2010-11-15)   
     410        """
     411       
     412        if not isinstance(exponent, Integer) or \
     413                isinstance(exponent, int):
     414                    try:
     415                        exponent = Integer(exponent)
     416                    except TypeError:
     417                        raise TypeError, "Pseudo-differential operators can only be raised to integer powers."
     418                       
     419        if exponent == 0:
     420            return self.parent()(1)
     421       
     422        if self._is_gen:
     423            z_inverse = self._symbol.parent().gen(0)
     424            return self.parent()(z_inverse**-exponent)   
     425        else:
     426            if exponent < 0:
     427                raise ValueError, "Pseudo-differential operators can not be raised to negative powers (except for the generator)."
     428            else:
     429                #inductively
     430                return self * self ** (exponent-1)
     431   
     432    def __call__(self, fn):
     433        """
     434        Apply this operator to a function.
     435       
     436        This can only be done for operators with only a positive part. Otherwise,
     437        a ValueError is raised.
     438
     439        AUTHORS:
     440       
     441            Timo Kluck (2010-11-15)   
     442        """
     443        if self._symbol.degree() > 0:
     444            raise ValueError, "Can only apply the positive part of a pseudo-differential operator to a function."
     445       
     446        ret = 0
     447        var = self.parent().var()
     448        for c, e in zip(self.coefficients(), self.exponents()):
     449            ret += c * diff(fn, var, e)
     450        return ret
     451       
     452    def derivative(self, *args):
     453        r"""
     454        Returns the pseudo-differential operator obtained by differentiation
     455        of the coefficients.
     456       
     457        This is most useful when the base ring is the symbolic ring, or a
     458        power series ring, or similar.
     459
     460        AUTHORS:
     461       
     462            Timo Kluck (2010-11-15)   
     463        """
     464        # differentiate a pseudo diff op's coefficients
     465        d = self.parent().gen(0)
     466        new_c = [diff(c,*args) for c in self.coefficients()]
     467        return sum(c * d ** e for c,e in zip(new_c,self.exponents()))
     468   
     469    def symbol(self):
     470        return self._symbol
     471       
     472    def pos_part(self):
     473        r"""
     474        Returns the positive part of the pseudo-differential operator.
     475       
     476        The positive part is the summands with non-negative exponents of $\partial_x$.
     477        These are the ones that can be applied to a function of x.
     478       
     479        .. NOTE::
     480            The current implementation requires a patch of laurent series,
     481            trac #10272
     482
     483        AUTHORS:
     484       
     485            Timo Kluck (2010-11-15)
     486        """
     487        new_symbol = self._symbol.truncate(1)
     488        return PseudoDiffOpAlgebraElement(self.parent(), new_symbol)
     489       
     490    def neg_part(self):
     491        r"""
     492        Returns the negative part of the pseudo-differential operator.
     493       
     494        The negative part is the summands with negative exponents of $\partial_x$.
     495        It is given by self - self.pos_part()
     496       
     497        .. NOTE::
     498            The current implementation requires a patch of laurent series,
     499            trac #10272
     500
     501        AUTHORS:
     502       
     503            Timo Kluck (2010-11-15)
     504        """
     505        return self - self.pos_part()
     506   
     507    def coefficients(self):
     508        r"""
     509        Returns a list of coefficients of self.
     510       
     511        To obtain the corresponding exponents, use self.exponents()
     512       
     513        See the documentation for LaurentSeries.coefficients() for details.
     514
     515        AUTHORS:
     516       
     517            Timo Kluck (2010-11-15)
     518        """
     519        return self._symbol.coefficients()
     520   
     521    def exponents(self):
     522        r"""
     523        Returns a list of exponents of self.
     524       
     525        To obtain the corresponding coefficients, use self.coefficients()
     526
     527        See the documentation for LaurentSeries.exponents() for details.
     528       
     529        AUTHORS:
     530       
     531            Timo Kluck (2010-11-15)
     532        """
     533        return [-e for e in self._symbol.exponents()]
     534   
     535    def dict(self):
     536        r"""
     537        Returns a dictionary with keys=>value equal to exponent=>coefficient.
     538       
     539        See the documentation for LaurentSeries.dict() for details.
     540       
     541        AUTHORS:
     542       
     543            Timo Kluck (2010-11-15)
     544        """
     545        return dict(zip(self.exponents(),self.coefficients()))
     546           
     547    def simplify(self):
     548        r"""
     549        Returns the pseudo-differential operator obtained by simplifying
     550        the coefficients.
     551       
     552        This is most useful when the base ring is the symbolic ring.
     553
     554        AUTHORS:
     555       
     556            Timo Kluck (2010-11-15)   
     557        """
     558        from sage.calculus.functional import simplify
     559        new_coeff = [simplify(c) for c in self.coefficients()]
     560        z_inverse = self._symbol.parent().gen(0)
     561        new_symbol = self._symbol.parent()(0)
     562        new_symbol = new_symbol.add_bigoh(self._symbol.prec())
     563        for c,e in zip(new_coeff,self.exponents()):
     564            new_symbol += c * z_inverse**-e
     565        return PseudoDiffOpAlgebraElement(self.parent(), new_symbol)
     566   
     567    def expand(self):
     568        r"""
     569        Returns the pseudo-differential operator obtained by expanding
     570        the coefficients.
     571       
     572        This is most useful when the base ring is the symbolic ring.
     573
     574        AUTHORS:
     575       
     576            Timo Kluck (2010-11-15)   
     577        """
     578        from sage.calculus.functional import expand
     579        new_coeff = [expand(c) for c in self.coefficients()]
     580        z_inverse = self._symbol.parent().gen(0)
     581        new_symbol = self._symbol.parent()(0)
     582        new_symbol = new_symbol.add_bigoh(self._symbol.prec())
     583        for c,e in zip(new_coeff,self.exponents()):
     584            new_symbol += c * z_inverse**-e
     585        return PseudoDiffOpAlgebraElement(self.parent(), new_symbol)
     586   
     587    def __getitem__(self,n):
     588        r"""
     589        returns the nth coefficient of this pseudo-differential operator.
     590        """
     591       
     592        return self._symbol[-n]
     593   
     594    def is_gen(self):
     595        return self._is_gen
     596       
     597    def is_monomial(self):
     598        r"""
     599        Returns True when this pseudo-differential operator consists of a single
     600        term in the expansion in powers of $\partial_x$.
     601       
     602        NOTE:
     603            self.is_monomial() returns False if its precision is not Infinity.
     604
     605        AUTHORS:
     606       
     607            Timo Kluck (2010-11-15)   
     608        """
     609        return len(self._symbol.coefficients())==1 and self._symbol.prec()==Infinity
     610       
     611    def is_zero(self):
     612        return len(self._symbol.coefficients())==0
     613   
     614    def degree(self):
     615        r"""
     616        Returns the maximum integer $n$ for which the coefficient of $\partial_x^n$
     617        is non-zero.
     618        """
     619        return -self._symbol.valuation()   
     620
     621    def add_bigoh(self, prec):
     622        return PseudoDiffOpAlgebraElement(self.parent(), self._symbol.add_bigoh(-prec))
     623
     624    def O(self,prec):
     625        return self.add_bigoh(self, prec)
     626       
     627    def prec(self):
     628        return -self._symbol.prec()
     629   
     630    def common_prec(self,other):
     631        return -self._symbol.common_prec(other._symbol)
     632   
     633    def _repr_(self):
     634        list = []
     635        for (c,e) in zip(self._symbol.coefficients(),self._symbol.exponents()):
     636            if(c==0):
     637                continue
     638            if(c==1):
     639                coeff=""
     640            elif(e!=0):
     641                coeff = "(%s)" % str(c)
     642            else:
     643                coeff = str(c)
     644            if(-e==1 or e==0):
     645                ex=""
     646            else:
     647                ex="^(%s)" % str(-e)
     648            if(e==0):
     649                v=""
     650            else:
     651                v="d"
     652            if(c==1 and e==0):
     653                coeff="1"
     654               
     655            list.append("%(coeff)s%(var)s%(ex)s" % {"coeff": coeff, "var": v,"ex": ex})
     656       
     657        prec=self._symbol.prec()   
     658        if(prec<Infinity):
     659            if(prec==-1):
     660                list.append("O(d)")
     661            elif(prec==0):
     662                list.append("O(1)")
     663            else:
     664                list.append("O(d^%d)" % -prec)
     665               
     666               
     667        if(len(list)==0):
     668            return "0"
     669        else:
     670            return " + ".join(list)
     671           
     672    def _latex_(self):
     673        list = []
     674        v=self.parent().var()._latex_()
     675        for (c,e) in zip(self._symbol.coefficients(),self._symbol.exponents()):
     676            if(c==0):
     677                continue
     678            if(c==1):
     679                coeff=""
     680            elif(e!=0):
     681                coeff = "\\left(%s\\right)" % c._latex_()
     682            else:
     683                coeff = c._latex_()
     684            if(-e==1 or e==0):
     685                ex=""
     686            else:
     687                ex="^{%s}" % str(-e)
     688            if(e==0):
     689                d=""
     690            else:
     691                d="\\partial_{%s}" % v
     692            if(c==1 and e==0):
     693                coeff="1"
     694
     695            list.append("%(coeff)s%(d)s%(ex)s" % {"coeff": coeff, "d": d, "ex": ex})
     696
     697        prec=self._symbol.prec()   
     698        if(prec<Infinity):
     699            if(prec==-1):
     700                list.append("\\mathcal{O}(%(var)s)" % {"var":v})
     701            elif(prec==0):
     702                list.append("\\mathcal{O}(1)")
     703            else:
     704                list.append("\\mathcal{O}(\\partial_{%(var)s}^{%(ex)s})" % {"var":v, "ex": -prec})               
     705
     706
     707        if(len(list)==0):
     708            return "0"
     709        else:
     710            return " + ".join(list)