예제 #1
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

        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} )`.
        E = UCF.gen
        if R is UCF:

            def val(x):
                if x > -1:
                    return (E(2 * x) + ~E(2 * x)) / R(-2)
                else:
                    return R(x)
        elif is_QuadraticField(R):

            def val(x):
                if x > -1:
                    return R(
                        (E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) / R(-2)
                else:
                    return R(x)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            def val(x):
                if x > -1:
                    return -R(cos(pi / SR(x)))
                else:
                    return R(x)

        entries = [
            SparseEntry(i, j, val(mat[i, j])) for i in range(n)
            for j in range(n) if mat[i, j] != 2
        ]
        bilinear = Matrix(R, n, entries)
        bilinear.set_immutable()
        return bilinear
예제 #2
0
    def cusp_reduction_table(self):
        r'''
        Returns a dictionary and the set of cusps.

        Assumes we have a finite set surjecting to the cusps (namely, P^1(O_F/N)). Runs through
        and computes a subset which represents the cusps, and shows how to go from any element 
        of P^1(O_F/N) to the chosen equivalent cusp.

        Takes as input the object representing P^1(O_F/N), where F is a number field
        (that is possibly Q), and N is some ideal in the field.  Runs the following algorithm:
                - take a remaining element C = (c:d) of P^1(O_F/N);
                - add this to the set of cusps, declaring it to be our chosen rep;
                - run through every translate C' = (c':d') of C under the stabiliser of infinity, and
                        remove this translate from the set of remaining elements;
                - store the matrix T in the stabiliser such that C' * T = C (as elements in P^1)
                        in the dictionary, with key C'.
        '''
        P = self.get_P1List()
        if hasattr(P.N(),'number_field'):
            K = P.N().number_field()
        else:
            K = QQ

        # from sage.modular.modsym.p1list_nf import lift_to_sl2_Ok
        from .my_p1list_nf import lift_to_sl2_Ok
        from sage.modular.modsym.p1list import lift_to_sl2z
        ## Define new function on the fly to pick which of Q/more general field we work in
        ## lift_to_matrix takes parameters c,d, then lifts (c:d) to a 2X2 matrix over the NF representing it
        lift_to_matrix = lambda c, d: lift_to_sl2z(c,d,P.N()) if K.degree() == 1 else lift_to_sl2_Ok(P.N(), c, d)

        ## Put all the points of P^1(O_F/N) into a list; these will corr. to our dictionary keys
        remaining_points = set(list(P)) if K == QQ else set([c.tuple() for c in P])
        reduction_table = {}
        cusp_set = []

        initial_points = len(remaining_points)

        ## Loop over all points of P^1(O_F/N)
        while len(remaining_points) > 0:
            ## Pick a new cusp representative
            c = remaining_points.pop()
            update_progress(1 - float(len(remaining_points)) / float(initial_points), "Finding cusps...")
            ## c is an MSymbol so not hashable. Create tuple that is
            ## Represent the cusp as a matrix, add to list of cusps, and add to dictionary
            new_cusp = Matrix(2,2,lift_to_matrix(c[0], c[1])) 
            new_cusp.set_immutable()
            cusp_set.append(new_cusp)
            reduction_table[c]=(new_cusp,matrix(2,2,1)) ## Set the value to I_2
            ## Now run over the whole orbit of this point under the stabiliser at infinity.
            ## For each elt of the orbit, explain how to reduce to the chosen cusp.

            ## Run over lifts of elements of O_F/N:
            if K == QQ:
                residues = Zmod(P.N())
                units = [1, -1]
            else:
                residues = P.N().residues()
                units = K.roots_of_unity()

            for hh in residues:
                h = K(hh) ## put into the number field
                ## Run over all finite order units in the number field
                for u in units:
                    ## Now have the matrix (u,h; 0,u^-1).
                    ## Compute the action of this matrix on c
                    new_c = P.normalize(u * c[0], u**-1 * c[1] + h * c[0])
                    if K != QQ: 
                        new_c = new_c.tuple()
                    if new_c not in reduction_table:
                        ## We've not seen this point before! But it's equivalent to c, so kill it!
                        ## (and also store the matrix we used to get to it)
                        remaining_points.remove(new_c)
                        T = matrix(2,2,[u,h,0,u**-1]) ## we used this matrix to get from c to new_c
                        reduction_table[new_c]=(new_cusp, T) ## update dictionary with the new_c + the matrix
                        if K != QQ:
                            assert P.normalize(*(vector(c) * T)).tuple() == new_c ## sanity check
                        else:
                            assert P.normalize(*(vector(c) * T)) == new_c ## sanity check

        return reduction_table, cusp_set