From a9baadcd721f53364513ae4b2e80318946f4a5da Mon Sep 17 00:00:00 2001 From: Ryuhei Mori Date: Fri, 24 Nov 2023 17:31:33 +0900 Subject: [PATCH 1/4] Improve performance of __getitem__ --- src/sage/rings/cfinite_sequence.py | 39 +++++++++++++----------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 26cce303581..646626423cd 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -391,7 +391,6 @@ def __init__(self, parent, ogf): rem = num % den if den != 1: self._a = R(num / den).list() - self._aa = (rem.valuation() * [0] + R(rem / den).list())[:self._deg] # needed for _get_item_ else: self._a = num.list() if len(self._a) < alen: @@ -650,28 +649,24 @@ def __getitem__(self, key): m = max(key.start, key.stop) return [self[ii] for ii in range(*key.indices(m + 1))] elif isinstance(key, Integral): - from sage.matrix.constructor import Matrix - d = self._deg - if (self._off <= key and key < self._off + len(self._a)): - return self._a[key - self._off] - elif d == 0: - return 0 - (quo, rem) = self.numerator().quo_rem(self.denominator()) - wp = quo[key - self._off] - if key < self._off: - return wp - A = Matrix(QQ, 1, d, self._c) - B = Matrix.identity(QQ, d - 1) - C = Matrix(QQ, d - 1, 1, 0) - if quo == 0: - off = self._off - V = Matrix(QQ, d, 1, self._a[:d][::-1]) + den = self.denominator() + num = self.numerator() + if self._off >= 0: + num = num.shift(-self._off) else: - off = 0 - V = Matrix(QQ, d, 1, self._aa[:d][::-1]) - M = Matrix.block([[A], [B, C]], subdivide=False) - - return wp + list(M ** (key - off) * V)[d - 1][0] + den = den.shift(self._off) + n = key - self._off + if n < 0: + return 0 + (quo, num) = num.quo_rem(den) + P = self.parent().polynomial_ring() + x = self.parent().gen() + m = n + while m: + num = P((num * den(-x)).list()[m % 2::2]) + den = P((den * den(-x)).list()[::2]) + m //= 2 + return quo[n] + num[0] / den[0] else: raise TypeError("invalid argument type") From 30985bc6eda1f8057e651080f11536d984499e34 Mon Sep 17 00:00:00 2001 From: Ryuhei Mori Date: Fri, 24 Nov 2023 18:47:22 +0900 Subject: [PATCH 2/4] __getitem__ with key greater than 64 bits --- src/sage/rings/cfinite_sequence.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 646626423cd..b8d76f677d5 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -661,12 +661,15 @@ def __getitem__(self, key): (quo, num) = num.quo_rem(den) P = self.parent().polynomial_ring() x = self.parent().gen() - m = n - while m: - num = P((num * den(-x)).list()[m % 2::2]) + if quo.degree() < n: + wp = 0 + else: + wp = quo[n] + while n: + num = P((num * den(-x)).list()[n % 2::2]) den = P((den * den(-x)).list()[::2]) - m //= 2 - return quo[n] + num[0] / den[0] + n //= 2 + return wp + num[0] / den[0] else: raise TypeError("invalid argument type") From 3cfec74b6c4224aaed8806df8f02e79e31b39a59 Mon Sep 17 00:00:00 2001 From: Ryuhei Mori Date: Tue, 28 Nov 2023 10:05:06 +0900 Subject: [PATCH 3/4] Small performance improvements --- src/sage/rings/cfinite_sequence.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index b8d76f677d5..f7da28e046c 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -649,25 +649,26 @@ def __getitem__(self, key): m = max(key.start, key.stop) return [self[ii] for ii in range(*key.indices(m + 1))] elif isinstance(key, Integral): + n = key - self._off + if n < 0: + return 0 den = self.denominator() num = self.numerator() if self._off >= 0: num = num.shift(-self._off) else: den = den.shift(self._off) - n = key - self._off - if n < 0: - return 0 (quo, num) = num.quo_rem(den) - P = self.parent().polynomial_ring() - x = self.parent().gen() if quo.degree() < n: wp = 0 else: wp = quo[n] + P = self.parent().polynomial_ring() + x = P.gen() while n: - num = P((num * den(-x)).list()[n % 2::2]) - den = P((den * den(-x)).list()[::2]) + nden = den(-x) + num = P((num * nden).list()[n % 2::2]) + den = P((den * nden).list()[::2]) n //= 2 return wp + num[0] / den[0] else: From 486c77618bd3dbdb629e0fae8796a1e7743ed099 Mon Sep 17 00:00:00 2001 From: Ryuhei Mori Date: Tue, 28 Nov 2023 17:35:55 +0900 Subject: [PATCH 4/4] Add a reference and examples for __getitem__ --- src/doc/en/reference/references/index.rst | 5 +++++ src/sage/rings/cfinite_sequence.py | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index fa67dade3ab..9d7fba94c49 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1044,6 +1044,11 @@ REFERENCES: *Guide to using plantri*, version 5.0, 2016. http://cs.anu.edu.au/~bdm/plantri/plantri-guide.txt +.. [BM2021] Alin Bostan and Ryuhei Mori, + *A simple and fast algorithm for computing the N-th term of a linearly recurrent sequence*, + Proceedings of Symposium on Simplicity in Algorithms (SOSA), pp. 118--132, 2021. + :doi:`10.1137/1.9781611976496.14` + .. [BMBFLR2008] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, S. Rinaldi, *Reconstructing words from a fixed palindromic length sequence*, Proc. TCS 2008, 5th IFIP diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index f7da28e046c..4d9353e57b8 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -644,6 +644,14 @@ def __getitem__(self, key): [0, 0, 1, 2, 3, 4, 5, 6, 7, 8] sage: s = C(x^3 * (1 - x)^-2); s[0:10] [0, 0, 0, 1, 2, 3, 4, 5, 6, 7] + sage: s = C(1/(1-x^1000)); s[10^18] + 1 + sage: s = C(1/(1-x^1000)); s[10^20] + 1 + + REFERENCES: + + - [BM2021]_ """ if isinstance(key, slice): m = max(key.start, key.stop)