def simplicial_complex(self): r""" Return a simplicial complex from a triangulation of the point configuration. OUTPUT: A :class:`~sage.homology.simplicial_complex.SimplicialComplex`. EXAMPLES:: sage: p = polytopes.cuboctahedron() sage: sc = p.triangulate(engine='internal').simplicial_complex() sage: sc Simplicial complex with 12 vertices and 16 facets Any convex set is contractable, so its reduced homology groups vanish:: sage: sc.homology() {0: 0, 1: 0, 2: 0, 3: 0} """ from sage.homology.simplicial_complex import SimplicialComplex from sage.misc.all import flatten vertex_set = set(flatten(self)) return SimplicialComplex(vertex_set = vertex_set, maximal_faces = self)
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 __init__(self, toric_variety, base_ring, check): r""" EXAMPLES:: sage: from sage.schemes.toric.chow_group import * sage: P2=toric_varieties.P2() sage: A = ChowGroup_class(P2,ZZ,True); A Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: is_ChowGroup(A) True sage: is_ChowCycle(A.an_element()) True TESTS:: sage: A_ZZ = P2.Chow_group() sage: 2 * A_ZZ.an_element() * 3 ( 6 | 0 | 0 ) sage: 1/2 * A_ZZ.an_element() * 1/3 Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for '*': 'Rational Field' and 'Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches' sage: A_ZZ.get_action(ZZ) Right scalar multiplication by Integer Ring on Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: A_ZZ.get_action(QQ) You can't multiply integer classes with fractional numbers. For that you need to go to the rational Chow group:: sage: A_QQ = P2.Chow_group(QQ) sage: 2 * A_QQ.an_element() * 3 ( 0 | 0 | 6 ) sage: 1/2 * A_QQ.an_element() * 1/3 ( 0 | 0 | 1/6 ) sage: A_QQ.get_action(ZZ) Right scalar multiplication by Integer Ring on QQ-Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: A_QQ.get_action(QQ) Right scalar multiplication by Rational Field on QQ-Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches """ self._variety = toric_variety # cones are automatically sorted by dimension self._cones = flatten( toric_variety.fan().cones() ) V = FreeModule(base_ring, len(self._cones)) W = self._rational_equivalence_relations(V) super(ChowGroup_class,self).__init__(V, W, check)
def __init__(self, toric_variety, base_ring, check): r""" EXAMPLES:: sage: from sage.schemes.toric.chow_group import * sage: P2=toric_varieties.P2() sage: A = ChowGroup_class(P2,ZZ,True); A Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: is_ChowGroup(A) True sage: is_ChowCycle(A.an_element()) True TESTS:: sage: A_ZZ = P2.Chow_group() sage: 2 * A_ZZ.an_element() * 3 ( 6 | 0 | 0 ) sage: 1/2 * A_ZZ.an_element() * 1/3 Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for *: 'Rational Field' and 'Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches' sage: A_ZZ.get_action(ZZ) Right scalar multiplication by Integer Ring on Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: A_ZZ.get_action(QQ) You can't multiply integer classes with fractional numbers. For that you need to go to the rational Chow group:: sage: A_QQ = P2.Chow_group(QQ) sage: 2 * A_QQ.an_element() * 3 ( 0 | 0 | 6 ) sage: 1/2 * A_QQ.an_element() * 1/3 ( 0 | 0 | 1/6 ) sage: A_QQ.get_action(ZZ) Right scalar multiplication by Integer Ring on QQ-Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches sage: A_QQ.get_action(QQ) Right scalar multiplication by Rational Field on QQ-Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches """ self._variety = toric_variety # cones are automatically sorted by dimension self._cones = flatten( toric_variety.fan().cones() ) V = FreeModule(base_ring, len(self._cones)) W = self._rational_equivalence_relations(V) super(ChowGroup_class,self).__init__(V, W, check)
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 _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)
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)