Ticket #14814: trac_14814power_series_inverse_latexfixfh.patch
File trac_14814power_series_inverse_latexfixfh.patch, 12.2 KB (added by , 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 1 1 r""" 2 Multivariate Power Series 2 Multivariate Power Series 3 3 4 4 Construct and manipulate multivariate power series over a given commutative 5 5 ring. Multivariate power series are implemented with totaldegree precision. … … Inversion:: 133 133 sage: f = 1  5*s^29  5*s^28*t + 4*s^18*t^35 + \ 134 134 4*s^17*t^36  s^45*t^25  s^44*t^26 + s^7*t^83 + \ 135 135 s^6*t^84 + R.O(101) 136 sage: h = 1/f; h136 sage: h = ~f; h 137 137 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 138 138 + 25*s^56*t^2 + s^45*t^25 + s^44*t^26  40*s^47*t^35  80*s^46*t^36 139 139  40*s^45*t^37 + 125*s^87 + 375*s^86*t + 375*s^85*t^2 + 125*s^84*t^3 … … AUTHORS: 159 159 # http://www.gnu.org/licenses/ 160 160 #***************************************************************************** 161 161 162 163 162 from sage.rings.power_series_ring_element import PowerSeries 164 163 165 164 from sage.rings.polynomial.all import is_PolynomialRing … … class MPowerSeries(PowerSeries): 574 573 sage: t = M.gens() 575 574 sage: f = t[0]^4*t[1]^3*t[2]^4  2*t[0]*t[1]^4*t[2]^7 \ 576 575 + 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 578 577 t0^4*t1^3*t2^4  2*t0*t1^4*t2^7 + 2*t1*t2^12 + 2*t0^7*t1^5*t2^2 579 578 + O(t0, t1, t2)^15 580 sage: f._latex_() 579 sage: f._latex_() 581 580 ' t_{0}^{4} t_{1}^{3} t_{2}^{4} + 3 t_{0} t_{1}^{4} t_{2}^{7} + 582 581 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}' 584 583 """ 585 584 if self._prec == infinity: 586 585 return "%s" % self._value() 587 return "%(val)s + O(%(gens)s)^ %(prec)s" \586 return "%(val)s + O(%(gens)s)^{%(prec)s}" \ 588 587 %{'val':self._value()._latex_(), 589 588 'gens':', '.join(g._latex_() for g in self.parent().gens()), 590 589 'prec':self._prec} … … class MPowerSeries(PowerSeries): 639 638 def __invert__(self): 640 639 """ 641 640 Return multiplicative inverse of this multivariate power series. 642 641 643 642 Currently implemented only if constant coefficient is a unit in the 644 643 base ring. 645 644 … … class MPowerSeries(PowerSeries): 647 646 648 647 sage: R.<a,b,c> = PowerSeriesRing(ZZ) 649 648 sage: f = 1 + a + b  a*b  b*c  a*c + R.O(4) 650 sage: 1/f649 sage: ~f 651 650 1  a  b + a^2 + 3*a*b + a*c + b^2 + b*c  a^3  5*a^2*b 652 651  2*a^2*c  5*a*b^2  4*a*b*c  b^3  2*b^2*c + O(a, b, c)^4 653 652 """ … … class MPowerSeries(PowerSeries): 786 785 f = c * self._bg_value 787 786 return MPowerSeries(self.parent(), f, prec=f.prec()) 788 787 789 def _div_(self, denom_r):788 def trailing_monomial(self): 790 789 """ 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 792 802 793 803 TESTS:: 794 804 805 sage: (ff).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 795 880 sage: R.<a,b,c> = PowerSeriesRing(ZZ) 796 881 sage: f = 1 + a + b  a*b + R.O(3) 797 882 sage: g = 1/f; g #indirect doctest 798 883 1  a  b + a^2 + 3*a*b + b^2 + O(a, b, c)^3 799 884 sage: g in R 800 885 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) 802 901 Traceback (most recent call last): 803 902 ... 804 TypeError: denominator must be a unit903 ValueError: Not divisible 805 904 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 806 916 """ 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 809 924 810 925 # def _r_action_(self, c): 811 926 # # multivariate power series rings are assumed to be commutative … … class MPowerSeries(PowerSeries): 1318 1433 The formal derivative of this power series, with respect to 1319 1434 variables supplied in ``args``. 1320 1435 1321 TESTS::1436 EXAMPLES:: 1322 1437 1323 1438 sage: T.<a,b> = PowerSeriesRing(ZZ,2) 1324 1439 sage: f = a + b + a^2*b + T.O(5) … … class MPowerSeries(PowerSeries): 1342 1457 new_prec = max(self.prec()len(variables), 0) 1343 1458 return R(deriv) + R.O(new_prec) 1344 1459 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 1345 1578 def ogf(self): 1346 1579 """ 1347 1580 Method from univariate power series not yet implemented