Ticket #14814: trac_14814-power_series_inverse_latex-fix-fh.patch

File trac_14814-power_series_inverse_latex-fix-fh.patch, 12.2 KB (added by hivert, 8 years ago)
  • sage/rings/multi_power_series_ring_element.py

    # HG changeset patch
    # User Florent Hivert <Florent.Hivert@lri.fr>
    # Date 1372425879 -7200
    # Node ID 7acbeb63c6fc683501d489e56b4869bddf55b2d9
    # Parent  22b859a7fa31c1ad5e23477693efc1f62ff6cf02
    Implement integration and division or power series.
    Fix latex of multivariate power series (missing {} in printing of exponent order)
    
    diff --git a/sage/rings/multi_power_series_ring_element.py b/sage/rings/multi_power_series_ring_element.py
    a b  
    11r"""
    2 Multivariate Power Series 
     2Multivariate Power Series
    33
    44Construct and manipulate multivariate power series over a given commutative
    55ring. Multivariate power series are implemented with total-degree precision.
    Inversion:: 
    133133    sage: f = 1 - 5*s^29 - 5*s^28*t + 4*s^18*t^35 + \
    134134    4*s^17*t^36 - s^45*t^25 - s^44*t^26 + s^7*t^83 + \
    135135    s^6*t^84 + R.O(101)
    136     sage: h = 1/f; h 
     136    sage: h = ~f; h
    137137    1 + 5*s^29 + 5*s^28*t - 4*s^18*t^35 - 4*s^17*t^36 + 25*s^58 + 50*s^57*t
    138138    + 25*s^56*t^2 + s^45*t^25 + s^44*t^26 - 40*s^47*t^35 - 80*s^46*t^36
    139139    - 40*s^45*t^37 + 125*s^87 + 375*s^86*t + 375*s^85*t^2 + 125*s^84*t^3
    AUTHORS: 
    159159#                  http://www.gnu.org/licenses/
    160160#*****************************************************************************
    161161
    162 
    163162from sage.rings.power_series_ring_element import PowerSeries
    164163
    165164from sage.rings.polynomial.all import is_PolynomialRing
    class MPowerSeries(PowerSeries): 
    574573            sage: t = M.gens()
    575574            sage: f = -t[0]^4*t[1]^3*t[2]^4 - 2*t[0]*t[1]^4*t[2]^7 \
    576575            + 2*t[1]*t[2]^12 + 2*t[0]^7*t[1]^5*t[2]^2 + M.O(15)
    577             sage: f 
     576            sage: f
    578577            -t0^4*t1^3*t2^4 - 2*t0*t1^4*t2^7 + 2*t1*t2^12 + 2*t0^7*t1^5*t2^2
    579578            + O(t0, t1, t2)^15
    580             sage: f._latex_() 
     579            sage: f._latex_()
    581580            '- t_{0}^{4} t_{1}^{3} t_{2}^{4} + 3 t_{0} t_{1}^{4} t_{2}^{7} +
    582581            2 t_{1} t_{2}^{12} + 2 t_{0}^{7} t_{1}^{5} t_{2}^{2}
    583             + O(t0, t1, t2)^15'
     582            + O(t0, t1, t2)^{15}'
    584583        """
    585584        if self._prec == infinity:
    586585            return "%s" % self._value()
    587         return "%(val)s + O(%(gens)s)^%(prec)s" \
     586        return "%(val)s + O(%(gens)s)^{%(prec)s}" \
    588587               %{'val':self._value()._latex_(),
    589588                 'gens':', '.join(g._latex_() for g in self.parent().gens()),
    590589                 'prec':self._prec}
    class MPowerSeries(PowerSeries): 
    639638    def __invert__(self):
    640639        """
    641640        Return multiplicative inverse of this multivariate power series.
    642        
     641
    643642        Currently implemented only if constant coefficient is a unit in the
    644643        base ring.
    645644
    class MPowerSeries(PowerSeries): 
    647646
    648647            sage: R.<a,b,c> = PowerSeriesRing(ZZ)
    649648            sage: f = 1 + a + b - a*b - b*c - a*c + R.O(4)
    650             sage: 1/f
     649            sage: ~f
    651650            1 - a - b + a^2 + 3*a*b + a*c + b^2 + b*c - a^3 - 5*a^2*b
    652651            - 2*a^2*c - 5*a*b^2 - 4*a*b*c - b^3 - 2*b^2*c + O(a, b, c)^4
    653652        """
    class MPowerSeries(PowerSeries): 
    786785        f = c * self._bg_value
    787786        return MPowerSeries(self.parent(), f, prec=f.prec())
    788787
    789     def _div_(self, denom_r):
     788    def trailing_monomial(self):
    790789        """
    791         Division by a unit works, but cancellation doesn't.
     790        Return the trailing monomial of ``self``
     791
     792        EXAMPLE::
     793
     794            sage: R.<a,b,c> = PowerSeriesRing(ZZ)
     795            sage: f = 1 + a + b - a*b + R.O(3)
     796            sage: f.trailing_monomial()
     797            1
     798            sage: f = a^2*b^3*f; f
     799            a^2*b^3 + a^3*b^3 + a^2*b^4 - a^3*b^4 + O(a, b, c)^8
     800            sage: f.trailing_monomial()
     801            a^2*b^3
    792802
    793803        TESTS::
    794804
     805            sage: (f-f).trailing_monomial()
     806            0
     807        """
     808        return self.polynomial().lt()
     809
     810    def quo_rem(self, other):
     811        r"""
     812        Quotient and remainder for increassing power division
     813
     814        INPUT: ``other`` - an element of the same power series ring as ``self``
     815
     816        EXAMPLE::
     817
     818            sage: R.<a,b,c> = PowerSeriesRing(ZZ)
     819            sage: f = 1 + a + b - a*b + R.O(3)
     820            sage: g = 1 + 2*a - 3*a*b + R.O(3)
     821            sage: q, r = f.quo_rem(g); q, r
     822            (1 - a + b + 2*a^2 + O(a, b, c)^3, 0 + O(a, b, c)^3)
     823            sage: f == q*g+r
     824            True
     825
     826            sage: q, r = (a*f).quo_rem(g); q, r
     827            (a - a^2 + a*b + 2*a^3 + O(a, b, c)^4, 0 + O(a, b, c)^4)
     828            sage: a*f == q*g+r
     829            True
     830
     831            sage: q, r = (a*f).quo_rem(a*g); q, r
     832            (1 - a + b + 2*a^2 + O(a, b, c)^3, 0 + O(a, b, c)^4)
     833            sage: a*f == q*(a*g)+r
     834            True
     835
     836            sage: q, r = (a*f).quo_rem(b*g); q, r
     837            (a - 3*a^2 + O(a, b, c)^3, a + a^2 + O(a, b, c)^4)
     838            sage: a*f == q*(b*g)+r
     839            True
     840
     841        TESTS::
     842
     843            sage: (f).quo_rem(R.zero())
     844            Traceback (most recent call last):
     845            ...
     846            ZeroDivisionError
     847
     848            sage: (f).quo_rem(R.zero().add_bigoh(2))
     849            Traceback (most recent call last):
     850            ...
     851            ZeroDivisionError
     852        """
     853        if other.parent() is not self.parent():
     854            raise ValueError, "Don't know how to divide by a element of %s"%(other.parent())
     855        other_tt = other.trailing_monomial()
     856        if not other_tt:
     857            raise ZeroDivisionError()
     858        mprec = min(self.prec(), other.prec())
     859        rem = self.parent().zero().add_bigoh(self.prec())
     860        quo = self.parent().zero().add_bigoh(self.prec()-other.valuation())
     861        while self:
     862            self_tt = self.trailing_monomial()
     863            assert self_tt
     864            if not other_tt.divides(self_tt):
     865                self -= self_tt
     866                rem += self_tt
     867            else:
     868                d = self_tt//other_tt
     869                self -= d * other
     870                quo += d
     871                quo = quo.add_bigoh(self.prec()-other_tt.degree())
     872        return quo, rem
     873
     874    def _div_(self, denom_r):
     875        r"""
     876        Division in the ring of power series.
     877
     878        EXAMPLE::
     879
    795880            sage: R.<a,b,c> = PowerSeriesRing(ZZ)
    796881            sage: f = 1 + a + b - a*b + R.O(3)
    797882            sage: g = 1/f; g #indirect doctest
    798883            1 - a - b + a^2 + 3*a*b + b^2 + O(a, b, c)^3
    799884            sage: g in R
    800885            True
    801             sage: g = a/(a*f)
     886            sage: g == ~f
     887            True
     888
     889        When possible, division by non unit also works::
     890
     891            sage: a/(a*f)
     892            1 - a - b + a^2 + 3*a*b + b^2 + O(a, b, c)^3
     893
     894            sage: a/(R.zero())
     895            Traceback (most recent call last):
     896            ZeroDivisionError
     897
     898            sage: (a*f)/f
     899            a + O(a, b, c)^4
     900            sage: f/(a*f)
    802901            Traceback (most recent call last):
    803902            ...
    804             TypeError: denominator must be a unit
     903            ValueError: Not divisible
    805904
     905        An example where one looses precision::
     906
     907            sage: ((1+a)*f - f) / a*f
     908            1 + 2*a + 2*b + O(a, b, c)^2
     909
     910        TESTS::
     911
     912            sage: ((a+b)*f) / f == (a+b)
     913            True
     914            sage: ((a+b)*f) / (a+b) == f
     915            True
    806916        """
    807         f = self._bg_value / denom_r._bg_value
    808         return MPowerSeries(self.parent(), f, prec=f.prec())
     917        if denom_r.is_unit(): # faster if denom_r is a unit
     918            return self*~denom_r
     919        quo, rem = self.quo_rem(denom_r)
     920        if rem:
     921            raise ValueError("Not divisible")
     922        else:
     923            return quo
    809924
    810925#    def _r_action_(self, c):
    811926#        # multivariate power series rings are assumed to be commutative
    class MPowerSeries(PowerSeries): 
    13181433        The formal derivative of this power series, with respect to
    13191434        variables supplied in ``args``.
    13201435
    1321         TESTS::
     1436        EXAMPLES::
    13221437
    13231438            sage: T.<a,b> = PowerSeriesRing(ZZ,2)
    13241439            sage: f = a + b + a^2*b + T.O(5)
    class MPowerSeries(PowerSeries): 
    13421457        new_prec = max(self.prec()-len(variables), 0)
    13431458        return R(deriv) + R.O(new_prec)
    13441459
     1460    def integral(self, *args):
     1461        """
     1462        The formal integral of this multivariate power series, with respect to
     1463        variables supplied in ``args``.
     1464
     1465        EXAMPLES::
     1466
     1467            sage: T.<a,b> = PowerSeriesRing(QQ,2)
     1468            sage: f = a + b + a^2*b + T.O(5)
     1469            sage: f.integral(a, 2)
     1470            1/6*a^3 + 1/2*a^2*b + 1/12*a^4*b + O(a, b)^7
     1471            sage: f.integral(a, b)
     1472            1/2*a^2*b + 1/2*a*b^2 + 1/6*a^3*b^2 + O(a, b)^7
     1473            sage: f.integral(a, 5)
     1474            1/720*a^6 + 1/120*a^5*b + 1/2520*a^7*b + O(a, b)^10
     1475
     1476        Only integration with respect to variables works::
     1477
     1478            sage: f.integral(a+b)
     1479            Traceback (most recent call last):
     1480            ...
     1481            ValueError: a + b is not a variable
     1482
     1483        .. warning:: Coefficient division.
     1484
     1485            If the base ring is not a field (e.g. `ZZ`), or if it has a non
     1486            zero characteristic, (e.g. `ZZ/3ZZ`), integration is not always
     1487            possible, while staying with the same base ring. In the first
     1488            case, Sage will report that it hasn't been able to coerce some
     1489            coefficient to the base ring::
     1490
     1491                sage: T.<a,b> = PowerSeriesRing(ZZ,2)
     1492                sage: f = a + T.O(5)
     1493                sage: f.integral(a)
     1494                Traceback (most recent call last):
     1495                ...
     1496                TypeError: no conversion of this rational to integer
     1497
     1498            One can get the correct result by changing the base ring first::
     1499
     1500                sage: f.change_ring(QQ).integral(a)
     1501                1/2*a^2 + O(a, b)^6
     1502
     1503            However, a correct result is returned if the denominator cancels::
     1504
     1505                sage: f = 2*b + T.O(5)
     1506                sage: f.integral(b)
     1507                b^2 + O(a, b)^6
     1508
     1509            In non zero characteristic, Sage will report that a zero division
     1510            occurred ::
     1511
     1512                sage: T.<a,b> = PowerSeriesRing(Zmod(3),2)
     1513                sage: (a^3).integral(a)
     1514                a^4
     1515                sage: (a^2).integral(a)
     1516                Traceback (most recent call last):
     1517                ...
     1518                ZeroDivisionError: Inverse does not exist.
     1519        """
     1520        from sage.misc.derivative import derivative_parse
     1521        res = self
     1522        for v in derivative_parse(args):
     1523            res = res._integral(v)
     1524        return res
     1525
     1526    def _integral(self, xx):
     1527        """
     1528        Formal integral for multivariate power series
     1529
     1530        INPUT: ``xx`` a generator of the power series ring
     1531
     1532        EXAMPLES::
     1533
     1534            sage: T.<a,b> = PowerSeriesRing(QQ,2)
     1535            sage: f = a + b + a^2*b + T.O(5)
     1536            sage: f._integral(a)
     1537            1/2*a^2 + a*b + 1/3*a^3*b + O(a, b)^6
     1538            sage: f._integral(b)
     1539            a*b + 1/2*b^2 + 1/2*a^2*b^2 + O(a, b)^6
     1540
     1541        TESTS:
     1542
     1543        We try to recognise variables even if they are not recognized as
     1544        genrators of the rings::
     1545
     1546            sage: T.<a,b> = PowerSeriesRing(QQ,2)
     1547            sage: a.is_gen()
     1548            True
     1549            sage: (a+0).is_gen()
     1550            False
     1551            sage: (a+b).integral(a+0)
     1552            1/2*a^2 + a*b
     1553
     1554            sage: T.<a,b> = PowerSeriesRing(ZZ,2)
     1555            sage: aa = a.change_ring(Zmod(5))
     1556            sage: aa.is_gen()
     1557            False
     1558            sage: aa.integral(aa)
     1559            -2*a^2
     1560            sage: aa.integral(a)
     1561            -2*a^2
     1562        """
     1563        P = self.parent()
     1564        R = P.base_ring()
     1565        xx = P(xx)
     1566        if not xx.is_gen():
     1567            for g in P.gens(): # try to find a generator equal to xx
     1568                if g == xx:
     1569                    xx = g
     1570                    break
     1571            else:
     1572                raise ValueError, "%s is not a variable"%(xx)
     1573        xxe = xx.exponents()[0]
     1574        pos = [i for i, c in enumerate(xxe) if c != 0][0] # get the position of the variable
     1575        res = { mon.eadd(xxe) : R(co / (mon[pos]+1)) for mon, co in self.dict().iteritems() }
     1576        return P( res ).add_bigoh(self.prec()+1)
     1577
    13451578    def ogf(self):
    13461579        """
    13471580        Method from univariate power series not yet implemented