Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
        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
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
        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
Ejemplo n.º 6
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)
Ejemplo n.º 7
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)