Ejemplo n.º 1
0
    def small_rhombicuboctahedron(self, exact=True, base_ring=None):
        """
        Return the (small) rhombicuboctahedron.

        The rhombicuboctahedron is an Archimedean solid with 24 vertices and 26
        faces. See the :wikipedia:`Rhombicuboctahedron` for more information.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        - ``base_ring`` -- the ring in which the coordinates will belong to. If
          it is not provided and ``exact=True`` it will be a the number field
          `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it
          will be the real double field.

        EXAMPLES::

            sage: sr = polytopes.small_rhombicuboctahedron()
            sage: sr.f_vector()
            (1, 24, 48, 26, 1)
            sage: sr.volume()
            80/3*sqrt2 + 32

        The faces are `8` equilateral triangles and `18` squares::

            sage: sum(1 for f in sr.faces(2) if len(f.vertices()) == 3)
            8
            sage: sum(1 for f in sr.faces(2) if len(f.vertices()) == 4)
            18

        Its non exact version::

            sage: sr = polytopes.small_rhombicuboctahedron(False)
            sage: sr
            A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24
            vertices
            sage: sr.f_vector()
            (1, 24, 48, 26, 1)
        """
        if base_ring is None and exact:
            from sage.rings.number_field.number_field import QuadraticField
            K = QuadraticField(2, 'sqrt2')
            sqrt2 = K.gen()
            base_ring = K
        else:
            if base_ring is None:
                base_ring = RDF
            sqrt2 = base_ring(2).sqrt()

        one = base_ring.one()
        a = sqrt2 + one
        verts = []
        verts.extend([s1*one, s2*one, s3*a] for s1,s2,s3 in itertools.product([1,-1], repeat=3))
        verts.extend([s1*one, s3*a, s2*one] for s1,s2,s3 in itertools.product([1,-1], repeat=3))
        verts.extend([s1*a, s2*one, s3*one] for s1,s2,s3 in itertools.product([1,-1], repeat=3))
        return Polyhedron(vertices=verts)
Ejemplo n.º 2
0
    def great_rhombicuboctahedron(self, exact=True, base_ring=None):
        """
        Return the great rhombicuboctahedron.

        The great rohombicuboctahedron (or truncated cuboctahedron) is an
        Archimedean solid with 48 vertices and 26 faces. For more information
        see the :wikipedia:`Truncated_cuboctahedron`.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        - ``base_ring`` -- the ring in which the coordinates will belong to. If
          it is not provided and ``exact=True`` it will be a the number field
          `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it
          will be the real double field.

        EXAMPLES::

            sage: gr = polytopes.great_rhombicuboctahedron()  # long time ~ 3sec
            sage: gr.f_vector()                               # long time
            (1, 48, 72, 26, 1)

        A faster implementation is obtained by setting ``exact=False``::

            sage: gr = polytopes.great_rhombicuboctahedron(exact=False)
            sage: gr.f_vector()
            (1, 48, 72, 26, 1)

        Its faces are 4 squares, 8 regular hexagons and 6 regular octagons::

            sage: sum(1 for f in gr.faces(2) if len(f.vertices()) == 4)
            12
            sage: sum(1 for f in gr.faces(2) if len(f.vertices()) == 6)
            8
            sage: sum(1 for f in gr.faces(2) if len(f.vertices()) == 8)
            6
        """
        if base_ring is None and exact:
            from sage.rings.number_field.number_field import QuadraticField
            K = QuadraticField(2, 'sqrt2')
            sqrt2 = K.gen()
            base_ring = K
        else:
            if base_ring is None:
                base_ring = RDF
            sqrt2 = base_ring(2).sqrt()

        one = base_ring.one()
        v1 = sqrt2 + 1
        v2 = 2*sqrt2 + 1
        verts = [ [s1*z1, s2*z2, s3*z3]
                       for z1,z2,z3 in itertools.permutations([one,v1,v2])
                       for s1,s2,s3 in itertools.product([1,-1], repeat=3)]
        return Polyhedron(vertices=verts, base_ring=base_ring)
Ejemplo n.º 3
0
    def six_hundred_cell(self, exact=False):
        """
        Return the standard 600-cell polytope.

        The 600-cell is a 4-dimensional regular polytope. In many ways this is
        an analogue of the icosahedron.

        .. WARNING::

            The coordinates are not exact by default. The computation with exact
            coordinates takes a huge amount of time.

        INPUT:

        - ``exact`` - (boolean, default ``False``) if ``True`` use exact
          coordinates instead of floating point approximations

        EXAMPLES::

            sage: p600 = polytopes.six_hundred_cell()
            sage: p600
            A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 120 vertices
            sage: p600.f_vector()
            (1, 120, 720, 1200, 600, 1)

        Computation with exact coordinates is currently too long to be useful::

            sage: p600 = polytopes.six_hundred_cell(exact=True) # not tested - very long time
            sage: len(list(p600.bounded_edges()))               # not tested - very long time
            120
        """
        if exact:
            from sage.rings.number_field.number_field import QuadraticField
            K = QuadraticField(5, 'sqrt5')
            sqrt5 = K.gen()
            g = (1 + sqrt5) / 2
            base_ring = K
        else:
            g = (1 + RDF(5).sqrt()) / 2
            base_ring = RDF

        q12 = base_ring(1) / base_ring(2)
        z   = base_ring.zero()
        verts = [[s1*q12, s2*q12, s3*q12, s4*q12] for s1,s2,s3,s4 in itertools.product([1,-1], repeat=4)]
        V = (base_ring)**4
        verts.extend(V.basis())
        verts.extend(-v for v in V.basis())
        pts = [[s1 * q12, s2*g/2, s3/(2*g), z] for (s1,s2,s3) in itertools.product([1,-1], repeat=3)]
        for p in AlternatingGroup(4):
            verts.extend(p(x) for x in pts)
        return Polyhedron(vertices=verts, base_ring=base_ring)
Ejemplo n.º 4
0
	def __init__(self, D):
		self.D = D
		assert (D*D - D) % 4 == 0
		self.field = QuadraticField(D)
		self.maxorder = self.field.maximal_order()
		self.Droot = self.field(D).sqrt()
		self.DrootHalf_coordinates_in_terms_of_powers = (self.Droot / 2).coordinates_in_terms_of_powers()
Ejemplo n.º 5
0
    def is_quasigeometric(self):
        """
        Decide whether the binary recurrence sequence is degenerate and similar to a geometric sequence,
        i.e. the union of multiple geometric sequences, or geometric after term ``u0``.

        If `\\alpha/\\beta` is a `k` th root of unity, where `k>1`, then necessarily `k = 2, 3, 4, 6`.
        Then `F = [[0,1],[c,b]` is diagonalizable, and `F^k = [[\\alpha^k, 0], [0,\\beta^k]]` is scaler
        matrix.  Thus for all values of `j` mod `k`, the `j` mod `k` terms of `u_n` form a geometric
        series.

        If `\\alpha` or `\\beta` is zero, this implies that `c=0`.  This is the case when `F` is
        singular.  In this case, `u_1, u_2, u_3, ...` is geometric.

        EXAMPLES::

            sage: S = BinaryRecurrenceSequence(0,1)
            sage: [S(i) for i in range(10)]
            [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
            sage: S.is_quasigeometric()
            True

            sage: R = BinaryRecurrenceSequence(3,0)
            sage: [R(i) for i in range(10)]
            [0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561]
            sage: R.is_quasigeometric()
            True
        """

        #First test if F is singular... i.e. beta = 0
        if self.c == 0:
            return True

        #Otherwise test if alpha/beta is a root of unity that is not 1
        else:
            if (self.b**2+4*self.c) != 0:    #thus alpha/beta != 1

                if (self.b**2+4*self.c).is_square():
                    A = sqrt((self.b**2+4*self.c))

                else:
                    K = QuadraticField((self.b**2+4*self.c), 'x')
                    A = K.gen()

                if ((self.b+A)/(self.b-A))**(6) == 1:
                    return True

        return False
Ejemplo n.º 6
0
    def icosidodecahedron(self, exact=True):
        """
        Return the Icosidodecahedron

        The Icosidodecahedron is a polyhedron with twenty triangular faces and
        twelve pentagonal faces. For more information see the
        :wikipedia:`Icosidodecahedron`.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        EXAMPLES::

            sage: gr = polytopes.icosidodecahedron()
            sage: gr.f_vector()
            (1, 30, 60, 32, 1)

        TESTS::

            sage: polytopes.icosidodecahedron(exact=False)
            A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 30 vertices
        """
        from sage.rings.number_field.number_field import QuadraticField
        from itertools import product

        K = QuadraticField(5, 'sqrt5')
        one = K.one()
        phi = (one+K.gen())/2

        gens = [((-1)**a*one/2, (-1)**b*phi/2, (-1)**c*(one+phi)/2)
                  for a,b,c in product([0,1],repeat=3)]
        gens.extend([(0,0,phi), (0,0,-phi)])

        verts = []
        for p in AlternatingGroup(3):
            verts.extend(p(x) for x in gens)

        if exact:
            return Polyhedron(vertices=verts,base_ring=K)
        else:
            verts = [(RR(x),RR(y),RR(z)) for x,y,z in verts]
            return Polyhedron(vertices=verts)
Ejemplo n.º 7
0
    def is_quasigeometric(self):
        """
        Decide whether the binary recurrence sequence is degenerate and similar to a geometric sequence,
        i.e. the union of multiple geometric sequences, or geometric after term ``u0``.

        If `\\alpha/\\beta` is a `k` th root of unity, where `k>1`, then necessarily `k = 2, 3, 4, 6`.
        Then `F = [[0,1],[c,b]` is diagonalizable, and `F^k = [[\\alpha^k, 0], [0,\\beta^k]]` is scaler
        matrix.  Thus for all values of `j` mod `k`, the `j` mod `k` terms of `u_n` form a geometric
        series.

        If `\\alpha` or `\\beta` is zero, this implies that `c=0`.  This is the case when `F` is
        singular.  In this case, `u_1, u_2, u_3, ...` is geometric.

        EXAMPLES::

            sage: S = BinaryRecurrenceSequence(0,1)
            sage: [S(i) for i in range(10)]
            [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
            sage: S.is_quasigeometric()
            True

            sage: R = BinaryRecurrenceSequence(3,0)
            sage: [R(i) for i in range(10)]
            [0, 1, 3, 9, 27, 81, 243, 729, 2187, 6561]
            sage: R.is_quasigeometric()
            True
        """
        # First test if F is singular... i.e. beta = 0
        if self.c == 0:
            return True

        # Otherwise test if alpha/beta is a root of unity that is not 1
        D = self.b**2 + 4 * self.c
        if D != 0:  # thus alpha/beta != 1
            if D.is_square():
                A = sqrt(D)
            else:
                K = QuadraticField(D, 'x')
                A = K.gen()
            if ((self.b + A) / (self.b - A))**6 == 1:
                return True

        return False
Ejemplo n.º 8
0
    def __classcall_private__(cls, data, base_ring=None, index_set=None):
        """
        Normalize arguments to ensure a unique representation.

        EXAMPLES::

            sage: W1 = CoxeterGroup(['A',2], implementation="reflection", base_ring=ZZ)
            sage: W2 = CoxeterGroup([[1,3],[3,1]], index_set=(1,2))
            sage: W1 is W2
            True
            sage: G1 = Graph([(1,2)])
            sage: W3 = CoxeterGroup(G1)
            sage: W1 is W3
            True
            sage: G2 = Graph([(1,2,3)])
            sage: W4 = CoxeterGroup(G2)
            sage: W1 is W4
            True
        """
        data = CoxeterMatrix(data, index_set=index_set)

        if base_ring is None:
            if data.is_simply_laced():
                base_ring = ZZ
            elif data.is_finite():
                letter = data.coxeter_type().cartan_type().type()
                if letter in ['B', 'C', 'F']:
                    base_ring = QuadraticField(2)
                elif letter == 'G':
                    base_ring = QuadraticField(3)
                elif letter == 'H':
                    base_ring = QuadraticField(5)
                else:
                    base_ring = UniversalCyclotomicField()
            else:
                base_ring = UniversalCyclotomicField()
        return super(CoxeterMatrixGroup,
                     cls).__classcall__(cls, data, base_ring, data.index_set())
Ejemplo n.º 9
0
    def icosahedron(self, exact=True, base_ring=None):
        """
        Return an icosahedron with edge length 1.

        The icosahedron is one of the Platonic sold. It has 20 faces and is dual
        to the :meth:`dodecahedron`.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        - ``base_ring`` -- (optional) the ring in which the coordinates will
          belong to.  Note that this ring must contain `\sqrt(5)`. If it is not
          provided and ``exact=True`` it will be the number field
          `\QQ[\sqrt(5)]` and if ``exact=False`` it will be the real double
          field.

        EXAMPLES::

            sage: ico = polytopes.icosahedron()
            sage: ico.f_vector()
            (1, 12, 30, 20, 1)
            sage: ico.volume()
            5/12*sqrt5 + 5/4

        Its non exact version::

            sage: ico = polytopes.icosahedron(exact=False)
            sage: ico.base_ring()
            Real Double Field
            sage: ico.volume()
            2.1816949907715726

        A version using `AA <sage.rings.qqbar.AlgebraicRealField>`::

            sage: ico = polytopes.icosahedron(base_ring=AA)   # long time
            sage: ico.base_ring()                             # long time
            Algebraic Real Field
            sage: ico.volume()                                # long time
            2.181694990624913?

        Note that if base ring is provided it must contain the square root of
        `5`. Otherwise you will get an error::

            sage: polytopes.icosahedron(base_ring=QQ)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational
        """
        if base_ring is None and exact:
            from sage.rings.number_field.number_field import QuadraticField
            K = QuadraticField(5, 'sqrt5')
            sqrt5 = K.gen()
            g = (1 + sqrt5) / 2
            base_ring = K
        else:
            if base_ring is None:
                base_ring = RDF
            g = (1 + base_ring(5).sqrt()) / 2

        r12 = base_ring.one() / 2
        z = base_ring.zero()
        pts = [[z, s1*r12, s2*g/2] for s1,s2 in itertools.product([1,-1],repeat=2)]
        verts = [p(v) for p in AlternatingGroup(3) for v in pts]
        return Polyhedron(vertices=verts, base_ring=base_ring)
Ejemplo n.º 10
0
    def is_degenerate(self):
        """
        Decide whether the binary recurrence sequence is degenerate.

        Let `\\alpha` and `\\beta` denote the roots of the characteristic polynomial
        `p(x) = x^2-bx -c`.  Let `a = u_1-u_0\\beta/(\\beta - \\alpha)` and
        `b = u_1-u_0\\alpha/(\\beta - \\alpha)`.  The sequence is, thus, given by
        `u_n = a \\alpha^n - b\\beta^n`.  Then we say that the sequence is nondegenerate
        if and only if `a*b*\\alpha*\\beta \\neq 0` and `\\alpha/\\beta` is not a
        root of unity.

        More concretely, there are 4 classes of degeneracy, that can all be formulated
        in terms of the matrix `F = [[0,1], [c, b]]`.

        - `F` is singular --  this corresponds to ``c`` = 0, and thus `\\alpha*\\beta = 0`. This sequence is geometric after term ``u0`` and so we call it ``quasigeometric``.

        - `v = [[u_0], [u_1]]` is an eigenvector of `F` -- this corresponds to a ``geometric`` sequence with `a*b = 0`.

        - `F` is nondiagonalizable -- this corresponds to `\\alpha = \\beta`.  This sequence will be the point-wise product of an arithmetic and geometric sequence.

        - `F^k` is scaler, for some `k>1` -- this corresponds to `\\alpha/\\beta` a `k` th root of unity. This sequence is a union of several geometric sequences, and so we again call it ``quasigeometric``.

        EXAMPLES::

            sage: S = BinaryRecurrenceSequence(0,1)
            sage: S.is_degenerate()
            True
            sage: S.is_geometric()
            False
            sage: S.is_quasigeometric()
            True

            sage: R = BinaryRecurrenceSequence(3,-2)
            sage: R.is_degenerate()
            False

            sage: T = BinaryRecurrenceSequence(2,-1)
            sage: T.is_degenerate()
            True
            sage: T.is_arithmetic()
            True

        """

        if (self.b**2+4*self.c) != 0:

            if (self.b**2+4*self.c).is_square():
                A = sqrt((self.b**2+4*self.c))

            else:
                K = QuadraticField((self.b**2+4*self.c), 'x')
                A = K.gen()

            aa = (self.u1 - self.u0*(self.b + A)/2)/(A)        #called `a` in Docstring
            bb = (self.u1 - self.u0*(self.b - A)/2)/(A)        #called `b` in Docstring

            #(b+A)/2 is called alpha in Docstring, (b-A)/2 is called beta in Docstring

            if (self.b - A) != 0:
                if ((self.b+A)/(self.b-A))**(6) == 1:
                    return True
            else:
                return True

            if aa*bb*(self.b + A)*(self.b - A) == 0:
                return True
            return False
        return True
Ejemplo n.º 11
0
def _semistable_reducible_primes(E):
    r"""Find a list containing all semistable primes l unramified in K/QQ
    for which the Galois image for E could be reducible.

    INPUT:

    - ``E`` - EllipticCurve - over a number field.

    OUTPUT:

    A list of primes, which contains all primes `l` unramified in
    `K/\mathbb{QQ}`, such that `E` is semistable at all primes lying
    over `l`, and the Galois image at `l` is reducible. If `E` has CM
    defined over its ground field, a ``ValueError`` is raised.

    EXAMPLES::

        sage: E = EllipticCurve([0, -1, 1, -10, -20]) # X_0(11)
        sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._semistable_reducible_primes(E)
        True
    """

    E = _over_numberfield(E)
    K = E.base_field()
    deg_one_primes = K.primes_of_degree_one_iter()

    bad_primes = set([]) # This will store the output.

    # We find two primes (of distinct residue characteristics) which are
    # of degree 1, unramified in K/Q, and at which E has good reduction.
    # Both of these primes will give us a nontrivial divisibility constraint
    # on the exceptional primes l. For both of these primes P, we precompute
    # a generator and the trace of Frob_P^12.

    precomp = []
    last_char = 0 # The residue characteristic of the most recent prime.

    while len(precomp) < 2:
        P = next(deg_one_primes)

        if not P.is_principal():
            continue

        det = P.norm()
        if det == last_char:
            continue

        if P.ramification_index() != 1:
            continue

        if E.has_bad_reduction(P):
            continue

        tr = E.reduction(P).trace_of_frobenius()
        x = P.gens_reduced()[0]

        precomp.append((x, _tr12(tr, det)))
        last_char = det

    x, tx = precomp[0]
    y, ty = precomp[1]

    Kgal = K.galois_closure('b')
    maps = K.embeddings(Kgal)

    for i in range(2 ** (K.degree() - 1)):
        ## We iterate through all possible characters. ##

        # Here, if i = i_{l-1} i_{l-2} cdots i_1 i_0 in binary, then i
        # corresponds to the character prod sigma_j^{i_j}.

        phi1x = 1
        phi2x = 1
        phi1y = 1
        phi2y = 1

        # We compute the two algebraic characters at x and y:
        for j in range(K.degree()):
            if i % 2 == 1:
                phi1x *= maps[j](x)
                phi1y *= maps[j](y)
            else:
                phi2x *= maps[j](x)
                phi2y *= maps[j](y)
            i = int(i/2)

        # Any prime with reducible image must divide both of:
        gx = phi1x**12 + phi2x**12 - tx
        gy = phi1y**12 + phi2y**12 - ty

        if (gx != 0) or (gy != 0):
            for prime in Integer(Kgal.ideal([gx, gy]).norm()).prime_factors():
                bad_primes.add(prime)

            continue

        ## It is possible that our curve has CM. ##

        # Our character must be of the form Nm^K_F for an imaginary
        # quadratic subfield F of K (which is the CM field if E has CM).
        # We compute F:

        a = (Integer(phi1x + phi2x)**2 - 4 * x.norm()).squarefree_part()

        # See #19229: the name given here, which is not used, should
        # not be the name of the generator of the base field.
        F = QuadraticField(a, 'gal_rep_nf_sqrt_a')

        # Next, we turn K into relative number field over F.

        K = K.relativize(F.embeddings(K)[0], K.variable_name()+'0')
        E = E.change_ring(K.structure()[1])

        ## We try to find a nontrivial divisibility condition. ##

        patience = 5 * K.absolute_degree()
        # Number of Frobenius elements to check before suspecting that E
        # has CM and computing the set of CM j-invariants of K to check.
        # TODO: Is this the best value for this parameter?

        while True:
            P = next(deg_one_primes)

            if not P.is_principal():
                continue

            try:
                tr = E.change_ring(P.residue_field()).trace_of_frobenius()
            except ArithmeticError: # Bad reduction at P.
                continue

            x = P.gens_reduced()[0].norm(F)
            div = (x**12).trace() - _tr12(tr, x.norm())

            patience -= 1

            if div != 0:
                # We found our divisibility constraint.

                for prime in Integer(div).prime_factors():
                    bad_primes.add(prime)

                # Turn K back into an absolute number field.

                E = E.change_ring(K.structure()[0])
                K = K.structure()[0].codomain()

                break

            if patience == 0:
                # We suspect that E has CM, so we check:
                f = K.structure()[0]
                if f(E.j_invariant()) in cm_j_invariants(f.codomain()):
                    raise ValueError("The curve E should not have CM.")

    L = sorted(bad_primes)
    return L
Ejemplo n.º 12
0
class CurlO:
	"""
	This class defines some helper functions for calculations in \curlO,
	where \curlO is the maximal order of some quadratic imaginary number
	field \K = \QQ(\sqrt{D}), where `D` is some negative integer.

	For example, this class defines a function `xgcd` which implements the
	extended Euclidean algorithm. This is based on the `divmod`
	function, also in this class.

	When representing an element `b` in \curlO, we use the representation
	`b = b1 + b2 (D + \sqrt{D})/2` for b1,b2 \in \ZZ. This can be calculated
	via the functions `from_tuple_b` and `as_tuple_b`.
	"""

	def __init__(self, D):
		self.D = D
		assert (D*D - D) % 4 == 0
		self.field = QuadraticField(D)
		self.maxorder = self.field.maximal_order()
		self.Droot = self.field(D).sqrt()
		self.DrootHalf_coordinates_in_terms_of_powers = (self.Droot / 2).coordinates_in_terms_of_powers()

	def divmod(self, a, b):
		"""
		Returns q,r such that a = q*b + r.
		This is division with remainder.
		It holds that `self.euclidean_func(r) < `self.euclidean_func(b)`.
		"""
		# Note that this implementation is quite naive!
		# Later, we can do better with QuadraticForm(...). (TODO)
		# Also, read here: http://www.fen.bilkent.edu.tr/~franz/publ/survey.pdf

		if b == 0: raise ZeroDivisionError
		a1,a2 = self.as_tuple_b(a)
		b1,b2 = self.as_tuple_b(b)

		#B = matrix([
		#	[b1, -b2 * (self.D**2 - self.D)/4],
		#	[b2, b1 + b2*self.D]
		#])
		Bdet = b1*b1 + b1*b2*self.D + b2*b2*(self.D**2 - self.D)/4
		Bdet = _simplify(Bdet)
		assert Bdet > 0
		qq1 = (a1*b1 + a1*b2*self.D + a2*b2*(self.D**2 - self.D)/4) / Bdet
		qq2 = (-a1*b2 + a2*b1) / Bdet
		assert _simplify(self.from_tuple_b(qq1,qq2) * b - a) == 0

		# Not sure on this.
		# From qq1 and qq2, we want to select q1,q2 \in \Z such that
		# `r = a - q * b` is minimal with regards to `self.euclidean_func`,
		# where `q = self.from_tuple_b(q1,q2)`.
		# Simply using `round` will not work in all cases; neither does `floor`.
		# Many test cases are (indirectly) in `test_solveR()`.
		# Now we are just checking multiple possibilities and use
		# the smallest one. Note that these are not all possible cases.
		solutions = []
		for q1 in [int(floor(qq1)) + i for i in [-1,0,1,2]]:
			for q2 in [int(floor(qq2)) + i for i in [-1,0,1,2]]:
				q = self.from_tuple_b(q1,q2)
				# q * b + r == a
				r = _simplify(a - q * b)
				euc_r = self.euclidean_func(r)
				solutions += [(euc_r, q, r)]
		euc_b = self.euclidean_func(b)
		euc_r, q, r = min(solutions)
		assert euc_r < euc_b, "%r < %r; r=%r, b=%r, a=%r" % (euc_r, euc_b, r, b, a)
		return q, r

	def euclidean_func(self, x):
		"""
		The Euclidean function of x. (Returns just |x|.)
		"""
		return self.field(x).abs()

	def divides(self, a, b):
		"""
		Returns whether `b` divides `a` without remainder.
		"""
		q, r = self.divmod(a, b)
		return r == 0

	def xgcd(self, a, b):
		"""
		The extended Euclidean algorithm. Mostly a standard implementation
		with a few fast paths. For the generic case, it uses `self.divmod`.

		INPUT:

		- `a`, `b` -- two elements of `self.maxorder`.

		OUTPUT:

		- A tuple `(d, s, t)`, such that `d == a * s + b * t` and
		  `d` divides both `s` and `t`. `d` is the greatest common divisor.
		  These are all elements of `self.maxorder`.
		"""
		if a == b: return a, 1, 0
		if a == -b: return a, 1, 0
		if a == 1: return 1, 1, 0
		if b == 1: return 1, 0, 1
		if a == 0: return b, 0, 1
		if b == 0: return a, 1, 0
		a1,a2 = self.as_tuple_b(a)
		b1,b2 = self.as_tuple_b(b)
		if a2 == b2 == 0:
			return orig_xgcd(a1, b1)
		if a1 == b1 == 0:
			d,s,t = orig_xgcd(a2, b2)
			B2 = (self.D + self.Droot) / 2
			return d * B2, s, t

		# a,b = map(self.field, [a,b])
		# gcd = 1
		# factors_a,factors_b = [dict(list(x.factor())) for x in [a,b]]
		# for q in factors_a.keys():
		# 	if q in factors_b:
		# 		e = min(factors_a[q], factors_b[q])
		# 		factors_a[q] -= e
		# 		factors_b[q] -= e
		# 		gcd *= q * e

		a,b = map(self.maxorder, [a,b])

		euc_a = self.euclidean_func(a)
		euc_b = self.euclidean_func(b)
		if euc_a < euc_b:
			d,s,t = self.xgcd(b, a)
			return d,t,s
		# We have euc_b <= euc_a now.
		q,r = self.divmod(a, b)
		# q * b + r == a.
		assert q * b + r == a
		# => a - b*q == r
		d2,s2,t2 = self.xgcd(b, r)
		# d2 = b * s2 + r * t2
		assert d2 == b * s2 + r * t2
		# => d2 = b * s2 + (a - b*q) * t2
		# => d2 = a * t2 + b * (s2 - q * t2)
		d = d2
		s = _simplify(t2)
		t = _simplify(s2 - q * t2)
		assert d == a * s + b * t
		assert self.divides(a, d)
		assert self.divides(b, d)
		return d, s, t

	def gcd(self, a, b):
		"""
		INPUT:

		- `a`, `b` -- elements of `self.maxorder`.

		OUTPUT:

		- An element `d` of `self.maxorder`. `d` is the greatest common divisor.
		"""
		d,_,_ = self.xgcd(a, b)
		return d

	def common_denom(self, *args):
		"""
		INPUT:

		- `*args` -- elements from `self.field`.

		OUTPUT:

		- The smallest element `d` of `self.maxorder` such that
		  `d * arg` is in `self.maxorder`, for all `arg` in `args`.
		"""
		tupleargs = [None] * len(args) * 2
		for i in range(len(args)):
			tupleargs[2*i],tupleargs[2*i+1] = self.as_tuple_b(args[i])
		return matrix(QQ, 1,len(tupleargs), tupleargs).denominator()

	def matrix_denom(self, mat):
		"""
		INPUT:

		- `mat` -- matrix over `self.field`.

		OUTPUT:

		- The smallest element `d` of `self.maxorder` such that
		  `d * mat` is over `self.maxorder`.
		"""
		denom = self.common_denom(*mat.list())
		denom = int(ZZ(denom))
		for v in mat.list():
			assert v * denom in self, "%r (D=%r)" % (mat, self.D)
		return denom

	def as_tuple_b(self, a):
		"""
		INPUT:

		- `a` -- an element in `self.field`.

		OUTPUT:

		- A tuple of rationals `(b1,b2)`, where `a = b1 + b2 (D + \sqrt{D})/2`.

		If `a` is in `self.maxorder`, `b1` and `b2` are integers.
		"""
		real_part, b2 = self.DrootHalf_coordinates_in_terms_of_powers(a)
		b1 = real_part - b2 * self.D / 2
		return (b1, b2)

	def from_tuple_b(self, b1, b2):
		"""
		INPUT:

		- `b1`,`b2` -- rational numbers.

		OUTPUT:

		- An element `b` in `self.field` with `b = b1 + b2 (D + \sqrt{D})/2`.

		If `b1`,`b2` are integers, `b` is in `self.maxorder`.
		"""
		b1 = QQ(b1)
		b2 = QQ(b2)
		return self.field(b1 + b2 * (self.D + self.Droot) / 2)

	def __contains__(self, item):
		"""
		Returns whether `item` is an element of `self.maxorder`.
		"""
		try:
			b1,b2 = self.as_tuple_b(item)
			b1,b2 = ZZ(b1), ZZ(b2)
		except TypeError: return False
		else: return True
Ejemplo n.º 13
0
def test_contains_imaginary_quadratic_field(D):
    K = QuadraticField(D)
    result = contains_imaginary_quadratic_field(K)
    assert result == (D < 0)
Ejemplo n.º 14
0
    def small_rhombicuboctahedron(self, exact=True, base_ring=None):
        """
        Return the (small) rhombicuboctahedron.

        The rhombicuboctahedron is an Archimedean solid with 24 vertices and 26
        faces. See the :wikipedia:`Rhombicuboctahedron` for more information.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        - ``base_ring`` -- the ring in which the coordinates will belong to. If
          it is not provided and ``exact=True`` it will be a the number field
          `\QQ[\phi]` where `\phi` is the golden ratio and if ``exact=False`` it
          will be the real double field.

        EXAMPLES::

            sage: sr = polytopes.small_rhombicuboctahedron()
            sage: sr.f_vector()
            (1, 24, 48, 26, 1)
            sage: sr.volume()
            80/3*sqrt2 + 32

        The faces are `8` equilateral triangles and `18` squares::

            sage: sum(1 for f in sr.faces(2) if len(f.vertices()) == 3)
            8
            sage: sum(1 for f in sr.faces(2) if len(f.vertices()) == 4)
            18

        Its non exact version::

            sage: sr = polytopes.small_rhombicuboctahedron(False)
            sage: sr
            A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 24
            vertices
            sage: sr.f_vector()
            (1, 24, 48, 26, 1)
        """
        if base_ring is None and exact:
            from sage.rings.number_field.number_field import QuadraticField
            K = QuadraticField(2, 'sqrt2')
            sqrt2 = K.gen()
            base_ring = K
        else:
            if base_ring is None:
                base_ring = RDF
            sqrt2 = base_ring(2).sqrt()

        one = base_ring.one()
        a = sqrt2 + one
        verts = []
        verts.extend([s1 * one, s2 * one, s3 * a]
                     for s1, s2, s3 in itertools.product([1, -1], repeat=3))
        verts.extend([s1 * one, s3 * a, s2 * one]
                     for s1, s2, s3 in itertools.product([1, -1], repeat=3))
        verts.extend([s1 * a, s2 * one, s3 * one]
                     for s1, s2, s3 in itertools.product([1, -1], repeat=3))
        return Polyhedron(vertices=verts)
Ejemplo n.º 15
0
    def icosahedron(self, exact=True, base_ring=None):
        """
        Return an icosahedron with edge length 1.

        The icosahedron is one of the Platonic sold. It has 20 faces and is dual
        to the :meth:`dodecahedron`.

        INPUT:

        - ``exact`` -- (boolean, default ``True``) If ``False`` use an
          approximate ring for the coordinates.

        - ``base_ring`` -- (optional) the ring in which the coordinates will
          belong to.  Note that this ring must contain `\sqrt(5)`. If it is not
          provided and ``exact=True`` it will be the number field
          `\QQ[\sqrt(5)]` and if ``exact=False`` it will be the real double
          field.

        EXAMPLES::

            sage: ico = polytopes.icosahedron()
            sage: ico.f_vector()
            (1, 12, 30, 20, 1)
            sage: ico.volume()
            5/12*sqrt5 + 5/4

        Its non exact version::

            sage: ico = polytopes.icosahedron(exact=False)
            sage: ico.base_ring()
            Real Double Field
            sage: ico.volume()
            2.1816949907715726

        A version using `AA <sage.rings.qqbar.AlgebraicRealField>`::

            sage: ico = polytopes.icosahedron(base_ring=AA)   # long time
            sage: ico.base_ring()                             # long time
            Algebraic Real Field
            sage: ico.volume()                                # long time
            2.181694990624913?

        Note that if base ring is provided it must contain the square root of
        `5`. Otherwise you will get an error::

            sage: polytopes.icosahedron(base_ring=QQ)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert 1/4*sqrt(5) + 1/4 to a rational
        """
        if base_ring is None and exact:
            from sage.rings.number_field.number_field import QuadraticField
            K = QuadraticField(5, 'sqrt5')
            sqrt5 = K.gen()
            g = (1 + sqrt5) / 2
            base_ring = K
        else:
            if base_ring is None:
                base_ring = RDF
            g = (1 + base_ring(5).sqrt()) / 2

        r12 = base_ring.one() / 2
        z = base_ring.zero()
        pts = [[z, s1 * r12, s2 * g / 2]
               for s1, s2 in itertools.product([1, -1], repeat=2)]
        verts = [p(v) for p in AlternatingGroup(3) for v in pts]
        return Polyhedron(vertices=verts, base_ring=base_ring)
Ejemplo n.º 16
0
    def is_degenerate(self):
        """
        Decide whether the binary recurrence sequence is degenerate.

        Let `\\alpha` and `\\beta` denote the roots of the characteristic polynomial
        `p(x) = x^2-bx -c`.  Let `a = u_1-u_0\\beta/(\\beta - \\alpha)` and
        `b = u_1-u_0\\alpha/(\\beta - \\alpha)`.  The sequence is, thus, given by
        `u_n = a \\alpha^n - b\\beta^n`.  Then we say that the sequence is nondegenerate
        if and only if `a*b*\\alpha*\\beta \\neq 0` and `\\alpha/\\beta` is not a
        root of unity.

        More concretely, there are 4 classes of degeneracy, that can all be formulated
        in terms of the matrix `F = [[0,1], [c, b]]`.

        - `F` is singular --  this corresponds to ``c`` = 0, and thus `\\alpha*\\beta = 0`. This sequence is geometric after term ``u0`` and so we call it ``quasigeometric``.

        - `v = [[u_0], [u_1]]` is an eigenvector of `F` -- this corresponds to a ``geometric`` sequence with `a*b = 0`.

        - `F` is nondiagonalizable -- this corresponds to `\\alpha = \\beta`.  This sequence will be the point-wise product of an arithmetic and geometric sequence.

        - `F^k` is scaler, for some `k>1` -- this corresponds to `\\alpha/\\beta` a `k` th root of unity. This sequence is a union of several geometric sequences, and so we again call it ``quasigeometric``.

        EXAMPLES::

            sage: S = BinaryRecurrenceSequence(0,1)
            sage: S.is_degenerate()
            True
            sage: S.is_geometric()
            False
            sage: S.is_quasigeometric()
            True

            sage: R = BinaryRecurrenceSequence(3,-2)
            sage: R.is_degenerate()
            False

            sage: T = BinaryRecurrenceSequence(2,-1)
            sage: T.is_degenerate()
            True
            sage: T.is_arithmetic()
            True

        """

        if (self.b**2 + 4 * self.c) != 0:

            if (self.b**2 + 4 * self.c).is_square():
                A = sqrt((self.b**2 + 4 * self.c))

            else:
                K = QuadraticField((self.b**2 + 4 * self.c), 'x')
                A = K.gen()

            aa = (self.u1 - self.u0 *
                  (self.b + A) / 2) / (A)  #called `a` in Docstring
            bb = (self.u1 - self.u0 *
                  (self.b - A) / 2) / (A)  #called `b` in Docstring

            #(b+A)/2 is called alpha in Docstring, (b-A)/2 is called beta in Docstring

            if (self.b - A) != 0:
                if ((self.b + A) / (self.b - A))**(6) == 1:
                    return True
            else:
                return True

            if aa * bb * (self.b + A) * (self.b - A) == 0:
                return True
            return False
        return True
Ejemplo n.º 17
0
def _semistable_reducible_primes(E):
    r"""Find a list containing all semistable primes l unramified in K/QQ
    for which the Galois image for E could be reducible.

    INPUT:

    - ``E`` - EllipticCurve - over a number field.

    OUTPUT:

    A list of primes, which contains all primes `l` unramified in
    `K/\mathbb{QQ}`, such that `E` is semistable at all primes lying
    over `l`, and the Galois image at `l` is reducible. If `E` has CM
    defined over its ground field, a ``ValueError`` is raised.

    EXAMPLES::

        sage: E = EllipticCurve([0, -1, 1, -10, -20]) # X_0(11)
        sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._semistable_reducible_primes(E)
        True
    """

    E = _over_numberfield(E)
    K = E.base_field()
    deg_one_primes = K.primes_of_degree_one_iter()

    bad_primes = set([]) # This will store the output.

    # We find two primes (of distinct residue characteristics) which are
    # of degree 1, unramified in K/Q, and at which E has good reduction.
    # Both of these primes will give us a nontrivial divisibility constraint
    # on the exceptional primes l. For both of these primes P, we precompute
    # a generator and the trace of Frob_P^12.

    precomp = []
    last_char = 0 # The residue characteristic of the most recent prime.

    while len(precomp) < 2:
        P = next(deg_one_primes)

        if not P.is_principal():
            continue

        det = P.norm()
        if det == last_char:
            continue

        if P.ramification_index() != 1:
            continue

        if E.has_bad_reduction(P):
            continue

        tr = E.reduction(P).trace_of_frobenius()
        x = P.gens_reduced()[0]

        precomp.append((x, _tr12(tr, det)))
        last_char = det

    x, tx = precomp[0]
    y, ty = precomp[1]

    Kgal = K.galois_closure('b')
    maps = K.embeddings(Kgal)

    for i in xrange(2 ** (K.degree() - 1)):
        ## We iterate through all possible characters. ##

        # Here, if i = i_{l-1} i_{l-2} cdots i_1 i_0 in binary, then i
        # corresponds to the character prod sigma_j^{i_j}.

        phi1x = 1
        phi2x = 1
        phi1y = 1
        phi2y = 1

        # We compute the two algebraic characters at x and y:
        for j in xrange(K.degree()):
            if i % 2 == 1:
                phi1x *= maps[j](x)
                phi1y *= maps[j](y)
            else:
                phi2x *= maps[j](x)
                phi2y *= maps[j](y)
            i = int(i/2)

        # Any prime with reducible image must divide both of:
        gx = phi1x**12 + phi2x**12 - tx
        gy = phi1y**12 + phi2y**12 - ty

        if (gx != 0) or (gy != 0):
            for prime in Integer(Kgal.ideal([gx, gy]).norm()).prime_factors():
                bad_primes.add(prime)

            continue

        ## It is possible that our curve has CM. ##

        # Our character must be of the form Nm^K_F for an imaginary
        # quadratic subfield F of K (which is the CM field if E has CM).
        # We compute F:

        a = (Integer(phi1x + phi2x)**2 - 4 * x.norm()).squarefree_part()

        # See #19229: the name given here, which is not used, should
        # not be the name of the generator of the base field.
        F = QuadraticField(a, 'gal_rep_nf_sqrt_a')

        # Next, we turn K into relative number field over F.

        K = K.relativize(F.embeddings(K)[0], K.variable_name()+'0')
        E = E.change_ring(K.structure()[1])

        ## We try to find a nontrivial divisibility condition. ##

        patience = 5 * K.absolute_degree()
        # Number of Frobenius elements to check before suspecting that E
        # has CM and computing the set of CM j-invariants of K to check.
        # TODO: Is this the best value for this parameter?

        while True:
            P = next(deg_one_primes)

            if not P.is_principal():
                continue

            try:
                tr = E.change_ring(P.residue_field()).trace_of_frobenius()
            except ArithmeticError: # Bad reduction at P.
                continue

            x = P.gens_reduced()[0].norm(F)
            div = (x**12).trace() - _tr12(tr, x.norm())

            patience -= 1

            if div != 0:
                # We found our divisibility constraint.

                for prime in Integer(div).prime_factors():
                    bad_primes.add(prime)

                # Turn K back into an absolute number field.

                E = E.change_ring(K.structure()[0])
                K = K.structure()[0].codomain()

                break

            if patience == 0:
                # We suspect that E has CM, so we check:
                f = K.structure()[0]
                if f(E.j_invariant()) in cm_j_invariants(f.codomain()):
                    raise ValueError("The curve E should not have CM.")

    L = sorted(bad_primes)
    return L