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
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