Skip to content

Commit 5161665

Browse files
author
Release Manager
committed
gh-36934: details fixed in cfinite_sequence.py fixing a few details in C-finite sequences main change : use `Parent` (new coercion framework) instead of `Ring` ### 📝 Checklist - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. URL: #36934 Reported by: Frédéric Chapoton Reviewer(s): Matthias Köppe
2 parents 227b91e + 48457d2 commit 5161665

File tree

1 file changed

+77
-65
lines changed

1 file changed

+77
-65
lines changed

src/sage/rings/cfinite_sequence.py

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,8 @@
8989

9090
from numbers import Integral
9191

92-
from sage.categories.fields import Fields
92+
from sage.categories.rings import Rings
9393
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
94-
from sage.rings.ring import CommutativeRing
9594
from sage.rings.integer_ring import ZZ
9695
from sage.rings.rational_field import QQ
9796
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
@@ -100,6 +99,7 @@
10099
from sage.rings.power_series_ring import PowerSeriesRing
101100
from sage.rings.fraction_field import FractionField
102101
from sage.structure.element import FieldElement, parent
102+
from sage.structure.parent import Parent
103103
from sage.structure.unique_representation import UniqueRepresentation
104104

105105
from sage.interfaces.gp import Gp
@@ -110,7 +110,7 @@
110110

111111
def CFiniteSequences(base_ring, names=None, category=None):
112112
r"""
113-
Return the ring of C-Finite sequences.
113+
Return the commutative ring of C-Finite sequences.
114114
115115
The ring is defined over a base ring (`\ZZ` or `\QQ` )
116116
and each element is represented by its ordinary generating function (ogf)
@@ -154,15 +154,15 @@ def CFiniteSequences(base_ring, names=None, category=None):
154154
elif len(names) > 1:
155155
raise NotImplementedError("Multidimensional o.g.f. not implemented.")
156156
if category is None:
157-
category = Fields()
158-
if not (base_ring in (QQ, ZZ)):
157+
category = Rings().Commutative()
158+
if base_ring not in [QQ, ZZ]:
159159
raise ValueError("O.g.f. base not rational.")
160160
polynomial_ring = PolynomialRing(base_ring, names)
161161
return CFiniteSequences_generic(polynomial_ring, category)
162162

163163

164164
class CFiniteSequence(FieldElement,
165-
metaclass=InheritComparisonClasscallMetaclass):
165+
metaclass=InheritComparisonClasscallMetaclass):
166166
r"""
167167
Create a C-finite sequence given its ordinary generating function.
168168
@@ -174,7 +174,7 @@ class CFiniteSequence(FieldElement,
174174
175175
OUTPUT:
176176
177-
- A CFiniteSequence object
177+
A CFiniteSequence object
178178
179179
EXAMPLES::
180180
@@ -247,7 +247,7 @@ class CFiniteSequence(FieldElement,
247247
@staticmethod
248248
def __classcall_private__(cls, ogf):
249249
r"""
250-
Ensures that elements created by :class:`CFiniteSequence` have the same
250+
Ensure that elements created by :class:`CFiniteSequence` have the same
251251
parent than the ones created by the parent itself and follow the category
252252
framework (they should be instance of :class:`CFiniteSequences` automatic
253253
element class).
@@ -299,9 +299,8 @@ def __classcall_private__(cls, ogf):
299299
sage: f4.parent()
300300
The ring of C-Finite sequences in y over Rational Field
301301
"""
302-
303302
br = ogf.base_ring()
304-
if not (br in (QQ, ZZ)):
303+
if br not in [QQ, ZZ]:
305304
br = QQ # if the base ring of the o.g.f is not QQ, we force it to QQ and see if the o.g.f converts nicely
306305

307306
# trying to figure out the ogf variables
@@ -388,7 +387,6 @@ def __init__(self, parent, ogf):
388387
# determine start values (may be different from _get_item_ values)
389388
alen = max(self._deg, num.degree() + 1)
390389
R = LaurentSeriesRing(br, parent.variable_name(), default_prec=alen)
391-
rem = num % den
392390
if den != 1:
393391
self._a = R(num / den).list()
394392
else:
@@ -400,7 +398,7 @@ def __init__(self, parent, ogf):
400398

401399
self._ogf = ogf
402400

403-
def _repr_(self):
401+
def _repr_(self) -> str:
404402
"""
405403
Return textual definition of sequence.
406404
@@ -414,10 +412,8 @@ def _repr_(self):
414412
if self._deg == 0:
415413
if self.ogf() == 0:
416414
return 'Constant infinite sequence 0.'
417-
else:
418-
return 'Finite sequence ' + str(self._a) + ', offset = ' + str(self._off)
419-
else:
420-
return 'C-finite sequence, generated by ' + str(self.ogf())
415+
return 'Finite sequence ' + str(self._a) + ', offset = ' + str(self._off)
416+
return 'C-finite sequence, generated by ' + str(self.ogf())
421417

422418
def __hash__(self):
423419
r"""
@@ -656,7 +652,8 @@ def __getitem__(self, key):
656652
if isinstance(key, slice):
657653
m = max(key.start, key.stop)
658654
return [self[ii] for ii in range(*key.indices(m + 1))]
659-
elif isinstance(key, Integral):
655+
656+
if isinstance(key, Integral):
660657
n = key - self._off
661658
if n < 0:
662659
return 0
@@ -679,8 +676,8 @@ def __getitem__(self, key):
679676
den = P((den * nden).list()[::2])
680677
n //= 2
681678
return wp + num[0] / den[0]
682-
else:
683-
raise TypeError("invalid argument type")
679+
680+
raise TypeError("invalid argument type")
684681

685682
def ogf(self):
686683
"""
@@ -726,14 +723,14 @@ def denominator(self):
726723
"""
727724
return self.ogf().denominator()
728725

729-
def recurrence_repr(self):
726+
def recurrence_repr(self) -> str:
730727
"""
731728
Return a string with the recurrence representation of
732729
the C-finite sequence.
733730
734731
OUTPUT:
735732
736-
- A string
733+
A string
737734
738735
EXAMPLES::
739736
@@ -892,7 +889,7 @@ def closed_form(self, n='n'):
892889
return expr
893890

894891

895-
class CFiniteSequences_generic(CommutativeRing, UniqueRepresentation):
892+
class CFiniteSequences_generic(Parent, UniqueRepresentation):
896893
r"""
897894
The class representing the ring of C-Finite Sequences
898895
@@ -912,13 +909,13 @@ class CFiniteSequences_generic(CommutativeRing, UniqueRepresentation):
912909

913910
def __init__(self, polynomial_ring, category):
914911
r"""
915-
Create the ring of CFiniteSequences over ``base_ring``
912+
Create the ring of CFiniteSequences over ``base_ring``.
916913
917914
INPUT:
918915
919916
- ``base_ring`` -- the base ring for the o.g.f (either ``QQ`` or ``ZZ``)
920917
- ``names`` -- an iterable of variables (should contain only one variable)
921-
- ``category`` -- the category of the ring (default: ``Fields()``)
918+
- ``category`` -- the category of the ring (default: ``Rings().Commutative()``)
922919
923920
TESTS::
924921
@@ -940,11 +937,14 @@ def __init__(self, polynomial_ring, category):
940937
base_ring = polynomial_ring.base_ring()
941938
self._polynomial_ring = polynomial_ring
942939
self._fraction_field = FractionField(self._polynomial_ring)
943-
CommutativeRing.__init__(self, base_ring, self._polynomial_ring.gens(), category)
940+
if category is None:
941+
category = Rings().Commutative()
942+
Parent.__init__(self, base_ring, names=self._polynomial_ring.gens(),
943+
category=category)
944944

945945
def _repr_(self):
946946
r"""
947-
Return the string representation of ``self``
947+
Return the string representation of ``self``.
948948
949949
EXAMPLES::
950950
@@ -956,7 +956,7 @@ def _repr_(self):
956956

957957
def _element_constructor_(self, ogf):
958958
r"""
959-
Construct a C-Finite Sequence
959+
Construct a C-Finite Sequence.
960960
961961
INPUT:
962962
@@ -986,9 +986,9 @@ def _element_constructor_(self, ogf):
986986
ogf = self.fraction_field()(ogf)
987987
return self.element_class(self, ogf)
988988

989-
def ngens(self):
989+
def ngens(self) -> int:
990990
r"""
991-
Return the number of generators of ``self``
991+
Return the number of generators of ``self``.
992992
993993
EXAMPLES::
994994
@@ -1026,6 +1026,18 @@ def gen(self, i=0):
10261026
raise ValueError("{} has only one generator (i=0)".format(self))
10271027
return self.polynomial_ring().gen()
10281028

1029+
def gens(self) -> tuple:
1030+
"""
1031+
Return the generators of ``self``.
1032+
1033+
EXAMPLES::
1034+
1035+
sage: C.<x> = CFiniteSequences(QQ)
1036+
sage: C.gens()
1037+
(x,)
1038+
"""
1039+
return (self.gen(0),)
1040+
10291041
def an_element(self):
10301042
r"""
10311043
Return an element of C-Finite Sequences.
@@ -1043,7 +1055,7 @@ def an_element(self):
10431055
x = self.gen()
10441056
return self((2 - x) / (1 - x - x**2))
10451057

1046-
def __contains__(self, x):
1058+
def __contains__(self, x) -> bool:
10471059
"""
10481060
Return ``True`` if x is an element of ``CFiniteSequences`` or
10491061
canonically coerces to this ring.
@@ -1194,7 +1206,7 @@ def guess(self, sequence, algorithm='sage'):
11941206
sage: r = C.guess([1,2,3,4,5])
11951207
Traceback (most recent call last):
11961208
...
1197-
ValueError: Sequence too short for guessing.
1209+
ValueError: sequence too short for guessing
11981210
11991211
With Berlekamp-Massey, if an odd number of values is given, the last one is dropped.
12001212
So with an odd number of values the result may not generate the last value::
@@ -1205,10 +1217,11 @@ def guess(self, sequence, algorithm='sage'):
12051217
[1, 2, 4, 8, 16]
12061218
"""
12071219
S = self.polynomial_ring()
1220+
12081221
if algorithm == 'bm':
12091222
from sage.matrix.berlekamp_massey import berlekamp_massey
12101223
if len(sequence) < 2:
1211-
raise ValueError('Sequence too short for guessing.')
1224+
raise ValueError('sequence too short for guessing')
12121225
R = PowerSeriesRing(QQ, 'x')
12131226
if len(sequence) % 2:
12141227
sequence.pop()
@@ -1217,10 +1230,11 @@ def guess(self, sequence, algorithm='sage'):
12171230
numerator = R(S(sequence) * denominator, prec=l).truncate()
12181231

12191232
return CFiniteSequence(numerator / denominator)
1220-
elif algorithm == 'pari':
1233+
1234+
if algorithm == 'pari':
12211235
global _gp
12221236
if len(sequence) < 6:
1223-
raise ValueError('Sequence too short for guessing.')
1237+
raise ValueError('sequence too short for guessing')
12241238
if _gp is None:
12251239
_gp = Gp()
12261240
_gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\
@@ -1236,37 +1250,35 @@ def guess(self, sequence, algorithm='sage'):
12361250
den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1])
12371251
if num == 0:
12381252
return 0
1239-
else:
1240-
return CFiniteSequence(num / den)
1241-
else:
1242-
from sage.matrix.constructor import matrix
1243-
from sage.arith.misc import integer_ceil as ceil
1244-
from numpy import trim_zeros
1245-
seq = sequence[:]
1246-
while seq and sequence[-1] == 0:
1247-
seq.pop()
1248-
l = len(seq)
1249-
if l == 0:
1250-
return 0
1251-
if l < 6:
1252-
raise ValueError('Sequence too short for guessing.')
1253-
1254-
hl = ceil(ZZ(l) / 2)
1255-
A = matrix([sequence[k: k + hl] for k in range(hl)])
1256-
K = A.kernel()
1257-
if K.dimension() == 0:
1258-
return 0
1259-
R = PolynomialRing(QQ, 'x')
1260-
den = R(trim_zeros(K.basis()[-1].list()[::-1]))
1261-
if den == 1:
1262-
return 0
1263-
offset = next((i for i, x in enumerate(sequence) if x), None)
1264-
S = PowerSeriesRing(QQ, 'x', default_prec=l - offset)
1265-
num = S(R(sequence) * den).truncate(ZZ(l) // 2 + 1)
1266-
if num == 0 or sequence != S(num / den).list():
1267-
return 0
1268-
else:
1269-
return CFiniteSequence(num / den)
1253+
return CFiniteSequence(num / den)
1254+
1255+
from sage.matrix.constructor import matrix
1256+
from sage.arith.misc import integer_ceil as ceil
1257+
from numpy import trim_zeros
1258+
seq = sequence[:]
1259+
while seq and sequence[-1] == 0:
1260+
seq.pop()
1261+
l = len(seq)
1262+
if l == 0:
1263+
return 0
1264+
if l < 6:
1265+
raise ValueError('sequence too short for guessing')
1266+
1267+
hl = ceil(ZZ(l) / 2)
1268+
A = matrix([sequence[k: k + hl] for k in range(hl)])
1269+
K = A.kernel()
1270+
if K.dimension() == 0:
1271+
return 0
1272+
R = PolynomialRing(QQ, 'x')
1273+
den = R(trim_zeros(K.basis()[-1].list()[::-1]))
1274+
if den == 1:
1275+
return 0
1276+
offset = next((i for i, x in enumerate(sequence) if x), None)
1277+
S = PowerSeriesRing(QQ, 'x', default_prec=l - offset)
1278+
num = S(R(sequence) * den).truncate(ZZ(l) // 2 + 1)
1279+
if num == 0 or sequence != S(num / den).list():
1280+
return 0
1281+
return CFiniteSequence(num / den)
12701282

12711283

12721284
r"""

0 commit comments

Comments
 (0)