def __init__(self, ogf, *args, **kwargs): """ Create a C-finite sequence given its ordinary generating function. INPUT: - ``ogf`` -- the ordinary generating function, a fraction of polynomials over the rationals OUTPUT: - A CFiniteSequence object EXAMPLES:: sage: R.<x> = QQ[] sage: CFiniteSequence((2-x)/(1-x-x^2)) # the Lucas sequence C-finite sequence, generated by (-x + 2)/(-x^2 - x + 1) sage: CFiniteSequence(x/(1-x)^3) # triangular numbers C-finite sequence, generated by x/(-x^3 + 3*x^2 - 3*x + 1) Polynomials are interpreted as finite sequences, or recurrences of degree 0:: sage: CFiniteSequence(x^2-4*x^5) Finite sequence [1, 0, 0, -4], offset = 2 sage: CFiniteSequence(1) Finite sequence [1], offset = 0 This implementation allows any polynomial fraction as o.g.f. by interpreting any power of `x` dividing the o.g.f. numerator or denominator as a right or left shift of the sequence offset:: sage: CFiniteSequence(x^2+3/x) Finite sequence [3, 0, 0, 1], offset = -1 sage: CFiniteSequence(1/x+4/x^3) Finite sequence [4, 0, 1], offset = -3 sage: P = LaurentPolynomialRing(QQ.fraction_field(), 'X') sage: X=P.gen() sage: CFiniteSequence(1/(1-X)) C-finite sequence, generated by 1/(-x + 1) The o.g.f. is always normalized to get a denominator constant coefficient of `+1`:: sage: CFiniteSequence(1/(x-2)) C-finite sequence, generated by -1/2/(-1/2*x + 1) TESTS:: sage: P.<x> = QQ[] sage: CFiniteSequence(0.1/(1-x)) Traceback (most recent call last): ... ValueError: O.g.f. base not rational. sage: P.<x,y> = QQ[] sage: CFiniteSequence(x*y) Traceback (most recent call last): ... NotImplementedError: Multidimensional o.g.f. not implemented. """ self._br = ogf.base_ring() if (self._br <> QQ) and (self._br <> ZZ) and not is_FiniteField(self._br): raise ValueError('O.g.f. base not proper.') P = PolynomialRing(self._br, 'x') if ogf in QQ: ogf = P(ogf) if hasattr(ogf,'numerator'): try: num = P(ogf.numerator()) den = P(ogf.denominator()) except TypeError: if ogf.numerator().parent().ngens() > 1: raise NotImplementedError('Multidimensional o.g.f. not implemented.') else: raise ValueError('Numerator and denominator must be polynomials.') else: num = P(ogf) den = 1 # Transform the ogf numerator and denominator to canonical form # to get the correct offset, degree, and recurrence coeffs and # start values. self._off = 0 self._deg = 0 if isinstance (ogf, FractionFieldElement) and den == 1: ogf = num # case p(x)/1: fall through if isinstance (ogf, (FractionFieldElement, FpTElement)): x = P.gen() if num.constant_coefficient() == 0: self._off = num.valuation() num = P(num / x**self._off) elif den.constant_coefficient() == 0: self._off = -den.valuation() den = P(den * x**self._off) 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() self._c = [-den.list()[i] for i in range(1, self._deg + 1)] if self._off >= 0: num = x**self._off * num else: den = x**(-self._off) * den # determine start values (may be different from _get_item_ values) R = LaurentSeriesRing(self._br, 'x') rem = num % den alen = max(self._deg, num.degree() + 1) R.set_default_prec (alen) if den <> 1: self._a = R(num/(den+O(x**alen))).list() self._aa = R(rem/(den+O(x**alen))).list()[:self._deg] # needed for _get_item_ else: self._a = num.list() if len(self._a) < alen: self._a.extend([0] * (alen - len(self._a))) super(CFiniteSequence, self).__init__(P.fraction_field(), num, den, *args, **kwargs) elif ogf.parent().is_integral_domain(): super(CFiniteSequence, self).__init__(ogf.parent().fraction_field(), P(ogf), 1, *args, **kwargs) self._c = [] self._off = P(ogf).valuation() if ogf == 0: self._a = [0] else: self._a = ogf.parent()((ogf / (ogf.parent().gen())**self._off)).list() else: raise ValueError("Cannot convert a " + str(type(ogf)) + " to CFiniteSequence.")