Beispiel #1
0
    def __call__(self, Q, P):
        from sage.rings.all import ZZ, QQ
        from sage.misc.all import sage_eval

        s, Q, P = self.raw(Q, P)
        raw = s

        if 'the prime to 2 part of the conductor' in s:
            prime_to_2_conductor_only = True
        else:
            prime_to_2_conductor_only = False
        x = QQ['x'].gen(0)
        i = s.find('y^2 = ') + len('y^2 = ')
        j = i + s[i:].find('\n')
        minimal_equation = sage_eval(s[i:j], locals={'x': x})

        s = s[j + 1:]
        i = s.find('[')
        j = s.find(']')
        minimal_disc = ZZ(eval(s[i + 1:j].replace(',', '**').replace(';',
                                                                     '*')))

        phrase = 'the conductor is '
        j = s.find(phrase)
        assert j != -1
        k = s[j:].find('\n')
        prime_to_2_conductor = ZZ(s[j + len(phrase):j + k])

        local_data = {}
        while True:
            i = s.find('p=')
            if i == -1:
                break
            j = s[i + 2:].find('p=')
            if j == -1:
                j = s.find('\n  \n')
                assert j != -1
            else:
                j = j + (i + 2)
            k = i + s[i:].find('\n')
            p = ZZ(s[i + 2:k])
            data = s[k + 1:j].strip().replace(' : ', ': ')
            local_data[p] = data
            s = s[j:]

        return ReductionData(raw, P, Q, minimal_equation, minimal_disc,
                             local_data, prime_to_2_conductor,
                             prime_to_2_conductor_only)
Beispiel #2
0
    def __call__(self, Q, P):
        from sage.rings.all import ZZ, QQ
        from sage.misc.all import sage_eval

        s, Q, P = self.raw(Q, P)
        raw = s

        if 'the prime to 2 part of the conductor' in s:
            prime_to_2_conductor_only = True
        else:
            prime_to_2_conductor_only = False
        x = QQ['x'].gen(0)
        i = s.find('y^2 = ') + len('y^2 = ')
        j = i + s[i:].find('\n')
        minimal_equation = sage_eval(s[i:j], locals={'x':x})


        s = s[j+1:]
        i = s.find('[')
        j = s.find(']')
        minimal_disc = ZZ(eval(s[i+1:j].replace(',','**').replace(';','*')))

        phrase = 'the conductor is '
        j = s.find(phrase)
        assert j != -1
        k = s[j:].find('\n')
        prime_to_2_conductor = ZZ(s[j+len(phrase):j+k])

        local_data = {}
        while True:
            i = s.find('p=')
            if i == -1:
                break
            j = s[i+2:].find('p=')
            if j == -1:
                j = s.find('\n  \n')
                assert j != -1
            else:
                j = j + (i+2)
            k = i + s[i:].find('\n')
            p = ZZ(s[i+2:k])
            data = s[k+1:j].strip().replace(' : ',': ')
            local_data[p] = data
            s = s[j:]

        return ReductionData(raw, P, Q, minimal_equation, minimal_disc, local_data,
                             prime_to_2_conductor, prime_to_2_conductor_only)
Beispiel #3
0
    def __call__(self, Q, P):
        from sage.rings.all import ZZ, QQ
        from sage.misc.all import sage_eval

        s, Q, P = self.raw(Q, P)
        raw = s

        if "the prime to 2 part of the conductor" in s:
            prime_to_2_conductor_only = True
        else:
            prime_to_2_conductor_only = False
        x = QQ["x"].gen(0)
        i = s.find("y^2 = ") + len("y^2 = ")
        j = i + s[i:].find("\n")
        minimal_equation = sage_eval(s[i:j], locals={"x": x})

        s = s[j + 1 :]
        i = s.find("[")
        j = s.find("]")
        minimal_disc = ZZ(eval(s[i + 1 : j].replace(",", "**").replace(";", "*")))

        phrase = "the conductor is "
        j = s.find(phrase)
        assert j != -1
        k = s[j:].find("\n")
        prime_to_2_conductor = ZZ(s[j + len(phrase) : j + k])

        local_data = {}
        while True:
            i = s.find("p=")
            if i == -1:
                break
            j = s[i + 2 :].find("p=")
            if j == -1:
                j = s.find("\n  \n")
                assert j != -1
            else:
                j = j + (i + 2)
            k = i + s[i:].find("\n")
            p = ZZ(s[i + 2 : k])
            data = s[k + 1 : j].strip().replace(" : ", ": ")
            local_data[p] = data
            s = s[j:]

        return ReductionData(
            raw, P, Q, minimal_equation, minimal_disc, local_data, prime_to_2_conductor, prime_to_2_conductor_only
        )
Beispiel #4
0
def buzzard_tpslopes(p, N, kmax):
    """
    Returns a vector of length kmax, whose `k`'th entry
    (`0 \leq k \leq k_{max}`) is the conjectural sequence
    of valuations of eigenvalues of `T_p` on forms of level
    `N`, weight `k`, and trivial character.

    This conjecture is due to Kevin Buzzard, and is only made assuming
    that `p` does not divide `N` and if `p` is
    `\Gamma_0(N)`-regular.

    EXAMPLES::

        sage: c = buzzard_tpslopes(2,1,50)
        sage: c[50]
        [4, 8, 13]

    Hence Buzzard would conjecture that the `2`-adic valuations
    of the eigenvalues of `T_2` on cusp forms of level 1 and
    weight `50` are `[4,8,13]`, which indeed they are,
    as one can verify by an explicit computation using, e.g., modular
    symbols::

        sage: M = ModularSymbols(1,50, sign=1).cuspidal_submodule()
        sage: T = M.hecke_operator(2)
        sage: f = T.charpoly('x')
        sage: f.newton_slopes(2)
        [13, 8, 4]

    AUTHORS:

    - Kevin Buzzard: several PARI/GP scripts

    - William Stein (2006-03-17): small Sage wrapper of Buzzard's
      scripts
    """
    v = gp().eval('tpslopes(%s, %s, %s)' % (p, N, kmax))
    v = sage_eval(v)
    v.insert(0, [])  # so v[k] = info about weight k (since python is 0-based)
    return v
Beispiel #5
0
def buzzard_tpslopes(p, N, kmax):
    """
    Returns a vector of length kmax, whose `k`'th entry
    (`0 \leq k \leq k_{max}`) is the conjectural sequence
    of valuations of eigenvalues of `T_p` on forms of level
    `N`, weight `k`, and trivial character.

    This conjecture is due to Kevin Buzzard, and is only made assuming
    that `p` does not divide `N` and if `p` is
    `\Gamma_0(N)`-regular.

    EXAMPLES::

        sage: c = buzzard_tpslopes(2,1,50)
        sage: c[50]
        [4, 8, 13]

    Hence Buzzard would conjecture that the `2`-adic valuations
    of the eigenvalues of `T_2` on cusp forms of level 1 and
    weight `50` are `[4,8,13]`, which indeed they are,
    as one can verify by an explicit computation using, e.g., modular
    symbols::

        sage: M = ModularSymbols(1,50, sign=1).cuspidal_submodule()
        sage: T = M.hecke_operator(2)
        sage: f = T.charpoly('x')
        sage: f.newton_slopes(2)
        [13, 8, 4]

    AUTHORS:

    - Kevin Buzzard: several PARI/GP scripts

    - William Stein (2006-03-17): small Sage wrapper of Buzzard's
      scripts
    """
    v = gp().eval('tpslopes(%s, %s, %s)'%(p,N,kmax))
    v = sage_eval(v)
    v.insert(0, [])   # so v[k] = info about weight k (since python is 0-based)
    return v
Beispiel #6
0
    def guess(self, sequence, algorithm='sage'):
        """
        Return the minimal CFiniteSequence that generates the sequence.

        Assume the first value has index 0.

        INPUT:

        - ``sequence`` -- list of integers
        - ``algorithm`` -- string
            - 'sage' - the default is to use Sage's matrix kernel function
            - 'pari' - use Pari's implementation of LLL
            - 'bm' - use Sage's Berlekamp-Massey algorithm

        OUTPUT:

        - a CFiniteSequence, or 0 if none could be found

        With the default kernel method, trailing zeroes are chopped
        off before a guessing attempt. This may reduce the data
        below the accepted length of six values.

        EXAMPLES::

            sage: C.<x> = CFiniteSequences(QQ)
            sage: C.guess([1,2,4,8,16,32])
            C-finite sequence, generated by -1/2/(x - 1/2)
            sage: r = C.guess([1,2,3,4,5])
            Traceback (most recent call last):
            ...
            ValueError: Sequence too short for guessing.

        With Berlekamp-Massey, if an odd number of values is given, the last one is dropped.
        So with an odd number of values the result may not generate the last value::

            sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r
            C-finite sequence, generated by -1/2/(x - 1/2)
            sage: r[0:5]
            [1, 2, 4, 8, 16]
        """
        S = self.polynomial_ring()
        if algorithm == 'bm':
            from sage.matrix.berlekamp_massey import berlekamp_massey
            if len(sequence) < 2:
                raise ValueError('Sequence too short for guessing.')
            R = PowerSeriesRing(QQ, 'x')
            if len(sequence) % 2:
                sequence.pop()
            l = len(sequence) - 1
            denominator = S(berlekamp_massey(sequence).reverse())
            numerator = R(S(sequence) * denominator, prec=l).truncate()

            return CFiniteSequence(numerator / denominator)
        elif algorithm == 'pari':
            global _gp
            if len(sequence) < 6:
                raise ValueError('Sequence too short for guessing.')
            if _gp is None:
                _gp = Gp()
                _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\
                if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\
                q=qflll(m,4)[1];if(length(q)==0,return(0));\
                p=sum(k=1,B,x^(k-1)*q[k,1]);\
                q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\
                if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\
                for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q")
            _gp.set('gf', sequence)
            _gp("gf=ggf(gf)")
            num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1])
            den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1])
            if num == 0:
                return 0
            else:
                return CFiniteSequence(num / den)
        else:
            from sage.matrix.constructor import matrix
            from sage.functions.other import ceil
            from numpy import trim_zeros
            seq = sequence[:]
            while seq and sequence[-1] == 0:
                seq.pop()
            l = len(seq)
            if l == 0:
                return 0
            if l < 6:
                raise ValueError('Sequence too short for guessing.')

            hl = ceil(ZZ(l) / 2)
            A = matrix([sequence[k:k + hl] for k in range(hl)])
            K = A.kernel()
            if K.dimension() == 0:
                return 0
            R = PolynomialRing(QQ, 'x')
            den = R(trim_zeros(K.basis()[-1].list()[::-1]))
            if den == 1:
                return 0
            offset = next((i for i, x in enumerate(sequence) if x), None)
            S = PowerSeriesRing(QQ, 'x', default_prec=l - offset)
            num = S(R(sequence) * den).truncate(ZZ(l) // 2 + 1)
            if num == 0 or sequence != S(num / den).list():
                return 0
            else:
                return CFiniteSequence(num / den)
Beispiel #7
0
    def guess(self, sequence, algorithm="sage"):
        """
        Return the minimal CFiniteSequence that generates the sequence.

        Assume the first value has index 0.

        INPUT:

        - ``sequence`` -- list of integers
        - ``algorithm`` -- string
            - 'sage' - the default is to use Sage's matrix kernel function
            - 'pari' - use Pari's implementation of LLL
            - 'bm' - use Sage's Berlekamp-Massey algorithm

        OUTPUT:

        - a CFiniteSequence, or 0 if none could be found

        With the default kernel method, trailing zeroes are chopped
        off before a guessing attempt. This may reduce the data
        below the accepted length of six values.

        EXAMPLES::

            sage: C.<x> = CFiniteSequences(QQ)
            sage: C.guess([1,2,4,8,16,32])
            C-finite sequence, generated by 1/(-2*x + 1)
            sage: r = C.guess([1,2,3,4,5])
            Traceback (most recent call last):
            ...
            ValueError: Sequence too short for guessing.

        With Berlekamp-Massey, if an odd number of values is given, the last one is dropped.
        So with an odd number of values the result may not generate the last value::

            sage: r = C.guess([1,2,4,8,9], algorithm='bm'); r
            C-finite sequence, generated by 1/(-2*x + 1)
            sage: r[0:5]
            [1, 2, 4, 8, 16]
        """
        S = self.polynomial_ring()
        if algorithm == "bm":
            from sage.matrix.berlekamp_massey import berlekamp_massey

            if len(sequence) < 2:
                raise ValueError("Sequence too short for guessing.")
            R = PowerSeriesRing(QQ, "x")
            if len(sequence) % 2 == 1:
                sequence = sequence[:-1]
            l = len(sequence) - 1
            denominator = S(berlekamp_massey(sequence).list()[::-1])
            numerator = R(S(sequence) * denominator, prec=l).truncate()

            return CFiniteSequence(numerator / denominator)
        elif algorithm == "pari":
            global _gp
            if len(sequence) < 6:
                raise ValueError("Sequence too short for guessing.")
            if _gp is None:
                _gp = Gp()
                _gp(
                    "ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\
                if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\
                q=qflll(m,4)[1];if(length(q)==0,return(0));\
                p=sum(k=1,B,x^(k-1)*q[k,1]);\
                q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\
                if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\
                for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q"
                )
            _gp.set("gf", sequence)
            _gp("gf=ggf(gf)")
            num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1])
            den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1])
            if num == 0:
                return 0
            else:
                return CFiniteSequence(num / den)
        else:
            from sage.matrix.constructor import matrix
            from sage.functions.other import floor, ceil
            from numpy import trim_zeros

            l = len(sequence)
            while l > 0 and sequence[l - 1] == 0:
                l -= 1
            sequence = sequence[:l]
            if l == 0:
                return 0
            if l < 6:
                raise ValueError("Sequence too short for guessing.")

            hl = ceil(ZZ(l) / 2)
            A = matrix([sequence[k : k + hl] for k in range(hl)])
            K = A.kernel()
            if K.dimension() == 0:
                return 0
            R = PolynomialRing(QQ, "x")
            den = R(trim_zeros(K.basis()[-1].list()[::-1]))
            if den == 1:
                return 0
            offset = next((i for i, x in enumerate(sequence) if x != 0), None)
            S = PowerSeriesRing(QQ, "x", default_prec=l - offset)
            num = S(R(sequence) * den).add_bigoh(floor(ZZ(l) / 2 + 1)).truncate()
            if num == 0 or sequence != S(num / den).list():
                return 0
            else:
                return CFiniteSequence(num / den)
Beispiel #8
0
    def riemann_roch_basis(self, D):
        r"""
        Return a basis for the Riemann-Roch space corresponding to
        `D`.

        This uses Singular's Brill-Noether implementation.

        INPUT:

        -  ``D`` - a divisor

        OUTPUT:

        A list of function field elements that form a basis of the Riemann-Roch space

        EXAMPLE::

            sage: R.<x,y,z> = GF(2)[]
            sage: f = x^3*y + y^3*z + x*z^3
            sage: C = Curve(f); pts = C.rational_points()
            sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ])
            sage: C.riemann_roch_basis(D)
            [x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)]

        ::

            sage: R.<x,y,z> = GF(5)[]
            sage: f = x^7 + y^7 + z^7
            sage: C = Curve(f); pts = C.rational_points()
            sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ])
            sage: C.riemann_roch_basis(D)
            [(-2*x + y)/(x + y), (-x + z)/(x + y)]


        .. NOTE::
            Currently this only works over prime field and divisors supported on rational points.
        """
        f = self.defining_polynomial()._singular_()
        singular = f.parent()
        singular.lib('brnoeth')
        try:
            X1 = f.Adj_div()
        except (TypeError, RuntimeError) as s:
            raise RuntimeError(str(s) + "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above).")
        X2 = singular.NSplaces(1, X1)
        # retrieve list of all computed closed points (possibly of degree >1)
        v = X2[3].sage_flattened_str_list()    # We use sage_flattened_str_list since iterating through
                                               # the entire list through the sage/singular interface directly
                                               # would involve hundreds of calls to singular, and timing issues with
                                               # the expect interface could crop up.  Also, this is vastly
                                               # faster (and more robust).
        v = [ v[i].partition(',') for i in range(len(v)) ]
        pnts = [ ( int(v[i][0]), int(v[i][2])-1 ) for i in range(len(v))]
        # retrieve coordinates of rational points
        R = X2[5][1][1]
        singular.set_ring(R)
        v = singular('POINTS').sage_flattened_str_list()
        coords = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)//3)]
        # build correct representation of D for singular
        Dsupport = D.support()
        Dcoeffs = []
        for x in pnts:
            if x[0] == 1:
                Dcoeffs.append(D.coefficient(coords[x[1]]))
            else:
                Dcoeffs.append(0)
        Dstr = str(tuple(Dcoeffs))
        G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec')
        # call singular's brill noether routine and return
        T = X2[1][2]
        T.set_ring()
        LG = G.BrillNoether(X2)
        LG = [X.split(',\n') for X in LG.sage_structured_str_list()]
        x,y,z = self.ambient_space().coordinate_ring().gens()
        vars = {'x':x, 'y':y, 'z':z}
        V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG]
        return V
Beispiel #9
0
 def __to_CC(self, s):
     s = s.replace('.E','.0E').replace(' ','')
     return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))
    def riemann_roch_basis(self, D):
        r"""
        Return a basis for the Riemann-Roch space corresponding to
        `D`.

        This uses Singular's Brill-Noether implementation.

        INPUT:

        -  ``D`` - a divisor

        OUTPUT:

        A list of function field elements that form a basis of the Riemann-Roch space

        EXAMPLE::

            sage: R.<x,y,z> = GF(2)[]
            sage: f = x^3*y + y^3*z + x*z^3
            sage: C = Curve(f); pts = C.rational_points()
            sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ])
            sage: C.riemann_roch_basis(D)
            [x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)]

        ::

            sage: R.<x,y,z> = GF(5)[]
            sage: f = x^7 + y^7 + z^7
            sage: C = Curve(f); pts = C.rational_points()
            sage: D = C.divisor([ (3, pts[0]), (-1,pts[1]), (10, pts[5]) ])
            sage: C.riemann_roch_basis(D)
            [(-2*x + y)/(x + y), (-x + z)/(x + y)]


        .. NOTE::
            Currently this only works over prime field and divisors supported on rational points.
        """
        f = self.defining_polynomial()._singular_()
        singular = f.parent()
        singular.lib('brnoeth')
        try:
            X1 = f.Adj_div()
        except (TypeError, RuntimeError) as s:
            raise RuntimeError(
                str(s) +
                "\n\n ** Unable to use the Brill-Noether Singular package to compute all points (see above)."
            )
        X2 = singular.NSplaces(1, X1)
        # retrieve list of all computed closed points (possibly of degree >1)
        v = X2[3].sage_flattened_str_list(
        )  # We use sage_flattened_str_list since iterating through
        # the entire list through the sage/singular interface directly
        # would involve hundreds of calls to singular, and timing issues with
        # the expect interface could crop up.  Also, this is vastly
        # faster (and more robust).
        v = [v[i].partition(',') for i in range(len(v))]
        pnts = [(int(v[i][0]), int(v[i][2]) - 1) for i in range(len(v))]
        # retrieve coordinates of rational points
        R = X2[5][1][1]
        singular.set_ring(R)
        v = singular('POINTS').sage_flattened_str_list()
        coords = [
            self(int(v[3 * i]), int(v[3 * i + 1]), int(v[3 * i + 2]))
            for i in range(len(v) // 3)
        ]
        # build correct representation of D for singular
        Dsupport = D.support()
        Dcoeffs = []
        for x in pnts:
            if x[0] == 1:
                Dcoeffs.append(D.coefficient(coords[x[1]]))
            else:
                Dcoeffs.append(0)
        Dstr = str(tuple(Dcoeffs))
        G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec')
        # call singular's brill noether routine and return
        T = X2[1][2]
        T.set_ring()
        LG = G.BrillNoether(X2)
        LG = [X.split(',\n') for X in LG.sage_structured_str_list()]
        x, y, z = self.ambient_space().coordinate_ring().gens()
        vars = {'x': x, 'y': y, 'z': z}
        V = [(sage_eval(a, vars) / sage_eval(b, vars)) for a, b in LG]
        return V
Beispiel #11
0
 def __to_CC(self, s):
     s = s.replace('.E','.0E').replace(' ','')
     return self.__CC(sage_eval(s, locals={'I':self.__CC.gen(0)}))
Beispiel #12
0
        Dcoeffs = []
        for x in pnts:
            if x[0] == 1:
                Dcoeffs.append(D.coefficient(coords[x[1]]))
            else:
                Dcoeffs.append(0)
        Dstr = str(tuple(Dcoeffs))
        G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec')
        # call singular's brill noether routine and return
        T = X2[1][2]
        T.set_ring()
        LG = G.BrillNoether(X2)
        LG = [X.split(',\n') for X in LG.sage_structured_str_list()]
        x,y,z = self.ambient_space().coordinate_ring().gens()
        vars = {'x':x, 'y':y, 'z':z}
        V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG]
        return V

    def rational_points(self, algorithm="enum", sort=True):
        r"""
        INPUT:
        
        
        -  ``algorithm`` - string:
        
        -  ``'enum'`` - straightforward enumeration
        
        -  ``'bn'`` - via Singular's brnoeth package.
        
        
        EXAMPLE::
Beispiel #13
0
        Dcoeffs = []
        for x in pnts:
            if x[0] == 1:
                Dcoeffs.append(D.coefficient(coords[x[1]]))
            else:
                Dcoeffs.append(0)
        Dstr = str(tuple(Dcoeffs))
        G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec')
        # call singular's brill noether routine and return
        T = X2[1][2]
        T.set_ring()
        LG = G.BrillNoether(X2)
        LG = [X.split(',\n') for X in LG.sage_structured_str_list()]
        x, y, z = self.ambient_space().coordinate_ring().gens()
        vars = {'x': x, 'y': y, 'z': z}
        V = [(sage_eval(a, vars) / sage_eval(b, vars)) for a, b in LG]
        return V

    def rational_points(self, algorithm="enum", sort=True):
        r"""
        INPUT:
        
        
        -  ``algorithm`` - string:
        
        -  ``'enum'`` - straightforward enumeration
        
        -  ``'bn'`` - via Singular's brnoeth package.
        
        
        EXAMPLE::
Beispiel #14
0
    def guess(sequence, algorithm='pari'):
        """
        Return the minimal CFiniteSequence that generates the sequence. Assume the first
        value has index 0.

        INPUT:

        - ``sequence`` -- list of integers
        
        - ``algorithm`` -- string
            - 'pari' - use Pari's implementation of LLL (fast)
            - 'bm' - use Sage's Berlekamp-Massey algorithm
            
        OUTPUT:
        
        - a CFiniteSequence, or 0 if none could be found
        
        EXAMPLES::

            sage: CFiniteSequence.guess([1,2,4,8,16,32])
            C-finite sequence, generated by 1/(-2*x + 1)
            sage: r = CFiniteSequence.guess([1,2,3,4,5])
            Traceback (most recent call last):
            ...
            ValueError: Sequence too short for guessing.
            sage: CFiniteSequence.guess([1,0,0,0,0,0])
            Finite sequence [1], offset = 0
            
        With Pari LLL, all values are taken into account, and if no o.g.f.
        can be found, `0` is returned::
        
            sage: CFiniteSequence.guess([1,0,0,0,0,1])
            0
            
        With Berlekamp-Massey, if an odd number of values is given, the last one is dropped.
        So with an odd number of values the result may not generate the last value::
        
            sage: r = CFiniteSequence.guess([1,2,4,8,9], algorithm='bm'); r
            C-finite sequence, generated by 1/(-2*x + 1)
            sage: r[0:5]
            [1, 2, 4, 8, 16]
        """
        S = PolynomialRing(QQ, 'x')
        if algorithm == 'bm':
            if len(sequence) < 2:
                raise ValueError('Sequence too short for guessing.')
            R = PowerSeriesRing(QQ, 'x')
            if len(sequence) % 2 == 1: sequence = sequence[:-1]
            l = len(sequence) - 1
            denominator = S(berlekamp_massey(sequence).list()[::-1])
            numerator = R(S(sequence) * denominator, prec=l).truncate()

            return CFiniteSequence(numerator / denominator)
        else:
            global _gp
            if len(sequence) < 6:
                raise ValueError('Sequence too short for guessing.')
            if _gp is None:
                _gp = Gp()
                _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\
                if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\
                q=qflll(m,4)[1];if(length(q)==0,return(0));\
                p=sum(k=1,B,x^(k-1)*q[k,1]);\
                q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\
                if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\
                for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q")
            _gp.set('gf', sequence)
            _gp("gf=ggf(gf)")
            num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1])
            den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1])
            if num == 0:
                return 0
            else:
                return CFiniteSequence(num / den)
        
        """