def unimodular_transformation(self, u):
        r"""
        Apply the transformation `u` to the underlying lattice `L`: `u^\tr L u`.
        
        INPUT:
        
        - `u` -- A unimodular matrix.
        
        OUTPUT:
        
        - A pair of a discriminant group and a homomorphism from self to this group.
        """
        n_disc = DiscriminantForm(u.transpose() * self._L * u)

        uinv = u.inverse()
        basis_images = [
            sum(map(operator.mul, b.lift(), self._dual_basis.columns()))
            for b in self.smith_form_gens()
        ]
        basis_images = [
            n_disc._dual_basis.solve_right(uinv * b).list()
            for b in basis_images
        ]

        coercion_hom = self.hom([
            sum(
                map(operator.mul, map(ZZ, b),
                    map(n_disc,
                        FreeModule(ZZ, self._L.nrows()).gens())))
            for b in basis_images
        ])

        return (n_disc, coercion_hom)
Example #2
0
    def ambient_module(self):
        """
        Return the ambient module.

        .. SEEALSO::

            :meth:`ambient_vector_space`

        OUTPUT:

        The domain of the linear expressions as a free module over the
        base ring.

        EXAMPLES::

            sage: from sage.geometry.linear_expression import LinearExpressionModule
            sage: L = LinearExpressionModule(QQ, ('x', 'y', 'z'))
            sage: L.ambient_module()
            Vector space of dimension 3 over Rational Field
            sage: M = LinearExpressionModule(ZZ, ('r', 's'))
            sage: M.ambient_module()
            Ambient free module of rank 2 over the principal ideal domain Integer Ring
            sage: M.ambient_vector_space()
            Vector space of dimension 2 over Rational Field
        """
        from sage.modules.all import FreeModule
        return FreeModule(self.base_ring(), self.ngens())
Example #3
0
def TestExpansionAmbient_vv(A):
    """
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.modularforms.modularform_testtype import *
            sage: ea = TestExpansionAmbient_vv(QQ)    
    """
    return EquivariantMonoidPowerSeriesModule(
        NNMonoid(), TrivialCharacterMonoid("1", ZZ),
        TrivialRepresentation(
            "1", FreeModule(A, ModularFormTestType_vectorvalued.rank)))
Example #4
0
    def vector_space(self):
        """
        Return the vector space of the underlying affine space.

        EXAMPLES::

            sage: G = AffineGroup(3, GF(5))
            sage: G.vector_space()
            Vector space of dimension 3 over Finite Field of size 5
        """
        return FreeModule(self.base_ring(), self.degree())
Example #5
0
        def _pow_int(self, n):
            r"""
            Returns the vector space of dimension `n` over ``self``.

            EXAMPLES::

                sage: QQ^4
                Vector space of dimension 4 over Rational Field
            """
            from sage.modules.all import FreeModule
            return FreeModule(self, n)
    def add_unimodular_lattice(self, L=None):
        r"""
        Add a unimodular lattice (which is not necessarily positive definite) to the underlying lattice
        and the resulting discriminant group and an isomorphism to ``self``.
        
        INPUT:
        
        - `L` -- The Gram matrix of a unimodular lattice or ``None`` (default: ``None``).
                 If ``None``, `E_8` will be added.
        
        OUTPUT:
        
        - A pair of a discriminant group and a homomorphism from self to this group.
        """
        if L is None:
            L = matrix(8, [
                2, -1, 0, 0, 0, 0, 0, 0, -1, 2, -1, 0, 0, 0, 0, 0, 0, -1, 2,
                -1, 0, 0, 0, -1, 0, 0, -1, 2, -1, 0, 0, 0, 0, 0, 0, -1, 2, -1,
                0, 0, 0, 0, 0, 0, -1, 2, -1, 0, 0, 0, 0, 0, 0, -1, 2, 0, 0, 0,
                -1, 0, 0, 0, 0, 2
            ])
        else:
            if L.base_ring() is not ZZ or all(e % 2 == 0 for e in L.diagonal()) \
              or L.det() != 1 :
                raise ValueError(
                    "L must be the Gram matrix of an even unimodular lattice")

        nL = self._L.block_sum(L)
        n_disc = DiscriminantForm(nL)

        basis_images = [
            sum(map(operator.mul, b.lift(), self._dual_basis.columns()))
            for b in self.smith_form_gens()
        ]
        basis_images = [
            n_disc._dual_basis.solve_right(
                vector(QQ,
                       b.list() + L.nrows() * [0])).list()
            for b in basis_images
        ]
        coercion_hom = self.hom([
            sum(
                map(operator.mul, map(ZZ, b),
                    map(n_disc,
                        FreeModule(ZZ, nL.nrows()).gens())))
            for b in basis_images
        ])

        return (n_disc, coercion_hom)
        def _split_hyperbolic(L):
            cur_cor = 2
            Lcor = L + cur_cor * identity_matrix(L.nrows())
            while not is_positive_definite(Lcor):
                cur_cor += 2
                Lcor = L + cur_cor * identity_matrix(L.nrows())

            a = FreeModule(ZZ, L.nrows()).gen(0)
            if a * L * a >= 0:
                Lcor_length_inc = max(3, a * L * a)
                cur_Lcor_length = Lcor_length_inc
                while True:
                    short_vectors = flatten(
                        QuadraticForm(Lcor).short_vector_list_up_to_length(
                            a * Lcor * a)[cur_Lcor_length -
                                          Lcor_length_inc:cur_Lcor_length],
                        max_level=1)
                    for a in short_vectors:
                        if a * L * a < 0:
                            break
                    else:
                        continue
                    break
            n = -a * L * a // 2

            short_vectors = E8.short_vector_list_up_to_length(n + 1)[-1]

            for v in short_vectors:
                for w in short_vectors:
                    if v * E8_gram * w == 2 * n - 1:
                        LE8_mat = L.block_sum(E8_gram)
                        v_form = vector(list(a) + list(v)) * LE8_mat
                        w_form = vector(list(a) + list(w)) * LE8_mat
                        Lred_basis = matrix(
                            ZZ, [v_form, w_form
                                 ]).right_kernel().basis_matrix().transpose()
                        Lred_basis = matrix(ZZ, Lred_basis)

                        return Lred_basis.transpose() * LE8_mat * Lred_basis
def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False):
    """
    Return a list of lists of short vectors `v`, sorted by length, with
    Q(`v`) < len_bound.
    
    INPUT:

    - ``len_bound`` -- bound for the length of the vectors.
    
    - ``up_to_sign_flag`` -- (default: ``False``) if set to True, then
      only one of the vectors of the pair `[v, -v]` is listed.

    OUTPUT:

    A list of lists of vectors such that entry `[i]` contains all
    vectors of length `i`.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.short_vector_list_up_to_length(3)
        [[(0, 0, 0, 0)], [(1, 0, 0, 0), (-1, 0, 0, 0)], []]
        sage: Q.short_vector_list_up_to_length(4)
        [[(0, 0, 0, 0)],
         [(1, 0, 0, 0), (-1, 0, 0, 0)],
         [],
         [(0, 1, 0, 0), (0, -1, 0, 0)]]
        sage: Q.short_vector_list_up_to_length(5)
        [[(0, 0, 0, 0)],
         [(1, 0, 0, 0), (-1, 0, 0, 0)],
         [],
         [(0, 1, 0, 0), (0, -1, 0, 0)],
         [(1, 1, 0, 0),
         (-1, -1, 0, 0),
         (-1, 1, 0, 0),
         (1, -1, 0, 0),
         (2, 0, 0, 0),
         (-2, 0, 0, 0)]]
        sage: Q.short_vector_list_up_to_length(5, True)
        [[(0, 0, 0, 0)],
         [(1, 0, 0, 0)],
         [],
         [(0, 1, 0, 0)],
         [(1, 1, 0, 0), (-1, 1, 0, 0), (2, 0, 0, 0)]]
        sage: Q = QuadraticForm(matrix(6, [2, 1, 1, 1, -1, -1, 1, 2, 1, 1, -1, -1, 1, 1, 2, 0, -1, -1, 1, 1, 0, 2, 0, -1, -1, -1, -1, 0, 2, 1, -1, -1, -1, -1, 1, 2]))
        sage: vs = Q.short_vector_list_up_to_length(8)
        sage: [len(vs[i]) for i in range(len(vs))]
        [1, 72, 270, 720, 936, 2160, 2214, 3600]
        sage: vs = Q.short_vector_list_up_to_length(30)  # long time (28s on sage.math, 2014)
        sage: [len(vs[i]) for i in range(len(vs))]       # long time
        [1, 72, 270, 720, 936, 2160, 2214, 3600, 4590, 6552, 5184, 10800, 9360, 12240, 13500, 17712, 14760, 25920, 19710, 26064, 28080, 36000, 25920, 47520, 37638, 43272, 45900, 59040, 46800, 75600]

    The cases of ``len_bound < 2`` led to exception or infinite runtime before.

    ::

        sage: Q.short_vector_list_up_to_length(-1)
        []
        sage: Q.short_vector_list_up_to_length(0)
        []
        sage: Q.short_vector_list_up_to_length(1)
        [[(0, 0, 0, 0, 0, 0)]]

    In the case of quadratic forms that are not positive definite an error is raised.

    ::

        sage: QuadraticForm(matrix(2, [2, 0, 0, -2])).short_vector_list_up_to_length(3)
        Traceback (most recent call last):
        ...
        ValueError: Quadratic form must be positive definite in order to enumerate short vectors

    Sometimes, PARI does not compute short vectors correctly.  It returns too long vectors.

    ::

        sage: Q = QuadraticForm(matrix(2, [72, 12, 12, 120]))
        sage: len_bound_pari = 2*22953421 - 2; len_bound_pari
        45906840
        sage: vs = list(Q._pari_().qfminim(len_bound_pari)[2])  # long time (18s on sage.math, 2014)
        sage: v = vs[0]; v  # long time
        [-65, 623]~
        sage: v.Vec() * Q._pari_() * v  # long time
        45907800
    """
    if not self.is_positive_definite() :
        raise ValueError( "Quadratic form must be positive definite in order to enumerate short vectors" )

    if len_bound <= 0:
        return []

    # Free module in which the vectors live
    V = FreeModule(ZZ, self.dim())

    # Adjust length for PARI. We need to subtract 1 because PARI returns
    # returns vectors of length less than or equal to b, but we want
    # strictly less. We need to double because the matrix is doubled.
    len_bound_pari = 2*(len_bound - 1)

    # Call PARI's qfminim()
    parilist = self._pari_().qfminim(len_bound_pari)[2].Vec()

    # List of lengths
    parilens = pari(r"(M,v) -> vector(#v, i, (v[i]~ * M * v[i])\2)")(self, parilist)

    # Sort the vectors into lists by their length
    vec_sorted_list = [list() for i in range(len_bound)]
    for i in range(len(parilist)):
        length = ZZ(parilens[i])
        # PARI can sometimes return longer vectors than requested.
        # E.g. : self.matrix() == matrix(2, [72, 12, 12, 120])
        #        len_bound = 22953421
        # gives maximal length 22955664
        if length < len_bound:
            v = parilist[i]
            sagevec = V(list(parilist[i]))
            vec_sorted_list[length].append(sagevec)
            if not up_to_sign_flag :
                vec_sorted_list[length].append(-sagevec)

    # Add the zero vector by hand
    vec_sorted_list[0].append(V.zero_vector())

    return vec_sorted_list
Example #9
0
    def to_sage(self):
        """
        EXAMPLES:
            sage: macaulay2(ZZ).to_sage()      #optional
            Integer Ring
            sage: macaulay2(QQ).to_sage()      #optional
            Rational Field

            sage: macaulay2(2).to_sage()       #optional
            2
            sage: macaulay2(1/2).to_sage()     #optional
            1/2
            sage: macaulay2(2/1).to_sage()     #optional
            2
            sage: _.parent()                   #optional
            Rational Field
            sage: macaulay2([1,2,3]).to_sage() #optional
            [1, 2, 3]

            sage: m = matrix([[1,2],[3,4]])
            sage: macaulay2(m).to_sage()       #optional
            [1 2]
            [3 4]

            sage: macaulay2(QQ['x,y']).to_sage()    #optional
            Multivariate Polynomial Ring in x, y over Rational Field
            sage: macaulay2(QQ['x']).to_sage()      #optional
            Univariate Polynomial Ring in x over Rational Field
            sage: macaulay2(GF(7)['x,y']).to_sage() #optional
            Multivariate Polynomial Ring in x, y over Finite Field of size 7

            sage: macaulay2(GF(7)).to_sage()       #optional
            Finite Field of size 7
            sage: macaulay2(GF(49, 'a')).to_sage() #optional
            Finite Field in a of size 7^2

            sage: R.<x,y> = QQ[]
            sage: macaulay2(x^2+y^2+1).to_sage()   #optional
            x^2 + y^2 + 1

            sage: R = macaulay2("QQ[x,y]")         #optional
            sage: I = macaulay2("ideal (x,y)")     #optional
            sage: I.to_sage()                      #optional
            Ideal (x, y) of Multivariate Polynomial Ring in x, y over Rational Field

            sage: X = R/I       #optional
            sage: X.to_sage()   #optional
            Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y)

            sage: R = macaulay2("QQ^2")  #optional
            sage: R.to_sage()            #optional
            Vector space of dimension 2 over Rational Field

            sage: m = macaulay2('"hello"')  #optional
            sage: m.to_sage()               #optional
            'hello'

        """
        repr_str = str(self)
        cls_str = str(self.cls())
        cls_cls_str = str(self.cls().cls())

        if repr_str == "ZZ":
            from sage.rings.all import ZZ
            return ZZ
        elif repr_str == "QQ":
            from sage.rings.all import QQ
            return QQ

        if cls_cls_str == "Type":
            if cls_str == "List":
                return [entry.to_sage() for entry in self]
            elif cls_str == "Matrix":
                from sage.matrix.all import matrix
                base_ring = self.ring().to_sage()
                entries = self.entries().to_sage()
                return matrix(base_ring, entries)
            elif cls_str == "Ideal":
                parent = self.ring().to_sage()
                gens = self.gens().entries().flatten().to_sage()
                return parent.ideal(*gens)
            elif cls_str == "QuotientRing":
                #Handle the ZZ/n case
                if "ZZ" in repr_str and "--" in repr_str:
                    from sage.rings.all import ZZ, GF
                    external_string = self.external_string()
                    zz, n = external_string.split("/")

                    #Note that n must be prime since it is
                    #coming from Macaulay 2
                    return GF(ZZ(n))

                ambient = self.ambient().to_sage()
                ideal = self.ideal().to_sage()
                return ambient.quotient(ideal)
            elif cls_str == "PolynomialRing":
                from sage.rings.all import PolynomialRing
                from sage.rings.polynomial.term_order import inv_macaulay2_name_mapping

                #Get the base ring
                base_ring = self.coefficientRing().to_sage()

                #Get a string list of generators
                gens = str(self.gens())[1:-1]

                # Check that we are dealing with default degrees, i.e. 1's.
                if self.degrees().any("x -> x != {1}").to_sage():
                    raise ValueError, "cannot convert Macaulay2 polynomial ring with non-default degrees to Sage"
                #Handle the term order
                external_string = self.external_string()
                order = None
                if "MonomialOrder" not in external_string:
                    order = "degrevlex"
                else:
                    for order_name in inv_macaulay2_name_mapping:
                        if order_name in external_string:
                            order = inv_macaulay2_name_mapping[order_name]
                if len(gens) > 1 and order is None:
                    raise ValueError, "cannot convert Macaulay2's term order to a Sage term order"

                return PolynomialRing(base_ring, order=order, names=gens)
            elif cls_str == "GaloisField":
                from sage.rings.all import ZZ, GF
                gf, n = repr_str.split(" ")
                n = ZZ(n)
                if n.is_prime():
                    return GF(n)
                else:
                    gen = str(self.gens())[1:-1]
                    return GF(n, gen)
            elif cls_str == "Boolean":
                if repr_str == "true":
                    return True
                elif repr_str == "false":
                    return False
            elif cls_str == "String":
                return str(repr_str)
            elif cls_str == "Module":
                from sage.modules.all import FreeModule
                if self.isFreeModule().to_sage():
                    ring = self.ring().to_sage()
                    rank = self.rank().to_sage()
                    return FreeModule(ring, rank)
        else:
            #Handle the integers and rationals separately
            if cls_str == "ZZ":
                from sage.rings.all import ZZ
                return ZZ(repr_str)
            elif cls_str == "QQ":
                from sage.rings.all import QQ
                repr_str = self.external_string()
                if "/" not in repr_str:
                    repr_str = repr_str + "/1"
                return QQ(repr_str)

            m2_parent = self.cls()
            parent = m2_parent.to_sage()

            if cls_cls_str == "PolynomialRing":
                from sage.misc.sage_eval import sage_eval
                gens_dict = parent.gens_dict()
                return sage_eval(self.external_string(), gens_dict)

        from sage.misc.sage_eval import sage_eval
        try:
            return sage_eval(repr_str)
        except Exception:
            raise NotImplementedError, "cannot convert %s to a Sage object" % repr_str
Example #10
0
    def cohomology(self, degree=None, weight=None, dim=False):
        r"""
        Return the bundle cohomology groups.

        INPUT:

        - ``degree`` -- ``None`` (default) or an integer. The degree of
          the cohomology group.

        - ``weight`` -- ``None`` (default) or a tuple of integers or a
          `M`-lattice point. A point in the dual lattice of the fan
          defining a torus character. The weight of the cohomology
          group.

        - ``dim`` -- Boolean (default: ``False``). Whether to return
          vector spaces or only their dimension.

        OUTPUT:

        The cohomology group of given cohomological ``degree`` and
        torus ``weight``.

        * If no ``weight`` is specified, the unweighted group (sum
          over all weights) is returned.

        * If no ``degree`` is specified, a dictionary whose keys are
          integers and whose values are the cohomology groups is
          returned. If, in addition, ``dim=True``, then an integral
          vector of the dimensions is returned.

        EXAMPLES::

            sage: V = toric_varieties.P2().sheaves.tangent_bundle()
            sage: V.cohomology(degree=0, weight=(0,0))
            Vector space of dimension 2 over Rational Field
            sage: V.cohomology(weight=(0,0), dim=True)
            (2, 0, 0)
            sage: for i,j in cartesian_product((list(range(-2,3)), list(range(-2,3)))):
            ....:       HH = V.cohomology(weight=(i,j), dim=True)
            ....:       if HH.is_zero(): continue
            ....:       print('H^*i(P^2, TP^2)_M({}, {}) = {}'.format(i,j,HH))
            H^*i(P^2, TP^2)_M(-1, 0) = (1, 0, 0)
            H^*i(P^2, TP^2)_M(-1, 1) = (1, 0, 0)
            H^*i(P^2, TP^2)_M(0, -1) = (1, 0, 0)
            H^*i(P^2, TP^2)_M(0, 0) = (2, 0, 0)
            H^*i(P^2, TP^2)_M(0, 1) = (1, 0, 0)
            H^*i(P^2, TP^2)_M(1, -1) = (1, 0, 0)
            H^*i(P^2, TP^2)_M(1, 0) = (1, 0, 0)
        """
        from sage.modules.all import FreeModule
        if weight is None:
            raise NotImplementedError('sum over weights is not implemented')
        else:
            weight = self.variety().fan().dual_lattice()(weight)
            weight.set_immutable()
        if degree is not None:
            return self.cohomology(weight=weight, dim=dim)[degree]
        C = self.cohomology_complex(weight)
        space_dim = self._variety.dimension()
        C_homology = C.homology()
        HH = dict()
        for d in range(space_dim + 1):
            try:
                HH[d] = C_homology[d]
            except KeyError:
                HH[d] = FreeModule(self.base_ring(), 0)
        if dim:
            HH = vector(ZZ, [HH[i].rank() for i in range(space_dim + 1)])
        return HH
Example #11
0
def _find_complete_set_of_restriction_vectors(L,
                                              R,
                                              additional_s=0,
                                              reduction_function=None):
    r"""
    Given a set R of elements in L^# (e.g. representatives for ( L^# / L ) / \pm 1)
    find a complete set of restriction vectors. (See [GKR])
    
    INPUT:
    
    - `L` -- A quadratic form.
    
    - `R` -- A list of tuples or vectors in L \otimes QQ (with
             given coordinates).

    - ``additional_s`` -- A non-negative integer; Number of additional
                          elements of `L` that should be returned.
    
    - ``reduction_function`` -- A function that takes a tuple representing an element in `L^\#`
                                and returs a pair of a reduced element in `L^\#` and a sign.
    
    OUTPUT:
    
    - A set S of pairs, the first of which is a vector corresponding to
      an element in L, and the second of which is an integer.
    
    TESTS::
    
        sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _find_complete_set_of_restriction_vectors
        sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import *
        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2])))
        sage: _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives)
        [((1, 0), 0), ((1, 0), 1), ((-2, 1), 1)]
        sage: _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives, reduction_function = indices.reduce_r)
        [((1, 0), 0), ((1, 0), 1), ((-2, 1), 1)]
        
    ::
     
        sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _local_restriction_matrix
        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(4, [2,0,0,1, 0,2,0,1, 0,0,2,1, 1,1,1,2])))
        sage: S = _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives)
        sage: _local_restriction_matrix(indices._r_representatives, S).rank()
        4
    """
    R = [map(vector, rs) for rs in R]

    length_inc = 5
    max_length = 5
    cur_length = 1
    short_vectors = L.short_vector_list_up_to_length(max_length, True)

    S = list()
    restriction_space = FreeModule(QQ, len(R)).span([])

    while (len(S) < len(R) + additional_s):
        while len(short_vectors[cur_length]) == 0:
            cur_length += 1
            if max_length >= cur_length:
                max_length += length_inc
                short_vectors = L.short_vector_list_up_to_length(
                    max_length, True)

        s = vector(short_vectors[cur_length].pop())

        rcands = Set([s.dot_product(r) for rs in R for r in rs])

        for r in rcands:
            v = _eval_restriction_vector(R, s, r, reduction_function)
            if len(S) - restriction_space.rank() < additional_s \
              or v not in restriction_space :
                S.append((s, r))
                restriction_space = restriction_space + FreeModule(
                    QQ, len(R)).span([v])

                if len(S) == len(R) + additional_s:
                    break

    return S
 def gens(self):
     # FIXME: This is incorrect for almost all indices m
     return [(1, tuple(self.__L_size * [0]))] + [
         (1, tuple(r)) for r in FreeModule(ZZ, self.__L_size).basis()
     ]
    def split_off_unimodular_lattice(self, L_basis_matrix, check=True):
        r"""
        Split off a unimodular lattice that is an orthogonal summand of self.
        
        INPUT:
        
        - ``L_basis_matrix`` -- A matrix over `\ZZ` whose number of rows equals the
                                size of the underlying lattice.
        
        - ``check`` -- A boolean (default: ``True``).  If ``True`` it will be
                       checked whether the given sublattice is a direct summand.

        
        OUTPUT:
        
        - A pair of a discriminant group and a homomorphism from self to this group.
        """
        if check and L_basis_matrix.base_ring() is not ZZ:
            raise ValueError("L_basis_matrix must define a sublattice")

        pre_bases = matrix(ZZ, [ [ l * self._L * b for l in L_basis_matrix.columns()]
                                 for b in FreeModule(ZZ, self._L.nrows()).gens() ]) \
                            .augment(identity_matrix(ZZ, self._L.nrows())).echelon_form()

        if check and pre_bases[:L_basis_matrix.ncols(), :L_basis_matrix.ncols(
        )] != identity_matrix(ZZ, L_basis_matrix.ncols()):
            raise ValueError(
                "The sublattice defined by L_basis_matrix must be unimodular")

        K_basis_matrix = pre_bases[L_basis_matrix.ncols():,
                                   L_basis_matrix.ncols():].transpose()
        if check and L_basis_matrix.column_module(
        ) + K_basis_matrix.column_module() != FreeModule(ZZ, self._L.nrows()):
            raise ValueError(
                "The sublattice defined by L_basis_matrix must be an orthogonal summand"
            )

        K = K_basis_matrix.transpose() * self._L * K_basis_matrix
        n_disc = DiscriminantForm(K)

        total_basis_matrix = L_basis_matrix.change_ring(QQ).augment(
            K_basis_matrix * n_disc._dual_basis)

        basis_images = [
            sum(map(operator.mul, b.lift(), self._dual_basis.columns()))
            for b in self.smith_form_gens()
        ]
        basis_images = [
            total_basis_matrix.solve_right(b)[-K_basis_matrix.ncols():]
            for b in basis_images
        ]

        coercion_hom = self.hom([
            sum(
                map(operator.mul, map(ZZ, b),
                    map(n_disc,
                        FreeModule(ZZ, K.nrows()).gens())))
            for b in basis_images
        ])

        return (n_disc, coercion_hom)
def _find_complete_set_of_restriction_vectors(L, R, additional_s = 0, reduction_function = None) :
    r"""
    Given a set R of elements in L^# (e.g. representatives for ( L^# / L ) / \pm 1)
    find a complete set of restriction vectors. (See [GKR])
    
    INPUT:
    
    - `L` -- A quadratic form.
    
    - `R` -- A list of tuples or vectors in L \otimes QQ (with
             given coordinates).

    - ``additional_s`` -- A non-negative integer; Number of additional
                          elements of `L` that should be returned.
    
    - ``reduction_function`` -- A function that takes a tuple representing an element in `L^\#`
                                and returs a pair of a reduced element in `L^\#` and a sign.
    
    OUTPUT:
    
    - A set S of pairs, the first of which is a vector corresponding to
      an element in L, and the second of which is an integer.
    
    TESTS::
    
        sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _find_complete_set_of_restriction_vectors
        sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import *
        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2])))
        sage: _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives)
        [((1, 0), 0), ((1, 0), 1), ((-2, 1), 1)]
        sage: _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives, reduction_function = indices.reduce_r)
        [((1, 0), 0), ((1, 0), 1), ((-2, 1), 1)]
        
    ::
     
        sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _local_restriction_matrix
        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(4, [2,0,0,1, 0,2,0,1, 0,0,2,1, 1,1,1,2])))
        sage: S = _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives)
        sage: _local_restriction_matrix(indices._r_representatives, S).rank()
        4
    """
    R = [map(vector, rs) for rs in R]
    
    length_inc = 5
    max_length = 5
    cur_length = 1
    short_vectors = L.short_vector_list_up_to_length(max_length, True)
    
    S = list()
    restriction_space = FreeModule(QQ, len(R)).span([])
    
    
    while (len(S) < len(R) + additional_s ) :
        while len(short_vectors[cur_length]) == 0 :
            cur_length += 1
            if max_length >= cur_length :
                max_length += length_inc
                short_vectors = L.short_vector_list_up_to_length(max_length, True)
        
        s = vector( short_vectors[cur_length].pop() )
        
        rcands = Set([ s.dot_product(r) for rs in R for r in rs ])
        
        for r in rcands :
            v = _eval_restriction_vector(R, s, r, reduction_function)
            if len(S) - restriction_space.rank() < additional_s \
              or v not in restriction_space :
                S.append((s, r))
                restriction_space = restriction_space + FreeModule(QQ, len(R)).span([v])
                
                if len(S) == len(R) + additional_s :
                    break
    
    return S
Example #15
0
def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False):
    """
    Return a list of lists of short vectors `v`, sorted by length, with
    Q(`v`) < len_bound.
    
    INPUT:

    - ``len_bound`` -- bound for the length of the vectors.
    
    - ``up_to_sign_flag`` -- (default: ``False``) if set to True, then
      only one of the vectors of the pair `[v, -v]` is listed.

    OUTPUT:

    A list of lists of vectors such that entry `[i]` contains all
    vectors of length `i`.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.short_vector_list_up_to_length(3)
        [[(0, 0, 0, 0)], [(1, 0, 0, 0), (-1, 0, 0, 0)], []]
        sage: Q.short_vector_list_up_to_length(4)
        [[(0, 0, 0, 0)],
         [(1, 0, 0, 0), (-1, 0, 0, 0)],
         [],
         [(0, 1, 0, 0), (0, -1, 0, 0)]]
        sage: Q.short_vector_list_up_to_length(5)
        [[(0, 0, 0, 0)],
         [(1, 0, 0, 0), (-1, 0, 0, 0)],
         [],
         [(0, 1, 0, 0), (0, -1, 0, 0)],
         [(1, 1, 0, 0),
         (-1, -1, 0, 0),
         (-1, 1, 0, 0),
         (1, -1, 0, 0),
         (2, 0, 0, 0),
         (-2, 0, 0, 0)]]
        sage: Q.short_vector_list_up_to_length(5, True)
        [[(0, 0, 0, 0)],
         [(1, 0, 0, 0)],
         [],
         [(0, 1, 0, 0)],
         [(1, 1, 0, 0), (-1, 1, 0, 0), (2, 0, 0, 0)]]
        sage: Q = QuadraticForm(matrix(6, [2, 1, 1, 1, -1, -1, 1, 2, 1, 1, -1, -1, 1, 1, 2, 0, -1, -1, 1, 1, 0, 2, 0, -1, -1, -1, -1, 0, 2, 1, -1, -1, -1, -1, 1, 2]))
        sage: vs = Q.short_vector_list_up_to_length(8)
        sage: [len(vs[i]) for i in range(len(vs))]
        [1, 72, 270, 720, 936, 2160, 2214, 3600]
        sage: vs = Q.short_vector_list_up_to_length(30)  # long time (28s on sage.math, 2014)
        sage: [len(vs[i]) for i in range(len(vs))]       # long time
        [1, 72, 270, 720, 936, 2160, 2214, 3600, 4590, 6552, 5184, 10800, 9360, 12240, 13500, 17712, 14760, 25920, 19710, 26064, 28080, 36000, 25920, 47520, 37638, 43272, 45900, 59040, 46800, 75600]

    The cases of ``len_bound < 2`` led to exception or infinite runtime before.

    ::

        sage: Q.short_vector_list_up_to_length(-1)
        []
        sage: Q.short_vector_list_up_to_length(0)
        []
        sage: Q.short_vector_list_up_to_length(1)
        [[(0, 0, 0, 0, 0, 0)]]

    In the case of quadratic forms that are not positive definite an error is raised.

    ::

        sage: QuadraticForm(matrix(2, [2, 0, 0, -2])).short_vector_list_up_to_length(3)
        Traceback (most recent call last):
        ...
        ValueError: Quadratic form must be positive definite in order to enumerate short vectors

    Sometimes, PARI does not compute short vectors correctly.  It returns too long vectors.

    ::

        sage: Q = QuadraticForm(matrix(2, [72, 12, 12, 120]))
        sage: len_bound_pari = 2*22953421 - 2; len_bound_pari
        45906840
        sage: vs = list(Q._pari_().qfminim(len_bound_pari)[2])  # long time (18s on sage.math, 2014)
        sage: v = vs[0]; v  # long time
        [-65, 623]~
        sage: v.Vec() * Q._pari_() * v  # long time
        45907800
    """
    if not self.is_positive_definite():
        raise ValueError("Quadratic form must be positive definite in order to enumerate short vectors")

    if len_bound <= 0:
        return []

    # Free module in which the vectors live
    V = FreeModule(ZZ, self.dim())

    # Adjust length for PARI. We need to subtract 1 because PARI returns
    # returns vectors of length less than or equal to b, but we want
    # strictly less. We need to double because the matrix is doubled.
    len_bound_pari = 2 * (len_bound - 1)

    # Call PARI's qfminim()
    parilist = self._pari_().qfminim(len_bound_pari)[2].Vec()

    # List of lengths
    parilens = pari(r"(M,v) -> vector(#v, i, (v[i]~ * M * v[i])\2)")(self, parilist)

    # Sort the vectors into lists by their length
    vec_sorted_list = [list() for i in range(len_bound)]
    for i in range(len(parilist)):
        length = ZZ(parilens[i])
        # PARI can sometimes return longer vectors than requested.
        # E.g. : self.matrix() == matrix(2, [72, 12, 12, 120])
        #        len_bound = 22953421
        # gives maximal length 22955664
        if length < len_bound:
            v = parilist[i]
            sagevec = V(list(parilist[i]))
            vec_sorted_list[length].append(sagevec)
            if not up_to_sign_flag:
                vec_sorted_list[length].append(-sagevec)

    # Add the zero vector by hand
    vec_sorted_list[0].append(V.zero_vector())

    return vec_sorted_list
    def __init__(self, L, reduced=True, weak_forms=False):
        r"""
        INPUT:

            - `L`                -- An even quadratic form, the index of the associated
                                    Jacobi forms.   
            - ``reduced``        -- If ``True`` the reduction of Fourier indices
                                    with respect to the full Jacobi group
                                    will be considered.
            - ``weak_forms``     -- If ``False`` the condition `|L| L^{-1} r**2 <= 4 |L| n`
                                    will be imposed.
        
        NOTE:

            The Fourier expansion of a form is assumed to be indexed
            `\sum c(n,r) q^n \zeta^r` . The indices are pairs `(n, r)`.
            
        TESTS:
        
            sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import JacobiFormD1Indices
            sage: JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2])))._r_representatives
            [[(0, 0)], [(-1, -1), (0, 1), (1, 0)], [(1, 1), (0, -1), (-1, 0)]]
            sage: JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2])))._r_reduced_representatives
            [(0, 0), (1, 1)]
        """
        self.__L = L
        ## This is two times the adjoint of L, which in all cases will be even
        self.__Ladj = QuadraticForm(2 * L.matrix().adjoint())

        self.__L_size = L.matrix().nrows()
        self.__reduced = reduced
        self.__weak_forms = weak_forms

        # We fix representatives for ZZ^N / L ZZ^N with minimal norm.
        Ladj = self.__Ladj
        preliminary_reps = [
            r.lift()
            for r in FreeModule(ZZ,
                                L.matrix().nrows()) / L.matrix().row_module()
        ]
        max_norm = max(Ladj(r) for r in preliminary_reps)

        short_vectors = [
            map(vector, rrs)
            for rrs in Ladj.short_vector_list_up_to_length(max_norm + 1)
        ]
        self.__L_span = L.matrix().row_space()

        representatives = list()
        for r in preliminary_reps:
            representatives.append(list())
            for rrs in short_vectors:
                for rr in rrs:
                    if r - rr in self.__L_span:
                        representatives[-1].append(tuple(rr))

                if len(representatives[-1]) != 0:
                    break

        # This is a list of lists.  All elements in the interior lists
        # have the same norm and the set of first elements of the interior
        # lists is a set of representatives for ZZ^N / L ZZ^N
        self._r_representatives = representatives

        representatives = list()
        for rs in self._r_representatives:
            if any(r in representatives
                   or tuple(map(operator.neg, r)) in representatives
                   for r in rs):
                continue

            for ri in rs[0]:
                if ri > 0:
                    representatives.append(rs[0])
                    break
                if ri < 0:
                    representatives.append(tuple(map(operator.neg, rs[0])))
                    break
            else:
                representatives.append(rs[0])

        self._r_reduced_representatives = representatives
Example #17
0
    nmb_forms_coords = row_groups[-1][2] + row_groups[-1][3]
    ch1 = JacobiFormD1WeightCharacter(k)
    for (s, m, start, length) in row_groups:
        row_labels_dict = row_labels[m]
        for f in jacobi_forms[m].graded_submodule(None).basis():
            f = f.fourier_expansion()
            v = vector(ZZ, len(row_labels_dict))
            for (l, i) in row_labels_dict.iteritems():
                v[i] = f[(ch1, l)]

            forms.append(
                vector(start * [0] + v.list() +
                       (nmb_forms_coords - start - length) * [0]))

    if relation_precision == precision:
        restriction_expansion = FreeModule(QQ, nmb_forms_coords).span(forms)
    else:
        restriction_expansion_matrix__big = matrix(len(forms),
                                                   nmb_forms_coords,
                                                   forms).transpose()
        restriction_expansion_matrix = restriction_expansion_matrix__big.matrix_from_rows(
            row_indices__small)

        restriction_expansion = restriction_expansion_matrix.column_module()

    restriction_expansions = global_restriction_matrix.column_module(
    ).intersection(restriction_expansion)
    restriction_pullback =   global_restriction_matrix.solve_right(restriction_expansions.basis_matrix().transpose()).column_space() \
                           + global_restriction_matrix.right_kernel().change_ring(QQ)
    jacobi_expansions = restriction_pullback.intersection(
        global_relation_matrix.right_kernel())