Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit aeea9a1

Browse files
hivertvbraun
authored andcommitted
Implement integration and division or power series.
Fix latex of multivariate power series (missing {} in printing of exponent order)
1 parent 036984d commit aeea9a1

File tree

1 file changed

+245
-12
lines changed

1 file changed

+245
-12
lines changed

src/sage/rings/multi_power_series_ring_element.py

+245-12
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
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
@@ -159,7 +159,6 @@
159159
# http://www.gnu.org/licenses/
160160
#*****************************************************************************
161161

162-
163162
from sage.rings.power_series_ring_element import PowerSeries
164163

165164
from sage.rings.polynomial.all import is_PolynomialRing
@@ -580,11 +579,11 @@ def _latex_(self):
580579
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}
@@ -647,7 +646,7 @@ def __invert__(self):
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
"""
@@ -786,26 +785,142 @@ def _lmul_(self, c):
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
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
805909
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
@@ -1318,7 +1433,7 @@ def derivative(self, *args):
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)
@@ -1342,6 +1457,124 @@ def derivative(self, *args):
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

0 commit comments

Comments
 (0)