Beispiel #1
0
    def _matrix_(self, R):
        r"""
        Return Sage matrix from this octave element.

        EXAMPLES::

            sage: A = octave('[1,2;3,4]')       # optional - octave
            sage: matrix(ZZ, A)                 # optional - octave
            [1 2]
            [3 4]
            sage: A = octave('[1,2;3,4.5]')     # optional - octave
            sage: matrix(RR, A)                 # optional - octave
            [1.00000000000000 2.00000000000000]
            [3.00000000000000 4.50000000000000]
        """
        from sage.matrix.all import MatrixSpace
        s = str(self).strip()
        v = s.split('\n ')
        nrows = len(v)
        if nrows == 0:
            return MatrixSpace(R,0,0)(0)
        ncols = len(v[0].split())
        M = MatrixSpace(R, nrows, ncols)
        v = sum([[x for x in w.split()] for w in v], [])
        return M(v)
Beispiel #2
0
      def _creation_by_determinant_helper(self, k, part):
        """
        EXAMPLES::
        
            sage: S = MacdonaldPolynomialsS(QQ)
            sage: a = S([2,1])
            sage: a._creation_by_determinant_helper(2,[1])
            (q^3*t-q^2*t-q+1)*McdS[2, 1] + (q^3-q^2*t-q+t)*McdS[3]
        """
        S = self.parent()
        q,t = S.q, S.t

        part += [0]*(k-len(part))

        if len(part) > k:
            raise ValueError, "the column to add is too small"

        #Create the matrix over the homogeneous symmetric
        #functions and take its determinant
        MS = MatrixSpace(sfa.SFAHomogeneous(S.base_ring()), k, k)
        h  = MS.base_ring()
        m = []
        for i in range(k):
            row = [0]*max(0, (i+1)-2-part[i])
            for j in range(max(0, (i+1)-2-part[i]),k):
                value = part[i]+j-i+1
                p = [value] if value > 0 else []
                row.append( (1-q**(part[i]+j-i+1)*t**(k-(j+1)))*h(p) )
            m.append(row)
        M = MS(m)
        res = M.det()

        #Convert to the Schurs
        res = S._s( res )
        return S._from_element(res)
Beispiel #3
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix
        base_ring = mat.base_ring()

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
        UCF = UniversalCyclotomicField()

        if R is None:
            R = UCF
        # if UCF.has_coerce_map_from(base_ring):
        #     R = UCF
        # else:
        #     R = base_ring

        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        if R is UCF:
            val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R(
                -2) if x > -1 else R.one() * x
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x

        MS = MatrixSpace(R, n, sparse=True)
        MC = MS._get_matrix_class()

        bilinear = MC(MS,
                      entries={(i, j): val(mat[i, j])
                               for i in range(n) for j in range(n)
                               if mat[i, j] != 2},
                      coerce=True,
                      copy=True)
        bilinear.set_immutable()
        return bilinear
Beispiel #4
0
    def _matrix_(self, R):
        r"""
        Return \sage matrix from this scilab element.

        EXAMPLES:
            sage: A = scilab('[1,2;3,4]')       # optional - scilab
            sage: matrix(ZZ, A)                 # optional - scilab
            [1 2]
            [3 4]
            sage: A = scilab('[1,2;3,4.5]')     # optional - scilab
            sage: matrix(RR, A)                 # optional - scilab
            [1.00000000000000 2.00000000000000]
            [3.00000000000000 4.50000000000000]
        """
        from sage.matrix.all import MatrixSpace
        from sage.rings.all import ZZ
        s = str(self).strip()
        v = s.split('\n ')
        nrows = len(v)
        if nrows == 0:
            return MatrixSpace(R,0,0)(0)
        ncols = len(v[0].split())
        M = MatrixSpace(R, nrows, ncols)
        v = sum([[x.rstrip('.') for x in w.split()] for w in v], [])
        return M(v)
Beispiel #5
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix
        base_ring = mat.base_ring()

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField

        UCF = UniversalCyclotomicField()
        if UCF.has_coerce_map_from(base_ring):
            R = UCF
        else:
            R = base_ring
        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        if R is UCF:
            val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R(-2) if x > -1 else R.one() * x
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x

        MS = MatrixSpace(R, n, sparse=True)
        MC = MS._get_matrix_class()

        bilinear = MC(
            MS,
            entries={(i, j): val(mat[i, j]) for i in range(n) for j in range(n) if mat[i, j] != 2},
            coerce=True,
            copy=True,
        )
        bilinear.set_immutable()
        return bilinear
Beispiel #6
0
    def _matrix_(self, R=None):
        r"""
        Return Sage matrix from this octave element.

        EXAMPLES::

            sage: A = octave('[1,2;3,4.5]')     # optional - octave
            sage: matrix(A)                     # optional - octave
            [1.0 2.0]
            [3.0 4.5]
            sage: _.base_ring()                 # optional - octave
            Real Double Field

            sage: A = octave('[I,1;-1,0]')      # optional - octave
            sage: matrix(A)                     # optional - octave
            [1.0*I   1.0]
            [ -1.0   0.0]
            sage: _.base_ring()                 # optional - octave
            Complex Double Field

            sage: A = octave('[1,2;3,4]')       # optional - octave
            sage: matrix(ZZ, A)                 # optional - octave
            [1 2]
            [3 4]
            sage: A = octave('[1,2;3,4.5]')     # optional - octave
            sage: matrix(RR, A)                 # optional - octave
            [1.00000000000000 2.00000000000000]
            [3.00000000000000 4.50000000000000]
        """
        oc = self.parent()
        if not self.ismatrix():
            raise TypeError('not an octave matrix')
        if R is None:
            R = self._get_sage_ring()

        s = str(self).strip('\n ')
        w = [u.strip().split(' ') for u in s.split('\n')]
        nrows = len(w)
        ncols = len(w[0])

        if self.iscomplex():
            w = [[to_complex(x,R) for x in row] for row in w]

        from sage.matrix.all import MatrixSpace
        s = str(self).strip()
        v = s.split('\n ')
        nrows = len(v)
        if nrows == 0:
            return MatrixSpace(R,0,0)(0)
        ncols = len(v[0].split())
        M = MatrixSpace(R, nrows, ncols)
        v = sum([[x for x in w.split()] for w in v], [])
        return M(v)
def matrix_clean_up(mat):
    r"""
    Apply get_cleaned_up_version to each object within
    each entry and return a cleaned up matrix
    """
    dim = mat.nrows()
    L = list()
    mat_space = MatrixSpace(CombinatorialScalarRing(),dim)
    prnt = mat_space.base_ring()
    for i in range(dim):
        L.append(list())
        for j in range(dim):
            L[i].append(CombinatorialScalarWrapper(mat[i,j].get_cleaned_up_version()))
    return mat_space(L)
def identity_matrix(dim):
    r"""
    Returns standard combinatorial identity matrix
    """
    mat_space = MatrixSpace(CombinatorialScalarRing(),dim)
    prnt = mat_space.base_ring()
    L = list()
    for i in range(dim):
        L.append(list())
        for j in range(dim):
            if i==j:
                L[i].append(prnt._one())
            else:
                L[i].append(prnt._zero())
    return mat_space(L)
def matrix_clean_up(mat):
    r"""
    Apply get_cleaned_up_version to each object within
    each entry and return a cleaned up matrix
    """
    dim = mat.nrows()
    L = list()
    mat_space = MatrixSpace(CombinatorialScalarRing(), dim)
    prnt = mat_space.base_ring()
    for i in range(dim):
        L.append(list())
        for j in range(dim):
            L[i].append(
                CombinatorialScalarWrapper(mat[i, j].get_cleaned_up_version()))
    return mat_space(L)
def identity_matrix(dim):
    r"""
    Returns standard combinatorial identity matrix
    """
    mat_space = MatrixSpace(CombinatorialScalarRing(), dim)
    prnt = mat_space.base_ring()
    L = list()
    for i in range(dim):
        L.append(list())
        for j in range(dim):
            if i == j:
                L[i].append(prnt._one())
            else:
                L[i].append(prnt._zero())
    return mat_space(L)
Beispiel #11
0
    def linear_space(self):
        r"""
        Return the space of the affine transformations represented as linear
        transformations.

        We can represent affine transformations `Ax + b` as linear
        transformations by

        .. MATH::

            \begin{pmatrix}
            A & b \\
            0 & 1
            \end{pmatrix}

        and lifting `x = (x_1, \ldots, x_n)` to `(x_1, \ldots, x_n, 1)`.

        .. SEEALSO::

            - :meth:`sage.groups.affine_gps.group_element.AffineGroupElement.matrix()`

        EXAMPLES::

            sage: G = AffineGroup(3, GF(5))
            sage: G.linear_space()
            Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 5
        """
        dp = self.degree() + 1
        return MatrixSpace(self.base_ring(), dp, dp)
Beispiel #12
0
def coxeter_matrix(t):
    """
    Returns the Coxeter matrix of type t.
    
    EXAMPLES::
    
        sage: coxeter_matrix(['A', 4])
        [1 3 2 2]
        [3 1 3 2]
        [2 3 1 3]
        [2 2 3 1]
        sage: coxeter_matrix(['B', 4])
        [1 3 2 2]
        [3 1 3 2]
        [2 3 1 4]
        [2 2 4 1]
        sage: coxeter_matrix(['C', 4])
        [1 3 2 2]
        [3 1 3 2]
        [2 3 1 4]
        [2 2 4 1]
        sage: coxeter_matrix(['D', 4])
        [1 3 2 2]
        [3 1 3 3]
        [2 3 1 2]
        [2 3 2 1]
    
    ::
    
        sage: coxeter_matrix(['E', 6])
        [1 2 3 2 2 2]
        [2 1 2 3 2 2]
        [3 2 1 3 2 2]
        [2 3 3 1 3 2]
        [2 2 2 3 1 3]
        [2 2 2 2 3 1]
    
    ::
    
        sage: coxeter_matrix(['F', 4])
        [1 3 2 2]
        [3 1 4 2]
        [2 4 1 3]
        [2 2 3 1]
    
    ::
    
        sage: coxeter_matrix(['G', 2])
        [1 6]
        [6 1]
    """
    ct = CartanType(t)
    cf = coxeter_matrix_as_function(ct)
    index_set = ct.index_set()
    MS = MatrixSpace(ZZ, len(index_set))
    m = MS(0)
    for i in range(len(index_set)):
        for j in range(len(index_set)):
            m[i, j] = cf(index_set[i], index_set[j])
    return m
def matrix_adjoint_lemma_40(mat):
    r"""
    Returns a matrix which is the target in the
    reduction of adjoint(A) times A to det(A) times I.
    """
    if mat.nrows() != mat.ncols():
        raise ValueError, "Make sure that this is indeed a Combinatorial Adjoint matrix"
    else:
        dim = mat.nrows()
        L = list()
        mat_space = MatrixSpace(CombinatorialScalarRing(), dim)
        for i in range(dim):
            L.append(list())
            for j in range(dim):
                if i == j:
                    copyset = deepcopy(mat[i, j].get_set())
                    for elm in copyset:
                        tmp = list(elm.get_object()[0].get_object())
                        #object is tuple, elements come from the actual tuple, hence double get_object()
                        index = tmp.index(CombinatorialObject('_', 1))
                        tmp[index] = elm.get_object()[1]
                        elm.set_object(tuple(tmp))
                else:
                    copyset = CombinatorialScalarWrapper(set())
                L[i].append(CombinatorialScalarWrapper(copyset))
        return mat_space(L)
def matrix_combinatorial_adjoint(mat):
    r"""
    Return Combinatorial Adjoint.
    """
    dim = mat.nrows()
    M = list()
    mat_space = MatrixSpace(CombinatorialScalarRing(), dim)
    prnt = mat_space.base_ring()
    #create list L of lists of sets, dimension is increased by one to mitigate index confusion
    L = list()
    for i in range(dim + 1):
        L.append(list())
        for j in range(dim + 1):
            L[i].append(set())
    P = Permutations(dim)
    for p in P:
        p_comb = CombinatorialScalarWrapper(
            [CombinatorialObject(p, p.signature())])
        l = list()
        for i in range(1, dim + 1):
            l.append(mat[p(i) - 1, i - 1])
        #This list will have empty sets, which will yield to an empty cartesian product
        #especially when the matrix input is triangular (except for the identity permutation).
        #We will now iterate through the selected entries in each column
        #and create a set of a singleton of an empty string that corresponds
        #to the "missing" element of the tuple described in definition 39.
        for i in range(1, dim + 1):
            copy_l = copy(l)
            copy_l[i - 1] = CombinatorialScalarWrapper(
                [CombinatorialObject('_', 1)])
            cp = CartesianProduct(p_comb, *copy_l)
            for tupel in cp:
                tupel = tuple(tupel)
                tupel_weight = 1
                tupel_sign = 1
                for elm in tupel:
                    tupel_sign = tupel_sign * elm.get_sign()
                    tupel_weight = tupel_weight * elm.get_weight()
                L[i][p(i)].add(
                    CombinatorialObject(tupel, tupel_sign, tupel_weight))
    #turn these sets into CombinatorialScalars
    for i in range(1, dim + 1):
        l = list()
        for j in range(1, dim + 1):
            l.append(CombinatorialScalarWrapper(L[i][j]))
        M.append(l)
    return mat_space(M)
Beispiel #15
0
    def module_composition_factors(self, algorithm=None):
        r"""
        Returns a list of triples consisting of [base field, dimension,
        irreducibility], for each of the Meataxe composition factors
        modules. The algorithm="verbose" option returns more information, but
        in Meataxe notation.

        EXAMPLES::

            sage: F=GF(3);MS=MatrixSpace(F,4,4)
            sage: M=MS(0)
            sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1
            sage: G = MatrixGroup([M])
            sage: G.module_composition_factors()
            [(Finite Field of size 3, 1, True),
             (Finite Field of size 3, 1, True),
             (Finite Field of size 3, 2, True)]
            sage: F = GF(7); MS = MatrixSpace(F,2,2)
            sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]
            sage: G = MatrixGroup(gens)
            sage: G.module_composition_factors()
            [(Finite Field of size 7, 2, True)]

        Type "G.module_composition_factors(algorithm='verbose')" to get a
        more verbose version.

        For more on MeatAxe notation, see
        http://www.gap-system.org/Manuals/doc/htm/ref/CHAP067.htm
        """
        from sage.misc.sage_eval import sage_eval
        F = self.base_ring()
        if not (F.is_finite()):
            raise NotImplementedError, "Base ring must be finite."
        q = F.cardinality()
        gens = self.gens()
        n = self.degree()
        MS = MatrixSpace(F, n, n)
        mats = []  # initializing list of mats by which the gens act on self
        W = self.matrix_space().row_space()
        for g in gens:
            p = MS(g.matrix())
            m = p.rows()
            mats.append(m)
        mats_str = str(gap([[list(r) for r in m] for m in mats]))
        gap.eval("M:=GModuleByMats(" + mats_str + ", GF(" + str(q) + "))")
        gap.eval("MCFs := MTX.CompositionFactors( M )")
        N = eval(gap.eval("Length(MCFs)"))
        if algorithm == "verbose":
            print gap.eval('MCFs') + "\n"
        L = []
        for i in range(1, N + 1):
            gap.eval("MCF := MCFs[%s]" % i)
            L.append(
                tuple([
                    sage_eval(gap.eval("MCF.field")),
                    eval(gap.eval("MCF.dimension")),
                    sage_eval(gap.eval("MCF.IsIrreducible"))
                ]))
        return sorted(L)
 def get_matrix_B(self):
     dim = self.get_dim()
     mat_space = MatrixSpace(CombinatorialScalarRing(), dim)
     L = list()
     for i in range(dim):
         L.append(list())
         for j in range(dim):
             L[i].append(self[i, j].get_B())
     return mat_space(L)
def matrix_combinatorial_adjoint(mat):
    r"""
    Return Combinatorial Adjoint.
    """
    dim = mat.nrows()
    M = list()
    mat_space = MatrixSpace(CombinatorialScalarRing(),dim)
    prnt = mat_space.base_ring()
    #create list L of lists of sets, dimension is increased by one to mitigate index confusion
    L = list()
    for i in range(dim+1):
        L.append(list())
        for j in range(dim+1):
            L[i].append(set())
    P = Permutations(dim)
    for p in P:
        p_comb = CombinatorialScalarWrapper([CombinatorialObject(p,p.signature())])
        l = list()
        for i in range(1,dim+1):
            l.append(mat[p(i)-1,i-1])
        #This list will have empty sets, which will yield to an empty cartesian product
        #especially when the matrix input is triangular (except for the identity permutation).
        #We will now iterate through the selected entries in each column
        #and create a set of a singleton of an empty string that corresponds 
        #to the "missing" element of the tuple described in definition 39.
        for i in range(1,dim+1):
            copy_l = copy(l)
            copy_l[i-1]=CombinatorialScalarWrapper([CombinatorialObject('_',1)])
            cp = CartesianProduct(p_comb,*copy_l)
            for tupel in cp:
                tupel = tuple(tupel)
                tupel_weight = 1
                tupel_sign = 1
                for elm in tupel:
                    tupel_sign = tupel_sign*elm.get_sign()
                    tupel_weight = tupel_weight*elm.get_weight()
                L[i][p(i)].add(CombinatorialObject(tupel,tupel_sign,tupel_weight))
    #turn these sets into CombinatorialScalars
    for i in range(1,dim+1):
        l = list()
        for j in range(1,dim+1):
            l.append(CombinatorialScalarWrapper(L[i][j]))
        M.append(l)
    return mat_space(M)
Beispiel #18
0
def find_mod2pow_splitting(i):
    P = F.primes_above(2)[0]
    if i == 1:
        R = ResidueRing(P, 1)
        M = MatrixSpace(R, 2)
        return [M(matrix_lift(a).list()) for a in find_mod2_splitting()]

    R = ResidueRing(P, i)
    M = MatrixSpace(R, 2)
    # arbitrary lift
    wbar = [M(matrix_lift(a).list()) for a in find_mod2pow_splitting(i - 1)]

    # Find lifts of wbar[1] and wbar[2] that have square -1
    k = P.residue_field()
    Mk = MatrixSpace(k, 2)

    t = 2**(i - 1)
    s = M(t)

    L = []
    for j in [1, 2]:
        C = Mk(matrix_lift(wbar[j]**2 + M(1)) / t)
        A = Mk(matrix_lift(wbar[j]))
        # Find all matrices B in Mk such that AB+BA=C.
        L.append([
            wbar[j] + s * M(matrix_lift(B)) for B in Mk if A * B + B * A == C
        ])

    g = M(F.gen())
    t = M(t)
    two = M(2)
    ginv = M(F.gen()**(-1))
    for w1 in L[0]:
        for w2 in L[1]:
            w0 = ginv * (two * g * wbar[3] - w1 - w2 - w1 * w2)
            w3 = g * w0 + w2 * w1
            if w0 * w0 != w0 - M(1):
                continue
            if w3 * w3 != M(-1):
                continue
            return w0, w1, w2, w3

    raise ValueError
Beispiel #19
0
        def _creation_by_determinant_helper(self, k, part):
            """
        EXAMPLES::
        
            sage: S = MacdonaldPolynomialsS(QQ)
            sage: a = S([2,1])
            sage: a._creation_by_determinant_helper(2,[1])
            (q^3*t-q^2*t-q+1)*McdS[2, 1] + (q^3-q^2*t-q+t)*McdS[3]
        """
            S = self.parent()
            q, t = S.q, S.t

            part += [0] * (k - len(part))

            if len(part) > k:
                raise ValueError, "the column to add is too small"

            #Create the matrix over the homogeneous symmetric
            #functions and take its determinant
            MS = MatrixSpace(sfa.SFAHomogeneous(S.base_ring()), k, k)
            h = MS.base_ring()
            m = []
            for i in range(k):
                row = [0] * max(0, (i + 1) - 2 - part[i])
                for j in range(max(0, (i + 1) - 2 - part[i]), k):
                    value = part[i] + j - i + 1
                    p = [value] if value > 0 else []
                    row.append(
                        (1 - q**(part[i] + j - i + 1) * t**(k -
                                                            (j + 1))) * h(p))
                m.append(row)
            M = MS(m)
            res = M.det()

            #Convert to the Schurs
            res = S._s(res)
            return S._from_element(res)
Beispiel #20
0
        def on_left_matrix(self, new_BR=None):
            """
            Returns the matrix of the action of self on the algebra my
            multiplication on the left

            If new_BR is specified, then the matrix will be over new_BR.

            TODO: split into to parts
             - build the endomorphism of multiplication on the left
             - build the matrix of an endomorphism

            EXAMPLES::

                sage: QS3 = SymmetricGroupAlgebra(QQ, 3)
                sage: a = QS3([2,1,3])
                sage: a.on_left_matrix()
                [0 0 1 0 0 0]
                [0 0 0 0 1 0]
                [1 0 0 0 0 0]
                [0 0 0 0 0 1]
                [0 1 0 0 0 0]
                [0 0 0 1 0 0]
                sage: a.on_left_matrix(RDF)
                [0.0 0.0 1.0 0.0 0.0 0.0]
                [0.0 0.0 0.0 0.0 1.0 0.0]
                [1.0 0.0 0.0 0.0 0.0 0.0]
                [0.0 0.0 0.0 0.0 0.0 1.0]
                [0.0 1.0 0.0 0.0 0.0 0.0]
                [0.0 0.0 0.0 1.0 0.0 0.0]

            AUTHOR: Mike Hansen
            """
            parent = self.parent()

            if parent.get_order() is None:
                cc = parent._combinatorial_class
            else:
                cc = parent.get_order()

            BR = parent.base_ring()
            if new_BR is None:
                new_BR = BR

            from sage.matrix.all import MatrixSpace
            MS = MatrixSpace(new_BR, parent.dimension(), parent.dimension())
            l = [(self * parent(m)).to_vector() for m in cc]
            return MS(l).transpose()
    def character_table(self):
        r"""
        Return the matrix of values of the irreducible characters of this
        group `G` at its conjugacy classes.

        The columns represent the conjugacy classes of
        `G` and the rows represent the different irreducible
        characters in the ordering given by GAP.

        OUTPUT: a matrix defined over a cyclotomic field

        EXAMPLES::

            sage: MatrixGroup(SymmetricGroup(2)).character_table()
            [ 1 -1]
            [ 1  1]
            sage: MatrixGroup(SymmetricGroup(3)).character_table()
            [ 1  1 -1]
            [ 2 -1  0]
            [ 1  1  1]
            sage: MatrixGroup(SymmetricGroup(5)).character_table()
            [ 1 -1 -1  1 -1  1  1]
            [ 4  0  1 -1 -2  1  0]
            [ 5  1 -1  0 -1 -1  1]
            [ 6  0  0  1  0  0 -2]
            [ 5 -1  1  0  1 -1  1]
            [ 4  0 -1 -1  2  1  0]
            [ 1  1  1  1  1  1  1]
        """
        #code from function in permgroup.py, but modified for
        #how gap handles these groups.
        G = self._gap_()
        cl = self.conjugacy_classes()
        from sage.rings.integer import Integer
        n = Integer(len(cl))
        irrG = G.Irr()
        ct = [[irrG[i][j] for j in range(n)] for i in range(n)]

        from sage.rings.all import CyclotomicField
        e = irrG.Flat().Conductor()
        K = CyclotomicField(e)
        ct = [[K(x) for x in v] for v in ct]

        # Finally return the result as a matrix.
        from sage.matrix.all import MatrixSpace
        MS = MatrixSpace(K, n)
        return MS(ct)
Beispiel #22
0
    def matrix_space(self):
        """
        Return the matrix space corresponding to this matrix group.

        This is a matrix space over the field of definition of this matrix
        group.

        EXAMPLES::

            sage: F = GF(5); MS = MatrixSpace(F,2,2)
            sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
            sage: G.matrix_space()
            Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5
            sage: G.matrix_space() is MS
            True
        """
        return MatrixSpace(self.base_ring(), self.degree())
Beispiel #23
0
    def solve_linear_system(self, A, b):
        """
        Use octave to compute a solution x to A\*x = b, as a list.

        INPUT:


        -  ``A`` - mxn matrix A with entries in QQ or RR

        -  ``b`` - m-vector b entries in QQ or RR (resp)


        OUTPUT: An list x (if it exists) which solves M\*x = b

        EXAMPLES::

            sage: M33 = MatrixSpace(QQ,3,3)
            sage: A   = M33([1,2,3,4,5,6,7,8,0])
            sage: V3  = VectorSpace(QQ,3)
            sage: b   = V3([1,2,3])
            sage: octave.solve_linear_system(A,b)    # optional - octave (and output is slightly random in low order bits)
            [-0.33333299999999999, 0.66666700000000001, -3.5236600000000002e-18]

        AUTHORS:

        - David Joyner and William Stein
        """
        m = A.nrows()
        n = A.ncols()
        if m != len(b):
            raise ValueError("dimensions of A and b must be compatible")
        from sage.matrix.all import MatrixSpace
        from sage.rings.all import QQ
        MS = MatrixSpace(QQ, m, 1)
        b = MS(list(b))  # converted b to a "column vector"
        sA = self.sage2octave_matrix_string(A)
        sb = self.sage2octave_matrix_string(b)
        self.eval("a = " + sA)
        self.eval("b = " + sb)
        soln = octave.eval("c = a \\ b")
        soln = soln.replace("\n\n ", "[")
        soln = soln.replace("\n\n", "]")
        soln = soln.replace("\n", ",")
        sol = soln[3:]
        return eval(sol)
Beispiel #24
0
    def matrix_space(self):
        """
        Return the space of matrices representing the general linear
        transformations.

        OUTPUT:

        The parent of the matrices `A` defining the affine group
        element `Ax+b`.

        EXAMPLES::

            sage: G = AffineGroup(3, GF(5))
            sage: G.matrix_space()
            Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 5
        """
        d = self.degree()
        return MatrixSpace(self.base_ring(), d, d)
Beispiel #25
0
def hamilton_quatalg(R):
    """
    Hamilton quaternion algebra over the commutative ring R,
    constructed as a free algebra quotient.

    INPUT:
        - R -- a commutative ring

    OUTPUT:
        - Q -- quaternion algebra
        - gens -- generators for Q

    EXAMPLES::

        sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(ZZ)
        sage: H
        Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Integer Ring
        sage: i^2
        -1
        sage: i in H
        True

    Note that there is another vastly more efficient models for
    quaternion algebras in Sage; the one here is mainly for testing
    purposes::

        sage: R.<i,j,k> = QuaternionAlgebra(QQ,-1,-1)  # much fast than the above 
    """
    n = 3
    from sage.algebras.free_algebra import FreeAlgebra
    from sage.matrix.all import MatrixSpace
    A = FreeAlgebra(R, n, 'i')
    F = A.monoid()
    i, j, k = F.gens()
    mons = [F(1), i, j, k]
    M = MatrixSpace(R, 4)
    mats = [
        M([0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0]),
        M([0, 0, 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0]),
        M([0, 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0, 0, 0])
    ]
    H3 = FreeAlgebraQuotient(A, mons, mats, names=('i', 'j', 'k'))
    return H3, H3.gens()
Beispiel #26
0
    def matrix_space(self):
        """
        Return the matrix space corresponding to this matrix group.

        This is a matrix space over the field of definition of this matrix
        group.

        EXAMPLES::

            sage: F = GF(5); MS = MatrixSpace(F,2,2)
            sage: G = MatrixGroup([MS(1), MS([1,2,3,4])])
            sage: G.matrix_space()
            Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5
        """
        try:
            return self.__matrix_space
        except AttributeError:
            pass
        self.__matrix_space = MatrixSpace(self.field_of_definition(), self.__n)
        return self.__matrix_space
Beispiel #27
0
def find_mod2_splitting():
    P = F.primes_above(2)[0]
    k = P.residue_field()
    M = MatrixSpace(k, 2)
    V = k**4
    g = k.gen()  # image of golden ratio

    m1 = M(-1)
    sqrt_minus_1 = [(w, V(w.list())) for w in M if w * w == m1]
    one = M(1)
    v_one = V(one.list())
    for w1, v1 in sqrt_minus_1:
        for w2, v2 in sqrt_minus_1:
            w0 = (g - 1) * (w1 + w2 - w1 * w2)
            w3 = g * w0 + w2 * w1
            if w0 * w0 != w0 - 1:
                continue
            if w3 * w3 != -1:
                continue
            if V.span([w0.list(), v1, v2, w3.list()]).dimension() == 4:
                return w0, w1, w2, w3
Beispiel #28
0
    def as_permutation_group(self, algorithm=None):
        r"""
        Return a permutation group representation for the group.

        In most cases occurring in practice, this is a permutation
        group of minimal degree (the degree begin determined from
        orbits under the group action). When these orbits are hard to
        compute, the procedure can be time-consuming and the degree
        may not be minimal.

        INPUT:

        - ``algorithm`` -- ``None`` or ``'smaller'``. In the latter
          case, try harder to find a permutation representation of
          small degree.

        OUTPUT:

        A permutation group isomorphic to ``self``. The
        ``algorithm='smaller'`` option tries to return an isomorphic
        group of low degree, but is not guaranteed to find the
        smallest one.

        EXAMPLES::

            sage: MS = MatrixSpace(GF(2), 5, 5)
            sage: A = MS([[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0]])
            sage: G = MatrixGroup([A])
            sage: G.as_permutation_group()
            Permutation Group with generators [(1,2)]
            sage: MS = MatrixSpace( GF(7), 12, 12)
            sage: GG = gap("ImfMatrixGroup( 12, 3 )")
            sage: GG.GeneratorsOfGroup().Length()
            3
            sage: g1 = MS(eval(str(GG.GeneratorsOfGroup()[1]).replace("\n","")))
            sage: g2 = MS(eval(str(GG.GeneratorsOfGroup()[2]).replace("\n","")))
            sage: g3 = MS(eval(str(GG.GeneratorsOfGroup()[3]).replace("\n","")))
            sage: G = MatrixGroup([g1, g2, g3])
            sage: G.cardinality()
            21499084800
            sage: set_random_seed(0); current_randstate().set_seed_gap()
            sage: P = G.as_permutation_group()
            sage: P.cardinality()
            21499084800
            sage: P.degree()  # random output
            144
            sage: set_random_seed(3); current_randstate().set_seed_gap()
            sage: Psmaller = G.as_permutation_group(algorithm="smaller")
            sage: Psmaller.cardinality()
            21499084800
            sage: Psmaller.degree()  # random output
            108

        In this case, the "smaller" option returned an isomorphic group of
        lower degree. The above example used GAP's library of irreducible
        maximal finite ("imf") integer matrix groups to construct the
        MatrixGroup G over GF(7). The section "Irreducible Maximal Finite
        Integral Matrix Groups" in the GAP reference manual has more
        details.
        """
        # Note that the output of IsomorphismPermGroup() depends on
        # memory locations and will change if you change the order of
        # doctests and/or architecture
        from sage.groups.perm_gps.permgroup import PermutationGroup
        if not self.is_finite():
            raise NotImplementedError, "Group must be finite."
        n = self.degree()
        MS = MatrixSpace(self.base_ring(), n, n)
        mats = []  # initializing list of mats by which the gens act on self
        for g in self.gens():
            p = MS(g.matrix())
            m = p.rows()
            mats.append(m)
        mats_str = str(gap([[list(r) for r in m] for m in mats]))
        gap.eval("iso:=IsomorphismPermGroup(Group(" + mats_str + "))")
        if algorithm == "smaller":
            gap.eval(
                "small:= SmallerDegreePermutationRepresentation( Image( iso ) );"
            )
            C = gap("Image( small )")
        else:
            C = gap("Image( iso )")
        return PermutationGroup(gap_group=C)
Beispiel #29
0
def half_integral_weight_modform_basis(chi, k, prec):
    r"""
    A basis for the space of weight `k/2` forms with character
    `\chi`. The modulus of `\chi` must be divisible by
    `16` and `k` must be odd and `>1`.
    
    INPUT:
    
    
    -  ``chi`` - a Dirichlet character with modulus
       divisible by 16
    
    -  ``k`` - an odd integer = 1
    
    -  ``prec`` - a positive integer
    
    
    OUTPUT: a list of power series
    
    .. warning::

       1. This code is very slow because it requests computation of a
          basis of modular forms for integral weight spaces, and that
          computation is still very slow.
    
       2. If you give an input prec that is too small, then the output
          list of power series may be larger than the dimension of the
          space of half-integral forms.
    
    EXAMPLES:
    
    We compute some half-integral weight forms of level 16\*7
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16*7).0^2,3,30)
        [q - 2*q^2 - q^9 + 2*q^14 + 6*q^18 - 2*q^21 - 4*q^22 - q^25 + O(q^30),
         q^2 - q^14 - 3*q^18 + 2*q^22 + O(q^30),
         q^4 - q^8 - q^16 + q^28 + O(q^30),
         q^7 - 2*q^15 + O(q^30)]
    
    The following illustrates that choosing too low of a precision can
    give an incorrect answer.
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16*7).0^2,3,20)
        [q - 2*q^2 - q^9 + 2*q^14 + 6*q^18 + O(q^20),
         q^2 - q^14 - 3*q^18 + O(q^20),
         q^4 - 2*q^8 + 2*q^12 - 4*q^16 + O(q^20),
         q^7 - 2*q^8 + 4*q^12 - 2*q^15 - 6*q^16 + O(q^20),
         q^8 - 2*q^12 + 3*q^16 + O(q^20)]
    
    We compute some spaces of low level and the first few possible
    weights.
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 3, 10)
        []
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 5, 10)
        [q - 2*q^3 - 2*q^5 + 4*q^7 - q^9 + O(q^10)]
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 7, 10)
        [q - 2*q^2 + 4*q^3 + 4*q^4 - 10*q^5 - 16*q^7 + 19*q^9 + O(q^10),
         q^2 - 2*q^3 - 2*q^4 + 4*q^5 + 4*q^7 - 8*q^9 + O(q^10),
         q^3 - 2*q^5 - 2*q^7 + 4*q^9 + O(q^10)]
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 9, 10)
        [q - 2*q^2 + 4*q^3 - 8*q^4 + 14*q^5 + 16*q^6 - 40*q^7 + 16*q^8 - 57*q^9 + O(q^10),
         q^2 - 2*q^3 + 4*q^4 - 8*q^5 - 8*q^6 + 20*q^7 - 8*q^8 + 32*q^9 + O(q^10),
         q^3 - 2*q^4 + 4*q^5 + 4*q^6 - 10*q^7 - 16*q^9 + O(q^10),
         q^4 - 2*q^5 - 2*q^6 + 4*q^7 + 4*q^9 + O(q^10),
         q^5 - 2*q^7 - 2*q^9 + O(q^10)]

    This example once raised an error (see trac #5792).

    ::

        sage: half_integral_weight_modform_basis(trivial_character(16),9,10)
        [q - 2*q^2 + 4*q^3 - 8*q^4 + 4*q^6 - 16*q^7 + 48*q^8 - 15*q^9 + O(q^10),
         q^2 - 2*q^3 + 4*q^4 - 2*q^6 + 8*q^7 - 24*q^8 + O(q^10),
         q^3 - 2*q^4 - 4*q^7 + 12*q^8 + O(q^10),
         q^4 - 6*q^8 + O(q^10)]

    
    ALGORITHM: Basmaji (page 55 of his Essen thesis, "Ein Algorithmus
    zur Berechnung von Hecke-Operatoren und Anwendungen auf modulare
    Kurven", http://wstein.org/scans/papers/basmaji/).
    
    Let `S = S_{k+1}(\epsilon)` be the space of cusp forms of
    even integer weight `k+1` and character
    `\varepsilon = \chi \psi^{(k+1)/2}`, where `\psi`
    is the nontrivial mod-4 Dirichlet character. Let `U` be the
    subspace of `S \times S` of elements `(a,b)` such
    that `\Theta_2 a = \Theta_3 b`. Then `U` is
    isomorphic to `S_{k/2}(\chi)` via the map
    `(a,b) \mapsto a/\Theta_3`.
    """

    if chi.modulus() % 16:
        raise ValueError, "the character must have modulus divisible by 16"

    if not k % 2:
        raise ValueError, "k (=%s) must be odd" % k

    if k < 3:
        raise ValueError, "k (=%s) must be at least 3" % k

    chi = chi.minimize_base_ring()
    psi = chi.parent()(DirichletGroup(4, chi.base_ring()).gen())
    eps = chi * psi**((k + 1) // 2)
    eps = eps.minimize_base_ring()
    M = constructor.ModularForms(eps, (k + 1) // 2)
    C = M.cuspidal_subspace()
    B = C.basis()

    # This computation of S below -- of course --dominates the whole function.
    #from sage.misc.all import cputime
    #tm  = cputime()
    #print "Computing basis..."
    S = [f.q_expansion(prec) for f in B]
    #print "Time to compute basis", cputime(tm)

    T2 = theta2_qexp(prec)
    T3 = theta_qexp(prec)
    n = len(S)
    MS = MatrixSpace(M.base_ring(), 2 * n, prec)
    A = copy(MS.zero_matrix())

    for i in range(n):
        T2f = T2 * S[i]
        T3f = T3 * S[i]
        for j in range(prec):
            A[i, j] = T2f[j]
            A[n + i, j] = -T3f[j]

    B = A.kernel().basis()
    a_vec = [sum([b[i] * S[i] for i in range(n)]) for b in B]
    if len(a_vec) == 0:
        return []
    R = a_vec[0].parent()
    t3 = R(T3)
    return [R(a) / t3 for a in a_vec]
Beispiel #30
0
def cartan_matrix(t):
    """
    Returns the Cartan matrix corresponding to type t.
    
    EXAMPLES::
    
        sage: cartan_matrix(['A', 4])
        [ 2 -1  0  0]
        [-1  2 -1  0]
        [ 0 -1  2 -1]
        [ 0  0 -1  2]
        sage: cartan_matrix(['B', 6])
        [ 2 -1  0  0  0  0]
        [-1  2 -1  0  0  0]
        [ 0 -1  2 -1  0  0]
        [ 0  0 -1  2 -1  0]
        [ 0  0  0 -1  2 -1]
        [ 0  0  0  0 -2  2]
        sage: cartan_matrix(['C', 4])
        [ 2 -1  0  0]
        [-1  2 -1  0]
        [ 0 -1  2 -2]
        [ 0  0 -1  2]
        sage: cartan_matrix(['D', 6])
        [ 2 -1  0  0  0  0]
        [-1  2 -1  0  0  0]
        [ 0 -1  2 -1  0  0]
        [ 0  0 -1  2 -1 -1]
        [ 0  0  0 -1  2  0]
        [ 0  0  0 -1  0  2]
        sage: cartan_matrix(['E',6])
        [ 2  0 -1  0  0  0]
        [ 0  2  0 -1  0  0]
        [-1  0  2 -1  0  0]
        [ 0 -1 -1  2 -1  0]
        [ 0  0  0 -1  2 -1]
        [ 0  0  0  0 -1  2]
        sage: cartan_matrix(['E',7])
        [ 2  0 -1  0  0  0  0]
        [ 0  2  0 -1  0  0  0]
        [-1  0  2 -1  0  0  0]
        [ 0 -1 -1  2 -1  0  0]
        [ 0  0  0 -1  2 -1  0]
        [ 0  0  0  0 -1  2 -1]
        [ 0  0  0  0  0 -1  2]
        sage: cartan_matrix(['E', 8])
        [ 2  0 -1  0  0  0  0  0]
        [ 0  2  0 -1  0  0  0  0]
        [-1  0  2 -1  0  0  0  0]
        [ 0 -1 -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 -1]
        [ 0  0  0  0  0  0 -1  2]
        sage: cartan_matrix(['F', 4])
        [ 2 -1  0  0]
        [-1  2 -1  0]
        [ 0 -2  2 -1]
        [ 0  0 -1  2]
    
    This is different from MuPAD-Combinat, due to different node
    convention?
    
    ::
    
        sage: cartan_matrix(['G', 2])
        [ 2 -3]
        [-1  2]
        sage: cartan_matrix(['A',1,1])
        [ 2 -2]
        [-2  2]
        sage: cartan_matrix(['A', 3, 1])
        [ 2 -1  0 -1]
        [-1  2 -1  0]
        [ 0 -1  2 -1]
        [-1  0 -1  2]
        sage: cartan_matrix(['B', 3, 1])
        [ 2  0 -1  0]
        [ 0  2 -1  0]
        [-1 -1  2 -1]
        [ 0  0 -2  2]
        sage: cartan_matrix(['C', 3, 1])
        [ 2 -1  0  0]
        [-2  2 -1  0]
        [ 0 -1  2 -2]
        [ 0  0 -1  2]
        sage: cartan_matrix(['D', 4, 1])
        [ 2  0 -1  0  0]
        [ 0  2 -1  0  0]
        [-1 -1  2 -1 -1]
        [ 0  0 -1  2  0]
        [ 0  0 -1  0  2]
        sage: cartan_matrix(['E', 6, 1])
        [ 2  0 -1  0  0  0  0]
        [ 0  2  0 -1  0  0  0]
        [-1  0  2  0 -1  0  0]
        [ 0 -1  0  2 -1  0  0]
        [ 0  0 -1 -1  2 -1  0]
        [ 0  0  0  0 -1  2 -1]
        [ 0  0  0  0  0 -1  2]
        sage: cartan_matrix(['E', 7, 1])
        [ 2 -1  0  0  0  0  0  0]
        [-1  2  0 -1  0  0  0  0]
        [ 0  0  2  0 -1  0  0  0]
        [ 0 -1  0  2 -1  0  0  0]
        [ 0  0 -1 -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]
        sage: cartan_matrix(['E', 8, 1])
        [ 2  0  0  0  0  0  0  0 -1]
        [ 0  2  0 -1  0  0  0  0  0]
        [ 0  0  2  0 -1  0  0  0  0]
        [ 0 -1  0  2 -1  0  0  0  0]
        [ 0  0 -1 -1  2 -1  0  0  0]
        [ 0  0  0  0 -1  2 -1  0  0]
        [ 0  0  0  0  0 -1  2 -1  0]
        [ 0  0  0  0  0  0 -1  2 -1]
        [-1  0  0  0  0  0  0 -1  2]
        sage: cartan_matrix(['F', 4, 1])
        [ 2 -1  0  0  0]
        [-1  2 -1  0  0]
        [ 0 -1  2 -1  0]
        [ 0  0 -2  2 -1]
        [ 0  0  0 -1  2]
        sage: cartan_matrix(['G', 2, 1])
        [ 2  0 -1]
        [ 0  2 -3]
        [-1 -1  2]
    """
    t = cartan_type.CartanType(t)
    dynkin_diagram = t.dynkin_diagram()
    index_set = t.index_set()
    MS = MatrixSpace(ZZ, len(index_set), sparse=True)
    m = MS(0)
    for i in range(len(index_set)):
        for j in range(len(index_set)):
            m[i, j] = dynkin_diagram[index_set[i], index_set[j]]
    return m
Beispiel #31
0
    def _compute(self, verbose=False):
        """
        Computes the list of curves, the matrix and prime-degree
        isogenies.

        EXAMPLES::

            sage: K.<i> = QuadraticField(-1)
            sage: E = EllipticCurve(K, [0,0,0,0,1])
            sage: C = E.isogeny_class()
            sage: C2 = C.copy()
            sage: C2._mat
            sage: C2._compute()
            sage: C2._mat
            [1 3 6 2]
            [3 1 2 6]
            [6 2 1 3]
            [2 6 3 1]

            sage: C2._compute(verbose=True)
            possible isogeny degrees: [2, 3] -actual isogeny degrees: {2, 3} -added curve #1 (degree 2)... -added tuple [0, 1, 2]... -added tuple [1, 0, 2]... -added curve #2 (degree 3)... -added tuple [0, 2, 3]... -added tuple [2, 0, 3]...... relevant degrees: [2, 3]... -now completing the isogeny class... -processing curve #1... -added tuple [1, 0, 2]... -added tuple [0, 1, 2]... -added curve #3... -added tuple [1, 3, 3]... -added tuple [3, 1, 3]... -processing curve #2... -added tuple [2, 3, 2]... -added tuple [3, 2, 2]... -added tuple [2, 0, 3]... -added tuple [0, 2, 3]... -processing curve #3... -added tuple [3, 2, 2]... -added tuple [2, 3, 2]... -added tuple [3, 1, 3]... -added tuple [1, 3, 3]...... isogeny class has size 4
            Sorting permutation = {0: 1, 1: 2, 2: 0, 3: 3}
            Matrix = [1 3 6 2]
            [3 1 2 6]
            [6 2 1 3]
            [2 6 3 1]

        TESTS:

        Check that :trac:`19030` is fixed (codomains of reverse isogenies were wrong)::

            sage: K.<i> = NumberField(x^2+1)
            sage: E = EllipticCurve([1, i + 1, 1, -72*i + 8, 95*i + 146])
            sage: C = E.isogeny_class()
            sage: curves = C.curves
            sage: isos = C.isogenies()
            sage: isos[0][3].codomain() == curves[3]
            True

        """
        from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix, unfill_isogeny_matrix
        from sage.matrix.all import MatrixSpace
        from sage.sets.set import Set
        self._maps = None

        E = self.E.global_minimal_model(semi_global=True)

        degs = possible_isogeny_degrees(E)
        if verbose:
            import sys
            sys.stdout.write(" possible isogeny degrees: %s" % degs)
            sys.stdout.flush()
        isogenies = E.isogenies_prime_degree(degs)
        if verbose:
            sys.stdout.write(" -actual isogeny degrees: %s" % Set([phi.degree() for phi in isogenies]))
            sys.stdout.flush()
        # Add all new codomains to the list and collect degrees:
        curves = [E]
        ncurves = 1
        degs = []
        # tuples (i,j,l,phi) where curve i is l-isogenous to curve j via phi
        tuples = []

        def add_tup(t):
            for T in [t, [t[1],t[0],t[2],0]]:
                if not T in tuples:
                    tuples.append(T)
                    if verbose:
                        sys.stdout.write(" -added tuple %s..." % T[:3])
                        sys.stdout.flush()

        for phi in isogenies:
            E2 = phi.codomain()
            d = ZZ(phi.degree())
            if not any([E2.is_isomorphic(E3) for E3 in curves]):
                curves.append(E2)
                if verbose:
                    sys.stdout.write(" -added curve #%s (degree %s)..." % (ncurves,d))
                    sys.stdout.flush()
                add_tup([0,ncurves,d,phi])
                ncurves += 1
                if not d in degs:
                    degs.append(d)
        if verbose:
            sys.stdout.write("... relevant degrees: %s..." % degs)
            sys.stdout.write(" -now completing the isogeny class...")
            sys.stdout.flush()

        i = 1
        while i < ncurves:
            E1 = curves[i]
            if verbose:
                sys.stdout.write(" -processing curve #%s..." % i)
                sys.stdout.flush()

            isogenies = E1.isogenies_prime_degree(degs)

            for phi in isogenies:
                E2 = phi.codomain()
                d = phi.degree()
                js = [j for j,E3 in enumerate(curves) if E2.is_isomorphic(E3)]
                if js: # seen codomain already -- up to isomorphism
                    j = js[0]
                    if phi.codomain()!=curves[j]:
                        iso = E2.isomorphism_to(curves[j])
                        phi.set_post_isomorphism(iso)
                    assert phi.domain()==curves[i] and phi.codomain()==curves[j]
                    add_tup([i,j,d,phi])
                else:
                    curves.append(E2)
                    if verbose:
                        sys.stdout.write(" -added curve #%s..." % ncurves)
                        sys.stdout.flush()
                    add_tup([i,ncurves,d,phi])
                    ncurves += 1
            i += 1

        if verbose:
            print("... isogeny class has size %s" % ncurves)

        # key function for sorting
        if E.has_rational_cm():
            key_function = lambda E: (-E.cm_discriminant(),flatten([list(ai) for ai in E.ainvs()]))
        else:
            key_function = lambda E: flatten([list(ai) for ai in E.ainvs()])

        self.curves = sorted(curves,key=key_function)
        perm = dict([(i,self.curves.index(E)) for i,E in enumerate(curves)])
        if verbose:
            print("Sorting permutation = %s" % perm)

        mat = MatrixSpace(ZZ,ncurves)(0)
        self._maps = [[0]*ncurves for i in range(ncurves)]
        for i,j,l,phi in tuples:
            if phi!=0:
                mat[perm[i],perm[j]] = l
                self._maps[perm[i]][perm[j]] = phi
        self._mat = fill_isogeny_matrix(mat)
        if verbose:
            print("Matrix = %s" % self._mat)

        if not E.has_rational_cm():
            self._qfmat = None
            return

        # In the CM case, we will have found some "horizontal"
        # isogenies of composite degree and would like to replace them
        # by isogenies of prime degree, mainly to make the isogeny
        # graph look better.  We also construct a matrix whose entries
        # are not degrees of cyclic isogenies, but rather quadratic
        # forms (in 1 or 2 variables) representing the isogeny
        # degrees.  For this we take a short cut: properly speaking,
        # when `\text{End}(E_1)=\text{End}(E_2)=O`, the set
        # `\text{Hom}(E_1,E_2)` is a rank `1` projective `O`-module,
        # hence has a well-defined ideal class associated to it, and
        # hence (using an identification between the ideal class group
        # and the group of classes of primitive quadratic forms of the
        # same discriminant) an equivalence class of quadratic forms.
        # But we currently only care about the numbers represented by
        # the form, i.e. which genus it is in rather than the exact
        # class.  So it suffices to find one form of the correct
        # discriminant which represents one isogeny degree from `E_1`
        # to `E_2` in order to obtain a form which represents all such
        # degrees.

        if verbose:
            print("Creating degree matrix (CM case)")

        allQs = {} # keys: discriminants d
                   # values: lists of equivalence classes of
                   # primitive forms of discriminant d
        def find_quadratic_form(d,n):
            if not d in allQs:
                from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives

                allQs[d] = BinaryQF_reduced_representatives(d, primitive_only=True)
            # now test which of the Qs represents n
            for Q in allQs[d]:
                if Q.solve_integer(n):
                    return Q
            raise ValueError("No form of discriminant %d represents %s" %(d,n))

        mat = self._mat
        qfmat = [[0 for i in range(ncurves)] for j in range(ncurves)]
        for i, E1 in enumerate(self.curves):
            for j, E2 in enumerate(self.curves):
                if j<i:
                    qfmat[i][j] = qfmat[j][i]
                    mat[i,j] = mat[j,i]
                elif i==j:
                    qfmat[i][j] = [1]
                    # mat[i,j] already 1
                else:
                    d = E1.cm_discriminant()
                    if d != E2.cm_discriminant():
                        qfmat[i][j] = [mat[i,j]]
                        # mat[i,j] already unique
                    else: # horizontal isogeny
                        q = find_quadratic_form(d,mat[i,j])
                        qfmat[i][j] = list(q)
                        mat[i,j] = q.small_prime_value()

        self._mat = mat
        self._qfmat = qfmat
        if verbose:
            print("new matrix = %s" % mat)
            print("matrix of forms = %s" % qfmat)
Beispiel #32
0
    def _compute(self):
        """
        Computes the list of curves, and possibly the matrix and
        prime-degree isogenies (depending on the algorithm selected).

        EXAMPLES::

            sage: isocls = EllipticCurve('48a1').isogeny_class('sage',use_tuple=False).copy()
            sage: isocls._mat
            sage: isocls._compute(); isocls._mat
            [0 2 2 2 0 0]
            [2 0 0 0 2 2]
            [2 0 0 0 0 0]
            [2 0 0 0 0 0]
            [0 2 0 0 0 0]
            [0 2 0 0 0 0]
        """
        algorithm = self._algorithm
        from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix, unfill_isogeny_matrix
        from sage.matrix.all import MatrixSpace
        self._maps = None
        if algorithm == "mwrank":
            try:
                E = self.E.mwrank_curve()
            except ValueError:
                E = self.E.minimal_model().mwrank_curve()
            I, A = E.isogeny_class(verbose=self._verbose)
            self._mat = MatrixSpace(ZZ, len(A))(A)
            self.curves = tuple(
                [constructor.EllipticCurve(ainvs) for ainvs in I])
        elif algorithm == "database":
            try:
                label = self.E.cremona_label(space=False)
            except RuntimeError:
                raise RuntimeError("unable to to find %s in the database" %
                                   self.E)
            db = sage.databases.cremona.CremonaDatabase()
            curves = db.isogeny_class(label)
            if len(curves) == 0:
                raise RuntimeError("unable to to find %s in the database" %
                                   self.E)
            # All curves will have the same conductor and isogeny class,
            # and there are are most 8 of them, so lexicographic sorting is okay.
            self.curves = tuple(sorted(curves,
                                       key=lambda E: E.cremona_label()))
            self._mat = None
        elif algorithm == "sage":
            curves = [self.E.minimal_model()]
            ijl_triples = []
            l_list = None
            i = 0
            while i < len(curves):
                E = curves[i]
                isogs = E.isogenies_prime_degree(l_list)
                for phi in isogs:
                    Edash = phi.codomain()
                    l = phi.degree()
                    # look to see if Edash is new.  Note that the
                    # curves returned by isogenies_prime_degree() are
                    # standard minimal models, so it suffices to check
                    # equality rather than isomorphism here.
                    try:
                        j = curves.index(Edash)
                    except ValueError:
                        j = len(curves)
                        curves.append(Edash)
                    ijl_triples.append((i, j, l, phi))
                if l_list is None:
                    l_list = [l for l in set([ZZ(f.degree()) for f in isogs])]
                i = i + 1
            self.curves = tuple(curves)
            ncurves = len(curves)
            self._mat = MatrixSpace(ZZ, ncurves)(0)
            self._maps = [[0] * ncurves for i in range(ncurves)]
            for i, j, l, phi in ijl_triples:
                self._mat[i, j] = l
                self._maps[i][j] = phi
        else:
            raise ValueError, "unknown algorithm '%s'" % algorithm
Beispiel #33
0
def ag_code(C, D, E):
    r"""
    INPUT:
        C -- a plane curve over a finite field F of prime order
        D -- a divisor on C
        E -- P1 + ... + Pn, another divisor, a sum of distinct
             points on X whose support is disjoint from that
             of D and with n > deg(D) > 0.

    OUTPUT:
        The linear code defined by C, D, and E as in Stichtenoth.

    Calls Singular's \code{BrillNoether functions}.  Will break on some
    singular curves or if the field size is too large, etc.; when
    this happens a ??? exception is raised.

    EXAMPLES:
        sage: x,y,z = ProjectiveSpace(2, GF(17), names = 'xyz').gens()
        sage: C   = Curve(y^2*z^7 - x^9 - x*z^8)
        sage: pts = C.rational_points(sorted=False)
        sage: D   = C.divisor([(3,pts[0]), (-1,pts[1]), (10,pts[5])]); D
        3*(0 : 0 : 1) - (0 : 1 : 0) + 10*(11 : 0 : 1)
        sage: E   = add([C.divisor(p) for p in [pts[2],pts[3],pts[4]]]); E
        (1 : 11 : 1) + (1 : 6 : 1) + (10 : 0 : 1)
        sage: V = ag_code(C, D,E)
        sage: V
        Linear code of length 2, dimension 2 over Finite Field of size 17
        sage: V.basis()
        [(12, 12), (11, 11), (12, 12), (2, 2), (2, 2), (3, 14), (13, 4), (7, 7), (7, 10)]

        sage: P2 = ProjectiveSpace(2, GF(11), names = ['x','y','z'])
        sage: x, y, z = P2.coordinate_ring().gens()
        sage: f = y^8 + x^8 - z^8
        sage: C = Curve(f)
        sage: pts = C.rational_points()
        sage: D = C.divisor(pts[0])*10 - C.divisor(pts[1]) + C.divisor(pts[5])*10
        sage: E = add([C.divisor(pts[i]) for i in [2,3,4,6,7,8,9,10,11]])
        sage: V = ag_code(C, D,E); V
        Linear code of length 8, dimension 2 over Finite Field of size 11
        sage: V.basis()
        [(6, 6), (11, 11), (13, 13), (13, 13), (15, 15), (8, 9), (3, 14), (7, 7), (9, 8)]

        sage: P2 = ProjectiveSpace(2, GF(11), names = ['x','y','z'])
        sage: x, y, z = P2.coordinate_ring().gens()
        sage: f = x^3*y - y^3*z + z^3*x
        sage: C = Curve(f)
        sage: pts = C.rational_points(sorted=False)
        sage: D = C.divisor(pts[0])*3 - C.divisor(pts[1]) + C.divisor(pts[5])*5
        sage: len(C.riemann_roch_basis(D))
        5
        sage: E = add([C.divisor(pts[i]) for i in [2,3,4,6,7,8,9,10,11]])
        sage: V = ag_code(C, D,E); V
        Linear code of length 8, dimension 5 over Finite Field of size 11
        sage: V.basis()
        [(1, 8, 4, 1, 10, 1, 5, 8), (2, 8, 1, 7, 3, 5, 8, 2), (1, 7, 4, 7, 5, 7, 4, 9), (0, 7, 0, 9, 5, 8, 6, 3), (6, 10, 1, 4, 6, 4, 8, 0)]
        sage: V.minimum_distance()
        3

    AUTHOR: David Joyner (2006-01)
    """
    F = C.base_ring()
    one = F(1)
    B = C.riemann_roch_basis(D)
    k = len(B)
    if k == 0:
        A = MatrixSpace(F, 0, 0)(0)
        return sage.coding.all.LinearCode(A)

    P = C.rational_points(algorithm="bn", sorted=False)  # algorithm="bn" does not work here ....

    N = len(P)
    pts = copy.copy(E.support())
    for p in pts:
        for i in range(k):
            if (B[i].denominator())(F(p[0]), F(p[1]), F(p[2])) == 0:
                pts.remove(p)
                break

    MS = MatrixSpace(F, len(B), len(pts))
    pts.sort()
    G = [[B[i](F(p[0]), F(p[1]), F(p[2])) for p in pts] for i in range(k)]
    G = MS(G)
    return linear_code.LinearCode(G)
Beispiel #34
0
def hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False):
    r"""
    Given a basis `B` of `q`-expansions for a space of modular forms
    with character `\varepsilon` to precision at least `\#B\cdot n+1`,
    this function computes the matrix of `T_n` relative to `B`.

    .. note::

       If the elements of B are not known to sufficient precision,
       this function will report that the vectors are linearly
       dependent (since they are to the specified precision).

    INPUT:

    - ``B`` - list of q-expansions

    - ``n`` - an integer >= 1

    - ``k`` - an integer

    - ``eps`` - Dirichlet character

    - ``already_echelonized`` -- bool (default: False); if True, use that the
      basis is already in Echelon form, which saves a lot of time.

    EXAMPLES::

        sage: sage.modular.modform.constructor.ModularForms_clear_cache()
        sage: ModularForms(1,12).q_expansion_basis()
        [
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6),
        1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6)
        ]
        sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(), 3, 12)
        Traceback (most recent call last):
        ...
        ValueError: The given basis vectors must be linearly independent.

        sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(30), 3, 12)
        [   252      0]
        [     0 177148]

    TESTS:

    This shows that the problem with finite fields reported at trac #8281 is solved::

        sage: bas_mod5 = [f.change_ring(GF(5)) for f in victor_miller_basis(12, 20)]
        sage: hecke_operator_on_basis(bas_mod5, 2, 12)
        [4 0]
        [0 1]

    This shows that empty input is handled sensibly (trac #12202)::

        sage: x = hecke_operator_on_basis([], 3, 12); x
        []
        sage: x.parent()
        Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 1 and degree 1
        sage: y = hecke_operator_on_basis([], 3, 12, eps=DirichletGroup(13).0^2); y
        []
        sage: y.parent()
        Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 12 and degree 4
    """
    if not isinstance(B, (list, tuple)):
        raise TypeError, "B (=%s) must be a list or tuple" % B
    if len(B) == 0:
        if eps is None:
            R = CyclotomicField(1)
        else:
            R = eps.base_ring()
        return MatrixSpace(R, 0)(0)
    f = B[0]
    R = f.base_ring()
    if eps is None:
        eps = DirichletGroup(1, R).gen(0)
    all_powerseries = True
    for x in B:
        if not is_PowerSeries(x):
            all_powerseries = False
    if not all_powerseries:
        raise TypeError, "each element of B must be a power series"
    n = Integer(n)
    k = Integer(k)
    prec = (f.prec() - 1) // n
    A = R**prec
    V = A.span_of_basis([g.padded_list(prec) for g in B],
                        already_echelonized=already_echelonized)
    return _hecke_operator_on_basis(B, V, n, k, eps)
Beispiel #35
0
def half_integral_weight_modform_basis(chi, k, prec):
    r"""
    A basis for the space of weight `k/2` forms with character
    `\chi`. The modulus of `\chi` must be divisible by
    `16` and `k` must be odd and `>1`.
    
    INPUT:
    
    
    -  ``chi`` - a Dirichlet character with modulus
       divisible by 16
    
    -  ``k`` - an odd integer = 1
    
    -  ``prec`` - a positive integer
    
    
    OUTPUT: a list of power series
    
    .. warning::

       1. This code is very slow because it requests computation of a
          basis of modular forms for integral weight spaces, and that
          computation is still very slow.
    
       2. If you give an input prec that is too small, then the output
          list of power series may be larger than the dimension of the
          space of half-integral forms.
    
    EXAMPLES:
    
    We compute some half-integral weight forms of level 16\*7
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16*7).0^2,3,30)
        [q - 2*q^2 - q^9 + 2*q^14 + 6*q^18 - 2*q^21 - 4*q^22 - q^25 + O(q^30),
         q^2 - q^14 - 3*q^18 + 2*q^22 + O(q^30),
         q^4 - q^8 - q^16 + q^28 + O(q^30),
         q^7 - 2*q^15 + O(q^30)]
    
    The following illustrates that choosing too low of a precision can
    give an incorrect answer.
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16*7).0^2,3,20)
        [q - 2*q^2 - q^9 + 2*q^14 + 6*q^18 + O(q^20),
         q^2 - q^14 - 3*q^18 + O(q^20),
         q^4 - 2*q^8 + 2*q^12 - 4*q^16 + O(q^20),
         q^7 - 2*q^8 + 4*q^12 - 2*q^15 - 6*q^16 + O(q^20),
         q^8 - 2*q^12 + 3*q^16 + O(q^20)]
    
    We compute some spaces of low level and the first few possible
    weights.
    
    ::
    
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 3, 10)
        []
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 5, 10)
        [q - 2*q^3 - 2*q^5 + 4*q^7 - q^9 + O(q^10)]
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 7, 10)
        [q - 2*q^2 + 4*q^3 + 4*q^4 - 10*q^5 - 16*q^7 + 19*q^9 + O(q^10),
         q^2 - 2*q^3 - 2*q^4 + 4*q^5 + 4*q^7 - 8*q^9 + O(q^10),
         q^3 - 2*q^5 - 2*q^7 + 4*q^9 + O(q^10)]
        sage: half_integral_weight_modform_basis(DirichletGroup(16,QQ).1, 9, 10)
        [q - 2*q^2 + 4*q^3 - 8*q^4 + 14*q^5 + 16*q^6 - 40*q^7 + 16*q^8 - 57*q^9 + O(q^10),
         q^2 - 2*q^3 + 4*q^4 - 8*q^5 - 8*q^6 + 20*q^7 - 8*q^8 + 32*q^9 + O(q^10),
         q^3 - 2*q^4 + 4*q^5 + 4*q^6 - 10*q^7 - 16*q^9 + O(q^10),
         q^4 - 2*q^5 - 2*q^6 + 4*q^7 + 4*q^9 + O(q^10),
         q^5 - 2*q^7 - 2*q^9 + O(q^10)]

    This example once raised an error (see trac #5792).

    ::

        sage: half_integral_weight_modform_basis(trivial_character(16),9,10)
        [q - 2*q^2 + 4*q^3 - 8*q^4 + 4*q^6 - 16*q^7 + 48*q^8 - 15*q^9 + O(q^10),
         q^2 - 2*q^3 + 4*q^4 - 2*q^6 + 8*q^7 - 24*q^8 + O(q^10),
         q^3 - 2*q^4 - 4*q^7 + 12*q^8 + O(q^10),
         q^4 - 6*q^8 + O(q^10)]

    
    ALGORITHM: Basmaji (page 55 of his Essen thesis, "Ein Algorithmus
    zur Berechnung von Hecke-Operatoren und Anwendungen auf modulare
    Kurven", http://wstein.org/scans/papers/basmaji/).
    
    Let `S = S_{k+1}(\epsilon)` be the space of cusp forms of
    even integer weight `k+1` and character
    `\varepsilon = \chi \psi^{(k+1)/2}`, where `\psi`
    is the nontrivial mod-4 Dirichlet character. Let `U` be the
    subspace of `S \times S` of elements `(a,b)` such
    that `\Theta_2 a = \Theta_3 b`. Then `U` is
    isomorphic to `S_{k/2}(\chi)` via the map
    `(a,b) \mapsto a/\Theta_3`.
    """

    if chi.modulus() % 16:
        raise ValueError, "the character must have modulus divisible by 16"
    
    if not k%2:
        raise ValueError, "k (=%s) must be odd"%k

    if k < 3:
        raise ValueError, "k (=%s) must be at least 3"%k

    chi = chi.minimize_base_ring()
    psi = chi.parent()(DirichletGroup(4, chi.base_ring()).gen())
    eps = chi*psi**((k+1) // 2)
    eps = eps.minimize_base_ring()
    M   = constructor.ModularForms(eps, (k+1)//2)
    C   = M.cuspidal_subspace()
    B   = C.basis()

    # This computation of S below -- of course --dominates the whole function.
    #from sage.misc.all import cputime
    #tm  = cputime()
    #print "Computing basis..."
    S   = [f.q_expansion(prec) for f in B]
    #print "Time to compute basis", cputime(tm)

    T2  = theta2_qexp(prec)
    T3  = theta_qexp(prec)
    n   = len(S)
    MS  = MatrixSpace(M.base_ring(), 2*n, prec)
    A   = copy(MS.zero_matrix())
    
    for i in range(n):
        T2f = T2*S[i]
        T3f = T3*S[i]
        for j in range(prec):
            A[i, j] = T2f[j]
            A[n+i, j] = -T3f[j]

    B = A.kernel().basis()
    a_vec = [sum([b[i]*S[i] for i in range(n)]) for b in B]
    if len(a_vec) == 0:
        return []
    R = a_vec[0].parent()
    t3 = R(T3)
    return [R(a) / t3 for a in a_vec]