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

Commit

Permalink
be specific about base ring, more doctests
Browse files Browse the repository at this point in the history
  • Loading branch information
rwst committed Mar 4, 2014
1 parent d69aaac commit a62b72c
Showing 1 changed file with 60 additions and 40 deletions.
100 changes: 60 additions & 40 deletions src/sage/rings/cfinite_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
r"""
C-Finite Sequences
CFiniteSequences are completely
defined by and equivalent to their ordinary generating function (OGF, which
is always a polynomial fraction).
C-finite sequences satisfy homogenous linear recurrences with constant coefficients:
C-finite infinite sequences satisfy homogenous linear recurrences with constant coefficients:
.. MATH::
a_{n+d} = c_0a_n + c_1a_{n+1} + \cdots + c_{d-1}a_{n+d-1}, \quad d\ge0.
CFiniteSequences are completely
defined by and equivalent to their ordinary generating function (OGF, which
is always a polynomial fraction).
EXAMPLES::
sage: R.<x>=ZZ[]
Expand Down Expand Up @@ -40,25 +40,10 @@
EXAMPLES::
sage: r=CFiniteSequence.guess([0,1,1,2,3,5,8]);
sage: r = CFiniteSequence.guess([0,1,1,2,3,5,8]);
sage: r == fibo
True
TESTS::
sage: CFiniteSequence(x/(1-x))
C-finite sequence, generated by x/(-x + 1)
sage: r = CFiniteSequence.from_recurrence([-1],[1])
sage: s = CFiniteSequence.from_recurrence([-1],[1,-1])
sage: r == s
True
sage: r = CFiniteSequence(x^3/(1-x-x^2))
sage: r.recurrence_repr()
'Homogenous linear recurrence with constant coefficients of degree 2: a(n+2) = 1*a(n) + 1*a(n+1), starting a(3...) = [1, 1]'
sage: s = CFiniteSequence.from_recurrence([1,1],[0,0,0,1,1])
sage: r == s
True
SEEALSO:
:func:`fibonacci`, :class:`BinaryRecurrenceSequence`
Expand Down Expand Up @@ -88,14 +73,13 @@
#*****************************************************************************

from sage.rings.integer import Integer
from sage.rings.rational import Rational
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.arith import gcd
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.polynomial.polynomial_element import Polynomial, is_Polynomial
from sage.rings.fraction_field_element import FractionFieldElement, is_FractionFieldElement
from sage.rings.laurent_series_ring import LaurentSeriesRing
from sage.rings.power_series_ring import PowerSeriesRing
from sage.rings.fraction_field_element import FractionFieldElement

from sage.matrix.berlekamp_massey import berlekamp_massey

Expand All @@ -108,14 +92,14 @@ def __init__(self, ogf, *args, **kwargs):
INPUT:
- ``ogf`` -- the ordinary generating function, a fraction of polynomials
- ``ogf`` -- the ordinary generating function, a fraction of polynomials over the rationals
OUTPUT:
- A CFiniteSequence object
This implementation allows any Laurent polynomial fraction as OGF by interpreting
This implementation allows any polynomial fraction as OGF by interpreting
any power of x dividing the OGF numerator or denominator as a right or left shift
of the sequence offset. This also enables subclassing from ``FractionFieldElement``
with usage of its member functions, so you can add, multiply,
Expand All @@ -132,25 +116,24 @@ def __init__(self, ogf, *args, **kwargs):
Finite sequence [3, 0, 0, 1], offset = -1
sage: CFiniteSequence(1/x+4/x^3)
Finite sequence [4, 0, 1], offset = -3
sage: CFiniteSequence(R(1)) # if constant only, convert
sage: CFiniteSequence(1) # if constant only, convert
Finite sequence [1], offset = 0
It should be possible to create from a symbolic expression::
The ogf is normalized to get a denominator constant coefficient of one::
sage: var('symbol') # not tested
sage: CFiniteSequence(symbol/(1-symbol)) # not tested
C-finite sequence, generated by 1/(-x + 1)
sage:
"""

OR = ogf.base_ring()
if (OR <> QQ) and (OR <> ZZ):
raise ValueError('OGF base not rational.')

self._off = 0
self._deg = 0
if is_FractionFieldElement(ogf):
P = PolynomialRing(QQ, 'x')
if isinstance (ogf, FractionFieldElement):
num = ogf.numerator()
den = ogf.denominator()
f = gcd(num, den)
P = PolynomialRing(QQ, 'x')
num = P(num / f)
den = P(den / f)
x = P.gen()
if num.constant_coefficient() == 0:
self._off = num.valuation()
Expand All @@ -161,11 +144,13 @@ def __init__(self, ogf, *args, **kwargs):
f = den.constant_coefficient()
num = P(num / f)
den = P(den / f)
f = gcd(num, den)
num = P(num / f)
den = P(den / f)
self._deg = den.degree()
super(CFiniteSequence, self).__init__(P.fraction_field(), num, den, *args, **kwargs)

R = LaurentSeriesRing(QQ, 'x')
x = R.gen()
alen = max(self._deg, num.degree() + 1)
R.set_default_prec (alen)
if den <> 1:
Expand All @@ -176,9 +161,9 @@ def __init__(self, ogf, *args, **kwargs):
self._a.extend([0] * (alen - len(self._a)))
self._c = [-den.list()[i] for i in range(1, self._deg + 1)]
elif ogf.parent().is_integral_domain():
super(CFiniteSequence, self).__init__(ogf.parent().fraction_field(), ogf, 1, *args, **kwargs)
super(CFiniteSequence, self).__init__(ogf.parent().fraction_field(), P(ogf), 1, *args, **kwargs)
self._c = []
self._off = ogf.valuation()
self._off = P(ogf).valuation()
if ogf == 0:
self._a = [0]
else:
Expand Down Expand Up @@ -212,6 +197,14 @@ def from_recurrence(cls, coefficients, values):
C-finite sequence, generated by x/(-x^2 - x + 1)
sage: CFiniteSequence.from_recurrence([-1,2],[0,1]) # natural numbers
C-finite sequence, generated by x/(x^2 - 2*x + 1)
sage: r = CFiniteSequence.from_recurrence([-1],[1])
sage: s = CFiniteSequence.from_recurrence([-1],[1,-1])
sage: r == s
True
sage: r = CFiniteSequence(x^3/(1-x-x^2))
sage: s = CFiniteSequence.from_recurrence([1,1],[0,0,0,1,1])
sage: r == s
True
"""

if not isinstance(coefficients, list):
Expand Down Expand Up @@ -278,12 +271,26 @@ def _sub_(self, other):
def _mul_(self, other):
"""
Multiplication of C-finite sequences.
EXAMPLES::
sage: r = CFiniteSequence.guess([1,2,3,4,5])
sage: (r*r)[0:5] # self-convolution
[1, 4, 10, 20, 35]
"""
return CFiniteSequence(self.ogf() * other.numerator()/other.denominator())

def _div_(self, other):
"""
Division of C-finite sequences.
EXAMPLES::
sage: r = CFiniteSequence.guess([1,2,3,4,5])
sage: (r/2)[0:5]
[1/2, 1, 3/2, 2, 5/2]
sage: (1/r)[0:5] # not tested
[1, -2, 1, 0, 0]
"""
return CFiniteSequence(self.ogf() / (other.numerator()/other.denominator()))

Expand Down Expand Up @@ -371,7 +378,7 @@ def __getitem__(self, key) :
if isinstance(key, slice):
m = max(key.start, key.stop)
return [self[ii] for ii in xrange(*key.indices(m + 1))]
elif isinstance(key, (Integer, int)):
elif isinstance(key, (int, Integer)):
from sage.matrix.constructor import Matrix
d = self._deg
if d == 0:
Expand Down Expand Up @@ -427,6 +434,9 @@ def recurrence_repr(self):
sage: r = CFiniteSequence((-2*x^3 + x^2 - x + 1)/(2*x^2 - 3*x + 1))
sage: r.recurrence_repr()
'Homogenous linear recurrence with constant coefficients of degree 2: a(n+2) = 3*a(n) - 2*a(n+1), starting a(0...) = [1, 2, 5, 9]'
sage: r = CFiniteSequence(x^3/(1-x-x^2))
sage: r.recurrence_repr()
'Homogenous linear recurrence with constant coefficients of degree 2: a(n+2) = 1*a(n) + 1*a(n+1), starting a(3...) = [1, 1]'
"""

if self._deg == 0:
Expand Down Expand Up @@ -480,6 +490,10 @@ def guess(sequence):
sage: CFiniteSequence.guess([1,2,4,8,16,32])
C-finite sequence, generated by 1/(-2*x + 1)
sage: r = CFiniteSequence.guess([0])
Sequence too short for guessing.
sage: r = CFiniteSequence.guess([0,0])
Constant infinite sequence 0.
"""

R = PowerSeriesRing(QQ, 'x')
Expand All @@ -501,4 +515,10 @@ def guess(sequence):
... x/(1-x)
sage: latex(r) # not implemented
\big\{a_{n\ge0}\big|a_{n+2}=\sum_{i=0}^{1}c_ia_{n+i}, c=\{1,1\}, a_{n<2}=\{0,0,0,1\}\big\}
Given a multivariate generating function, the generating coefficient must
be given as extra parameter::
sage: r = CFiniteSequence(1/(1-y-x*y), x) # not tested
"""

0 comments on commit a62b72c

Please sign in to comment.