Esempio n. 1
0
File: ideal.py Progetto: CETHop/sage
    def _naive_ideal(self, ring):
        r"""
        Return the "naive" subideal.

        INPUT:

        - ``ring`` -- the ambient ring of the ideal.

        OUTPUT:

        A subideal of the toric ideal in the polynomial ring ``ring``.

        EXAMPLES::

            sage: A = matrix([[1,1,1],[0,1,2]])
            sage: IA = ToricIdeal(A)
            sage: IA.ker()
            Free module of degree 3 and rank 1 over Integer Ring
            User basis matrix:
            [ 1 -2  1]
            sage: IA._naive_ideal(IA.ring())
            Ideal (-z1^2 + z0*z2) of Multivariate Polynomial Ring in z0, z1, z2 over Rational Field
        """
        x = ring.gens()
        binomials = []
        for row in self.ker().matrix().rows():
            xpos = prod(x[i]**max( row[i],0) for i in range(0,len(x)))
            xneg = prod(x[i]**max(-row[i],0) for i in range(0,len(x)))
            binomials.append(xpos - xneg)
        return ring.ideal(binomials)
Esempio n. 2
0
    def all_vv_verifs(self, u, v, dim):
        a,b = set(u).union(set(v))
        a1,b1 = symbolic_max_plus_matrices_band(dim, 2, 'v', 'v', typ='sym')
        d1 = {a:a1, b:b1}
        a2,b2 = symbolic_max_plus_matrices_band(dim, 2, 'v', 'v', typ='full')
        d2 = {a:a2, b:b2}

        mu1 = prod(d1[i] for i in u)
        mu2 = prod(d2[i] for i in u)
        mv1 = prod(d1[i] for i in v)
        mv2 = prod(d2[i] for i in v)

        is_identity = is_vv_identity(u,v,dim)

        self.assertEqual(is_identity,
                         mu1 == mv1,
                         'u = {} v = {} dim = {}'.format(u,v,dim))
        self.assertEqual(mu1 == mv1, mu2 == mv2,
                         'u = {} v = {} dim = {}'.format(u,v,dim))
        if is_identity:
            elts = [random_integer_max_plus_matrices_band(
                       dim, -1000, 1000, ord('v'), ord('v')) \
                    for _ in range(100)]
            zo = {a:0, b:1}
            t0 = tuple(zo[i] for i in u)
            t1 = tuple(zo[i] for i in v)
            self.assertTrue(is_relation(t0,t1, elts, True),
                            'u = {} v = {} dim = {}'.format(u,v,dim))
            self.assertTrue(is_relation(t0,t1,elts,False),
                            'u = {} v = {} dim = {}'.format(u,v,dim))
Esempio n. 3
0
 def d_vector(self):
     n = self.parent().rk
     one = self.parent().ambient_field()(1)
     factors = self.lift_to_field().factor()
     initial = []
     non_initial = []
     [(initial if x[1] > 0 and len(x[0].monomials()) == 1 else non_initial).append(x[0]**x[1]) for x in factors]
     initial = prod(initial+[one]).numerator()
     non_initial = prod(non_initial+[one]).denominator()
     v1 = vector(non_initial.exponents()[0][:n])
     v2 = vector(initial.exponents()[0][:n])
     return tuple(v1-v2)
Esempio n. 4
0
        def scalar(self, y):
            r"""
            Return the scalar product of ``self`` and ``y``.

            The scalar product is given by

            .. MATH::

                (I_{\lambda}, I_{\mu}) = \delta_{\lambda,\mu}
                \frac{1}{a_{\lambda}},

            where `a_{\lambda}` is given by

            .. MATH::

                a_{\lambda} = q^{|\lambda| + 2 n(\lambda)} \prod_k
                \prod_{i=1}^{l_k} (1 - q^{-i})

            where `n(\lambda) = \sum_i (i - 1) \lambda_i` and
            `\lambda = (1^{l_1}, 2^{l_2}, \ldots, m^{l_m})`.

            Note that `a_{\lambda}` can be interpreted as the number
            of automorphisms of a certain object in a category
            corresponding to `\lambda`. See Lemma 2.8 in [Schiffmann]_
            for details.

            EXAMPLES::

                sage: R.<q> = ZZ[]
                sage: H = HallAlgebra(R, q)
                sage: H[1].scalar(H[1])
                1/(q - 1)
                sage: H[2].scalar(H[2])
                1/(q^2 - q)
                sage: H[2,1].scalar(H[2,1])
                1/(q^5 - 2*q^4 + q^3)
                sage: H[1,1,1,1].scalar(H[1,1,1,1])
                1/(q^16 - q^15 - q^14 + 2*q^11 - q^8 - q^7 + q^6)
                sage: H.an_element().scalar(H.an_element())
                (4*q^2 + 9)/(q^2 - q)
            """
            q = self.parent()._q
            f = lambda la: ~( q**(sum(la) + 2*la.weighted_size())
                              * prod(prod((1 - q**-i) for i in range(1,k+1))
                                     for k in la.to_exp()) )
            y = self.parent()(y)
            ret = q.parent().zero()
            for mx, cx in self:
                cy = y.coefficient(mx)
                if cy != 0:
                    ret += cx * cy * f(mx)
            return ret
    def defining_polynomials(self):
        """
        Return the pair of products of cyclotomic polynomials.

        EXAMPLES::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: Hyp(alpha_beta=([1/4,3/4],[0,0])).defining_polynomials()
            (x^2 + 1, x^2 - 2*x + 1)
        """
        up = prod(cyclotomic_polynomial(d) for d in self._cyclo_up)
        down = prod(cyclotomic_polynomial(d) for d in self._cyclo_down)
        return (up, down)
Esempio n. 6
0
    def braid(self, n, K=QQ, names=None):
        r"""
        The braid arrangement.

        INPUT:

        - ``n`` -- integer

        - ``K`` -- field (default: ``QQ``)

        - ``names`` -- tuple of strings or ``None`` (default); the
          variable names for the ambient space

        OUTPUT:

        The hyperplane arrangement consisting of the `n(n-1)/2`
        hyperplanes `\{ x_i - x_j = 0 : 1 \leq i \leq j \leq n \}`.

        EXAMPLES::

            sage: hyperplane_arrangements.braid(4)
            Arrangement of 6 hyperplanes of dimension 4 and rank 3
        """
        x = polygen(QQ, 'x')
        A = self.graphical(graphs.CompleteGraph(n), K, names=names)
        charpoly = prod(x-i for i in range(n))
        A.characteristic_polynomial.set_cache(charpoly)
        return A
Esempio n. 7
0
    def e_one_star_patch(self, v, n):
        r"""
        Return the n-th iterated patch of normal vector v.

        INPUT:

        - ``v`` -- vector, the normal vector
        - ``n`` -- integer

        EXAMPLES::

            sage: from slabbe.mult_cont_frac import FullySubtractive
            sage: FullySubtractive().e_one_star_patch((1,e,pi), 4)
            Patch of 21 faces
        """
        from sage.combinat.e_one_star import E1Star, Patch, Face
        from sage.misc.misc_c import prod
        if v is None:
            v = (random(), random(), random())
        it = self.coding_iterator(v)
        keys = [next(it) for _ in range(n)]
        D = self.dual_substitutions()
        L = prod(D[key] for key in reversed(keys))
        dual_sub = E1Star(L)
        cube = Patch([Face((1,0,0),1), Face((0,1,0),2), Face((0,0,1),3)])
        return dual_sub(cube)
Esempio n. 8
0
    def quantum_determinant(self, u=None):
        """
        Return the quantum determinant of ``self``.

        The quantum determinant is defined by:

        .. MATH::

            \operatorname{qdet}(u) = \sum_{\sigma \in S_n} (-1)^{\sigma}
            \prod_{k=1}^n T_{\sigma(k),k}(u - k + 1).

        EXAMPLES::

            sage: Y = Yangian(QQ, 2, 2)
            sage: Y.quantum_determinant()
            u^4 + (-2 + t(1)[1,1] + t(1)[2,2])*u^3
             + (1 - t(1)[1,1] + t(1)[1,1]*t(1)[2,2] - t(1)[1,2]*t(1)[2,1]
                - 2*t(1)[2,2] + t(2)[1,1] + t(2)[2,2])*u^2
             + (-t(1)[1,1]*t(1)[2,2] + t(1)[1,1]*t(2)[2,2]
                + t(1)[1,2]*t(1)[2,1] - t(1)[1,2]*t(2)[2,1]
                - t(1)[2,1]*t(2)[1,2] + t(1)[2,2] + t(1)[2,2]*t(2)[1,1]
                - t(2)[1,1] - t(2)[2,2])*u
             - t(1)[1,1]*t(2)[2,2] + t(1)[1,2]*t(2)[2,1] + t(2)[1,1]*t(2)[2,2]
                - t(2)[1,2]*t(2)[2,1] + t(2)[2,2]
        """
        if u is None:
            u = PolynomialRing(self.base_ring(), 'u').gen(0)
        from sage.combinat.permutation import Permutations
        n = self._n
        return sum(p.sign() * prod(self.defining_polynomial(p[k], k+1, u - k)
                                   for k in range(n))
                   for p in Permutations(n))
def Polya(G, poids):
    """
    Implantation de la formule d'énumération de Pòlya

    INPUT:

    - ``G`` -- un groupe de permutations d'un ensemble `E`
    - ``poids`` -- la liste des poids `w(c)` des éléments `c` d'un ensemble `F`

    Cette fonction renvoie la série génératrice par poids des
    fonctions de `E` dans `F`:

    .. math:: \sum_{f\in E^F} \prod_{e\in E} w(f(e))

    EXAMPLES:

    On calcule le nombre de colliers bicolores à rotation près::

        sage: Polya(CyclicPermutationGroup(5), [1,1])
        8

    Même chose, raffinée par nombre de perles d'une couleur donnée::

        sage: q = QQ['q'].gen()
        sage: Polya(CyclicPermutationGroup(5), [1,q])
        q^5 + q^4 + 2*q^3 + 2*q^2 + q + 1

    .. TODO:: Rajouter ici les autres exemples!

    """
    return sum(prod( p(k, poids) for k in type_cyclique(sigma))
               for sigma in G) / G.cardinality()
Esempio n. 10
0
def homogenous_symmetric_function(j, x):
    r"""
    Return a complete homogeneous symmetric polynomial
    (:wikipedia:`Complete_homogeneous_symmetric_polynomial`).

    INPUT:

    - ``j`` -- the degree as a nonnegative integer

    - ``x`` -- an iterable of variables

    OUTPUT:

    A polynomial of the common parent of all entries of ``x``

    EXAMPLES::

        sage: from sage.rings.polynomial.omega import homogenous_symmetric_function
        sage: P = PolynomialRing(ZZ, 'X', 3)
        sage: homogenous_symmetric_function(0, P.gens())
        1
        sage: homogenous_symmetric_function(1, P.gens())
        X0 + X1 + X2
        sage: homogenous_symmetric_function(2, P.gens())
        X0^2 + X0*X1 + X1^2 + X0*X2 + X1*X2 + X2^2
        sage: homogenous_symmetric_function(3, P.gens())
        X0^3 + X0^2*X1 + X0*X1^2 + X1^3 + X0^2*X2 +
        X0*X1*X2 + X1^2*X2 + X0*X2^2 + X1*X2^2 + X2^3
    """
    from sage.combinat.integer_vector import IntegerVectors
    from sage.misc.misc_c import prod

    return sum(prod(xx**pp for xx, pp in zip(x, p))
               for p in IntegerVectors(j, length=len(x)))
Esempio n. 11
0
        def sum_of_partitions(self, la):
            r"""
            Return the sum over all sets partitions whose shape is ``la``,
            scaled by `\prod_i m_i!` where `m_i` is the multiplicity
            of `i` in ``la``.

            INPUT:

            - ``la`` -- an integer partition

            OUTPUT:

            - an element of ``self``

            EXAMPLES::

                sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                sage: w.sum_of_partitions([2,1,1])
                2*w{{1}, {2}, {3, 4}} + 2*w{{1}, {2, 3}, {4}} + 2*w{{1}, {2, 4}, {3}}
                 + 2*w{{1, 2}, {3}, {4}} + 2*w{{1, 3}, {2}, {4}} + 2*w{{1, 4}, {2}, {3}}
            """
            la = Partition(la)
            c = prod([factorial(_) for _ in la.to_exp()])
            P = SetPartitions()
            return self.sum_of_terms([(P(m), c) for m in SetPartitions(sum(la), la)], distinct=True)
Esempio n. 12
0
    def _homogeneous_generators_noncommutative_variables_zero_Hecke(self, r):
        r"""
        Returns the ``r^{th}`` homogeneous generator, viewed as an element inside the
        affine zero Hecke algebra. This is the sum of all cyclicly decreasing elements
        of order ``r``.

        INPUT:

        - ``r`` -- A positive integer

        OUTPUT:

        - An element of the affine zero Hecke algebra.

        EXAMPLES::

            sage: g = SymmetricFunctions(QQ).kBoundedSubspace(3,1).K_kschur()
            sage: g._homogeneous_generators_noncommutative_variables_zero_Hecke(2)
            T1*T0 + T2*T0 + T0*T3 + T3*T2 + T3*T1 + T2*T1
            sage: g._homogeneous_generators_noncommutative_variables_zero_Hecke(0)
            1
        """
        from sage.combinat.root_system.weyl_group import WeylGroup
        from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebraT
        W = WeylGroup(['A',self.k,1])
        H = IwahoriHeckeAlgebraT(W, 0, base_ring = self.base_ring())
        Hgens = H.algebra_generators()
        S = [w.reduced_word() for w in W.pieri_factors() if w.length() == r]
        return sum( (prod((Hgens[i] for i in w), 1) for w in S), 0 )
Esempio n. 13
0
File: bch.py Progetto: sagemath/sage
    def bch_to_grs(self):
        r"""
        Returns the underlying GRS code from which ``self`` was derived.

        EXAMPLES::

            sage: C = codes.BCHCode(GF(2), 15, 3)
            sage: RS = C.bch_to_grs()
            sage: RS
            [15, 13, 3] Reed-Solomon Code over GF(16)
            sage: C.generator_matrix() * RS.parity_check_matrix().transpose() == 0
            True
        """
        l = self.jump_size()
        b = self.offset()
        n = self.length()
        designed_distance = self.designed_distance()
        grs_dim = n - designed_distance + 1

        alpha = self.primitive_root()
        alpha_l = alpha ** l
        alpha_b = alpha ** b
        evals = [alpha_l ** i for i in range(n)]
        pcm = [alpha_b ** i for i in range(n)]

        multipliers_product = [1/prod([evals[i] - evals[h] for h in range(n) if h != i]) for i in range(n)]
        column_multipliers = [multipliers_product[i]/pcm[i] for i in range(n)]

        return GeneralizedReedSolomonCode(evals, grs_dim, column_multipliers)
def pure_tensor(P, vects, indices=None):
    r"""
    Return the product of a collection of linear forms corresponding to vectors

    INPUT:

    - ``P`` -- a polynomial ring
    - ``vects`` -- a list of coefficient vectors
    - ``indices`` -- (default: ``None``) a collection of indices for the list
      ``vects`` corresponding to the linear forms which will be included in the
      product.  Indices may be repeated.  If ``None``, then each vector will be
      included in the product once.

    OUTPUT:

    - the corresponding product of linear forms in the polynomial ring ``P``

    EXAMPLES:

        sage: P.<x, y> = PolynomialRing(QQ)
        sage: vects = [[1,0],[0,1],[1,1]]
        sage: pure_tensor(P, vects).factor()
        y * x * (x + y)
        sage: pure_tensor(P, vects, [0, 2, 2]).factor()
        x * (x + y)^2
    """
    if indices is None:
        indices = range(len(vects))
    terms = [linear_form(P, vects[i]) for i in indices]
    return prod(terms, P.one())
Esempio n. 15
0
    def _convert_factors_(self, factors):
        r"""
        Helper method. Try to convert some ``factors`` to an
        element of one of the Cartesian factors and return the product of
        all these factors.

        INPUT:

        - ``factors`` -- a tuple or other iterable.

        OUTPUT:

        An element of this Cartesian product.

        EXAMPLES::

            sage: from sage.rings.asymptotic.growth_group import GrowthGroup
            sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ')
            sage: e1 = G._convert_factors_([x^2])
            sage: (e1, e1.parent())
            (x^2, Growth Group x^ZZ * log(x)^QQ * y^QQ)
        """
        from sage.misc.misc_c import prod

        def get_factor(data):
            for factor in self.cartesian_factors():
                try:
                    return factor, factor(data)
                except (ValueError, TypeError):
                    pass
            raise ValueError("%s is not in any of the factors of %s" % (data, self))

        return prod(self.cartesian_injection(*get_factor(f)) for f in factors)
Esempio n. 16
0
def m_to_s_stat(R, I, K):
    r"""
    Returns the statistic for the expansion of the Monomial basis element indexed by two
    compositions, as in formula (36) of Tevlin's "Noncommutative Analogs of Monomial Symmetric
    Functions, Cauchy Identity, and Hall Scalar Product".

    INPUT:

    - ``R`` -- A ring
    - ``I``, ``K`` -- compositions

    OUTPUT:

    - An integer

    EXAMPLES::

        sage: from sage.combinat.ncsf_qsym.combinatorics import m_to_s_stat
        sage: m_to_s_stat(QQ,Composition([2,1]), Composition([1,1,1]))
        -1
        sage: m_to_s_stat(QQ,Composition([3]), Composition([1,2]))
        -2
    """
    stat = 0
    for J in Compositions(I.size()):
        if (I.is_finer(J) and  K.is_finer(J)):
            pvec = [0] + Composition(I).refinement_splitting_lengths(J).partial_sums()
            pp = prod( R( len(I) - pvec[i] ) for i in range( len(pvec)-1 ) )
            stat += R((-1)**(len(I)-len(K)) / pp * coeff_lp(K,J))
    return stat
Esempio n. 17
0
    def tree_factorial(self):
        """
        Returns the tree-factorial of ``self``

        Definition:

        The tree-factorial `T!` of a tree `T` is the product `\prod_{v\in
        T}\#\mbox{children}(v)`.

        EXAMPLES::

            sage: LT = LabelledOrderedTrees()
            sage: t = LT([LT([],label=6),LT([],label=1)],label=9)
            sage: t.tree_factorial()
            3

            sage: BinaryTree([[],[[],[]]]).tree_factorial()
            15

        TESTS::

            sage: BinaryTree().tree_factorial()
            1
        """
        nb = self.node_number()
        if nb <= 1:
            return 1
        else:
            return nb*prod(s.tree_factorial() for s in self)
Esempio n. 18
0
            def is_symmetric(self):
                r"""
                Determine if a `NCSym^*` function, expressed in the
                `\mathbf{w}` basis, is symmetric.

                A function `f` in the `\mathbf{w}` basis is a symmetric
                function if it is in the image of `\chi^*`. That is to say we
                have

                .. MATH::

                    f = \sum_{\lambda} c_{\lambda} \prod_i m_i(\lambda)!
                    \sum_{\lambda(A) = \lambda} \mathbf{w}_A

                where the second sum is over all set partitions `A` whose
                shape `\lambda(A)` is equal to `\lambda` and `m_i(\mu)` is
                the multiplicity of `i` in the partition `\mu`.

                OUTPUT:

                - ``True`` if `\lambda(A)=\lambda(B)` implies the coefficients of
                  `\mathbf{w}_A` and `\mathbf{w}_B` are equal, ``False`` otherwise

                EXAMPLES::

                    sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w()
                    sage: elt = w.sum_of_partitions([2,1,1])
                    sage: elt.is_symmetric()
                    True
                    sage: elt -= 3*w.sum_of_partitions([1,1])
                    sage: elt.is_symmetric()
                    True
                    sage: w = SymmetricFunctionsNonCommutingVariables(ZZ).dual().w()
                    sage: elt = w.sum_of_partitions([2,1,1]) / 2
                    sage: elt.is_symmetric()
                    False
                    sage: elt = w[[1,3],[2]]
                    sage: elt.is_symmetric()
                    False
                    sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + 2*w[[1,3],[2]]
                    sage: elt.is_symmetric()
                    False
                """
                d = {}
                R = self.base_ring()
                for A, coeff in self:
                    la = A.shape()
                    exp = prod([factorial(_) for _ in la.to_exp()])
                    if la not in d:
                        if coeff / exp not in R:
                            return False
                        d[la] = [coeff, 1]
                    else:
                        if d[la][0] != coeff:
                            return False
                        d[la][1] += 1
                # Make sure we've seen each set partition of the shape
                return all(d[la][1] == SetPartitions(la.size(), la).cardinality() for la in d)
Esempio n. 19
0
    def Ish(self, n, K=QQ, names=None):
        r"""
        Return the Ish arrangement.

        INPUT:

        - ``n`` -- integer

        - ``K`` -- field (default:``QQ``)

        - ``names`` -- tuple of strings or ``None`` (default); the
          variable names for the ambient space

        OUTPUT:

        The Ish arrangement, which is the set of `n(n-1)` hyperplanes.

        .. MATH::

            \{ x_i - x_j = 0 : 1 \leq i \leq j \leq n \} 
            \cup 
            \{ x_1 - x_j = i : 1 \leq i \leq j \leq n \}.

        EXAMPLES::

            sage: a = hyperplane_arrangements.Ish(3);  a
            Arrangement of 6 hyperplanes of dimension 3 and rank 2
            sage: a.characteristic_polynomial()
            x^3 - 6*x^2 + 9*x
            sage: b = hyperplane_arrangements.Shi(3)
            sage: b.characteristic_polynomial()
            x^3 - 6*x^2 + 9*x

        TESTS::

            sage: a.characteristic_polynomial.clear_cache()  # long time
            sage: a.characteristic_polynomial()              # long time
            x^3 - 6*x^2 + 9*x

        REFERENCES:

        ..  [AR] D. Armstrong, B. Rhoades
            "The Shi arrangement and the Ish arrangement"
            :arxiv:`1009.1655`
        """
        H = make_parent(K, n, names)
        x = H.gens()
        hyperplanes = []
        for i in range(n):
            for j in range(i+1, n):
                hyperplanes.append(x[i] - x[j])
                hyperplanes.append(x[0] - x[j] - (i+1))
        A = H(*hyperplanes)
        x = polygen(QQ, 'x')
        charpoly = x * sum([(-1)**k * stirling_number2(n, n-k) *
                            prod([(x - 1 - j) for j in range(k, n-1)]) for k in range(0, n)])
        A.characteristic_polynomial.set_cache(charpoly)
        return A
Esempio n. 20
0
    def __init__(self, params, asym=False):
        # set parameters
        (self.alpha, self.beta, self.rho, self.rho_f, self.eta, self.bound, self.n, self.k) = params

        self.x0 = ZZ(1)
        
        self.primes = [random_prime(2**self.eta, lbound = 2**(self.eta - 1), proof=False) for i in range(self.n)]
        primes = self.primes
        
        self.x0 = prod(primes)

        # generate CRT coefficients
        self.coeff = [ZZ((self.x0/p_i) * ZZ(Zmod(p_i)(self.x0/p_i)**(-1))) for p_i in primes]

        # generate secret g_i
        self.g = [random_prime(2**self.alpha, proof=False) for i in range(self.n)]

        # generate zs and zs^(-1)
        z = []
        zinv = []

        # generate z and z^(-1)
        if not asym:
            while True:
                z = ZZ.random_element(self.x0)  
                try:
                    zinv = ZZ(Zmod(self.x0)(z)**(-1))
                    break
                except ZeroDivisionError:
                    ''' Error occurred, retry sampling '''

            z, self.zinv = zip(*[(z,zinv) for i in range(self.k)])

        else: # asymmetric version
            for i in range(self.k):
                while True:
                    z_i = ZZ.random_element(self.x0)  
                    try:
                        zinv_i = ZZ(Zmod(self.x0)(z_i)**(-1))
                        break
                    except ZeroDivisionError:
                        ''' Error occurred, retry sampling '''

                z.append(z_i)
                zinv.append(zinv_i)

            self.zinv = zinv

        # generate p_zt
        zk = Zmod(self.x0)(1)
        self.p_zt = 0
        for z_i in z:
            zk *= Zmod(self.x0)(z_i)
        for i in range(self.n):
            self.p_zt += Zmod(self.x0)(ZZ(Zmod(self.primes[i])(self.g[i])**(-1) * Zmod(self.primes[i])(zk)) * ZZ.random_element(2**self.beta) * (self.x0/self.primes[i]))

        self.p_zt = Zmod(self.x0)(self.p_zt)
Esempio n. 21
0
def tropical_evaluation(f):
    try:
        # This is an hack to use the same code on polynomials, laurent polynomials and rational expressions
        f = f.parent().fraction_field()(f)
        num_exponents = f.numerator().exponents()
        if type(num_exponents[0]) != int:
            num_exponent = map(min, zip(*num_exponents))
        else:
            num_exponent = [min(num_exponents)]
        den_exponents = f.denominator().exponents()
        if type(den_exponents[0]) != int:
            den_exponent = map(min, zip(*den_exponents))
        else:
            den_exponent = [min(den_exponents)]
        variables = f.parent().gens()
        return prod(map(lambda x,p: x**p, variables,num_exponent))*prod(map(lambda x,p: x**(-p), variables,den_exponent))
    except: # This should only happen when f is a constant
        return 1
Esempio n. 22
0
def lee_osullivan_module(points, parameters, wy):
    r"""
    Returns the analytically straight-forward basis for the `\GF q[x]` module
    containing all interpolation polynomials, as according to Lee and
    O'Sullivan.

    The module is constructed in the following way: Let `R(x)` be the Lagrange
    interpolation polynomial through the sought interpolation points `(x_i,
    y_i)`, i.e. `R(x_i) = y_i`. Let `G(x) = \prod_{i=1}^n (x-x_i)`. Then the
    `i`'th row of the basis matrix of the module is the coefficient-vector of
    the following polynomial in `\GF q[x][y]`:

        `P_i(x,y) = G(x)^{[i-s]} (y - R(x))^{i - [i-s]} y^{[i-s]}` ,

    where `[a]` for real `a` is `a` when `a > 0` and 0 otherwise. It is easily
    seen that `P_i(x,y)` is an interpolation polynomial, i.e. it is zero with
    multiplicity at least `s` on each of the points `(x_i, y_i)`.


    INPUT:

    - ``points`` -- a list of tuples ``(xi, yi)`` such that we seek ``Q`` with
      ``(xi,yi)`` being a root of ``Q`` with multiplicity ``s``.

    - ``parameters`` -- (default: ``None``) a pair of integers, where:
        - the first integer is the multiplicity parameter `s` of Guruswami-Sudan algorithm and
        - the second integer is the list size parameter.

    - ``wy`` -- an integer, the `y`-weight, where we seek ``Q`` of low
      ``(1,wy)`` weighted degree.

    EXAMPLES::

        sage: from sage.coding.guruswami_sudan.interpolation import lee_osullivan_module
        sage: F = GF(11)
        sage: points = [(F(0), F(2)), (F(1), F(5)), (F(2), F(0)), (F(3), F(4)), (F(4), F(9))\
                , (F(5), F(1)), (F(6), F(9)), (F(7), F(10))]
        sage: params = (1, 1)
        sage: wy = 1
        sage: lee_osullivan_module(points, params, wy)
        [x^8 + 5*x^7 + 3*x^6 + 9*x^5 + 4*x^4 + 2*x^3 + 9*x   0]
        [ 10*x^7 + 4*x^6 + 9*x^4 + 7*x^3 + 2*x^2 + 9*x + 9   1]
    """
    s, l = parameters[0], parameters[1]
    F = points[0][0].parent()
    PF = F['x']
    x = PF.gens()[0]
    R = PF.lagrange_polynomial(points)
    G = prod(x - points[i][0] for i in range(0, len(points)))
    PFy = PF['y']
    y = PFy.gens()[0]
    ybasis = [(y-R)**i * G**(s-i) for i in range(0, s+1)] \
            + [y**(i-s) * (y-R)**s for i in range(s+1, l+1)]
    def pad(lst):
        return lst + [0]*(l+1-len(lst))
    modbasis = [pad(yb.coefficients(sparse=False)) for yb in ybasis]
    return matrix(PF, modbasis)
Esempio n. 23
0
 def cluster_variable(self, g_vector):
     g_vector = tuple(g_vector)
     if not g_vector in self.g_vectors_so_far():
         # Should we let the self.F_polynomial below handle raising the exception?
         raise ValueError("This Cluster Variable has not been computed yet.")
     F_std = self.F_polynomial(g_vector).subs(self._yhat)
     g_mon = prod([self.ambient().gen(i)**g_vector[i] for i in xrange(self.rk)])
     # LaurentPolynomial_mpair does not know how to compute denominators, we need to lift to its fraction field
     F_trop = self.ambient_field()(self.F_polynomial(g_vector).subs(self._y)).denominator()
     return self.retract(g_mon*F_std*F_trop)
Esempio n. 24
0
 def Y(self, j):
     r"""
     The j-th element of the Y-pattern in the universal coefficient semifield
     C.f. CA4 definition 3.10
     Uses CA4 Proposition 3.13
     """
     Y = prod(map(lambda y,c: y**c, self.parent()._U.gens(), self.c_vector(j)))
     for i in range(self.parent()._n):
         Y *= self.F_polynomial(i)**self.b_matrix()[i,j]
     return self.parent()._U.fraction_field()(Y)
Esempio n. 25
0
def logpp_binom(n, p, p_prec):
    """returns the (integral) power series p^n*(log_p(1+p*z)/log_p(1+p) choose n)"""
    #prod=1+0*z
    L = logpp_gam(p, p_prec)
    ans = prod([(L - j) for j in range(n)])
    #for j in range(0,n):
    #    prod=prod*(L-j)
    ans *= (p ** n) / factorial(n)
    
    return ps_normalize(ans.truncate(p_prec), p, p_prec)
Esempio n. 26
0
    def encode(self, m, S):
        ''' encodes a vector m (in Zmod(q)^n) to index set S '''

        zinv = prod([self.zinv[i] for i in S])

        m = vector(Zmod(self.q),m)

        zero = vector(Zmod(self.q),self.D_sigmap_I()) # random encoding of 0
        c = self.Rq(list(zero + m))

        return c * zinv
Esempio n. 27
0
                def on_basis(A):
                    k = A.size()
                    ret = R.zero()
                    if n < k:
                        return ret

                    for p in Permutations(k):
                        if P(p.to_cycles()) == A:
                            # -1 for indexing
                            ret += R.sum(prod(x[I[i]][I[p[i] - 1]] for i in range(k)) for I in Subsets(range(n), k))
                    return ret
Esempio n. 28
0
def logp_binom(n, p, p_prec):
    """returns the (integral) power series (log_p(1+z)/log_p(1+p) choose n)"""
    #prod=1+0*z
    if n == 0:
        return PolynomialRing(QQ, 'y')(1)
    L = logp_gam(p, p_prec)
    ans = prod([(L - j) for j in range(n)])
    #for j in range(0,n):
    #    prod=prod*(L-j)
    ans = ans / factorial(n)
    
    return ps_normalize(ans.truncate(p_prec+1), p, p_prec) #Do we need the +1?
Esempio n. 29
0
    def index(self):
        r"""
        Return the index of self in the full modular group. This is equal to
        the index in `SL(2, \ZZ / N\ZZ)` of the image of this group modulo
        `\Gamma(N)`.

        EXAMPLE::

            sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroupFromGroup(MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])])).index()
            2
        """
        return prod([p**(3*e-2)*(p*p-1) for (p,e) in self.level().factor()]) // self.image_mod_n().order()
Esempio n. 30
0
    def encode(self, m, S):
        ''' encodes a vector m (in ZZ^n) to index set S '''

        c = Zmod(self.x0)(0)

        for i in range(self.n):
            r_i = ZZ.random_element(2**self.rho)
            c += Zmod(self.x0)((m[i] + self.g[i] * r_i) * self.coeff[i])

        zinv = prod([self.zinv[i] for i in S])

        return Zmod(self.x0)(c * zinv)
Esempio n. 31
0
    def homogeneous_noncommutative_variables(self, la):
        r"""
        Give the homogeneous function indexed by `la`, viewed inside the Nil-Coxeter algebra.
        This is only defined in finite type `A`, `B` and affine types `A^{(1)}`, `B^{(1)}`, `C^{(1)}`, `D^{(1)}`.

        INPUT:

        - ``la`` -- a partition with first part bounded by the rank of the Weyl group

        EXAMPLES::

            sage: U = NilCoxeterAlgebra(WeylGroup(['B',2,1]))
            sage: U.homogeneous_noncommutative_variables([2,1])
            u[1,2,0] + 2*u[2,1,0] + u[0,2,0] + u[0,2,1] + u[1,2,1] + u[2,1,2] + u[2,0,2] + u[1,0,2]

        TESTS::

            sage: U = NilCoxeterAlgebra(WeylGroup(['B',2,1]))
            sage: U.homogeneous_noncommutative_variables([])
            1

        """
        return prod(
            self.homogeneous_generator_noncommutative_variables(p) for p in la)
Esempio n. 32
0
    def nu2(self):
        r"""
        Return the number of elliptic points of order 2 for this congruence
        subgroup `\Gamma_0(N)`. The number of these is given by a standard formula:
        0 if `N` is divisible by 4 or any prime congruent to -1 mod 4, and
        otherwise `2^d` where d is the number of odd primes dividing `N`.

        EXAMPLES::

            sage: Gamma0(2).nu2()
            1
            sage: Gamma0(4).nu2()
            0
            sage: Gamma0(21).nu2()
            0
            sage: Gamma0(1105).nu2()
            8
            sage: [Gamma0(n).nu2() for n in [1..19]]
            [1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0]
        """
        n = self.level()
        if n % 4 == 0:
            return ZZ(0)
        return prod([1 + kronecker_symbol(-4, p) for p, _ in n.factor()])
Esempio n. 33
0
def m_to_s_stat(R, I, K):
    r"""
    Return the coefficient of the complete non-commutative symmetric
    function `S^K` in the expansion of the monomial non-commutative
    symmetric function `M^I` with respect to the complete basis
    over the ring `R`. This is the coefficient in formula (36) of
    Tevlin's paper [Tev2007]_.

    INPUT:

    - ``R`` -- A ring, supposed to be a `\QQ`-algebra
    - ``I``, ``K`` -- compositions

    OUTPUT:

    - The coefficient of `S^K` in the expansion of `M^I` in the
      complete basis of the non-commutative symmetric functions
      over ``R``.

    EXAMPLES::

        sage: from sage.combinat.ncsf_qsym.combinatorics import m_to_s_stat
        sage: m_to_s_stat(QQ, Composition([2,1]), Composition([1,1,1]))
        -1
        sage: m_to_s_stat(QQ, Composition([3]), Composition([1,2]))
        -2
        sage: m_to_s_stat(QQ, Composition([2,1,2]), Composition([2,1,2]))
        8/3
    """
    stat = 0
    for J in Compositions(I.size()):
        if (I.is_finer(J) and  K.is_finer(J)):
            pvec = [0] + Composition(I).refinement_splitting_lengths(J).partial_sums()
            pp = prod( R( len(I) - pvec[i] ) for i in range( len(pvec)-1 ) )
            stat += R((-1)**(len(I)-len(K)) / pp * coeff_lp(K,J))
    return stat
Esempio n. 34
0
def _span_of_forms_in_weight(forms,
                             weight,
                             prec,
                             stop_dim=None,
                             use_random=False):
    r"""
    Utility function. Given a nonempty list of pairs ``(k,f)``, where `k` is an
    integer and `f` is a power series, and a weight l, return all weight l
    forms obtained by multiplying together the given forms.

    INPUT:

    - ``forms`` -- list of pairs `(k, f)` with k an integer and f a power
      series (all over the same base ring)
    - ``weight`` -- an integer
    - ``prec`` -- an integer (less than or equal to the precision of all the
      forms in ``forms``) -- precision to use in power series computations.
    - ``stop_dim`` -- an integer: stop as soon as we have enough forms to span
      a submodule of this rank (a saturated one if the base ring is `\ZZ`).
      Ignored if ``use_random`` is False.
    - ``use_random`` -- which algorithm to use. If True, tries random products
      of the generators of the appropriate weight until a large enough
      submodule is found (determined by ``stop_dim``). If False, just tries
      everything.

    Note that if the given forms do generate the whole space, then
    ``use_random=True`` will often be quicker (particularly if the weight is
    large); but if the forms don't generate, the randomized algorithm is no
    help and will actually be substantially slower, because it needs to do
    repeated echelon form calls to check if vectors are in a submodule, while
    the non-randomized algorithm just echelonizes one enormous matrix at the
    end.

    EXAMPLES::

        sage: import sage.modular.modform.ring as f
        sage: forms = [(4, 240*eisenstein_series_qexp(4,5)), (6,504*eisenstein_series_qexp(6,5))]
        sage: f._span_of_forms_in_weight(forms, 12, prec=5)
        Vector space of degree 5 and dimension 2 over Rational Field
        Basis matrix:
        [        1         0    196560  16773120 398034000]
        [        0         1       -24       252     -1472]
        sage: f._span_of_forms_in_weight(forms, 24, prec=5)
        Vector space of degree 5 and dimension 3 over Rational Field
        Basis matrix:
        [          1           0           0    52416000 39007332000]
        [          0           1           0      195660    12080128]
        [          0           0           1         -48        1080]
        sage: ModularForms(1, 24).q_echelon_basis(prec=5)
        [
        1 + 52416000*q^3 + 39007332000*q^4 + O(q^5),
        q + 195660*q^3 + 12080128*q^4 + O(q^5),
        q^2 - 48*q^3 + 1080*q^4 + O(q^5)
        ]

    Test the alternative randomized algorithm::

        sage: f._span_of_forms_in_weight(forms, 24, prec=5, use_random=True, stop_dim=3)
        Vector space of degree 5 and dimension 3 over Rational Field
        Basis matrix:
        [          1           0           0    52416000 39007332000]
        [          0           1           0      195660    12080128]
        [          0           0           1         -48        1080]
    """
    t = verbose('multiplying forms up to weight %s' % weight)
    # Algorithm: run through the monomials of the appropriate weight, and build
    # up the vector space they span.

    n = len(forms)
    R = forms[0][1].base_ring()
    V = R**prec
    W = V.zero_submodule()
    shortforms = [f[1].truncate_powerseries(prec) for f in forms]

    # List of weights
    from sage.combinat.integer_vector_weighted import WeightedIntegerVectors
    wts = list(WeightedIntegerVectors(weight, [f[0] for f in forms]))
    t = verbose("calculated weight list", t)
    N = len(wts)

    if use_random:
        if stop_dim is None:
            raise ValueError("stop_dim must be provided if use_random is True")
        shuffle(wts)

        for c in range(N):
            w = V(
                prod(shortforms[i]**wts[c][i]
                     for i in range(n)).padded_list(prec))
            if w in W:
                continue
            W = V.span(list(W.gens()) + [w])
            if stop_dim and W.rank() == stop_dim:
                if R != ZZ or W.index_in_saturation() == 1:
                    verbose("Succeeded after %s of %s" % (c, N), t)
                    return W
        verbose("Nothing worked", t)
        return W
    else:
        G = [
            V(prod(forms[i][1]**c[i] for i in range(n)).padded_list(prec))
            for c in wts
        ]
        t = verbose('found %s candidates' % N, t)
        W = V.span(G)
        verbose('span has dimension %s' % W.rank(), t)
        return W
Esempio n. 35
0
def attack(m, q, r=4, sigma=3.0, subfield_only=False):
    K = CyclotomicField(m, 'z')
    z = K.gen()
    OK = K.ring_of_integers()
    G = K.galois_group()

    n = euler_phi(m)
    mprime = m / r
    nprime = euler_phi(mprime)
    Gprime = [tau for tau in G if tau(z**r) == z**r]

    R = PolynomialRing(IntegerRing(), 'a')
    a = R.gen()
    phim = a**n + 1
    D = DiscreteGaussianDistributionIntegerSampler(sigma)

    print "sampling f,g"
    while True:
        f = sum([D() * z**i for i in range(n)])
        fx = sum([f[i] * a**i for i in range(n)])

        res = inverse(fx, phim, q)
        if res[0]:
            f_inv = sum([res[1][i] * z**i for i in range(n)])
            print "f_inv * f = %s (mod %d)" % ((f * f_inv).mod(q), q)
            break

    g = sum([D() * z**i for i in range(n)])
    print "done sampling f, g"

    #h = [g*f^{-1)]_q
    h = (g * f_inv).mod(q)

    lognorm_f = log(f.vector().norm(), 2)
    lognorm_g = log(g.vector().norm(), 2)

    print "f*h - g = %s" % (f * h - g).mod(q)
    print "log q = ", log(q, 2).n(precision)
    print "log |f| = %s, log |g| = %s" % (lognorm_f.n(precision),
                                          lognorm_g.n(precision))
    print "log |(f,g)| = ", log(
        sqrt(f.vector().norm()**2 + g.vector().norm()**2), 2).n(precision)

    print "begin computing N(f), N(g), N(h), Tr(h), fbar"
    fprime = norm(f, Gprime)
    gprime = norm(g, Gprime)
    hprime = norm(h, Gprime).mod(q)
    htr = trace(h, Gprime)
    fbar = prod([tau(f) for tau in Gprime[1:]])
    print "end computing N(f), N(g), N(h), Tr(h), fbar"

    lognorm_fp = log(fprime.vector().norm(), 2)
    lognorm_gp = log(gprime.vector().norm(), 2)

    print "%d * log |f| - log |f'| = %s" % (r, r * lognorm_f.n(precision) -
                                            lognorm_fp.n(precision))
    print "log |(f', g')| = ", log(
        sqrt(fprime.vector().norm()**2 + gprime.vector().norm()**2),
        2).n(precision)
    print "log |N(f), Tr(g fbar)| = ", log(
        sqrt(fprime.vector().norm()**2 +
             trace(g * fbar, Gprime).vector().norm()**2), 2).n(precision)

    #(fprime, gprime) lies in the lattice \Lambda_hprime^q
    print "f'*h' - g' = %s " % (hprime * fprime - gprime).mod(q)
    print "N(f) Tr(h) - Tr(g fbar) = %s" % (htr * fprime -
                                            trace(g * fbar, Gprime)).mod(q)

    if not subfield_only:
        ntru_full = NTRU(h, K, q)
        full_sv = ntru_full.shortest_vector()

        print "log |v| = %s" % log(full_sv.norm(), 2).n(precision)

    ntru_subfield = NTRU_subfield(hprime, q, nprime, r)
    ntru_trace_subfield = NTRU_subfield(htr, q, nprime, r)

    print "begin computing Shortest Vector of subfield lattice"
    norm_sv = ntru_subfield.shortest_vector()
    tr_sv = ntru_trace_subfield.shortest_vector()
    print "end computing Shortest Vector of subfield lattice"

    norm_xp = sum(
        [coerce(Integer, norm_sv[i]) * z**(r * i) for i in range(nprime)])
    tr_xp = sum(
        [coerce(Integer, tr_sv[i]) * z**(r * i) for i in range(nprime)])

    print "Norm map: log |(x',y')| = ", log(norm_sv.norm(), 2).n(precision)
    print "Trace map: log |(x', y')| = ", log(tr_sv.norm(), 2).n(precision)
    #test if xprime belongs to <fprime>
    mat = []
    for i in range(nprime):
        coordinate = (fprime * z**(r * i)).vector().list()
        mat.append([coordinate[r * j] for j in range(nprime)])
    FL = IntegerLattice(mat)
    print norm_sv[:nprime] in FL
    print tr_sv[:nprime] in FL

    norm_x = norm_xp
    norm_y = mod_q(norm_x * h, q)

    tr_x = tr_xp
    tr_y = mod_q(tr_x * h, q)

    print "Norm map: log |(x,y)| = ", log(
        sqrt(norm_x.vector().norm()**2 + norm_y.vector().norm()**2),
        2).n(precision)
    print "Trace map: log |(x,y)| = ", log(
        sqrt(tr_x.vector().norm()**2 + tr_y.vector().norm()**2),
        2).n(precision)
Esempio n. 36
0
    def sample(self, S):
        # draw an element of Rq from a Gaussian distribution of Z^n (with param sigmaprime)
        # then encode at index set S

        return self.D_sigmap_ZZ() * prod([self.zinv[i] for i in S])
Esempio n. 37
0
    def affine_algebraic_patch(self, cone=None, names=None):
        r"""
        Return the affine patch corresponding to ``cone`` as an affine
        algebraic scheme.

        INPUT:

        - ``cone`` -- a :class:`Cone
          <sage.geometry.cone.ConvexRationalPolyhedralCone>` `\sigma`
          of the fan. It can be omitted for an affine toric variety,
          in which case the single generating cone is used.

        OUTPUT:

        An :class:`affine algebraic subscheme
        <sage.schemes.affine.affine_subscheme.AlgebraicScheme_subscheme_affine>`
        corresponding to the patch `\mathop{Spec}(\sigma^\vee \cap M)`
        associated to the cone `\sigma`.

        See also :meth:`affine_patch`, which expresses the patches as
        subvarieties of affine toric varieties instead.

        REFERENCES:

        ..

            David A. Cox, "The Homogeneous Coordinate Ring of a Toric
            Variety", Lemma 2.2.
            :arxiv:`alg-geom/9210008v2`

        EXAMPLES::

            sage: P2.<x,y,z> = toric_varieties.P2()
            sage: cone = P2.fan().generating_cone(0)
            sage: V = P2.subscheme(x^3+y^3+z^3)
            sage: V.affine_algebraic_patch(cone)
            Closed subscheme of Affine Space of dimension 2 over Rational Field defined by:
              z0^3 + z1^3 + 1

            sage: cone = Cone([(0,1),(2,1)])
            sage: A2Z2.<x,y> = AffineToricVariety(cone)
            sage: A2Z2.affine_algebraic_patch()
            Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
              -z0*z1 + z2^2
            sage: V = A2Z2.subscheme(x^2+y^2-1)
            sage: patch = V.affine_algebraic_patch();  patch
            Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
              -z0*z1 + z2^2,
              z0 + z1 - 1
            sage: nbhd_patch = V.neighborhood([1,0]).affine_algebraic_patch();  nbhd_patch
            Closed subscheme of Affine Space of dimension 3 over Rational Field defined by:
              -z0*z1 + z2^2,
              z0 + z1 - 1
            sage: nbhd_patch.embedding_center()
            (0, 1, 0)

        Here we got two defining equations. The first one describes
        the singularity of the ambient space and the second is the
        pull-back of `x^2+y^2-1` ::

            sage: lp = LatticePolytope([(1,0,0),(1,1,0),(1,1,1),(1,0,1),(-2,-1,-1)],
            ....:                      lattice=ToricLattice(3))
            sage: X.<x,y,u,v,t> = CPRFanoToricVariety(Delta_polar=lp)
            sage: Y = X.subscheme(x*v+y*u+t)
            sage: cone = Cone([(1,0,0),(1,1,0),(1,1,1),(1,0,1)])
            sage: Y.affine_algebraic_patch(cone)
            Closed subscheme of Affine Space of dimension 4 over Rational Field defined by:
              z0*z2 - z1*z3,
              z1 + z3 + 1
        """
        from sage.modules.free_module_element import vector
        from sage.misc.misc_c import prod
        ambient = self.ambient_space()
        fan = ambient.fan()
        if cone is None:
            assert ambient.is_affine()
            cone = fan.generating_cone(0)
        else:
            cone = fan.embed(cone)
        # R/I = C[sigma^dual cap M]
        R, I, dualcone = ambient._semigroup_ring(cone, names)

        # inhomogenize the Cox homogeneous polynomial with respect to the given cone
        inhomogenize = dict((ambient.coordinate_ring().gen(i), 1)
                            for i in range(0, fan.nrays())
                            if i not in cone.ambient_ray_indices())
        polynomials = [
            p.subs(inhomogenize) for p in self.defining_polynomials()
        ]

        # map the monomial x^{D_m} to m, see reference.
        n_rho_matrix = cone.rays().matrix()

        def pullback_polynomial(p):
            result = R.zero()
            for coefficient, monomial in p:
                exponent = monomial.exponents()[0]
                exponent = [exponent[i] for i in cone.ambient_ray_indices()]
                exponent = vector(ZZ, exponent)
                m = n_rho_matrix.solve_right(exponent)
                assert all(x in ZZ for x in m), \
                    'The polynomial '+str(p)+' does not define a ZZ-divisor!'
                m_coeffs = dualcone.Hilbert_coefficients(m)
                result += coefficient * prod(
                    R.gen(i)**m_coeffs[i] for i in range(0, R.ngens()))
            return result

        # construct the affine algebraic scheme to use as patch
        polynomials = [pullback_polynomial(_) for _ in polynomials]
        from sage.schemes.affine.affine_space import AffineSpace
        patch_cover = AffineSpace(R)
        polynomials = list(I.gens()) + polynomials
        polynomials = [x for x in polynomials if not x.is_zero()]
        patch = patch_cover.subscheme(polynomials)

        # TODO: If the cone is not smooth, then the coordinate_ring()
        # of the affine toric variety is wrong; it should be the
        # G-invariant part. So we can't construct the embedding
        # morphism in that case.
        if cone.is_smooth():
            x = ambient.coordinate_ring().gens()
            phi = []
            for i in range(0, fan.nrays()):
                if i in cone.ambient_ray_indices():
                    phi.append(pullback_polynomial(x[i]))
                else:
                    phi.append(1)
            patch._embedding_morphism = patch.hom(phi, self)
        else:
            patch._embedding_morphism = (
                NotImplementedError,
                'I only know how to construct embedding morphisms for smooth patches'
            )

        try:
            point = self.embedding_center()
        except AttributeError:
            return patch

        # it remains to find the preimage of point
        # map m to the monomial x^{D_m}, see reference.
        F = ambient.coordinate_ring().fraction_field()
        image = []
        for m in dualcone.Hilbert_basis():
            x_Dm = prod([F.gen(i)**(m * n) for i, n in enumerate(fan.rays())])
            image.append(x_Dm)
        patch._embedding_center = tuple(f(list(point)) for f in image)
        return patch
Esempio n. 38
0
    def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None):
        r"""
        Creation of hypergeometric motives.

        INPUT:

        three possibilities are offered, each describing a quotient
        of products of cyclotomic polynomials.

        - ``cyclotomic`` -- a pair of lists of nonnegative integers,
          each integer `k` represents a cyclotomic polynomial `\Phi_k`

        - ``alpha_beta`` -- a pair of lists of rationals,
          each rational represents a root of unity

        - ``gamma_list`` -- a pair of lists of nonnegative integers,
          each integer `n` represents a polynomial `x^n - 1`

        In the last case, it is also allowed to send just one list of signed
        integers where signs indicate to which part the integer belongs to.

        EXAMPLES::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: Hyp(cyclotomic=([2],[1]))
            Hypergeometric data for [1/2] and [0]

            sage: Hyp(alpha_beta=([1/2],[0]))
            Hypergeometric data for [1/2] and [0]
            sage: Hyp(alpha_beta=([1/5,2/5,3/5,4/5],[0,0,0,0]))
            Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0]

            sage: Hyp(gamma_list=([5],[1,1,1,1,1]))
            Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0]
            sage: Hyp(gamma_list=([5,-1,-1,-1,-1,-1]))
            Hypergeometric data for [1/5, 2/5, 3/5, 4/5] and [0, 0, 0, 0]
        """
        if gamma_list is not None:
            if isinstance(gamma_list[0], (list, tuple)):
                pos, neg = gamma_list
                gamma_list = pos + [-u for u in neg]
            cyclotomic = gamma_list_to_cyclotomic(gamma_list)
        if cyclotomic is not None:
            cyclo_up, cyclo_down = cyclotomic
            if any(x in cyclo_up for x in cyclo_down):
                raise ValueError('overlapping parameters not allowed')
            deg = sum(euler_phi(x) for x in cyclo_down)
            up_deg = sum(euler_phi(x) for x in cyclo_up)
            if up_deg != deg:
                msg = 'not the same degree: {} != {}'.format(up_deg, deg)
                raise ValueError(msg)
            cyclo_up.sort()
            cyclo_down.sort()
            alpha = cyclotomic_to_alpha(cyclo_up)
            beta = cyclotomic_to_alpha(cyclo_down)
        elif alpha_beta is not None:
            alpha, beta = alpha_beta
            if len(alpha) != len(beta):
                raise ValueError('alpha and beta not of the same length')
            alpha = sorted(u - floor(u) for u in alpha)
            beta = sorted(u - floor(u) for u in beta)
            cyclo_up = alpha_to_cyclotomic(alpha)
            cyclo_down = alpha_to_cyclotomic(beta)
            deg = sum(euler_phi(x) for x in cyclo_down)

        self._cyclo_up = tuple(cyclo_up)
        self._cyclo_down = tuple(cyclo_down)
        self._alpha = tuple(alpha)
        self._beta = tuple(beta)
        self._deg = deg
        self._gamma_array = cyclotomic_to_gamma(cyclo_up, cyclo_down)
        self._trace_coeffs = {}
        up = QQ.prod(capital_M(d) for d in cyclo_up)
        down = QQ.prod(capital_M(d) for d in cyclo_down)
        self._M_value = up / down
        if 0 in alpha:
            self._swap = HypergeometricData(alpha_beta=(beta, alpha))
        if self.weight() % 2:
            self._sign_param = 1
        else:
            if (deg % 2) != (0 in alpha):
                self._sign_param = prod(cyclotomic_polynomial(v).disc()
                                        for v in cyclo_down)
            else:
                self._sign_param = prod(cyclotomic_polynomial(v).disc()
                                        for v in cyclo_up)
Esempio n. 39
0
    def _sage_(self):
        """
        EXAMPLES::

            sage: m = lie('[[1,0,3,3],[12,4,-4,7],[-1,9,8,0],[3,-5,-2,9]]') # optional - lie
            sage: m.sage()  # optional - lie
            [ 1  0  3  3]
            [12  4 -4  7]
            [-1  9  8  0]
            [ 3 -5 -2  9]

        """
        t = self.type()
        if t == 'grp':
            raise ValueError(
                "cannot convert Lie groups to native Sage objects")
        elif t == 'mat':
            import sage.matrix.constructor
            data = sage_eval(str(self).replace('\n', '').strip())
            return sage.matrix.constructor.matrix(data)
        elif t == 'pol':
            from sage.rings.all import PolynomialRing, QQ

            # Figure out the number of variables
            s = str(self)
            open_bracket = s.find('[')
            close_bracket = s.find(']')
            nvars = len(s[open_bracket:close_bracket].split(','))

            # create the polynomial ring
            R = PolynomialRing(QQ, nvars, 'x')
            x = R.gens()
            pol = R.zero()

            # Split up the polynomials into terms
            terms = []
            for termgrp in s.split(' - '):
                # The first entry in termgrp has
                # a negative coefficient
                termgrp = "-" + termgrp.strip()
                terms += termgrp.split('+')
            # Make sure we don't accidentally add a negative
            # sign to the first monomial
            if s[0] != "-":
                terms[0] = terms[0][1:]

            # go through all the terms in s
            for term in terms:
                xpos = term.find('X')
                coef = eval(term[:xpos].strip())
                exps = eval(term[xpos + 1:].strip())
                monomial = prod([x[i]**exps[i] for i in range(nvars)])
                pol += coef * monomial

            return pol
        elif t == 'tex':
            return repr(self)
        elif t == 'vid':
            return None
        else:
            return ExpectElement._sage_(self)
Esempio n. 40
0
    def points(self, **kwds):
        r"""
        Return some or all rational points of a projective scheme.

        Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound
        are returned. For a zero-dimensional subscheme, all points are returned regardless of whether the base
        ring is a field or not.

        For number fields, this uses the
        Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for
        computing algebraic numbers up to a given height [DK2013]_ or
        uses the chinese remainder theorem and points modulo primes
        for larger bounds.

        The algorithm requires floating point arithmetic, so the user is
        allowed to specify the precision for such calculations.
        Additionally, due to floating point issues, points
        slightly larger than the bound may be returned. This can be controlled
        by lowering the tolerance.


        INPUT:

        - ``bound`` - a real number

        - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4

        - ``precision`` - the precision to use for computing the elements of bounded height of number fields.

        - ``algorithm`` - either 'sieve' or 'enumerate' algorithms can be used over `QQ`. If
          not specified, enumerate is used only for small height bounds.

        OUTPUT:

        - a list of rational points of a projective scheme

        EXAMPLES::

            sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], QQ)
            sage: X = P.subscheme([x - y, z^2 - 2*w^2])
            sage: X(P.base_ring()).points()
            []

        ::

            sage: u = QQ['u'].0
            sage: P.<x,y,z,w> = ProductProjectiveSpaces([1,1], NumberField(u^2 - 2, 'v'))
            sage: X = P.subscheme([x^2 - y^2, z^2 - 2*w^2])
            sage: sorted(X(P.base_ring()).points())
            [(-1 : 1 , -v : 1), (-1 : 1 , v : 1), (1 : 1 , -v : 1), (1 : 1 , v : 1)]

        ::

            sage: u = QQ['u'].0
            sage: K = NumberField(u^2 + 1, 'v')
            sage: P.<x,y,z,w> = ProductProjectiveSpaces([1, 1], K)
            sage: P(K).points(bound=1)
            [(-1 : 1 , -1 : 1), (-1 : 1 , -v : 1), (-1 : 1 , 0 : 1), (-1 : 1 , v : 1),
            (-1 : 1 , 1 : 0), (-1 : 1 , 1 : 1), (-v : 1 , -1 : 1), (-v : 1 , -v : 1),
            (-v : 1 , 0 : 1), (-v : 1 , v : 1), (-v : 1 , 1 : 0), (-v : 1 , 1 : 1),
            (0 : 1 , -1 : 1), (0 : 1 , -v : 1), (0 : 1 , 0 : 1), (0 : 1 , v : 1),
            (0 : 1 , 1 : 0), (0 : 1 , 1 : 1), (v : 1 , -1 : 1), (v : 1 , -v : 1),
            (v : 1 , 0 : 1), (v : 1 , v : 1), (v : 1 , 1 : 0), (v : 1 , 1 : 1),
            (1 : 0 , -1 : 1), (1 : 0 , -v : 1), (1 : 0 , 0 : 1), (1 : 0 , v : 1),
            (1 : 0 , 1 : 0), (1 : 0 , 1 : 1), (1 : 1 , -1 : 1), (1 : 1 , -v : 1),
            (1 : 1 , 0 : 1), (1 : 1 , v : 1), (1 : 1 , 1 : 0), (1 : 1 , 1 : 1)]

        ::

            sage: P.<x,y,z,u,v> = ProductProjectiveSpaces([2, 1], GF(3))
            sage: P(P.base_ring()).points()
            [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 0), (0 : 0 : 1 , 1 : 1), (0 : 0 : 1 , 2 : 1),
            (0 : 1 : 0 , 0 : 1), (0 : 1 : 0 , 1 : 0), (0 : 1 : 0 , 1 : 1), (0 : 1 : 0 , 2 : 1),
            (0 : 1 : 1 , 0 : 1), (0 : 1 : 1 , 1 : 0), (0 : 1 : 1 , 1 : 1), (0 : 1 : 1 , 2 : 1),
            (0 : 2 : 1 , 0 : 1), (0 : 2 : 1 , 1 : 0), (0 : 2 : 1 , 1 : 1), (0 : 2 : 1 , 2 : 1),
            (1 : 0 : 0 , 0 : 1), (1 : 0 : 0 , 1 : 0), (1 : 0 : 0 , 1 : 1), (1 : 0 : 0 , 2 : 1),
            (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 0), (1 : 0 : 1 , 1 : 1), (1 : 0 : 1 , 2 : 1),
            (1 : 1 : 0 , 0 : 1), (1 : 1 : 0 , 1 : 0), (1 : 1 : 0 , 1 : 1), (1 : 1 : 0 , 2 : 1),
            (1 : 1 : 1 , 0 : 1), (1 : 1 : 1 , 1 : 0), (1 : 1 : 1 , 1 : 1), (1 : 1 : 1 , 2 : 1), 
            (1 : 2 : 1 , 0 : 1), (1 : 2 : 1 , 1 : 0), (1 : 2 : 1 , 1 : 1), (1 : 2 : 1 , 2 : 1),
            (2 : 0 : 1 , 0 : 1), (2 : 0 : 1 , 1 : 0), (2 : 0 : 1 , 1 : 1), (2 : 0 : 1 , 2 : 1),
            (2 : 1 : 0 , 0 : 1), (2 : 1 : 0 , 1 : 0), (2 : 1 : 0 , 1 : 1), (2 : 1 : 0 , 2 : 1),
            (2 : 1 : 1 , 0 : 1), (2 : 1 : 1 , 1 : 0), (2 : 1 : 1 , 1 : 1), (2 : 1 : 1 , 2 : 1),
            (2 : 2 : 1 , 0 : 1), (2 : 2 : 1 , 1 : 0), (2 : 2 : 1 , 1 : 1), (2 : 2 : 1 , 2 : 1)]

        ::

            sage: PP.<x,y,z,u,v> = ProductProjectiveSpaces([2,1], QQ)
            sage: X = PP.subscheme([x + y, u*u-v*u])
            sage: X.rational_points(bound=2)
            [(-2 : 2 : 1 , 0 : 1),
             (-2 : 2 : 1 , 1 : 1),
             (-1 : 1 : 0 , 0 : 1),
             (-1 : 1 : 0 , 1 : 1),
             (-1 : 1 : 1 , 0 : 1),
             (-1 : 1 : 1 , 1 : 1),
             (-1/2 : 1/2 : 1 , 0 : 1),
             (-1/2 : 1/2 : 1 , 1 : 1),
             (0 : 0 : 1 , 0 : 1),
             (0 : 0 : 1 , 1 : 1),
             (1/2 : -1/2 : 1 , 0 : 1),
             (1/2 : -1/2 : 1 , 1 : 1),
             (1 : -1 : 1 , 0 : 1),
             (1 : -1 : 1 , 1 : 1),
             (2 : -2 : 1 , 0 : 1),
             (2 : -2 : 1 , 1 : 1)]

        better to enumerate with low codimension::

            sage: PP.<x,y,z,u,v,a,b,c> = ProductProjectiveSpaces([2,1,2], QQ)
            sage: X = PP.subscheme([x*u^2*a, b*z*u*v,z*v^2*c ])
            sage: len(X.rational_points(bound=1, algorithm='enumerate'))
            232
         """
        B = kwds.pop('bound', 0)
        X = self.codomain()

        from sage.schemes.product_projective.space import is_ProductProjectiveSpaces
        if not is_ProductProjectiveSpaces(X) and X.base_ring() in Fields():
            # no points
            if X.dimension() == -1:
                return []
            # if X is zero-dimensional
            if X.dimension() == 0:
                points = set()
                # find points from all possible affine patches
                for I in xmrange([n + 1 for n in X.ambient_space().dimension_relative_components()]):
                    [Y,phi] = X.affine_patch(I, True)
                    aff_points = Y.rational_points()
                    for PP in aff_points:
                        points.add(phi(PP))
                return list(points)
        R = self.value_ring()
        points = []
        if is_RationalField(R):
            if not B > 0:
                raise TypeError("a positive bound B (= %s) must be specified"%B)
            alg = kwds.pop('algorithm', None)
            if alg is None:
                # sieve should only be called for subschemes and if the bound is not very small
                N = prod([k+1 for k in X.ambient_space().dimension_relative_components()])
                if isinstance(X, AlgebraicScheme_subscheme) and B**N > 5000:
                    from sage.schemes.product_projective.rational_point import sieve
                    return sieve(X, B)
                else:
                    from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field
                    return enum_product_projective_rational_field(self, B)
            elif alg == 'sieve':
                from sage.schemes.product_projective.rational_point import sieve
                return sieve(X, B)
            elif alg == 'enumerate':
                from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field
                return enum_product_projective_rational_field(self, B)
            else:
                raise ValueError("algorithm must be 'sieve' or 'enumerate'")
        elif R in NumberFields():
            if not B > 0:
                raise TypeError("a positive bound B (= %s) must be specified"%B)
            from sage.schemes.product_projective.rational_point import enum_product_projective_number_field
            return enum_product_projective_number_field(self, bound=B)
        elif is_FiniteField(R):
            from sage.schemes.product_projective.rational_point import enum_product_projective_finite_field
            return enum_product_projective_finite_field(self)
        else:
            raise TypeError("unable to enumerate points over %s" % R)
Esempio n. 41
0
 def to_ideal(exps):
     if len(exps)==0:
         return ring.zero_ideal()
     gens = [prod([v ** e for v, e in zip(ring.gens(), expo) if e != 0]) for expo in exps]
     return ring.ideal(gens or ring(1))
Esempio n. 42
0
def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001):
    r"""
    Return the covariant and Julia invariant from Cremona-Stoll [CS2003]_.

    In [CS2003]_ and [HS2018]_ the Julia invariant is denoted as `\Theta(F)`
    or `R(F, z(F))`. Note that you may get faster convergence if you first move
    `z_0(F)` to the fundamental domain before computing the true covariant

    INPUT:

    - ``F`` -- binary form of degree at least 3 with no multiple roots

    - ``z0_cov`` -- boolean, compute only the `z_0` invariant. Otherwise, solve
      the minimization problem

    - ``prec``-- positive integer. precision to use in CC

    - ``emb`` -- embedding into CC

    - ``error_limit`` -- sets the error tolerance (default:0.000001)


    OUTPUT: a complex number, a real number

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import covariant_z0
        sage: R.<x,y> = QQ[]
        sage: F = 19*x^8 - 262*x^7*y + 1507*x^6*y^2 - 4784*x^5*y^3 + 9202*x^4*y^4\
        ....: - 10962*x^3*y^5 + 7844*x^2*y^6 - 3040*x*y^7 + 475*y^8
        sage: covariant_z0(F, prec=80, z0_cov=True)
        (1.3832330115323681438175 + 0.31233552177413614978744*I,
         3358.4074848663492819259)
        sage: F = -x^8 + 6*x^7*y - 7*x^6*y^2 - 12*x^5*y^3 + 27*x^4*y^4\
        ....: - 4*x^3*y^5 - 19*x^2*y^6 + 10*x*y^7 - 5*y^8
        sage: covariant_z0(F, prec=80)
        (0.64189877107807122203366 + 1.1852516565091601348355*I,
         3134.5148284344627168276)

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(x^3 + 2*x^2*y - 3*x*y^2, z0_cov=True)[0]
        0.230769230769231 + 0.799408065031789*I
        sage: -1/covariant_z0(-y^3 + 2*y^2*x + 3*y*x^2, z0_cov=True)[0]
        0.230769230769231 + 0.799408065031789*I

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(2*x^2*y - 3*x*y^2, z0_cov=True)[0]
        0.750000000000000 + 1.29903810567666*I
        sage: -1/covariant_z0(-x^3 - x^2*y + 2*x*y^2, z0_cov=True)[0] + 1
        0.750000000000000 + 1.29903810567666*I

    ::

        sage: R.<x,y> = QQ[]
        sage: covariant_z0(x^2*y - x*y^2, prec=100) # tol 1e-28
         (0.50000000000000000000000000003 + 0.86602540378443864676372317076*I,
         1.5396007178390020386910634147)

    TESTS::

        sage: R.<x,y>=QQ[] 
        sage: covariant_z0(x^2 + 24*x*y + y^2)
        Traceback (most recent call last):
        ...
        ValueError: must be at least degree 3
        sage: covariant_z0((x+y)^3, z0_cov=True)
        Traceback (most recent call last):
        ...
        ValueError: cannot have multiple roots for z0 invariant
        sage: covariant_z0(x^3 + 3*x*y + y)
        Traceback (most recent call last):
        ...
        TypeError: must be a binary form
        sage: covariant_z0(-2*x^2*y^3 + 3*x*y^4 + 127*y^5)
        Traceback (most recent call last):
        ...
        ValueError: cannot have a root with multiplicity >= 5/2
        sage: covariant_z0((x^2+2*y^2)^2)
        Traceback (most recent call last):
        ...
        ValueError: must have at least 3 distinct roots
    """
    R = F.parent()
    d = ZZ(F.degree())
    if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()):
        raise TypeError('must be a binary form')
    if d < 3:
        raise ValueError('must be at least degree 3')

    f = F.subs({R.gen(1): 1}).univariate_polynomial()
    if f.degree() < d:
        # we have a root at infinity
        if f.constant_coefficient() != 0:
            # invert so we find all roots!
            mat = matrix(ZZ, 2, 2, [0, -1, 1, 0])
        else:
            t = 0
            while f(t) == 0:
                t += 1
            mat = matrix(ZZ, 2, 2, [t, -1, 1, 0])
    else:
        mat = matrix(ZZ, 2, 2, [1, 0, 0, 1])
    f = F(list(mat * vector(R.gens()))).subs({
        R.gen(1): 1
    }).univariate_polynomial()
    # now we have a single variable polynomial with all the roots of F
    K = ComplexField(prec=prec)
    if f.base_ring() != K:
        if emb is None:
            f = f.change_ring(K)
        else:
            f = f.change_ring(emb)
    roots = f.roots()
    if max(ex for _, ex in roots) > 1 or f.degree() < d - 1:
        if z0_cov:
            raise ValueError('cannot have multiple roots for z0 invariant')
        else:
            # just need a starting point for Newton's method
            f = f.lc() * prod([p for p, ex in f.factor()
                               ])  # removes multiple roots
            if f.degree() < 3:
                raise ValueError('must have at least 3 distinct roots')
            roots = f.roots()
    roots = [p for p, _ in roots]

    # finding quadratic Q_0, gives us our covariant, z_0
    dF = f.derivative()
    n = ZZ(f.degree())
    PR = PolynomialRing(K, 'x,y')
    x, y = PR.gens()
    # finds Stoll and Cremona's Q_0
    q  = sum([(1/(dF(r).abs()**(2/(n-2)))) * ((x-(r*y)) * (x-(r.conjugate()*y)))\
              for r in roots])
    # this is Q_0 , always positive def as long as F has distinct roots
    A = q.monomial_coefficient(x**2)
    B = q.monomial_coefficient(x * y)
    C = q.monomial_coefficient(y**2)
    # need positive root
    try:
        z = ((-B + ((B**2) - (4 * A * C)).sqrt()) / (2 * A))
    except ValueError:
        raise ValueError("not enough precision")
    if z.imag() < 0:
        z = (-B - ((B**2) - (4 * A * C)).sqrt()) / (2 * A)

    if z0_cov:
        FM = f  # for Julia's invariant
    else:
        # solve the minimization problem for 'true' covariant
        CF = ComplexIntervalField(
            prec=prec)  # keeps trac of our precision error
        z = CF(z)
        FM = F(list(mat * vector(R.gens()))).subs({
            R.gen(1): 1
        }).univariate_polynomial()
        from sage.rings.polynomial.complex_roots import complex_roots
        L1 = complex_roots(FM, min_prec=prec)
        L = []
        err = z.diameter()
        # making sure multiplicity isn't too large using convergence conditions in paper
        for p, e in L1:
            if e >= d / 2:
                raise ValueError(
                    'cannot have a root with multiplicity >= %s/2' % d)
            for _ in range(e):
                L.append(p)
        RCF = PolynomialRing(CF, 'u,t')
        a = RCF(0)
        c = RCF(0)
        u, t = RCF.gens()
        for l in L:
            a += u**2 / ((t - l) * (t - l.conjugate()) + u**2)
            c += (t - l.real()) / ((t - l) * (t - l.conjugate()) + u**2)
        # Newton's Method, to find solutions. Error bound is less than diameter of our z
        err = z.diameter()
        zz = z.diameter()
        g1 = a.numerator() - d / 2 * a.denominator()
        g2 = c.numerator()
        G = vector([g1, g2])
        J = jacobian(G, [u, t])
        v0 = vector([z.imag(), z.real()])  # z0 as starting point
        # finds our correct z
        while err <= zz:
            NJ = J.subs({u: v0[0], t: v0[1]})
            NJinv = NJ.inverse()
            # inverse for CIF matrix seems to return fractions not CIF elements, fix them
            if NJinv.base_ring() != CF:
                NJinv = matrix(CF, 2, 2, [
                    CF(zw.numerator() / zw.denominator())
                    for zw in NJinv.list()
                ])
            w = z
            v0 = v0 - NJinv * G.subs({u: v0[0], t: v0[1]})
            z = v0[1].constant_coefficient(
            ) + v0[0].constant_coefficient() * CF.gen(0)
            err = z.diameter()  # precision
            zz = (w - z).abs()  # difference in w and z
        else:
            if err > error_limit or err.is_NaN():
                raise ValueError(
                    "accuracy of Newton's root not within tolerance(%s > %s), increase precision"
                    % (err, error_limit))
        if z.imag() <= z.diameter():
            raise ArithmeticError(
                "Newton's method converged to z not in the upper half plane")
        z = z.center()

    # Julia's invariant
    if FM.base_ring() != ComplexField(prec=prec):
        FM = FM.change_ring(ComplexField(prec=prec))
    tF = z.real()
    uF = z.imag()
    th = FM.lc().abs()**2
    for r, ex in FM.roots():
        for _ in range(ex):
            th = th * ((((r - tF).abs())**2 + uF**2) / uF)

    # undo shift and invert (if needed)
    # since F \cdot m ~ m^(-1)\cdot z
    # we apply m to z to undo m acting on F
    l = mat * vector([z, 1])
    return l[0] / l[1], th
Esempio n. 43
0
 def matprod(elts):
     return prod(reversed(elts), id_mat)
Esempio n. 44
0
def diffop(word):
    dlog = [Rat(log(a).diff().canonicalize_radical()) for a in word]
    factors = [(Dx - sum(dlog[:i])) for i in range(len(dlog))]
    dop = prod(reversed([(Dx - sum(dlog[:i])) for i in range(len(dlog) + 1)]))
    dop = dop.numerator()
    return dop
Esempio n. 45
0
        def to_matrix(self, side="right", on_space="primal"):
            r"""
            Return ``self`` as a matrix acting on the underlying vector
            space.

            - ``side`` -- optional (default: ``"right"``) whether the
              action of ``self`` is on the ``"left"`` or on the ``"right"``

            - ``on_space`` -- optional (default: ``"primal"``) whether
              to act as the reflection representation on the given
              basis, or to act on the dual reflection representation
              on the dual basis

            EXAMPLES::

                sage: W = ReflectionGroup(['A',2])           # optional - gap3
                sage: for w in W:                            # optional - gap3
                ....:     w.reduced_word()                   # optional - gap3
                ....:     [w.to_matrix(), w.to_matrix(on_space="dual")] # optional - gap3
                []
                [
                [1 0]  [1 0]
                [0 1], [0 1]
                ]
                [2]
                [
                [ 1  1]  [ 1  0]
                [ 0 -1], [ 1 -1]
                ]
                [1]
                [
                [-1  0]  [-1  1]
                [ 1  1], [ 0  1]
                ]
                [1, 2]
                [
                [-1 -1]  [ 0 -1]
                [ 1  0], [ 1 -1]
                ]
                [2, 1]
                [
                [ 0  1]  [-1  1]
                [-1 -1], [-1  0]
                ]
                [1, 2, 1]
                [
                [ 0 -1]  [ 0 -1]
                [-1  0], [-1  0]
                ]

            TESTS::

                sage: W = ReflectionGroup(['F',4])           # optional - gap3
                sage: all(w.to_matrix(side="left") == W.from_reduced_word(reversed(w.reduced_word())).to_matrix(side="right").transpose() for w in W) # optional - gap3
                True
                sage: all(w.to_matrix(side="right") == W.from_reduced_word(reversed(w.reduced_word())).to_matrix(side="left").transpose() for w in W) # optional - gap3
                True
            """
            W = self.parent()
            if W._reflection_representation is None:
                if side == "left":
                    w = ~self
                elif side == "right":
                    w = self
                else:
                    raise ValueError('side must be "left" or "right"')

                Delta = W.independent_roots()
                Phi = W.roots()
                M = Matrix([Phi[w(Phi.index(alpha)+1)-1] for alpha in Delta])
                mat = W.base_change_matrix() * M
            else:
                refl_repr = W._reflection_representation
                id_mat = identity_matrix(QQ, refl_repr[W.index_set()[0]].nrows())
                mat = prod([refl_repr[i] for i in self.reduced_word()], id_mat)

            if on_space == "primal":
                if side == "left":
                    mat = mat.transpose()
            elif on_space == "dual":
                if side == "left":
                    mat = mat.inverse()
                else:
                    mat = mat.inverse().transpose()
            else:
                raise ValueError('on_space must be "primal" or "dual"')

            mat.set_immutable()
            return mat
Esempio n. 46
0
    def _Q_poly(self, a, m):
        r"""
        Return the element `Q^{(a)}_m` as a polynomial.

        We start with the relation

        .. MATH::

            (Q^{(a)}_{m-1})^2 = Q^{(a)}_m Q^{(a)}_{m-2} + \mathcal{Q}_{a,m-1},

        which implies

        .. MATH::

            Q^{(a)}_m = \frac{Q^{(a)}_{m-1}^2 - \mathcal{Q}_{a,m-1}}{
            Q^{(a)}_{m-2}}.

        This becomes our relation used for reducing the Q-system to the
        fundamental representations.

        For twisted Q-systems, we use

        .. MATH::

            (Q^{(a)}_{m-1})^2 = Q^{(a)}_m Q^{(a)}_{m-2}
             + \prod_{b \neq a} (Q^{(b)}_{m-1})^{-A_{ba}}.

        .. NOTE::

            This helper method is defined in order to use the
            division implemented in polynomial rings.

        EXAMPLES::

            sage: Q = QSystem(QQ, ['A',8])
            sage: Q._Q_poly(1, 2)
            q1^2 - q2
            sage: Q._Q_poly(3, 2)
            q3^2 - q2*q4
            sage: Q._Q_poly(6, 3)
            q6^3 - 2*q5*q6*q7 + q4*q7^2 + q5^2*q8 - q4*q6*q8

        Twisted types::

            sage: Q = QSystem(QQ, ['E',6,2], twisted=True)
            sage: Q._Q_poly(1,2)
            q1^2 - q2
            sage: Q._Q_poly(2,2)
            q2^2 - q1*q3
            sage: Q._Q_poly(3,2)
            -q2^2*q4 + q3^2
            sage: Q._Q_poly(4,2)
            q4^2 - q3
            sage: Q._Q_poly(3,3)
            2*q1*q2^2*q4^2 - q1^2*q3*q4^2 + q2^4 - 2*q1*q2^2*q3
             + q1^2*q3^2 - 2*q2^2*q3*q4 + q3^3

            sage: Q = QSystem(QQ, ['D',4,3], twisted=True)
            sage: Q._Q_poly(1,2)
            q1^2 - q2
            sage: Q._Q_poly(2,2)
            -q1^3 + q2^2
            sage: Q._Q_poly(1,3)
            q1^3 + q1^2 - 2*q1*q2
            sage: Q._Q_poly(2,3)
            3*q1^4 - 2*q1^3*q2 - 3*q1^2*q2 + q2^3 + q2^2
        """
        if m == 0 or m == self._level:
            return self._poly.one()
        if m == 1:
            return self._poly.gen(self._Irev[a])

        cm = self._cm
        m -= 1  # So we don't have to do it everywhere

        cur = self._Q_poly(a, m)**2
        if self._twisted:
            ret = prod(
                self._Q_poly(b, m)**-cm[self._Irev[b], self._Irev[a]]
                for b in self._cm.dynkin_diagram().neighbors(a))
        else:
            ret = self._poly.one()
            i = self._Irev[a]
            for b in self._cm.dynkin_diagram().neighbors(a):
                j = self._Irev[b]
                for k in range(-cm[i, j]):
                    ret *= self._Q_poly(b, (m * cm[j, i] - k) // cm[i, j])
        cur -= ret
        if m > 1:
            cur //= self._Q_poly(a, m - 1)
        return cur
Esempio n. 47
0
def norm(t, G):
    return prod([tau(t) for tau in G])
Esempio n. 48
0
    def amortized_padic_H_values(self,
                                 t,
                                 testp=None,
                                 verbose=False,
                                 use_c=False):
        """
        INPUT:

        - `t` -- a rational number

        OUTPUT:

        - a dictionary with inputs `p` and outputs the corresponding p-adic H value at `t`.

        TESTS::

            sage: for cyca, cycb, t in [
            ...:    ([6], [1, 1], 331),
            ...:    ([4, 2, 2], [3, 1, 1],  3678),
            ...:    ([22], [1, 1, 20], 1337/507734),
            ...:    ([5],[1,1,1,1], 2313),
            ...:    ([12],[2,2,1,1], 313)
            ...:]:
            ...:    H = AmortizingHypergeometricData(1000, cyclotomic=(cyca, cycb))
            ...:    for p, v in H.amortized_padic_H_values(t).items():
            ...:        if v != H.naive_padic_H_value(t=t, p=p, verbose=False):
            ...:            print(p, cyca, cycb, t)
        """
        ## TODO: skip over intermediate ranges with positive p-shift
        #pshift = self.pshift
        #for last_zero, s in reversed(list(enumerate(pshift))):
        #    if s == 0:
        #        break
        #breaks = self.breaks[:last_zero+2] # also include the endpoint of the last interval
        #pshift = pshift[:last_zero+1]
        #starts = breaks[:-1]
        #ends = breaks[1:]
        # TODO: fix global sign from (-p)^eta
        #        forests = {}
        tmp = identity_matrix(2)
        vectors = {p: tmp for p in self._prime_range(t)[1][0]}

        #        def update(p, A):
        #            # If the interval was empty we get A=1
        #            if not (isinstance(A, Integer) and A == 1):
        #                vectors[p][0] *= A
        #                vectors[p][1] *= A[0,0]
        #                vectors[p] %= p
        def multiplier(x):
            return -x if x else -1

        def functional_eqn(a, g, c, d):
            return (multiplier(a - g - c / d) if a >= g else
                    1) * (multiplier(a - g - c / d + 1) if a <= g else 1)


#        feq_seed = prod(a if a else -1 for a in self._alpha) / prod(b if b else -1 for b in self._beta)
#        for p in self._prime_range(t)[1][0]:
#            R = vectors[p].base_ring()
#            update(p, self.fix_break(t, ZZ(0), p, R, feq_seed))
#            if p == testp:
#                P_start = R(t)**1 * H.pochhammer_quotient(p, 1)
#                assert vectors[p][1] == P_start, "brk = 0, %s != %s" % (vectors[p][1], P_start)

        for start, end in zip(self.starts, self.ends):
            d = start.denominator()
            for pclass in range(d):
                if d.gcd(pclass) != 1:
                    continue
                c = (d * start * (pclass - 1)) % d
                feq_seed = t * prod(
                    functional_eqn(a, start, c, d)
                    for a in self._alpha) / prod(
                        functional_eqn(b, start, c, d) for b in self._beta)
                feq_seed_num = feq_seed.numer()
                feq_seed_den = feq_seed.denom()
                if pclass == 1:
                    pmult = self.break_mults_p1[start]
                else:
                    pmult = self.break_mults[start]
                fixbreak = matrix(
                    ZZ, 2, 2,
                    [feq_seed_den, 0, feq_seed_den * pmult, feq_seed_num])
                # this updates vectors
                self.amortized_padic_H_values_interval(
                    vectors,
                    t,
                    start,
                    end,
                    pclass,
                    fixbreak,
                    testp=testp,
                    use_c=use_c,
                )
        return {p: (vectors[p][1, 0] / vectors[p][0, 0]) % p for p in vectors}
Esempio n. 49
0
def _tutte_polynomial_internal(G, x, y, edge_selector, cache=None):
    """
    Does the recursive computation of the Tutte polynomial.

    INPUT:

    - ``G`` -- the graph
    - ``x,y`` -- the variables `x,y` respectively
    - ``edge_selector`` -- the heuristic for selecting edges used in the
      deletion contraction recurrence

    TESTS::

        sage: P = graphs.CycleGraph(5)
        sage: P.tutte_polynomial() # indirect doctest
        x^4 + x^3 + x^2 + x + y
    """
    if G.num_edges() == 0:
        return x.parent().one()

    def recursive_tp(graph=None):
        """
        The recursive call -- used so that we do not have to specify
        the same arguments everywhere.
        """
        if graph is None:
            graph = G
        return _tutte_polynomial_internal(graph,
                                          x,
                                          y,
                                          edge_selector,
                                          cache=cache)

    #Remove loops
    with removed_loops(G) as loops:
        if loops:
            return y**len(loops) * recursive_tp()

    uG = underlying_graph(G)
    em = edge_multiplicities(G)
    d = list(em.values())

    def yy(start, end):
        return sum(y**i for i in range(start, end + 1))

    #Lemma 1
    if G.is_forest():
        return prod(x + yy(1, d_i - 1) for d_i in d)

    #Theorem 1: from Haggard, Pearce, Royle 2008
    blocks, cut_vertices = G.blocks_and_cut_vertices()
    if len(blocks) > 1:
        return prod([recursive_tp(G.subgraph(block)) for block in blocks])

    components = G.connected_components_number()
    edge = edge_selector(G)
    unlabeled_edge = edge[:2]

    with removed_edge(G, edge):
        if G.connected_components_number() > components:
            with contracted_edge(G, unlabeled_edge):
                return x * recursive_tp()

    ##################################
    # We are in the biconnected case #
    ##################################

    # Theorem 4: from Haggard, Pearce, and Royle Note that the formula
    # at http://homepages.ecs.vuw.ac.nz/~djp/files/TOMS10.pdf is
    # slightly incorrect.  The initial sum should only go to n-2
    # instead of n (allowing for the last part of the recursion).
    # Additionally, the first operand of the final product should be
    # (x+y^{1...(d_n+d_{n-1}-1)}) instead of just (x+y^(d_n+d_{n-1}-1)
    if uG.num_verts() == uG.num_edges():  # G is a multi-cycle
        n = len(d)
        result = 0
        for i in range(n - 2):
            term = (prod((x + yy(1, d_j - 1)) for d_j in d[i + 1:]) * prod(
                (yy(0, d_k - 1)) for d_k in d[:i]))
            result += term
        #The last part of the recursion
        result += (x + yy(1, d[-1] + d[-2] - 1)) * prod(
            yy(0, d_i - 1) for d_i in d[:-2])
        return result

    # Theorem 3 from Haggard, Pearce, and Royle, adapted to multi-ears
    ear = Ear.find_ear(uG)
    if ear is not None:
        if (ear.is_cycle and ear.vertices == G.vertices()):
            #The graph is an ear (cycle) We should never be in this
            #case since we check for multi-cycles above
            return y + sum(x**i for i in range(1, ear.s))
        else:
            with ear.removed_from(G):
                #result = sum(x^i for i in range(ear.s)) #single ear case
                result = sum(
                    (prod(x + yy(1, em[e] - 1)
                          for e in ear.unlabeled_edges[i + 1:]) *
                     prod(yy(0, em[e] - 1) for e in ear.unlabeled_edges[:i]))
                    for i in range(len(ear.unlabeled_edges)))
                result *= recursive_tp()

                with contracted_edge(G,
                                     [ear.end_points[0], ear.end_points[-1]]):
                    result += prod(
                        yy(0, em[e] - 1)
                        for e in ear.unlabeled_edges) * recursive_tp()

            return result

    #Theorem 2
    if len(em) == 1:  # the graph is just a multiedge
        return x + sum(y**i for i in range(1, em[unlabeled_edge]))
    else:
        with removed_multiedge(G, unlabeled_edge):
            result = recursive_tp()
            with contracted_edge(G, unlabeled_edge):
                result += sum(
                    y**i for i in range(em[unlabeled_edge])) * recursive_tp()
        return result
Esempio n. 50
0
    def amortized_padic_H_values_interval(self,
                                          ans,
                                          t,
                                          start,
                                          end,
                                          pclass,
                                          fixbreak,
                                          testp=None,
                                          use_c=False):
        r"""
        Return a dictionary
            p -> M[p]

        (0, P_m0)*A[p] = A[p][0,0] (S, P_m1)
        where
        P_m = t^m \prod_i (alpha_i)_m ^* / (beta_i)_m ^* mod p,
        m0 = floor(start(p-1)) + 1,
        m1 = floor(end(p-1)),
        S = \sum_{m = m0} ^{m1 - 1} P_m


        EXAMPLES::

            sage: for cyca, cycb, start, end, p, t in [
            ....:     ([6], [1, 1], 0, 1/6, 97, 1),
            ....:     ([4, 2, 2], [3, 1, 1], 1/3, 1/2, 97, 1),
            ....:     ([22], [1, 1, 20], 3/20, 5/22, 1087, 1),
            ....:     ([22], [1, 1, 20], 3/20, 5/22, 1087, 1337/507734),
            ....:     ([22], [1, 1, 20], 3/20, 5/22, 1019, 1337/507734)]:
            ....:     H = AmortizingHypergeometricData(p+40, cyclotomic=(cyca, cycb))
            ....:     pclass = p % start.denominator()
            ....:     shift, offset = H._starts_to_rationals[start][pclass]
            ....:     amortized = H.amortized_padic_H_values_interval(t=t, start=start, end=end, pclass=pclass)
            ....:     t = GF(p)(t)
            ....:     naive_sum = 0
            ....:     for k in range(floor(start*(p-1))+1, floor(end * (p-1))):
            ....:         naive_sum += t**k * H.pochhammer_quotient(p, k)
            ....:     naive_res = vector(GF(p), (naive_sum, t**floor(end * (p-1)) * H.pochhammer_quotient(p, floor(end * (p-1) ))))
            ....:     M = matrix(GF(p), amortized[p])
            ....:     res = (vector(GF(p), [0,t**(floor(start*(p-1))+1) * H.pochhammer_quotient(p, floor(start*(p-1))+1 )])*M/M[0,0])
            ....:     if naive_res != res:
            ....:         print(cyca, cycb, start, end, p, t, naive_res, res)

        """
        d = start.denominator()
        shift, offset = self._starts_to_rationals[start][pclass]

        def mbound(p):
            # FIXME
            # in practice we are getting
            # prod up mbound - 1
            # there is something wrong with the Tree
            # once we fix that, we should fix the bound here
            return max((end * (p - 1)).floor() - (start * (p - 1)).floor(), 1)

        f, g, mats = self._matrices(t=t,
                                    start=start,
                                    shift=shift,
                                    offset=offset)

        if use_c:
            k = f.parent().gen()
            y = self.interval_mults[start]
            M = matrix([[g, 0], [y * g, f]])
            indices = self._prime_range(t)[d][pclass]
            remainder_forest(
                M,
                lambda p: p,  #lambda p: mbound_c(p,start,end),
                mbound_dict_c(indices, start, end),
                kbase=1,
                indices=indices,
                V=fixbreak,
                ans=ans)
        else:
            forest = AccRemForest(
                self.N,
                cut_functions={None: mbound},
                bottom_generator=mats,
                prec=1,
                primes=self._prime_range(t)[d][pclass],
            )
            bottom = forest.tree_bottom()
            # Now we have a formula for
            # (0, P_m0)*A[p] =  A[p][0,0] (\sum_{m = m0} ^{m1 - 1} P_m, P_m1)
            # with
            # m0 = floor(start * (p-1)) + 1
            # m1 = floor(end * (p-1))
            if testp in bottom:
                print(
                    "amortized_padic_H_values_interval(t=%s, start=%s, end=%s, pclass=%s)"
                    % (t, start, end, pclass))
                p = testp
                R = GF(p)
                if bottom[testp] != 1:
                    M = bottom[testp].change_ring(R)
                    # FIXME why the -1?  Probably because partial_factorial doesn't include right endpoint
                    assert M == prod(
                        elt.change_ring(GF(R)) for elt in mats(
                            floor(end * (p - 1)) - floor(start * (p - 1)) - 1))

                    t = R(t)
                    naive_sum = 0
                    pmult = self.interval_mults[start]
                    for k in range(
                            floor(start * (p - 1)) + 1, floor(end * (p - 1))):
                        naive_sum += t**k * self.pochhammer_quotient(p, k)
                    naive_sum *= pmult
                    naive_res = vector(
                        R, (naive_sum, t**floor(end * (p - 1)) *
                            self.pochhammer_quotient(p, floor(end * (p - 1)))))

                    res = vector(R, [
                        0, t**(floor(start * (p - 1)) + 1) *
                        self.pochhammer_quotient(p,
                                                 floor(start * (p - 1)) + 1)
                    ]) * M / M[0, 0]
                    assert naive_res == res, "%s != %s, M = %s" % (naive_res,
                                                                   res, M)
            # set ans
            for k, M in bottom.items():
                ans[k] = ans[k] * fixbreak * M
Esempio n. 51
0
    def divisor_of_order(self):
        """
        Return a divisor of the order of this torsion subgroup of a modular
        abelian variety.

        OUTPUT:

        A divisor of this torsion subgroup.

        EXAMPLES::

            sage: t = J0(37)[1].rational_torsion_subgroup()
            sage: t.divisor_of_order()
            3

            sage: J = J1(19)
            sage: J.rational_torsion_subgroup().divisor_of_order()
            4383

            sage: J = J0(45)
            sage: J.rational_cusp_subgroup().order()
            32
            sage: J.rational_cuspidal_subgroup().order()
            64
            sage: J.rational_torsion_subgroup().divisor_of_order()
            64
        """
        try:
            return self._divisor_of_order
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()

        if A.dimension() == 0:
            self._divisor_of_order = ZZ(1)
            return self._divisor_of_order

        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._divisor_of_order = QQ((A.level()-1)/12).numerator()
            return self._divisor_of_order

        # The elliptic curve case
        if A.dimension() == 1:
            self._divisor_of_order = A.elliptic_curve().torsion_order()
            return self._divisor_of_order

        # The J1(p) case
        if A.is_J1() and N.is_prime():
            epsilons = [epsilon for epsilon in DirichletGroup(N)
                        if not epsilon.is_trivial() and epsilon.is_even()]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._divisor_of_order = ZZ(N/(2**(N-3))*prod(bernoullis))
            return self._divisor_of_order

        # The Gamma0 case
        if all(is_Gamma0(G) for G in A.groups()):
            self._divisor_of_order = A.rational_cuspidal_subgroup().order()
            return self._divisor_of_order

        # Unhandled case
        self._divisor_of_order = ZZ(1)
        return self._divisor_of_order
Esempio n. 52
0
    def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None):
        r"""
        Store conjugacy representatives up to block length
        ``max_block_length`` (a non-negative integer, default: 0)
        in the internal dictionary. Previously calculated data is reused.
        This is a helper function for e.g. :meth:`class_number`.

        The set of all (hyperbolic) conjugacy types of block length
        ``t`` is stored in ``self._conj_block[t]``.
        The set of all primitive representatives (so far) with
        discriminant ``D`` is stored in ``self._conj_prim[D]``.
        The set of all non-primitive representatives (so far) with
        discriminant ``D`` is stored in ``self._conj_nonprim[D]``.

        The case of non-positive discriminants is done manually.

        INPUT:

        - ``max_block_length`` -- A non-negative integer (default: ``0``),
                                  the maximal block length.

        - ``D``                -- An element/discriminant of the base ring or
                                  more generally an upper bound for the
                                  involved discriminants. If ``D != None``
                                  then an upper bound for ``max_block_length``
                                  is deduced from ``D`` (default: ``None``).

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(n=5)
            sage: G.element_repr_method("conj")
            sage: G._conjugacy_representatives(2)

            sage: list(G._conj_block[2])
            [((4, 1), (3, 1)), ((2, 2),), ((3, 2),), ((3, 1), (1, 1)), ((4, 1), (1, 1)), ((4, 1), (2, 1)), ((3, 1), (2, 1)), ((2, 1), (1, 1))]

            sage: [key for key in sorted(G._conj_prim)]
            [-4, lam - 3, 0, 4*lam, 7*lam + 6, 9*lam + 5, 15*lam + 6, 33*lam + 21]
            sage: for key in sorted(G._conj_prim):
            ....:     print(G._conj_prim[key])
            [[S], [S]]
            [[U], [U]]
            [[V(4)]]
            [[V(3)], [V(2)]]
            [[V(1)*V(4)]]
            [[V(3)*V(4)], [V(1)*V(2)]]
            [[V(1)*V(3)], [V(2)*V(4)]]
            [[V(2)*V(3)]]
            sage: [key for key in sorted(G._conj_nonprim)]
            [-lam - 2, lam - 3, 32*lam + 16]

            sage: for key in sorted(G._conj_nonprim):
            ....:     print(G._conj_nonprim[key])
            [[U^(-2)], [U^2], [U^(-2)], [U^2]]
            [[U^(-1)], [U^(-1)]]
            [[V(2)^2], [V(3)^2]]

            sage: G.element_repr_method("default")
        """

        from sage.combinat.partition import OrderedPartitions
        from sage.combinat.combinat import tuples
        from sage.arith.all import divisors

        if not D is None:
            max_block_length = max(coerce_AA(0),
                                   coerce_AA((D + 4) /
                                             (self.lam()**2))).sqrt().floor()
        else:
            try:
                max_block_length = ZZ(max_block_length)
                if max_block_length < 0:
                    raise TypeError
            except TypeError:
                raise ValueError(
                    "max_block_length must be a non-negative integer!")

        if not hasattr(self, "_max_block_length"):
            self._max_block_length = ZZ(0)
            self._conj_block = {}
            self._conj_nonprim = {}
            self._conj_prim = {}

            # It is not clear how to define the class number for D=0:
            # Conjugacy classes are V(n-1)^(+-k) for arbitrary k
            # and the trivial class (what about self_conj_block[0]?).
            #
            # One way is to define it using the fixed points and in
            # that case V(n-1) would be a good representative.
            # The non-primitive case is unclear however...
            #
            # We set it here to ensure that 0 is enlisted as a discriminant...
            #
            self._conj_prim[ZZ(0)] = []
            self._conj_prim[ZZ(0)].append(self.V(self.n() - 1))

            self._elliptic_conj_reps()

        if max_block_length <= self._max_block_length:
            return

        def is_cycle(seq):
            length = len(seq)
            for n in divisors(length):
                if n < length and is_cycle_of_length(seq, n):
                    return True
            return False

        def is_cycle_of_length(seq, n):
            for i in range(n, len(seq)):
                if seq[i] != seq[i % n]:
                    return False
            return True

        j_list = range(1, self.n())

        for t in range(self._max_block_length + 1, max_block_length + 1):
            t_ZZ = ZZ(t)
            if t_ZZ not in self._conj_block:
                self._conj_block[t_ZZ] = set()

            partitions = OrderedPartitions(t).list()
            for par in partitions:
                len_par = len(par)
                exp_list = tuples(j_list, len_par)
                for ex in exp_list:
                    keep = True
                    if len_par > 1:
                        for k in range(-1, len_par - 1):
                            if ex[k] == ex[k + 1]:
                                keep = False
                                break
                    # We don't want powers of V(1)
                    elif ex[0] == 1:
                        keep = False
                    # But: Do we maybe want powers of V(n-1)??
                    # For now we exclude the parabolic cases...
                    elif ex[0] == self.n() - 1:
                        keep = False

                    if keep:
                        conj_type = cyclic_representative(
                            tuple((ZZ(ex[k]), ZZ(par[k]))
                                  for k in range(len_par)))
                        self._conj_block[t_ZZ].add(conj_type)

            for el in self._conj_block[t_ZZ]:
                group_el = prod(
                    [self.V(el[k][0])**el[k][1] for k in range(len(el))])

                #if el != group_el.conjugacy_type():
                #    raise AssertionError("This shouldn't happen!")

                D = group_el.discriminant()
                if coerce_AA(D) < 0:
                    raise AssertionError("This shouldn't happen!")
                if coerce_AA(D) == 0:
                    raise AssertionError("This shouldn't happen!")
                    #continue

                # The primitive cases
                #if group_el.is_primitive():
                if not ((len(el) == 1 and el[0][1] > 1) or is_cycle(el)):
                    if D not in self._conj_prim:
                        self._conj_prim[D] = []
                    self._conj_prim[D].append(group_el)
                # The remaining cases
                else:
                    if D not in self._conj_nonprim:
                        self._conj_nonprim[D] = []
                    self._conj_nonprim[D].append(group_el)

        self._max_block_length = max_block_length
Esempio n. 53
0
    def possible_orders(self, proof=True):
        """
        Return the possible orders of this torsion subgroup. Outside of special
        cases, this is done by computing a divisor and multiple of the order.

        INPUT:

        - ``proof`` -- a boolean (default: True)

        OUTPUT:

        - an array of positive integers

        The computation of the rational torsion order of J1(p) is conjectural
        and will only be used if proof=False. See Section 6.2.3 of [CES2003]_.

        EXAMPLES::

            sage: J0(11).rational_torsion_subgroup().possible_orders()
            [5]
            sage: J0(33).rational_torsion_subgroup().possible_orders()
            [100, 200]

            sage: J1(13).rational_torsion_subgroup().possible_orders()
            [19]
            sage: J1(16).rational_torsion_subgroup().possible_orders()
            [1, 2, 4, 5, 10, 20]
        """
        try:
            if proof:
                return self._possible_orders
            else:
                return self._possible_orders_proof_false
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()
        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._possible_orders = [QQ((A.level()-1)/12).numerator()]
            self._possible_orders_proof_false = self._possible_orders
            return self._possible_orders

        # the elliptic curve case
        if A.dimension() == 1:
            self._possible_orders = [A.elliptic_curve().torsion_order()]
            self._possible_orders_proof_false = self._possible_orders
            return self._possible_orders

        # the conjectural J1(p) case
        if not proof and A.is_J1() and N.is_prime():
            epsilons = [epsilon for epsilon in DirichletGroup(N)
                        if not epsilon.is_trivial() and epsilon.is_even()]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._possible_orders_proof_false = [ZZ(N/(2**(N-3))*prod(bernoullis))]
            return self._possible_orders_proof_false

        u = self.multiple_of_order()
        l = self.divisor_of_order()

        assert u % l == 0
        O = [l * d for d in divisors(u//l)]
        self._possible_orders = O
        if u == l:
            self._possible_orders_proof_false = O
        return O
Esempio n. 54
0
    def __call__(self, s, prec=53):
        """
        Evaluate this complex `L`-series at `s`.

        INPUT:

        - ``s`` -- complex number

        - ``prec`` -- integer (default: 53) the number of bits of precision
          used in computing the lseries of the newforms.

        OUTPUT:

        a complex number L(A, s).

        EXAMPLES::

            sage: L = J0(23).lseries()
            sage: L(1)
            0.248431866590600
            sage: L(1, prec=100)
            0.24843186659059968120725033931

            sage: L = J0(389)[0].lseries()
            sage: L(1) # long time (2s) abstol 1e-10
            -1.33139759782370e-19
            sage: L(1, prec=100) # long time (2s) abstol 1e-20
            6.0129758648142797032650287762e-39
            sage: L.rational_part()
            0

            sage: L = J1(23)[0].lseries()
            sage: L(1)
            0.248431866590600

            sage: J = J0(11) * J1(11)
            sage: J.lseries()(1)
            0.0644356903227915

            sage: L = JH(17,[2]).lseries()
            sage: L(1)
            0.386769938387780

        """
        abelian_variety = self.abelian_variety()
        # Check for easy dimension zero case
        if abelian_variety.dimension() == 0:
            return CC(1)
        try:
            factors = self.__factors[prec]
            return prod(L(s) for L in factors)
        except AttributeError:
            self.__factors = {}
        except KeyError:
            pass
        abelian_variety = self.abelian_variety()
        newforms = abelian_variety.newform_decomposition('a')

        factors = [
            newform.lseries(embedding=i, prec=prec) for newform in newforms
            for i in range(newform.base_ring().degree())
        ]
        self.__factors[prec] = factors

        return prod(L(s) for L in factors)
Esempio n. 55
0
    def multiple_of_order(self, maxp=None, proof=True):
        """
        Return a multiple of the order.

        INPUT:

        - ``proof`` -- a boolean (default: True)

        The computation of the rational torsion order of J1(p) is conjectural
        and will only be used if proof=False. See Section 6.2.3 of [CES2003]_.

        EXAMPLES::

            sage: J = J1(11); J
            Abelian variety J1(11) of dimension 1
            sage: J.rational_torsion_subgroup().multiple_of_order()
            5

            sage: J = J0(17)
            sage: J.rational_torsion_subgroup().order()
            4

        This is an example where proof=False leads to a better bound and better
        performance. ::

            sage: J = J1(23)
            sage: J.rational_torsion_subgroup().multiple_of_order() # long time (2s)
            9406793
            sage: J.rational_torsion_subgroup().multiple_of_order(proof=False)
            408991
        """

        try:
            if proof:
                return self._multiple_of_order
            else:
                return self._multiple_of_order_proof_false
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()

        if A.dimension() == 0:
            self._multiple_of_order = ZZ(1)
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._multiple_of_order = QQ((A.level()-1)/12).numerator()
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # The elliptic curve case
        if A.dimension() == 1:
            self._multiple_of_order = A.elliptic_curve().torsion_order()
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # The conjectural J1(p) case
        if not proof and A.is_J1() and N.is_prime():
            epsilons = [epsilon for epsilon in DirichletGroup(N)
                        if not epsilon.is_trivial() and epsilon.is_even()]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._multiple_of_order_proof_false = ZZ(N/(2**(N-3))*prod(bernoullis))
            return self._multiple_of_order_proof_false

        # The Gamma0 and Gamma1 case
        if all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())):
            self._multiple_of_order = self.multiple_of_order_using_frobp()
            return self._multiple_of_order

        # Unhandled case
        raise NotImplementedError("No implemented algorithm")
Esempio n. 56
0
    def _convert_factors_(self, factors):
        r"""
        Helper method. Try to convert some ``factors`` to an
        element of one of the Cartesian factors and return the product of
        all these factors.

        INPUT:

        - ``factors`` -- a tuple or other iterable.

        OUTPUT:

        An element of this Cartesian product.

        EXAMPLES::

            sage: from sage.rings.asymptotic.growth_group import GrowthGroup
            sage: G = GrowthGroup('x^ZZ * log(x)^QQ * y^QQ')
            sage: e1 = G._convert_factors_([x^2])
            sage: (e1, e1.parent())
            (x^2, Growth Group x^ZZ * log(x)^QQ * y^QQ)

        ::

            sage: G = GrowthGroup('(QQ_+)^n * n^ZZ * UU^n')
            sage: n = SR.var('n')
            sage: G((-2)^n)
            2^n*(-1)^n
        """
        from sage.misc.misc_c import prod
        from .growth_group import PartialConversionValueError
        from .misc import combine_exceptions

        def get_factors(data):
            result = []
            errors = []
            for factor in self.cartesian_factors():
                try:
                    try:
                        result.append((factor, factor(data)))
                        break
                    except PartialConversionValueError as e:
                        try:
                            element, todo = e.element.split()
                        except NotImplementedError as nie:
                            raise combine_exceptions(
                                ValueError('cannot split {}: no splitting '
                                           'implemented'.format(e.element)),
                                nie)
                        except ValueError as ve:
                            raise combine_exceptions(
                                ValueError('cannot split {} after failed '
                                           'conversion into element of '
                                           '{}'.format(e.element, factor)),
                                ve)
                        assert todo is not None
                        result.append((factor, element))
                        data = todo
                except (ValueError, TypeError) as error:
                    errors.append(error)
            if not result:
                raise combine_exceptions(
                    ValueError('%s is not in any of the factors of %s' % (data, self)),
                    *errors)
            return result

        return prod(self.cartesian_injection(*fs)
                    for f in factors for fs in get_factors(f))
Esempio n. 57
0
 def RQ(delta):
     # this is the quotient R(F_0,z)/R(F_0,z(F)) for a generic z
     # at distance delta from j. See Lemma 4.2 in [HS2018].
     cd = cosh(delta).n(prec=prec)
     sd = sinh(delta).n(prec=prec)
     return prod([cd + (cost*phi[0] + sint*phi[1])*sd for phi in phis])
Esempio n. 58
0
    def H_value(self, p, f, t, ring=None):
        """
        Return the trace of the Frobenius, computed in terms of Gauss sums
        using the hypergeometric trace formula.

        INPUT:

        - `p` -- a prime number

        - `f` -- an integer such that `q = p^f`

        - `t` -- a rational parameter

        - ``ring`` -- optional (default ``UniversalCyclotomicfield``)

        The ring could be also ``ComplexField(n)`` or ``QQbar``.

        OUTPUT:

        an integer

        .. WARNING::

            This is apparently working correctly as can be tested
            using ComplexField(70) as value ring.

            Using instead UniversalCyclotomicfield, this is much
            slower than the `p`-adic version :meth:`padic_H_value`.

        EXAMPLES:

        With values in the UniversalCyclotomicField (slow)::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4))
            sage: [H.H_value(3,i,-1) for i in range(1,3)]
            [0, -12]
            sage: [H.H_value(5,i,-1) for i in range(1,3)]
            [-4, 276]
            sage: [H.H_value(7,i,-1) for i in range(1,3)]  # not tested
            [0, -476]
            sage: [H.H_value(11,i,-1) for i in range(1,3)]  # not tested
            [0, -4972]
            sage: [H.H_value(13,i,-1) for i in range(1,3)]  # not tested
            [-84, -1420]

        With values in ComplexField::

            sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)]
            [-4, 276]

        Check issue from :trac:`28404`::

            sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2]))
            sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1]))
            sage: [H1.H_value(5,1,i) for i in range(2,5)]
            [1, -4, -4]
            sage: [H2.H_value(5,1,QQ(i)) for i in range(2,5)]
            [-4, 1, -4]

        REFERENCES:

        - [BeCoMe]_ (Theorem 1.3)
        - [Benasque2009]_
        """
        alpha = self._alpha
        beta = self._beta
        t = QQ(t)
        if 0 in alpha:
            return self._swap.H_value(p, f, ~t, ring)
        if ring is None:
            ring = UniversalCyclotomicField()
        gamma = self.gamma_array()
        q = p ** f

        m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)}
        D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta)
        # also: D = (self.weight() + 1 - m[0]) // 2
        M = self.M_value()

        Fq = GF(q)
        gen = Fq.multiplicative_generator()
        zeta_q = ring.zeta(q - 1)

        tM = Fq(M / t)
        for k in range(q - 1):
            if gen ** k == tM:
                teich = zeta_q ** k
                break

        gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)]

        sigma = sum(q**(D + m[0] - m[r]) *
                    prod(gauss_table[(-v * r) % (q - 1)]**gv
                         for v, gv in gamma.items()) *
                    teich ** r
                    for r in range(q - 1))
        resu = ZZ(-1) ** m[0] / (1 - q) * sigma
        if not ring.is_exact():
            resu = resu.real_part().round()
        return resu
Esempio n. 59
0
def fundamental_group(f, simplified=True, projective=False):
    r"""
    Return a presentation of the fundamental group of the complement of
    the algebraic set defined by the polynomial ``f``.

    INPUT:

    - ``f`` -- a polynomial in two variables, with coefficients in either
      the rationals or a number field with a fixed embedding in `\QQbar`

    - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the
      presentation will be simplified (see below)

    - ``projective`` -- boolean (default: ``False``); if set to ``True``,
      the fundamental group of the complement of the projective completion
      of the curve will be computed, otherwise, the fundamental group of
      the complement in the affine plane will be computed

    If ``simplified`` is ``False``, the returned presentation has as
    many generators as degree of the polynomial times the points in the
    base used to create the segments that surround the discriminant. In
    this case, the generators are granted to be meridians of the curve.

    OUTPUT:

    A presentation of the fundamental group of the complement of the
    curve defined by ``f``.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >
        sage: fundamental_group(f, simplified=False) # optional - sirocco
        Finitely presented group < ... >

    ::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >

    It is also possible to have coefficients in a number field with a
    fixed embedding in `\QQbar`::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0]
        sage: zeta
        -0.50000000000000000? - 0.866025403784439?*I
        sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta)
        sage: F.inject_variables()
        Defining zeta
        sage: R.<x,y> = F[]
        sage: f = y^3 + x^3 +zeta *x + 1
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < x0 |  >
    """
    (x, y) = f.variables()
    F = f.base_ring()
    g = f.factor().radical().prod()
    d = g.degree(y)
    while not g.coefficient(y**d) in F or (projective and g.total_degree() > d):
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    segs = segments(disc)
    vertices = list(set(flatten(segs)))
    Faux = FreeGroup(d)
    F = FreeGroup(d * len(vertices))
    rels = []
    if projective:
        rels.append(prod(F.gen(i) for i in range(d)))
    braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs])
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        b = braidcomputed[1]
        i = vertices.index(seg[0])
        j = vertices.index(seg[1])
        for k in range(d):
            el1 = Faux([k + 1]) * b.inverse()
            el2 = k + 1
            w1 = F([sign(a)*d*i + a for a in el1.Tietze()])
            w2 = F([d*j + el2])
            rels.append(w1/w2)
    G = F / rels
    if simplified:
        return G.simplified()
    else:
        return G
Esempio n. 60
0
        def demazure_character(self, w, f=None):
            r"""
            Returns the Demazure character associated to ``w``.

            INPUT:

            - ``w`` -- an element of the ambient weight lattice
              realization of the crystal, or a reduced word, or an element
              in the associated Weyl group

            OPTIONAL:

            - ``f`` -- a function from the crystal to a module

            This is currently only supported for crystals whose underlying
            weight space is the ambient space.

            The Demazure character is obtained by applying the Demazure operator
            `D_w` (see :meth:`sage.categories.regular_crystals.RegularCrystals.ParentMethods.demazure_operator`)
            to the highest weight element of the classical crystal. The simple
            Demazure operators `D_i` (see
            :meth:`sage.categories.regular_crystals.RegularCrystals.ElementMethods.demazure_operator_simple`)
            do not braid on the level of crystals, but on the level of characters they do.
            That is why it makes sense to input ``w`` either as a weight, a reduced word,
            or as an element of the underlying Weyl group.

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',2], shape = [2,1])
                sage: e = T.weight_lattice_realization().basis()
                sage: weight = e[0] + 2*e[2]
                sage: weight.reduced_word()
                [2, 1]
                sage: T.demazure_character(weight)
                x1^2*x2 + x1*x2^2 + x1^2*x3 + x1*x2*x3 + x1*x3^2

                sage: T = crystals.Tableaux(['A',3],shape=[2,1])
                sage: T.demazure_character([1,2,3])
                x1^2*x2 + x1*x2^2 + x1^2*x3 + x1*x2*x3 + x2^2*x3
                sage: W = WeylGroup(['A',3])
                sage: w = W.from_reduced_word([1,2,3])
                sage: T.demazure_character(w)
                x1^2*x2 + x1*x2^2 + x1^2*x3 + x1*x2*x3 + x2^2*x3

                sage: T = crystals.Tableaux(['B',2], shape = [2])
                sage: e = T.weight_lattice_realization().basis()
                sage: weight = -2*e[1]
                sage: T.demazure_character(weight)
                x1^2 + x1*x2 + x2^2 + x1 + x2 + x1/x2 + 1/x2 + 1/x2^2 + 1

                sage: T = crystals.Tableaux("B2",shape=[1/2,1/2])
                sage: b2=WeylCharacterRing("B2",base_ring=QQ).ambient()
                sage: T.demazure_character([1,2],f=lambda x:b2(x.weight()))
                b2(-1/2,1/2) + b2(1/2,-1/2) + b2(1/2,1/2)

            REFERENCES:

            .. [D1974] \M. Demazure, Desingularisation des varietes de Schubert,
               Ann. E. N. S., Vol. 6, (1974), p. 163-172

            .. [M2009] Sarah Mason, An Explicit Construction of Type A Demazure Atoms,
               Journal of Algebraic Combinatorics, Vol. 29, (2009), No. 3, p.295-313.
               :arXiv:`0707.4267`
            """
            from sage.misc.misc_c import prod
            from sage.rings.integer_ring import ZZ
            from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
            if hasattr(w, 'reduced_word'):
                word = w.reduced_word()
            else:
                word = w
            n = self.weight_lattice_realization().n
            u = self.algebra(ZZ).sum_of_monomials(self.module_generators)
            u = self.demazure_operator(u, word)
            if f is None:
                x = ['x%s' % i for i in range(1, n + 1)]
                P = PolynomialRing(ZZ, x)
                # TODO: use P.linear_combination when PolynomialRing will be a ModulesWithBasis
                return sum((coeff * prod((x[i]**(c.weight()[i])
                                          for i in range(n)), P.one())
                            for c, coeff in u), P.zero())
            else:
                return sum((coeff * f(c)) for c, coeff in u)