def subfield_from_elements(self,
                           alpha,
                           name=None,
                           polred=True,
                           threshold=None):
    r"""
    Return the subfield generated by the elements ``alpha``.

    INPUT:

    - ``alpha`` - list of elements in this number field

    - ``name`` - a name for the generator of the new number field

    - ``polred`` (boolean, default ``True``) - whether to optimize the generator of
      the newly created field

    - ``threshold`` (positive number, default ``None``) - threshold to be passed to
      the ``do_polred`` function

    EXAMPLES::

        sage: from flatsurf.geometry.subfield import subfield_from_elements

        sage: x = polygen(QQ)
        sage: poly = x^4 - 4*x^2 + 1
        sage: emb = AA.polynomial_root(poly, RIF(0.51, 0.52))
        sage: K.<a> = NumberField(poly, embedding=emb)
        sage: sqrt2 = -a^3 + 3*a
        sage: sqrt3 = -a^2 + 2
        sage: assert sqrt2 ** 2 == 2 and sqrt3 ** 2 == 3
        sage: L, elts, phi = subfield_from_elements(K, [sqrt2, 1 - sqrt2/3])
        sage: L
        Number Field in a0 with defining polynomial x^2 - 2 with a0 = 1.414213562373095?
        sage: elts
        [a0, -1/3*a0 + 1]
        sage: phi
        Ring morphism:
          From: Number Field in a0 with defining polynomial x^2 - 2 with a0 = 1.414213562373095?
          To:   Number Field in a with defining polynomial x^4 - 4*x^2 + 1 with a = 0.5176380902050415?
          Defn: a0 |--> -a^3 + 3*a
        sage: assert phi(elts[0]) == sqrt2
        sage: assert phi(elts[1]) == 1 - sqrt2/3

        sage: L, elts, phi = subfield_from_elements(K, [1, sqrt3])
        sage: assert phi(elts[0]) == 1
        sage: assert phi(elts[1]) == sqrt3

    TESTS::

        sage: from flatsurf.geometry.subfield import subfield_from_elements
        sage: x = polygen(QQ)

        sage: p = x^8 - 12*x^6 + 23*x^4 - 12*x^2 + 1
        sage: K.<a> = NumberField(p)
        sage: sqrt2 = 6/7*a^7 - 71/7*a^5 + 125/7*a^3 - 43/7*a
        sage: sqrt3 = 3/7*a^6 - 32/7*a^4 + 24/7*a^2 + 10/7
        sage: sqrt5 = 8/7*a^6 - 90/7*a^4 + 120/7*a^2 - 27/7
        sage: assert sqrt2**2 == 2 and sqrt3**2 == 3 and sqrt5**2 == 5
        sage: L, elts, phi = subfield_from_elements(K, [sqrt2, sqrt3], name='b')
        sage: assert phi(elts[0]) == sqrt2
        sage: assert phi(elts[1]) == sqrt3
        sage: L, elts, phi = subfield_from_elements(K, [sqrt2, sqrt5], name='b')
        sage: assert phi(elts[0]) == sqrt2
        sage: assert phi(elts[1]) == sqrt5
        sage: L, elts, phi = subfield_from_elements(K, [sqrt3, sqrt5], name='b')
        sage: assert phi(elts[0]) == sqrt3
        sage: assert phi(elts[1]) == sqrt5
        sage: L, elts, phi = subfield_from_elements(K, [-149582/214245 + 21423/5581*sqrt2], name='b')
        sage: assert L.polynomial() == x^2 - 2
        sage: L, elts, phi = subfield_from_elements(K, [131490/777 - 1359/22*sqrt3], name='b')
        sage: assert L.polynomial() == x^2 - 3
        sage: L, elts, phi = subfield_from_elements(K, [12241829/177 - 321121/22459 * sqrt5], name='b')
        sage: assert L.polynomial() == x^2 - x - 1

        sage: from sage.rings.qqbar import number_field_elements_from_algebraics
        sage: R.<x> = QQ[]
        sage: p1 = x^3 - x - 1
        sage: roots1 = p1.roots(QQbar, False)
        sage: for _ in range(10):
        ....:     p2 = R.random_element(degree=2)
        ....:     while not p2.is_irreducible(): p2 = R.random_element(degree=2)
        ....:     roots2 = p2.roots(QQbar, False)
        ....:     K, (a1,b1,c1,a2,b2), phi = number_field_elements_from_algebraics(roots1 + roots2)
        ....:     u1 = 1 - a1/17 + 3/7*a1**2
        ....:     u2 = 2 + 33/35 * a1
        ....:     L, (v1,v2), phi = subfield_from_elements(K, [u1, u2], threshold=100)
        ....:     assert L.polynomial() == p1
        ....:     assert phi(v1) == u1 and phi(v2) == u2
    """
    V = VectorSpace(QQ, self.degree())
    alpha = [self(a) for a in alpha]

    # Rational case
    if all(a.is_rational() for a in alpha):
        return (QQ, [QQ(a) for a in alpha], self.coerce_map_from(QQ))

    # Saturate with multiplication
    vecs = [a.vector() for a in alpha]
    U = V.subspace(vecs)
    modified = True
    while modified:
        modified = False
        d = U.dimension()
        if d == self.degree():
            return (self, alpha, Hom(self, self, Fields()).identity())
        B = U.basis()
        for i in range(d):
            for j in range(i, d):
                v = (self(B[i]) * self(B[j])).vector()
                if v not in U:
                    U += V.subspace([v])
                    modified = True

    # Strict subfield, find a generator
    vgen = None
    for b in U.basis():
        if self(b).minpoly().degree() == d:
            vgen = b
            break
    if vgen is None:
        s = 1
        while True:
            vgen = U.random_element(proba=0.5, x=-s, y=s)
            if self(vgen).minpoly().degree() == d:
                break
            s *= 2

    # Minimize the generator via PARI polred
    gen = self(vgen)
    p = gen.minpoly()
    if polred:
        if threshold:
            fwd, back, q = do_polred(p, threshold)
        else:
            fwd, back, q = do_polred(p)
    else:
        q = p
        fwd = back = self.polynomial_ring().gen()

    new_gen = fwd(gen)
    assert new_gen.minpoly() == q
    K, hom = self.subfield(new_gen, name=name)

    # need to express the elements in the basis 1, a, a^2, ..., a^(d-1)
    M = matrix(QQ, [(new_gen**i).vector() for i in range(d)])
    new_alpha = [K(M.solve_left(elt.vector())) for elt in alpha]

    return (K, new_alpha, hom)
Beispiel #2
0
 def __getitem__(self, a):
     if a == 1:
         return 1 / (1 - x)
     else:
         return QQ(1 - a).sign() / (x - a)
Beispiel #3
0
    def to_sage(self):
        """
        EXAMPLES:
            sage: macaulay2(ZZ).to_sage()      #optional
            Integer Ring
            sage: macaulay2(QQ).to_sage()      #optional
            Rational Field

            sage: macaulay2(2).to_sage()       #optional
            2
            sage: macaulay2(1/2).to_sage()     #optional
            1/2
            sage: macaulay2(2/1).to_sage()     #optional
            2
            sage: _.parent()                   #optional
            Rational Field
            sage: macaulay2([1,2,3]).to_sage() #optional
            [1, 2, 3]

            sage: m = matrix([[1,2],[3,4]])
            sage: macaulay2(m).to_sage()       #optional
            [1 2]
            [3 4]

            sage: macaulay2(QQ['x,y']).to_sage()    #optional
            Multivariate Polynomial Ring in x, y over Rational Field
            sage: macaulay2(QQ['x']).to_sage()      #optional
            Univariate Polynomial Ring in x over Rational Field
            sage: macaulay2(GF(7)['x,y']).to_sage() #optional
            Multivariate Polynomial Ring in x, y over Finite Field of size 7

            sage: macaulay2(GF(7)).to_sage()       #optional
            Finite Field of size 7
            sage: macaulay2(GF(49, 'a')).to_sage() #optional
            Finite Field in a of size 7^2

            sage: R.<x,y> = QQ[]
            sage: macaulay2(x^2+y^2+1).to_sage()   #optional
            x^2 + y^2 + 1

            sage: R = macaulay2("QQ[x,y]")         #optional
            sage: I = macaulay2("ideal (x,y)")     #optional
            sage: I.to_sage()                      #optional
            Ideal (x, y) of Multivariate Polynomial Ring in x, y over Rational Field

            sage: X = R/I       #optional
            sage: X.to_sage()   #optional
            Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y)

            sage: R = macaulay2("QQ^2")  #optional
            sage: R.to_sage()            #optional
            Vector space of dimension 2 over Rational Field

            sage: m = macaulay2('"hello"')  #optional
            sage: m.to_sage()               #optional
            'hello'

        """
        repr_str = str(self)
        cls_str = str(self.cls())
        cls_cls_str = str(self.cls().cls())

        if repr_str == "ZZ":
            from sage.rings.all import ZZ
            return ZZ
        elif repr_str == "QQ":
            from sage.rings.all import QQ
            return QQ

        if cls_cls_str == "Type":
            if cls_str == "List":
                return [entry.to_sage() for entry in self]
            elif cls_str == "Matrix":
                from sage.matrix.all import matrix
                base_ring = self.ring().to_sage()
                entries = self.entries().to_sage()
                return matrix(base_ring, entries)
            elif cls_str == "Ideal":
                parent = self.ring().to_sage()
                gens = self.gens().entries().flatten().to_sage()
                return parent.ideal(*gens)
            elif cls_str == "QuotientRing":
                #Handle the ZZ/n case
                if "ZZ" in repr_str and "--" in repr_str:
                    from sage.rings.all import ZZ, GF
                    external_string = self.external_string()
                    zz, n = external_string.split("/")

                    #Note that n must be prime since it is
                    #coming from Macaulay 2
                    return GF(ZZ(n))

                ambient = self.ambient().to_sage()
                ideal = self.ideal().to_sage()
                return ambient.quotient(ideal)
            elif cls_str == "PolynomialRing":
                from sage.rings.all import PolynomialRing
                from sage.rings.polynomial.term_order import inv_macaulay2_name_mapping

                #Get the base ring
                base_ring = self.coefficientRing().to_sage()

                #Get a string list of generators
                gens = str(self.gens())[1:-1]

                # Check that we are dealing with default degrees, i.e. 1's.
                if self.degrees().any("x -> x != {1}").to_sage():
                    raise ValueError, "cannot convert Macaulay2 polynomial ring with non-default degrees to Sage"
                #Handle the term order
                external_string = self.external_string()
                order = None
                if "MonomialOrder" not in external_string:
                    order = "degrevlex"
                else:
                    for order_name in inv_macaulay2_name_mapping:
                        if order_name in external_string:
                            order = inv_macaulay2_name_mapping[order_name]
                if len(gens) > 1 and order is None:
                    raise ValueError, "cannot convert Macaulay2's term order to a Sage term order"

                return PolynomialRing(base_ring, order=order, names=gens)
            elif cls_str == "GaloisField":
                from sage.rings.all import ZZ, GF
                gf, n = repr_str.split(" ")
                n = ZZ(n)
                if n.is_prime():
                    return GF(n)
                else:
                    gen = str(self.gens())[1:-1]
                    return GF(n, gen)
            elif cls_str == "Boolean":
                if repr_str == "true":
                    return True
                elif repr_str == "false":
                    return False
            elif cls_str == "String":
                return str(repr_str)
            elif cls_str == "Module":
                from sage.modules.all import FreeModule
                if self.isFreeModule().to_sage():
                    ring = self.ring().to_sage()
                    rank = self.rank().to_sage()
                    return FreeModule(ring, rank)
        else:
            #Handle the integers and rationals separately
            if cls_str == "ZZ":
                from sage.rings.all import ZZ
                return ZZ(repr_str)
            elif cls_str == "QQ":
                from sage.rings.all import QQ
                repr_str = self.external_string()
                if "/" not in repr_str:
                    repr_str = repr_str + "/1"
                return QQ(repr_str)

            m2_parent = self.cls()
            parent = m2_parent.to_sage()

            if cls_cls_str == "PolynomialRing":
                from sage.misc.sage_eval import sage_eval
                gens_dict = parent.gens_dict()
                return sage_eval(self.external_string(), gens_dict)

        from sage.misc.sage_eval import sage_eval
        try:
            return sage_eval(repr_str)
        except Exception:
            raise NotImplementedError, "cannot convert %s to a Sage object" % repr_str
Beispiel #4
0
def enumerate_totallyreal_fields_all(n,
                                     B,
                                     verbose=0,
                                     return_seqs=False,
                                     return_pari_objects=True):
    r"""
    Enumerates *all* totally real fields of degree ``n`` with discriminant
    at most ``B``, primitive or otherwise.

    INPUT:

    - ``n`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``verbose`` -- boolean or nonnegative integer or string (default: 0)
      give a verbose description of the computations being performed. If
      ``verbose`` is set to ``2`` or more then it outputs some extra
      information. If ``verbose`` is a string then it outputs to a file
      specified by ``verbose``
    - ``return_seqs`` -- (boolean, default False) If ``True``, then return
      the polynomials as sequences (for easier exporting to a file). This
      also returns a list of four numbers, as explained in the OUTPUT
      section below.
    - ``return_pari_objects`` -- (boolean, default: True) if both
      ``return_seqs`` and ``return_pari_objects`` are ``False`` then it
      returns the elements as Sage objects; otherwise it returns pari
      objects.

    EXAMPLES::

        sage: enumerate_totallyreal_fields_all(4, 2000)
        [[725, x^4 - x^3 - 3*x^2 + x + 1],
        [1125, x^4 - x^3 - 4*x^2 + 4*x + 1],
        [1600, x^4 - 6*x^2 + 4],
        [1957, x^4 - 4*x^2 - x + 1],
        [2000, x^4 - 5*x^2 + 5]]
        sage: enumerate_totallyreal_fields_all(1, 10)
        [[1, x - 1]]

    TESTS:

    Each of the outputs must be elements of Sage if ``return_pari_objects``
    is set to ``False``::

        sage: enumerate_totallyreal_fields_all(2, 10)
        [[5, x^2 - x - 1], [8, x^2 - 2]]
        sage: type(enumerate_totallyreal_fields_all(2, 10)[0][1])
        <type 'sage.libs.cypari2.gen.Gen'>
        sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent()
        Univariate Polynomial Ring in x over Rational Field


    In practice most of these will be found by
    :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`,
    which is guaranteed to return all primitive fields but often returns
    many non-primitive ones as well. For instance, only one of the five
    fields in the example above is primitive, but
    :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`
    finds four out of the five (the exception being `x^4 - 6x^2 + 4`).

    The following was fixed in :trac:`13101`::

        sage: enumerate_totallyreal_fields_all(8, 10^6)  # long time (about 2 s)
        []
    """

    S = []
    counts = [0, 0, 0, 0]
    if len(divisors(n)) > 4:
        raise ValueError("Only implemented for n = p*q with p,q prime")
    for d in divisors(n):
        if d > 1 and d < n:
            Sds = enumerate_totallyreal_fields_prim(
                d, int(math.floor((1. * B)**(1. * d / n))), verbose=verbose)
            for i in range(len(Sds)):
                if verbose:
                    print("=" * 80)
                    print("Taking F =", Sds[i][1])
                F = NumberField(ZZx(Sds[i][1]), 't')
                T = enumerate_totallyreal_fields_rel(F,
                                                     n / d,
                                                     B,
                                                     verbose=verbose,
                                                     return_seqs=return_seqs)
                if return_seqs:
                    for i in range(4):
                        counts[i] += T[0][i]
                    S += [[t[0], pari(t[1]).Polrev()] for t in T[1]]
                else:
                    S += [[t[0], t[1]] for t in T]
                j = i + 1
                for E in enumerate_totallyreal_fields_prim(
                        n / d,
                        int(
                            math.floor((1. * B)**(1. / d) /
                                       (1. * Sds[i][0])**(n * 1. / d**2)))):
                    for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')):
                        if EF.degree() == n and EF.disc() <= B:
                            S.append(
                                [EF.disc(),
                                 pari(EF.absolute_polynomial())])
    S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose)
    S.sort(cmp=lambda x, y: cmp(x[0], y[0]) or cmp(x[1], y[1]))
    weed_fields(S)

    # Output.
    if verbose:
        saveout = sys.stdout
        if isinstance(verbose, str):
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
        print("=" * 80)
        print("Polynomials tested: {}".format(counts[0]))
        print("Polynomials with discriminant with large enough square"
              " divisor: {}".format(counts[1]))
        print("Irreducible polynomials: {}".format(counts[2]))
        print("Polynomials with nfdisc <= B: {}".format(counts[3]))
        for i in range(len(S)):
            print(S[i])
        if isinstance(verbose, str):
            fsock.close()
        sys.stdout = saveout

    # Make sure to return elements that belong to Sage
    if return_seqs:
        return [[ZZ(_) for _ in counts],
                [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]]
                 for s in S]]
    elif return_pari_objects:
        return S
    else:
        Px = PolynomialRing(QQ, 'x')
        return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])] for s in S]
Beispiel #5
0
    def next_state(self, val):
        r"""
        Build the next state for type `A_{2n}^{(2)\dagger}`.

        TESTS::

            sage: KRT = crystals.TensorProductOfKirillovReshetikhinTableaux(CartanType(['A', 4, 2]).dual(), [[2,1]])
            sage: from sage.combinat.rigged_configurations.bij_type_A2_dual import KRTToRCBijectionTypeA2Dual
            sage: bijection = KRTToRCBijectionTypeA2Dual(KRT(pathlist=[[-1,2]]))
            sage: bijection.cur_path.insert(0, [])
            sage: bijection.cur_dims.insert(0, [0, 1])
            sage: bijection.cur_path[0].insert(0, [2])
            sage: bijection.next_state(2)
        """
        n = self.n
        tableau_height = len(self.cur_path[0]) - 1

        if val > 0:
            # If it is a regular value, we follow the A_n rules
            KRTToRCBijectionTypeA.next_state(self, val)
            return

        pos_val = -val

        if pos_val == 0:
            if len(self.ret_rig_con[pos_val - 1]) > 0:
                max_width = self.ret_rig_con[n - 1][0]
            else:
                max_width = 1
            max_width = self.ret_rig_con[n - 1].insert_cell(max_width)
            width_n = max_width + 1

            # Follow regular A_n rules
            for a in reversed(range(tableau_height, n - 1)):
                max_width = self.ret_rig_con[a].insert_cell(max_width)
                self._update_vacancy_nums(a + 1)
                self._update_partition_values(a + 1)
            self._update_vacancy_nums(tableau_height)
            self._update_partition_values(tableau_height)
            if tableau_height > 0:
                self._update_vacancy_nums(tableau_height - 1)
                self._update_partition_values(tableau_height - 1)

            # Make the new string at n quasi-singular
            p = self.ret_rig_con[n - 1]
            for i in range(len(p)):
                if p._list[i] == width_n:
                    p.rigging[i] = p.rigging[i] - QQ(1) / QQ(2)
                    break
            return

        case_S = [None] * n
        pos_val = -val

        # Always add a cell to the first singular value in the first
        #   tableau we are updating.
        if len(self.ret_rig_con[pos_val - 1]) > 0:
            max_width = self.ret_rig_con[pos_val - 1][0]
        else:
            max_width = 1

        # Add cells similar to type A_n but we move to the right until we
        #   reach the value of n-1
        for a in range(pos_val - 1, n - 1):
            max_width = self.ret_rig_con[a].insert_cell(max_width)
            case_S[a] = max_width

        # Special case for n
        # If we find a quasi-singular string first, then we are in case (Q, S)
        #   otherwise we will find a singular string and insert 2 cells
        partition = self.ret_rig_con[n - 1]
        num_rows = len(partition)
        case_QS = False
        for i in range(num_rows + 1):
            if i == num_rows:
                max_width = 0
                if case_QS:
                    partition._list.append(1)
                    partition.vacancy_numbers.append(None)
                    # Go through our partition until we find a length of greater than 1
                    j = len(partition._list) - 1
                    while j >= 0 and partition._list[j] == 1:
                        j -= 1
                    partition.rigging.insert(j + 1, None)
                    width_n = 1
                else:
                    # Go through our partition until we find a length of greater than 2
                    j = len(partition._list) - 1
                    while j >= 0 and partition._list[j] <= 2:
                        j -= 1
                    partition._list.insert(j + 1, 2)
                    partition.vacancy_numbers.insert(j + 1, None)
                    partition.rigging.insert(j + 1, None)
                break
            elif partition._list[i] <= max_width:
                if partition.vacancy_numbers[i] == partition.rigging[i]:
                    max_width = partition._list[i]
                    if case_QS:
                        partition._list[i] += 1
                        width_n = partition._list[i]
                        partition.rigging[i] = None
                    else:
                        j = i - 1
                        while j >= 0 and partition._list[j] <= max_width + 2:
                            partition.rigging[j + 1] = partition.rigging[
                                j]  # Shuffle it along
                            j -= 1
                        partition._list.pop(i)
                        partition._list.insert(j + 1, max_width + 2)
                        partition.rigging[j + 1] = None
                    break
                elif partition.vacancy_numbers[i] - QQ(1) / QQ(
                        2) == partition.rigging[i] and not case_QS:
                    case_QS = True
                    partition._list[i] += 1
                    partition.rigging[i] = None
                    # No need to set max_width here since we will find a singular string

        # Now go back following the regular C_n (ish) rules
        for a in reversed(range(tableau_height, n - 1)):
            if case_S[a] == max_width:
                self._insert_cell_case_S(self.ret_rig_con[a])
            else:
                max_width = self.ret_rig_con[a].insert_cell(max_width)
            self._update_vacancy_nums(a + 1)
            self._update_partition_values(a + 1)

        # Update the final rigged partitions
        if tableau_height < n:
            self._update_vacancy_nums(tableau_height)
            self._update_partition_values(tableau_height)

        if pos_val <= tableau_height:
            for a in range(pos_val - 1, tableau_height):
                self._update_vacancy_nums(a)
                self._update_partition_values(a)
            if pos_val > 1:
                self._update_vacancy_nums(pos_val - 2)
                self._update_partition_values(pos_val - 2)
        elif tableau_height > 0:
            self._update_vacancy_nums(tableau_height - 1)
            self._update_partition_values(tableau_height - 1)

        if case_QS:
            # Make the new string quasi-singular
            num_rows = len(partition)
            for i in range(num_rows):
                if partition._list[i] == width_n:
                    partition.rigging[i] = partition.rigging[i] - QQ(1) / QQ(2)
                    break
Beispiel #6
0
    def multiple_of_order(self, maxp=None, proof=True):
        """
        Return a multiple of the order.

        INPUT:

        - ``proof`` -- a boolean (default: True)

        The computation of the rational torsion order of J1(p) is conjectural
        and will only be used if proof=False. See Section 6.2.3 of [CES2003]_.

        EXAMPLES::

            sage: J = J1(11); J
            Abelian variety J1(11) of dimension 1
            sage: J.rational_torsion_subgroup().multiple_of_order()
            5

            sage: J = J0(17)
            sage: J.rational_torsion_subgroup().order()
            4

        This is an example where proof=False leads to a better bound and better
        performance. ::

            sage: J = J1(23)
            sage: J.rational_torsion_subgroup().multiple_of_order() # long time (2s)
            9406793
            sage: J.rational_torsion_subgroup().multiple_of_order(proof=False)
            408991
        """

        try:
            if proof:
                return self._multiple_of_order
            else:
                return self._multiple_of_order_proof_false
        except:
            pass

        A = self.abelian_variety()
        N = A.level()

        if A.dimension() == 0:
            self._multiple_of_order = ZZ(1)
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._multiple_of_order = QQ((A.level() - 1) / 12).numerator()
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # The elliptic curve case
        if A.dimension() == 1:
            self._multiple_of_order = A.elliptic_curve().torsion_order()
            self._multiple_of_order_proof_false = self._multiple_of_order
            return self._multiple_of_order

        # The conjectural J1(p) case
        if not proof and A.is_J1() and N.is_prime():
            epsilons = [
                epsilon for epsilon in DirichletGroup(N)
                if not epsilon.is_trivial() and epsilon.is_even()
            ]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._multiple_of_order_proof_false = ZZ(N / (2**(N - 3)) *
                                                     prod(bernoullis))
            return self._multiple_of_order_proof_false

        # The Gamma0 and Gamma1 case
        if all((is_Gamma0(G) or is_Gamma1(G) for G in A.groups())):
            self._multiple_of_order = self.multiple_of_order_using_frobp()
            return self._multiple_of_order

        # Unhandled case
        raise NotImplementedError("No implemented algorithm")
Beispiel #7
0
    def descend_to(self, K, f=None):
        r"""
        Given an elliptic curve self defined over a field `L` and a
        subfield `K` of `L`, return all elliptic curves over `K` which
        are isomorphic over `L` to self.

        INPUT:

        - `K` -- a field which embeds into the base field `L` of self.

        - `f` (optional) -- an embedding of `K` into `L`.  Ignored if
          `K` is `\QQ`.

        OUTPUT:

        A list (possibly empty) of elliptic curves defined over `K`
        which are isomorphic to self over `L`, up to isomorphism over
        `K`.

        .. NOTE::

           Currently only implemented over number fields.  To extend
           to other fields of characteristic not 2 or 3, what is
           needed is a method giving the preimages in `K^*/(K^*)^m` of
           an element of the base field, for `m=2,4,6`.

        EXAMPLES::

            sage: E = EllipticCurve([1,2,3,4,5])
            sage: E.descend_to(ZZ)
            Traceback (most recent call last):
            ...
            TypeError: Input must be a field.

        ::

            sage: F.<b> = QuadraticField(23)
            sage: G.<a> = F.extension(x^3+5)
            sage: E = EllipticCurve(j=1728*b).change_ring(G)
            sage: EF = E.descend_to(F); EF
            [Elliptic Curve defined by y^2 = x^3 + (27*b-621)*x + (-1296*b+2484) over Number Field in b with defining polynomial x^2 - 23]
            sage: all([Ei.change_ring(G).is_isomorphic(E) for Ei in EF])
            True

        ::

            sage: L.<a> = NumberField(x^4 - 7)
            sage: K.<b> = NumberField(x^2 - 7, embedding=a^2)
            sage: E = EllipticCurve([a^6,0])
            sage: EK = E.descend_to(K); EK
            [Elliptic Curve defined by y^2 = x^3 + b*x over Number Field in b with defining polynomial x^2 - 7,
            Elliptic Curve defined by y^2 = x^3 + 7*b*x over Number Field in b with defining polynomial x^2 - 7]
            sage: all([Ei.change_ring(L).is_isomorphic(E) for Ei in EK])
            True

        ::

            sage: K.<a> = QuadraticField(17)
            sage: E = EllipticCurve(j = 2*a)
            sage: E.descend_to(QQ)
            []

        TESTS:

        Check that :trac:`16456` is fixed::

            sage: K.<a> = NumberField(x^3-2)
            sage: E = EllipticCurve('11a1').quadratic_twist(2)
            sage: EK = E.change_ring(K)
            sage: EK2 = EK.change_weierstrass_model((a,a,a,a+1))
            sage: EK2.descend_to(QQ)
            [Elliptic Curve defined by y^2 = x^3 + x^2 - 41*x - 199 over Rational Field]

            sage: k.<i> = QuadraticField(-1)
            sage: E = EllipticCurve(k,[0,0,0,1,0])
            sage: E.descend_to(QQ)
            [Elliptic Curve defined by y^2 = x^3 + x over Rational Field,
            Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field]

        """
        if not K.is_field():
            raise TypeError("Input must be a field.")
        L = self.base_field()
        if L is K:
            return self
        elif L == K:  # number fields can be equal but not identical
            return self.base_extend(K)

        # Construct an embedding f of K in L, and check that the
        # j-invariant is in the image, otherwise return an empty list:

        j = self.j_invariant()
        from sage.rings.all import QQ
        if K == QQ:
            try:
                jK = QQ(j)
            except (ValueError, TypeError):
                return []
        elif f is None:
            embeddings = K.embeddings(L)
            if len(embeddings) == 0:
                raise TypeError(
                    "Input must be a subfield of the base field of the curve.")
            for g in embeddings:
                try:
                    jK = g.preimage(j)
                    f = g
                    break
                except Exception:
                    pass
            if f is None:
                return []
        else:
            try:
                if f.domain() != K:
                    raise ValueError("embedding has wrong domain")
                if f.codomain() != L:
                    raise ValueError("embedding has wrong codomain")
            except AttributeError:
                raise ValueError("invalid embedding: %s" % s)
            try:
                jK = f.preimage(j)
            except Exception:
                return []

        # Now we have the j-invariant in K and must find all twists
        # which work, separating the cases of j=0 and j=1728.

        if L.characteristic():
            raise NotImplementedError(
                "Not implemented in positive characteristic")

        if jK == 0:
            t = -54 * self.c6()
            try:
                dlist = t.descend_mod_power(K, 6)
                # list of d in K such that t/d is in L*^6
            except AttributeError:
                raise NotImplementedError("Not implemented over %s" % L)
            Elist = [EllipticCurve([0, 0, 0, 0, d]) for d in dlist]
        elif jK == 1728:
            t = -27 * self.c4()
            try:
                dlist = t.descend_mod_power(K, 4)
                # list of d in K such that t/d is in L*^4
            except AttributeError:
                raise NotImplementedError("Not implemented over %s" % L)
            Elist = [EllipticCurve([0, 0, 0, d, 0]) for d in dlist]
        else:
            c4, c6 = self.c_invariants()
            t = c6 / c4
            try:
                dlist = t.descend_mod_power(K, 2)
                # list of d in K such that t/d is in L*^2
            except AttributeError:
                raise NotImplementedError("Not implemented over %s" % L)
            c = -27 * jK / (jK - 1728)  # =-27c4^3/c6^2
            a4list = [c * d**2 for d in dlist]
            a6list = [2 * a4 * d for a4, d in zip(a4list, dlist)]
            Elist = [
                EllipticCurve([0, 0, 0, a4, a6])
                for a4, a6 in zip(a4list, a6list)
            ]

        if K is QQ:
            Elist = [E.minimal_model() for E in Elist]
        return Elist
Beispiel #8
0
def FormsSpace(analytic_type, group=3, base_ring=ZZ, k=QQ(0), ep=None):
    r"""
    Return the FormsSpace with the given ``analytic_type``, ``group``
    ``base_ring`` and degree (``k``, ``ep``).

    INPUT:

    - ``analytic_type``   -- An element of ``AnalyticType()`` describing
                             the analytic type of the space.

    - ``group``           -- The index of the (Hecke triangle) group of the
                             space (default: `3`).

    - ``base_ring``       -- The base ring of the space
                             (default: ``ZZ``).

    - ``k``               -- The weight of the space, a rational number
                             (default: ``0``).

    - ``ep``              -- The multiplier of the space, `1`, `-1`
                             or ``None`` (in case ``ep`` should be
                             determined from ``k``). Default: ``None``.

    For the variables ``group``, ``base_ring``, ``k``, ``ep``
    the same arguments as for the class ``FormsSpace_abstract`` can be used.
    The variables will then be put in canonical form.
    In particular the multiplier ``ep`` is calculated
    as usual from ``k`` if ``ep == None``.

    OUTPUT:

    The FormsSpace with the given properties.

    EXAMPLES::

        sage: from sage.modular.modform_hecketriangle.constructor import FormsSpace
        sage: FormsSpace([])
        ZeroForms(n=3, k=0, ep=1) over Integer Ring
        sage: FormsSpace(["quasi"]) # not implemented

        sage: FormsSpace("cusp", group=5, base_ring=CC, k=12, ep=1)
        CuspForms(n=5, k=12, ep=1) over Complex Field with 53 bits of precision

        sage: FormsSpace("holo")
        ModularForms(n=3, k=0, ep=1) over Integer Ring

        sage: FormsSpace("weak", group=6, base_ring=ZZ, k=0, ep=-1)
        WeakModularForms(n=6, k=0, ep=-1) over Integer Ring

        sage: FormsSpace("mero", group=7, base_ring=ZZ, k=2, ep=-1)
        MeromorphicModularForms(n=7, k=2, ep=-1) over Integer Ring

        sage: FormsSpace(["quasi", "cusp"], group=5, base_ring=CC, k=12, ep=1)
        QuasiCuspForms(n=5, k=12, ep=1) over Complex Field with 53 bits of precision

        sage: FormsSpace(["quasi", "holo"])
        QuasiModularForms(n=3, k=0, ep=1) over Integer Ring

        sage: FormsSpace(["quasi", "weak"], group=6, base_ring=ZZ, k=0, ep=-1)
        QuasiWeakModularForms(n=6, k=0, ep=-1) over Integer Ring

        sage: FormsSpace(["quasi", "mero"], group=7, base_ring=ZZ, k=2, ep=-1)
        QuasiMeromorphicModularForms(n=7, k=2, ep=-1) over Integer Ring

        sage: FormsSpace(["quasi", "cusp"], group=infinity, base_ring=ZZ, k=2, ep=-1)
        QuasiCuspForms(n=+Infinity, k=2, ep=-1) over Integer Ring
    """

    from .space import canonical_parameters
    (group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep)

    from .analytic_type import AnalyticType
    AT = AnalyticType()
    analytic_type = AT(analytic_type)

    if analytic_type <= AT("mero"):
        if analytic_type <= AT("weak"):
            if analytic_type <= AT("holo"):
                if analytic_type <= AT("cusp"):
                    if analytic_type <= AT([]):
                        from .space import ZeroForm
                        return ZeroForm(group=group, base_ring=base_ring, k=k, ep=ep)
                    else:
                        from .space import CuspForms
                        return CuspForms(group=group, base_ring=base_ring, k=k, ep=ep)
                else:
                    from .space import ModularForms
                    return ModularForms(group=group, base_ring=base_ring, k=k, ep=ep)
            else:
                from .space import WeakModularForms
                return WeakModularForms(group=group, base_ring=base_ring, k=k, ep=ep)
        else:
            from .space import MeromorphicModularForms
            return MeromorphicModularForms(group=group, base_ring=base_ring, k=k, ep=ep)
    elif analytic_type <= AT(["mero", "quasi"]):
        if analytic_type <= AT(["weak", "quasi"]):
            if analytic_type <= AT(["holo", "quasi"]):
                if analytic_type <= AT(["cusp", "quasi"]):
                    if analytic_type <= AT(["quasi"]):
                        raise ValueError("There should be only non-quasi ZeroForms. That could be changed but then this exception should be removed.")
                        from .space import ZeroForm
                        return ZeroForm(group=group, base_ring=base_ring, k=k, ep=ep)
                    else:
                        from .space import QuasiCuspForms
                        return QuasiCuspForms(group=group, base_ring=base_ring, k=k, ep=ep)
                else:
                    from .space import QuasiModularForms
                    return QuasiModularForms(group=group, base_ring=base_ring, k=k, ep=ep)
            else:
                from .space import QuasiWeakModularForms
                return QuasiWeakModularForms(group=group, base_ring=base_ring, k=k, ep=ep)
        else:
            from .space import QuasiMeromorphicModularForms
            return QuasiMeromorphicModularForms(group=group, base_ring=base_ring, k=k, ep=ep)
    else:
        raise NotImplementedError("Analytic type not implemented.")
def neighbor_iteration(seeds,
                       p,
                       mass=None,
                       max_classes=ZZ(10)**3,
                       algorithm=None,
                       max_neighbors=1000,
                       verbose=False):
    r"""
    Return all classes in the `p`-neighbor graph of ``self``.

    Starting from the given seeds, this function successively
    finds p-neighbors untill no new quadratic form (class) is obtained.

    INPUT:

    - ``seeds`` -- a list of quadratic forms in the same genus

    - ``p`` -- a prime number

    - ``mass`` -- (optional) a rational number; the mass of this genus

    - ``max_classes`` -- (default: ``1000``) break the computation when ``max_classes`` are found

    - ``algorithm`` -- (optional) one of 'orbits', 'random', 'exaustion'

    - ``max_random_trys`` -- (default: ``1000``) the maximum number of neigbors
                             computed for a single lattice

    OUTPUT:

    - a list of quadratic forms

    EXAMPLES::

        sage: from sage.quadratic_forms.quadratic_form__neighbors import neighbor_iteration
        sage: Q = QuadraticForm(ZZ,3,[1,0,0,2,1,3])
        sage: Q.det()
        46
        sage: mass = Q.conway_mass()
        sage: g1 = neighbor_iteration([Q],3, mass=mass, algorithm = 'random') # long time
        sage: g2 = neighbor_iteration([Q],3, algorithm = 'exaustion') # long time
        sage: g3 = neighbor_iteration([Q],3, algorithm = 'orbits')
        sage: mass == sum(1/q.number_of_automorphisms() for q in g1) # long time
        True
        sage: mass == sum(1/q.number_of_automorphisms() for q in g2) # long time
        True
        sage: mass == sum(1/q.number_of_automorphisms() for q in g3)
        True
    """
    p = ZZ(p)
    from sage.quadratic_forms.quadratic_form import QuadraticForm
    if not all(isinstance(s, QuadraticForm) for s in seeds):
        raise ValueError("seeds must be a list of quadratic forms")
    if algorithm is None:
        n = seeds[0].dim()
        if p**n > ZZ(2)**18:
            # too many lines to compute the orbits fast
            algorithm = 'random'
        else:
            algorithm = 'orbits'
    if mass is None:
        # no mass bound
        mass = max_classes

    if algorithm == 'orbits':

        def p_divisible_vectors(Q, max_neighbors):
            yield from iter(v.lift() for v in Q.orbits_lines_mod_p(p)
                            if v != 0 and Q(v.lift()).valuation(p) > 0)
            return
    elif algorithm == 'exaustion':

        def p_divisible_vectors(Q, max_neighbors):
            k = 0
            v = Q.find_primitive_p_divisible_vector__next(p)
            while k < max_neighbors:
                k = k + 1
                v = Q.find_primitive_p_divisible_vector__next(p, v)
                if v is not None:
                    yield v
    elif algorithm == 'random':

        def p_divisible_vectors(Q, max_neighbors):
            k = 0
            while k < max_neighbors:
                k = k + 1
                v = Q.find_primitive_p_divisible_vector__random(p)
                yield v
    else:
        raise ValueError("unknown algorithm")
    waiting_list = list(seeds)
    isom_classes = []
    mass_count = QQ(0)
    n_isom_classes = ZZ(0)
    while len(waiting_list
              ) > 0 and mass_count < mass and n_isom_classes < max_classes:
        # find all p-neighbors of Q
        Q = waiting_list.pop()
        for v in p_divisible_vectors(Q, max_neighbors):
            Q_neighbor = Q.find_p_neighbor_from_vec(p, v)
            if not any(
                    Q_neighbor.is_globally_equivalent_to(S)
                    for S in isom_classes):
                Q_neighbor = Q_neighbor.lll()
                isom_classes.append(Q_neighbor)
                waiting_list.append(Q_neighbor)
                n_isom_classes += 1
                mass_count += Q_neighbor.number_of_automorphisms()**(-1)
                if verbose:
                    print(max_neighbors)
                    print(len(waiting_list))
                if mass_count == mass and n_isom_classes >= max_classes:
                    break

    if len(isom_classes) >= max_classes:
        Warning(
            "reached the maximum number of isometry classes=%s. Increase the optional argument max_classes to obtain more."
            % max_classes)

    if mass is not None:
        assert mass_count <= mass
        if mass < mass_count:
            raise Warning("not all classes in the genus were found")
    return isom_classes
Beispiel #10
0
    def descend_to(self, K, f=None):
        r"""
        Given a subfield `K` and an elliptic curve self defined over a field `L`,
        this function determines whether there exists an elliptic curve over `K`
        which is isomorphic over `L` to self. If one exists, it finds it.

        INPUT:

        - `K` -- a subfield of the base field of self.
        - `f` -- an embedding of `K` into the base field of self.

        OUTPUT:

        Either an elliptic curve defined over `K` which is isomorphic to self
        or None if no such curve exists.

        .. NOTE::

            This only works over number fields and QQ.

        EXAMPLES::

            sage: E = EllipticCurve([1,2,3,4,5])
            sage: E.descend_to(ZZ)
            Traceback (most recent call last):
            ...
            TypeError: Input must be a field.

        ::

            sage: F.<b> = QuadraticField(23)
            sage: G.<a> = F.extension(x^3+5)
            sage: E = EllipticCurve(j=1728*b).change_ring(G)
            sage: E.descend_to(F)
            Elliptic Curve defined by y^2 = x^3 + (8957952*b-206032896)*x + (-247669456896*b+474699792384) over Number Field in b with defining polynomial x^2 - 23

        ::

            sage: L.<a> = NumberField(x^4 - 7)
            sage: K.<b> = NumberField(x^2 - 7)
            sage: E = EllipticCurve([a^6,0])
            sage: E.descend_to(K)
            Elliptic Curve defined by y^2 = x^3 + 1296/49*b*x over Number Field in b with defining polynomial x^2 - 7

        ::

            sage: K.<a> = QuadraticField(17)
            sage: E = EllipticCurve(j = 2*a)
            sage: print E.descend_to(QQ)
            None
        """
        if not K.is_field():
            raise TypeError, "Input must be a field."
        if self.base_field() == K:
            return self
        j = self.j_invariant()
        from sage.rings.all import QQ
        if K == QQ:
            f = QQ.embeddings(self.base_field())[0]
            if j in QQ:
                jbase = QQ(j)
            else:
                return None
        elif f == None:
            embeddings = K.embeddings(self.base_field())
            if len(embeddings) == 0:
                raise TypeError, "Input must be a subfield of the base field of the curve."
            for g in embeddings:
                try:
                    jbase = g.preimage(j)
                    f = g
                    break
                except StandardError:
                    pass
            if f == None:
                return None
        else:
            try:
                jbase = f.preimage(j)
            except StandardError:
                return None
        E = EllipticCurve(j=jbase)
        E2 = EllipticCurve(self.base_field(), [f(a) for a in E.a_invariants()])
        if jbase == 0:
            d = self.is_sextic_twist(E2)
            if d == 1:
                return E
            if d == 0:
                return None
            Etwist = E2.sextic_twist(d)
        elif jbase == 1728:
            d = self.is_quartic_twist(E2)
            if d == 1:
                return E
            if d == 0:
                return None
            Etwist = E2.quartic_twist(d)
        else:
            d = self.is_quadratic_twist(E2)
            if d == 1:
                return E
            if d == 0:
                return None
            Etwist = E2.quadratic_twist(d)
        if Etwist.is_isomorphic(self):
            try:
                Eout = EllipticCurve(
                    K, [f.preimage(a) for a in Etwist.a_invariants()])
            except StandardError:
                return None
            else:
                return Eout
Beispiel #11
0
def rational_type(f, n=ZZ(3), base_ring=ZZ):
    r"""
    Return the basic analytic properties that can be determined
    directly from the specified rational function ``f``
    which is interpreted as a representation of an
    element of a FormsRing for the Hecke Triangle group
    with parameter ``n`` and the specified ``base_ring``.

    In particular the following degree of the generators is assumed:

    `deg(1) := (0, 1)`
    `deg(x) := (4/(n-2), 1)`
    `deg(y) := (2n/(n-2), -1)`
    `deg(z) := (2, -1)`

    The meaning of homogeneous elements changes accordingly.

    INPUT:

    - ``f``              -- A rational function in ``x,y,z,d`` over ``base_ring``.

    - ``n``              -- An integer greater or equal to `3` corresponding
                            to the ``HeckeTriangleGroup`` with that parameter
                            (default: `3`).

    - ``base_ring``      -- The base ring of the corresponding forms ring, resp.
                            polynomial ring (default: ``ZZ``).

    OUTPUT:

    A tuple ``(elem, h**o, k, ep, analytic_type)`` describing the basic
    analytic properties of `f` (with the interpretation indicated above).

    - ``elem``           -- ``True`` if `f` has a homogeneous denominator.

    - ``h**o``           -- ``True`` if `f` also has a homogeneous numerator.

    - ``k``              -- ``None`` if `f` is not homogeneous, otherwise
                            the weight of `f` (which is the first component
                            of its degree).

    - ``ep``             -- ``None`` if `f` is not homogeneous, otherwise
                            the multiplier of `f` (which is the second component
                            of its degree)

    - ``analytic_type``  -- The ``AnalyticType`` of `f`.

    For the zero function the degree `(0, 1)` is choosen.

    This function is (heavily) used to determine the type of elements
    and to check if the element really is contained in its parent.


    EXAMPLES::

        sage: from sage.modular.modform_hecketriangle.constructor import rational_type
        sage: (x,y,z,d) = var("x,y,z,d")

        sage: rational_type(0, n=4)
        (True, True, 0, 1, zero)

        sage: rational_type(1, n=12)
        (True, True, 0, 1, modular)

        sage: rational_type(x^3 - y^2)
        (True, True, 12, 1, cuspidal)

        sage: rational_type(x * z, n=7)
        (True, True, 14/5, -1, quasi modular)

        sage: rational_type(1/(x^3 - y^2) + z/d)
        (True, False, None, None, quasi weakly holomorphic modular)

        sage: rational_type(x^3/(x^3 - y^2))
        (True, True, 0, 1, weakly holomorphic modular)

        sage: rational_type(1/(x + z))
        (False, False, None, None, None)

        sage: rational_type(1/x + 1/z)
        (True, False, None, None, quasi meromorphic modular)

        sage: rational_type(d/x, n=10)
        (True, True, -1/2, 1, meromorphic modular)

        sage: rational_type(1.1 * z * (x^8-y^2), n=8, base_ring=CC)
        (True, True, 22/3, -1, quasi cuspidal)

        sage: rational_type(x-y^2, n=infinity)
        (True, True, 4, 1, modular)

        sage: rational_type(x*(x-y^2), n=infinity)
        (True, True, 8, 1, cuspidal)

        sage: rational_type(1/x, n=infinity)
        (True, True, -4, 1, weakly holomorphic modular)
    """

    from .analytic_type import AnalyticType
    AT = AnalyticType()

    # Determine whether f is zero
    if (f == 0):
        #       elem, h**o, k,     ep,    analytic_type
        return (True, True, QQ(0), ZZ(1), AT([]))

    analytic_type = AT(["quasi", "mero"])

    R              = PolynomialRing(base_ring,'x,y,z,d')
    F              = FractionField(R)
    (x,y,z,d)      = R.gens()
    R2             = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z')
    dhom           = R.hom( R2.gens() + (R2.base().gen(),), R2)

    f              = F(f)

    num            = R(f.numerator())
    denom          = R(f.denominator())
    ep_num         = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in   dhom(num).monomials()])
    ep_denom       = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in dhom(denom).monomials()])

    if (n == infinity):
        hom_num    = R(   num.subs(x=x**4, y=y**2, z=z**2) )
        hom_denom  = R( denom.subs(x=x**4, y=y**2, z=z**2) )
    else:
        n          = ZZ(n)
        hom_num    = R(   num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) )
        hom_denom  = R( denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) )

    # Determine whether the denominator of f is homogeneous
    if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()):
        elem = True
    else:
        #       elem,  h**o,  k,    ep,   analytic_type
        return (False, False, None, None, None)


    # Determine whether f is homogeneous
    if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()):
        h**o   = True
        if (n == infinity):
            weight = (dhom(hom_num).degree() - dhom(hom_denom).degree())
        else:
            weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n-2)
        ep     = ep_num.pop() / ep_denom.pop()
    # TODO: decompose f (resp. its degrees) into homogeneous parts
    else:
        h**o   = False
        weight = None
        ep     = None

    # Note that we intentionally leave out the d-factor!
    if (n == infinity):
        finf_pol = (x-y**2)
    else:
        finf_pol = x**n-y**2

    # Determine whether f is modular
    if not ( (num.degree(z) > 0) or (denom.degree(z) > 0) ):
        analytic_type = analytic_type.reduce_to("mero")

    # Determine whether f is holomorphic
    if (dhom(denom).is_constant()):
        analytic_type = analytic_type.reduce_to(["quasi", "holo"])
        # Determine whether f is cuspidal in the sense that finf divides it...
        # Bug in singular: finf_pol.divides(1.0) fails over RR
        if (not dhom(num).is_constant() and finf_pol.divides(num)):
            if (n != infinity or x.divides(num)):
                analytic_type = analytic_type.reduce_to(["quasi", "cusp"])
    else:
        # -> Because of a bug with singular in some cases
        try:
            while (finf_pol.divides(denom)):
                # a simple "denom /= finf_pol" is strangely not enough for non-exact rings
                # and dividing would/may result with an element of the quotient ring of the polynomial ring
                denom = denom.quo_rem(finf_pol)[0]
                denom = R(denom)
            if (n == infinity):
                while (x.divides(denom)):
                    # a simple "denom /= x" is strangely not enough for non-exact rings
                    # and dividing would/may result with an element of the quotient ring of the polynomial ring
                    denom = denom.quo_rem(x)[0]
                    denom = R(denom)
        except TypeError:
            pass

        # Determine whether f is weakly holomorphic in the sense that at most powers of finf occur in denom
        if (dhom(denom).is_constant()):
            analytic_type = analytic_type.reduce_to(["quasi", "weak"])

    return (elem, h**o, weight, ep, analytic_type)
Beispiel #12
0
def dimension__vector_valued(k, L, conjugate=False):
    r"""
    Compute the dimension of the space of weight `k` vector valued modular forms
    for the Weil representation (or its conjugate) attached to the lattice `L`.
    
    See [Borcherds, Borcherds - Reflection groups of Lorentzian lattices] for a proof
    of the formula that we use here.
    
    INPUT:
    
    - `k` -- A half-integer.
    
    - ``L`` -- An quadratic form.
    
    - ``conjugate`` -- A boolean; If ``True``, then compute the dimension for
                       the conjugated Weil representation.
    
    OUTPUT:
        An integer.

    TESTS::

        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 1, 1, 2])))
        1
        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 2])))
        1
        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 4])))
        1
    """
    if 2 * k not in ZZ:
        raise ValueError("Weight must be half-integral")
    if k <= 0:
        return 0
    if k < 2:
        raise NotImplementedError("Weight <2 is not implemented.")

    if L.matrix().rank() != L.matrix().nrows():
        raise ValueError(
            "The lattice (={0}) must be non-degenerate.".format(L))

    L_dimension = L.matrix().nrows()
    if L_dimension % 2 != ZZ(2 * k) % 2:
        return 0

    plus_basis = ZZ(L_dimension + 2 * k) % 4 == 0

    ## The bilinear and the quadratic form attached to L
    quadratic = lambda x: L(x) // 2
    bilinear = lambda x, y: L(x + y) - L(x) - L(y)

    ## A dual basis for L
    (elementary_divisors, dual_basis_pre, _) = L.matrix().smith_form()
    elementary_divisors = elementary_divisors.diagonal()
    dual_basis = map(operator.div, list(dual_basis_pre), elementary_divisors)

    L_level = ZZ(lcm([b.denominator() for b in dual_basis]))

    (elementary_divisors, _, discriminant_basis_pre) = (
        L_level * matrix(dual_basis)).change_ring(ZZ).smith_form()
    elementary_divisors = filter(lambda d: d not in ZZ,
                                 (elementary_divisors / L_level).diagonal())
    elementary_divisors_inv = map(ZZ, [ed**-1 for ed in elementary_divisors])
    discriminant_basis = matrix(
        map(operator.mul,
            discriminant_basis_pre.inverse().rows()[:len(elementary_divisors)],
            elementary_divisors)).transpose()
    ## This is a form over QQ, so that we cannot use an instance of QuadraticForm
    discriminant_form = discriminant_basis.transpose() * L.matrix(
    ) * discriminant_basis

    if conjugate:
        discriminant_form = -discriminant_form

    if prod(elementary_divisors_inv) > 100:
        disc_den = discriminant_form.denominator()
        disc_bilinear_pre = \
            cython_lambda( ', '.join(   ['int a{0}'.format(i) for i in range(discriminant_form.nrows())]
                                        + ['int b{0}'.format(i) for i in range(discriminant_form.nrows())] ),
                           ' + '.join('{0} * a{1} * b{2}'.format(disc_den * discriminant_form[i,j], i, j)
                                      for i in range(discriminant_form.nrows())
                                      for j in range(discriminant_form.nrows())) )
        disc_bilinear = lambda *a: disc_bilinear_pre(*a) / disc_den
    else:
        disc_bilinear = lambda *xy: vector(ZZ, xy[:discriminant_form.nrows(
        )]) * discriminant_form * vector(ZZ, xy[discriminant_form.nrows():])

    disc_quadratic = lambda *a: disc_bilinear(*(2 * a)) / 2

    ## red gives a normal form for elements in the discriminant group
    red = lambda x: map(operator.mod, x, elementary_divisors_inv)

    def is_singl(x):
        y = red(map(operator.neg, x))
        for (e, f) in zip(x, y):
            if e < f:
                return -1
            elif e > f:
                return 1
        return 0

    ## singls and pairs are elements of the discriminant group that are, respectively,
    ## fixed and not fixed by negation.
    singls = list()
    pairs = list()
    for x in mrange(elementary_divisors_inv):
        si = is_singl(x)
        if si == 0:
            singls.append(x)
        elif si == 1:
            pairs.append(x)

    if plus_basis:
        subspace_dimension = len(singls + pairs)
    else:
        subspace_dimension = len(pairs)

    ## 200 bits are, by far, sufficient to distinguish 12-th roots of unity
    ## by increasing the precision by 4 for each additional dimension, we
    ## compensate, by far, the errors introduced by the QR decomposition,
    ## which are of the size of (absolute error) * dimension
    CC = ComplexIntervalField(200 + subspace_dimension * 4)

    zeta_order = ZZ(
        lcm([8, 12] + map(lambda ed: 2 * ed, elementary_divisors_inv)))

    zeta = CC(exp(2 * pi * I / zeta_order))
    sqrt2 = CC(sqrt(2))
    drt = CC(sqrt(L.det()))

    Tmat = diagonal_matrix(CC, [
        zeta**(zeta_order * disc_quadratic(*a))
        for a in (singls + pairs if plus_basis else pairs)
    ])
    if plus_basis:
        Smat = zeta**(zeta_order / 8 * L_dimension) / drt  \
               * matrix( CC, [  [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls]
                              + [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in pairs]
                              for gamma in singls] \
                           + [  [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls]
                              + [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) + zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg, delta)))) for delta in pairs]
                              for gamma in pairs] )
    else:
        Smat = zeta**(zeta_order / 8 * L_dimension) / drt  \
               * matrix( CC, [  [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) - zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg,delta))))  for delta in pairs]
                               for gamma in pairs ] )
    STmat = Smat * Tmat

    ## This function overestimates the number of eigenvalues, if it is not correct
    def eigenvalue_multiplicity(mat, ev):
        mat = matrix(CC, mat - ev * identity_matrix(subspace_dimension))
        return len(
            filter(lambda row: all(e.contains_zero() for e in row),
                   _qr(mat).rows()))

    rti = CC(exp(2 * pi * I / 8))
    S_ev_multiplicity = [
        eigenvalue_multiplicity(Smat, rti**n) for n in range(8)
    ]
    ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities
    ## this asserts that the computed multiplicities are correct
    assert sum(S_ev_multiplicity) == subspace_dimension

    rho = CC(exp(2 * pi * I / 12))
    ST_ev_multiplicity = [
        eigenvalue_multiplicity(STmat, rho**n) for n in range(12)
    ]
    ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities
    ## this asserts that the computed multiplicities are correct
    assert sum(ST_ev_multiplicity) == subspace_dimension

    T_evs = [
        ZZ((zeta_order * disc_quadratic(*a)) % zeta_order) / zeta_order
        for a in (singls + pairs if plus_basis else pairs)
    ]

    return subspace_dimension * (1 + QQ(k) / 12) \
           - ZZ(sum( (ST_ev_multiplicity[n] * ((-2 * k - n) % 12)) for n in range(12) )) / 12 \
           - ZZ(sum( (S_ev_multiplicity[n] * ((2 * k + n) % 8)) for n in range(8) )) / 8 \
           - sum(T_evs)
Beispiel #13
0
 def _rad(self, center):
     return RBF.one() << QQ(center).valuation(2)
Beispiel #14
0
    def is_genus(self, signature_pair, even=True):
        r"""
        Return ``True`` if there is a lattice with this signature and discriminant form.

        .. TODO::

            implement the same for odd lattices

        INPUT:

        - signature_pair -- a tuple of non negative integers ``(s_plus, s_minus)``
        - even -- bool (default: ``True``)

        EXAMPLES::

            sage: L = IntegralLattice("D4").direct_sum(IntegralLattice(3 * Matrix(ZZ,2,[2,1,1,2])))
            sage: D = L.discriminant_group()
            sage: D.is_genus((6,0))
            True

        Let us see if there is a lattice in the genus defined by the same discriminant form
        but with a different signature::

            sage: D.is_genus((4,2))
            False
            sage: D.is_genus((16,2))
            True
        """
        s_plus = ZZ(signature_pair[0])
        s_minus = ZZ(signature_pair[1])
        if s_plus < 0 or s_minus < 0:
            raise ValueError("signature invariants must be non negative")
        rank = s_plus + s_minus
        signature = s_plus - s_minus
        D = self.cardinality()
        det = (-1)**s_minus * D
        if rank < len(self.invariants()):
            return False
        if even and self._modulus_qf != 2:
            raise ValueError("the discriminant form of an even lattice has"
                             "values modulo 2.")
        if (not even) and not (self._modulus == self._modulus_qf == 1):
            raise ValueError("the discriminant form of an odd lattice has"
                             "values modulo 1.")
        if not even:
            raise NotImplementedError("at the moment sage knows how to do this only for even genera. " +
                                      " Help us to implement this for odd genera.")
        for p in D.prime_divisors():
            # check the determinant conditions
            Q_p = self.primary_part(p)
            gram_p = Q_p.gram_matrix_quadratic()
            length_p = len(Q_p.invariants())
            u = det.prime_to_m_part(p)
            up = gram_p.det().numerator().prime_to_m_part(p)
            if p != 2 and length_p == rank:
                if legendre_symbol(u, p) != legendre_symbol(up, p):
                    return False
            if p == 2:
                if rank % 2 != length_p % 2:
                    return False
                n = (rank - length_p) / 2
                if u % 4 != (-1)**(n % 2) * up % 4:
                    return False
                if rank == length_p:
                    a = QQ(1) / QQ(2)
                    b = QQ(3) / QQ(2)
                    diag = gram_p.diagonal()
                    if not (a in diag or b in diag):
                        if u % 8 != up % 8:
                            return False
        if self.brown_invariant() != signature:
            return False
        return True
Beispiel #15
0
    def normal_cone(self):
        r"""
        Return the (closure of the) normal cone of the triangulation.

        Recall that a regular triangulation is one that equals the
        "crease lines" of a convex piecewise-linear function. This
        support function is not unique, for example, you can scale it
        by a positive constant. The set of all piecewise-linear
        functions with fixed creases forms an open cone. This cone can
        be interpreted as the cone of normal vectors at a point of the
        secondary polytope, which is why we call it normal cone. See
        [GKZ]_ Section 7.1 for details.

        OUTPUT:

        The closure of the normal cone. The `i`-th entry equals the
        value of the piecewise-linear function at the `i`-th point of
        the configuration.

        For an irregular triangulation, the normal cone is empty. In
        this case, a single point (the origin) is returned.

        EXAMPLES::

            sage: triangulation = polytopes.hypercube(2).triangulate(engine='internal')
            sage: triangulation
            (<0,1,3>, <0,2,3>)
            sage: N = triangulation.normal_cone();  N
            4-d cone in 4-d lattice
            sage: N.rays()
            (-1,  0,  0,  0),
            ( 1,  0,  1,  0),
            (-1,  0, -1,  0),
            ( 1,  0,  0, -1),
            (-1,  0,  0,  1),
            ( 1,  1,  0,  0),
            (-1, -1,  0,  0)
            in Ambient free module of rank 4
            over the principal ideal domain Integer Ring
            sage: N.dual().rays()
            (-1, 1, 1, -1)
            in Ambient free module of rank 4
            over the principal ideal domain Integer Ring

        TESTS::

            sage: polytopes.simplex(2).triangulate().normal_cone()
            3-d cone in 3-d lattice
            sage: _.dual().is_trivial()
            True
        """
        if not self.point_configuration().base_ring().is_subring(QQ):
            raise NotImplementedError('Only base rings ZZ and QQ are supported')
        from sage.libs.ppl import Variable, Constraint, Constraint_System, Linear_Expression, C_Polyhedron
        from sage.matrix.constructor import matrix
        from sage.misc.misc import uniq
        from sage.rings.arith import lcm
        pc = self.point_configuration()
        cs = Constraint_System()
        for facet in self.interior_facets():
            s0, s1 = self._boundary_simplex_dictionary()[facet]
            p = set(s0).difference(facet).pop()
            q = set(s1).difference(facet).pop()
            origin = pc.point(p).reduced_affine_vector()
            base_indices = [ i for i in s0 if i!=p ]
            base = matrix([ pc.point(i).reduced_affine_vector()-origin for i in base_indices ])
            sol = base.solve_left( pc.point(q).reduced_affine_vector()-origin )
            relation = [0]*pc.n_points()
            relation[p] = sum(sol)-1
            relation[q] = 1
            for i, base_i in enumerate(base_indices):
                relation[base_i] = -sol[i]
            rel_denom = lcm([QQ(r).denominator() for r in relation])
            relation = [ ZZ(r*rel_denom) for r in relation ]
            ex = Linear_Expression(relation,0)
            cs.insert(ex >= 0)
        from sage.modules.free_module import FreeModule
        ambient = FreeModule(ZZ, self.point_configuration().n_points())
        if cs.empty():
            cone = C_Polyhedron(ambient.dimension(), 'universe')
        else:
            cone = C_Polyhedron(cs)
        from sage.geometry.cone import _Cone_from_PPL
        return _Cone_from_PPL(cone, lattice=ambient)
    def angles(self, numerical=False, return_adjacent_edges=False):
        r"""
        Return the set of angles around the vertices of the surface.

        These are given as multiple of `2 \pi`.

        EXAMPLES::

            sage: import flatsurf.geometry.similarity_surface_generators as sfg
            sage: sfg.translation_surfaces.regular_octagon().angles()
            [3]
            sage: S = sfg.translation_surfaces.veech_2n_gon(5)
            sage: S.angles()
            [2, 2]
            sage: S.angles(numerical=True)
            [2.0, 2.0]
            sage: S.angles(return_adjacent_edges=True)
            [(2, [(0, 1), (0, 5), (0, 9), (0, 3), (0, 7)]),
             (2, [(0, 0), (0, 4), (0, 8), (0, 2), (0, 6)])]
            sage: S.angles(numerical=True, return_adjacent_edges=True)
            [(2.0, [(0, 1), (0, 5), (0, 9), (0, 3), (0, 7)]),
             (2.0, [(0, 0), (0, 4), (0, 8), (0, 2), (0, 6)])]

            sage: sfg.translation_surfaces.veech_2n_gon(6).angles()
            [5]
            sage: sfg.translation_surfaces.veech_double_n_gon(5).angles()
            [3]
            sage: sfg.translation_surfaces.cathedral(1, 1).angles()
            [3, 3, 3]

            sage: from flatsurf import polygons, similarity_surfaces
            sage: B = similarity_surfaces.billiard(polygons.triangle(1, 2, 5))
            sage: H = B.minimal_cover(cover_type="half-translation")
            sage: S = B.minimal_cover(cover_type="translation")
            sage: H.angles()
            [1/2, 5/2, 1/2, 1/2]
            sage: S.angles()
            [1, 5, 1, 1]

            sage: H.angles(return_adjacent_edges=True)
             [(1/2, [...]), (5/2, [...]), (1/2, [...]), (1/2, [...])]
            sage: S.angles(return_adjacent_edges=True)
             [(1, [...]), (5, [...]), (1, [...]), (1, [...])]
        """
        if not self.is_finite():
            raise NotImplementedError("the set of edges is infinite!")

        edges = set(self.edge_iterator())
        angles = []

        if return_adjacent_edges:
            while edges:
                pair = p, e = next(iter(edges))
                ve = self.polygon(p).edge(e)
                angle = 0
                adjacent_edges = []
                while pair in edges:
                    adjacent_edges.append(pair)
                    edges.remove(pair)
                    f = (e - 1) % self.polygon(p).num_edges()
                    ve = self.polygon(p).edge(e)
                    vf = -self.polygon(p).edge(f)
                    ppair = pp, ff = self.opposite_edge(p, f)
                    angle += (ve[0] > 0 and vf[0] <= 0) or (
                        ve[0] < 0 and vf[0] >= 0) or (ve[0] == vf[0] == 0)
                    pair, p, e = ppair, pp, ff
                if numerical:
                    angles.append((float(angle) / 2, adjacent_edges))
                else:
                    angles.append((QQ((angle, 2)), adjacent_edges))
        else:
            while edges:
                pair = p, e = next(iter(edges))
                angle = 0
                while pair in edges:
                    edges.remove(pair)
                    f = (e - 1) % self.polygon(p).num_edges()
                    ve = self.polygon(p).edge(e)
                    vf = -self.polygon(p).edge(f)
                    ppair = pp, ff = self.opposite_edge(p, f)
                    angle += (ve[0] > 0 and vf[0] <= 0) or (
                        ve[0] < 0 and vf[0] >= 0) or (ve[0] == vf[0] == 0)
                    pair, p, e = ppair, pp, ff
                if numerical:
                    angles.append(float(angle) / 2)
                else:
                    angles.append(QQ((angle, 2)))

        return angles
Beispiel #17
0
    def possible_orders(self, proof=True):
        """
        Return the possible orders of this torsion subgroup. Outside of special
        cases, this is done by computing a divisor and multiple of the order.

        INPUT:

        - ``proof`` -- a boolean (default: True)

        OUTPUT:

        - an array of positive integers

        The computation of the rational torsion order of J1(p) is conjectural
        and will only be used if proof=False. See Section 6.2.3 of [CES2003]_.

        EXAMPLES::

            sage: J0(11).rational_torsion_subgroup().possible_orders()
            [5]
            sage: J0(33).rational_torsion_subgroup().possible_orders()
            [100, 200]

            sage: J1(13).rational_torsion_subgroup().possible_orders()
            [19]
            sage: J1(16).rational_torsion_subgroup().possible_orders()
            [1, 2, 4, 5, 10, 20]
        """
        try:
            if proof:
                return self._possible_orders
            else:
                return self._possible_orders_proof_false
        except AttributeError:
            pass

        A = self.abelian_variety()
        N = A.level()
        # return the order of the cuspidal subgroup in the J0(p) case
        if A.is_J0() and N.is_prime():
            self._possible_orders = [QQ((A.level() - 1) / 12).numerator()]
            self._possible_orders_proof_false = self._possible_orders
            return self._possible_orders

        # the elliptic curve case
        if A.dimension() == 1:
            self._possible_orders = [A.elliptic_curve().torsion_order()]
            self._possible_orders_proof_false = self._possible_orders
            return self._possible_orders

        # the conjectural J1(p) case
        if not proof and A.is_J1() and N.is_prime():
            epsilons = [
                epsilon for epsilon in DirichletGroup(N)
                if not epsilon.is_trivial() and epsilon.is_even()
            ]
            bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons]
            self._possible_orders_proof_false = [
                ZZ(N / (2**(N - 3)) * prod(bernoullis))
            ]
            return self._possible_orders_proof_false

        u = self.multiple_of_order()
        l = self.divisor_of_order()

        assert u % l == 0
        O = [l * d for d in divisors(u // l)]
        self._possible_orders = O
        if u == l:
            self._possible_orders_proof_false = O
        return O
Beispiel #18
0
def _test_monodromy_matrices():
    r"""
    TESTS::

        sage: from ore_algebra.analytic.monodromy import _test_monodromy_matrices
        sage: _test_monodromy_matrices()
    """
    from sage.all import matrix
    from ore_algebra import DifferentialOperators
    Dops, x, Dx = DifferentialOperators()

    h = QQ(1) / 2
    i = QQi.gen()

    def norm(m):
        return sum(c.abs()**2 for c in m.list()).sqrtpos()

    mon = monodromy_matrices((x**2 + 1) * Dx - 1, QQ(1000000))
    assert norm(mon[0] - CBF(pi).exp()) < RBF(1e-10)
    assert norm(mon[1] - CBF(-pi).exp()) < RBF(1e-10)

    mon = monodromy_matrices((x**2 - 1) * Dx - 1, QQ(0))
    assert all(m == -1 for m in mon)

    dop = (x**2 + 1) * Dx**2 + 2 * x * Dx
    mon = monodromy_matrices(dop, QQbar(i + 1))  # mon[0] <--> i
    assert norm(mon[0] - matrix(CBF, [[1, pi *
                                       (1 + 2 * i)], [0, 1]])) < RBF(1e-10)
    assert norm(mon[1] - matrix(CBF, [[1, -pi *
                                       (1 + 2 * i)], [0, 1]])) < RBF(1e-10)
    mon = monodromy_matrices(dop, QQbar(-i + 1))  # mon[0] <--> -i
    assert norm(mon[0] - matrix(CBF, [[1, pi *
                                       (-1 + 2 * i)], [0, 1]])) < RBF(1e-10)
    assert norm(mon[1] - matrix(CBF, [[1, pi *
                                       (1 - 2 * i)], [0, 1]])) < RBF(1e-10)
    mon = monodromy_matrices(dop, QQbar(i))  # mon[0] <--> i
    assert norm(mon[0] - matrix(CBF, [[1, 0], [2 * pi * i, 1]])) < RBF(1e-10)
    assert norm(mon[1] - matrix(CBF, [[1, 0], [-2 * pi * i, 1]])) < RBF(1e-10)
    mon = monodromy_matrices(dop, QQbar(i), sing=[QQbar(i)])
    assert len(mon) == 1
    assert norm(mon[0] - matrix(CBF, [[1, 0], [2 * pi * i, 1]])) < RBF(1e-10)
    mon = monodromy_matrices(dop, QQbar(i), sing=[QQbar(-i)])
    assert len(mon) == 1
    assert norm(mon[0] - matrix(CBF, [[1, 0], [-2 * pi * i, 1]])) < RBF(1e-10)
    mon = monodromy_matrices(dop, QQbar(-i), sing=[QQbar(i)])
    assert len(mon) == 1
    assert norm(mon[0] - matrix(CBF, [[1, 0], [-2 * pi * i, 1]])) < RBF(1e-10)
    mon = monodromy_matrices(dop, QQbar(i), sing=[])
    assert mon == []

    dop = (x**2 + 1) * (x**2 - 1) * Dx**2 + 1
    mon = monodromy_matrices(dop, QQ(0), sing=[QQ(1), QQbar(i)])
    m0 = dop.numerical_transition_matrix([0, i + 1, 2 * i, i - 1, 0])
    assert norm(m0 - mon[0]) < RBF(1e-10)
    m1 = dop.numerical_transition_matrix([0, 1 - i, 2, 1 + i, 0])
    assert norm(m1 - mon[1]) < RBF(1e-10)

    dop = x * (x - 3) * (x - 4) * (x**2 - 6 * x + 10) * Dx**2 - 1
    mon = monodromy_matrices(dop, QQ(-1))
    m0 = dop.numerical_transition_matrix([-1, -i, 1, i, -1])
    assert norm(m0 - mon[0]) < RBF(1e-10)
    m1 = dop.numerical_transition_matrix(
        [-1, i / 2, 3 - i / 2, 3 + h, 3 + i / 2, i / 2, -1])
    assert norm(m1 - mon[1]) < RBF(1e-10)
    m2 = dop.numerical_transition_matrix(
        [-1, i / 2, 3 + i / 2, 4 - i / 2, 4 + h, 4 + i / 2, i / 2, -1])
    assert norm(m2 - mon[2]) < RBF(1e-10)
    m3 = dop.numerical_transition_matrix([-1, 3 + i + h, 3 + 2 * i, -1])
    assert norm(m3 - mon[3]) < RBF(1e-10)
    m4 = dop.numerical_transition_matrix(
        [-1, 3 - 2 * i, 3 - i + h, 3 - i / 2, -1])
    assert norm(m4 - mon[4]) < RBF(1e-10)

    dop = (x - i)**2 * (x + i) * Dx - 1
    mon = monodromy_matrices(dop, 0)
    assert norm(mon[0] + i) < RBF(1e-10)
    assert norm(mon[1] - i) < RBF(1e-10)

    dop = (x - i)**2 * (x + i) * Dx**2 - 1
    mon = monodromy_matrices(dop, 0)
    m0 = dop.numerical_transition_matrix([0, i + 1, 2 * i, i - 1, 0])
    assert norm(m0 - mon[0]) < RBF(1e-10)
    m1 = dop.numerical_transition_matrix([0, -i - 1, -2 * i, -i + 1, 0])
    assert norm(m1 - mon[1]) < RBF(1e-10)
Beispiel #19
0
    def check(self, cb, sing, n, ini_tb, est, next_stride):
        r"""
        Test if it is time to halt the computation of the sum of a series.

        INPUT:

        - cb: BoundCallbacks object, see the documentation of that class;
        - sing: boolean, True signals a singular index where we should return
          infinity without even trying to compute a better bound (this is useful
          to avoid special-casing singular indices elsewhere);
        - n: current index;
        - ini_tb: previous tail bound (can be infinite);
        - est: real interval, heuristic estimate of the absolute value of the
          tail of the series, **whose lower bound must tend to zero or
          eventually become negative**, and whose width can be used to provide
          an indication of interval blow-up in the computation; typically
          something like abs(first nonzero neglected term);
        - next_stride: indication of how many additional terms the caller
          intends to sum before calling us again.

        OUTPUT:

        (done, bound) where done is a boolean indicating if it is time to stop
        the computation, and bound is a rigorous (possibly infinite) bound on
        the tail of the series.

        TESTS::

            sage: from ore_algebra import DifferentialOperators
            sage: from ore_algebra.analytic.bounds import DiffOpBound
            sage: from ore_algebra.analytic.naive_sum import series_sum
            sage: Dops, x, Dx = DifferentialOperators()
            sage: maj = DiffOpBound(Dx-1, max_effort=0)
            sage: series_sum(Dx-1, [1], 2, 1e-50, stride=1)
            ([7.3890560989306502272304274605750078131803155705...])
        """
        if sing:
            return False, IR('inf')

        eps = self.eps

        # XXX We shouldn't force the caller to give a full-precision estimate...
        accuracy = max(est.accuracy(), -int((est.rad() or RR(1)).log(2)))
        width = IR(est.rad())
        est = IR(est)
        intervals_blowing_up = (accuracy < self.prec
                                or safe_le(self.eps >> 2, width))
        if intervals_blowing_up:
            if self.fast_fail:
                logger.debug("n=%d, est=%s, width=%s", n, est, width)
                raise PrecisionError
            if safe_le(self.eps, width):
                # Aim for tail_bound < width instead of tail_bound < self.eps
                eps = width

        if safe_lt(eps, est) and accuracy >= self.prec and not self.force:
            # It is important to test the inequality with the *interval* est, to
            # avoid getting caught in an infinite loop when est increases
            # indefinitely due to interval blow-up. When however the lower bound
            # of est increases too, we are probably climbing a term hump (think
            # exp(1000)): it is better not to halt the computation yet, in the
            # hope of getting at least a reasonable relative error.
            logger.debug("n=%d, est=%s, width=%s", n, est, width)
            assert width.is_finite()
            return False, IR('inf')

        resid = cb.get_residuals()

        tb = IR('inf')
        while True:
            prev_tb = tb
            tb = cb.get_bound(resid)
            logger.debug("n=%d, est=%s, width=%s, tail_bound=%s", n, est,
                         width, tb)
            bound_getting_worse = ini_tb.is_finite() and not safe_lt(
                tb, ini_tb)
            if safe_lt(tb, eps):
                logger.debug("--> ok")
                return True, tb
            elif self.force and not self.maj.can_refine():
                break
            elif (prev_tb.is_finite() and not safe_le(tb, prev_tb >> 8)
                  or not self.maj.can_refine()):
                if bound_getting_worse:
                    # The bounds are out of control, stop asap.
                    # Subtle point: We could also end up here because of a hump.
                    # But then, typically, est > ε, so that we shouldn't even
                    # have entered the rigorous phase unless the intervals are
                    # blowing up badly.
                    # Note: it seems best *not* to do this when prev_tb is
                    # non-finite, because we may be waiting to get past a
                    # singularity of the recurrence. (XXX: Unfortunately, we
                    # have no way of deciding if the bound is infinite because
                    # of a genuine mathematical reason or an evaluation issue.)
                    logger.debug(
                        "--> bounds out of control ({} became {})".format(
                            ini_tb, tb))
                    return True, tb
                else:
                    # Refining no longer seems to help: sum more terms
                    logger.debug("--> refining doesn't help")
                    break
            elif intervals_blowing_up or bound_getting_worse:
                # Adding more terms is likely to make the result worse and
                # worse, but we can try refining the majorant as much as
                # possible before giving up. (Note that unlike in the previous
                # branch, we do not stop asap if the bound is getting worse in
                # the present case.)
                logger.debug("--> intervals blowing up or bound getting worse")
                self.maj.refine()
            else:
                thr = tb * est**(QQ(next_stride * (self.maj.effort()**2 + 2)) /
                                 (n + 1))
                if safe_le(thr, eps):
                    # Try summing a few more terms before refining
                    logger.debug(
                        "--> above refinement threshold ({} <= {})".format(
                            thr, eps))
                    break
                else:
                    logger.debug("--> bad bound but refining may help")
                    self.maj.refine()
        logger.debug("--> ko")
        return False, tb
Beispiel #20
0
def lift_map(target):
    r"""
    Create a lift map, to be used for lifting the cross ratios of a matroid
    representation.

    .. SEEALSO::

        :meth:`lift_cross_ratios() <sage.matroids.utilities.lift_cross_ratios>`

    INPUT:

    - ``target`` -- a string describing the target (partial) field.

    OUTPUT:

    - a dictionary

    Depending on the value of ``target``, the following lift maps will be created:

    - "reg": a lift map from `\GF3` to the regular partial field `(\ZZ, <-1>)`.

    - "sru": a lift map from `\GF7` to the
      sixth-root-of-unity partial field `(\QQ(z), <z>)`, where `z` is a sixth root
      of unity. The map sends 3 to `z`.

    - "dyadic": a lift map from `\GF{11}` to the dyadic partial field `(\QQ, <-1, 2>)`.

    - "gm": a lift map from `\GF{19}` to the golden mean partial field
      `(\QQ(t), <-1,t>)`, where `t` is a root of `t^2-t-1`. The map sends `5` to `t`.

    The example below shows that the latter map satisfies three necessary conditions stated in
    :meth:`lift_cross_ratios() <sage.matroids.utilities.lift_cross_ratios>`

    EXAMPLES::

        sage: from sage.matroids.utilities import lift_map
        sage: lm = lift_map('gm')
        sage: for x in lm:
        ....:     if (x == 1) is not (lm[x] == 1):
        ....:         print('not a proper lift map')
        ....:     for y in lm:
        ....:         if (x+y == 0) and not (lm[x]+lm[y] == 0):
        ....:             print('not a proper lift map')
        ....:         if (x+y == 1) and not (lm[x]+lm[y] == 1):
        ....:             print('not a proper lift map')
        ....:         for z in lm:
        ....:             if (x*y==z) and not (lm[x]*lm[y]==lm[z]):
        ....:                 print('not a proper lift map')

    """
    if target == "reg":
        R = GF(3)
        return {R(1): ZZ(1)}

    if target == "sru":
        R = GF(7)
        z = ZZ['z'].gen()
        S = NumberField(z * z - z + 1, 'z')
        z = S(z)
        return {R.one(): S.one(), R(3): z, R(3)**(-1): z**5}

    if target == "dyadic":
        R = GF(11)
        return {R(1): QQ(1), R(-1): QQ(-1), R(2): QQ(2), R(6): QQ((1, 2))}

    if target == "gm":
        R = GF(19)
        t = QQ['t'].gen()
        G = NumberField(t * t - t - 1, 't')
        return {
            R(1): G(1),
            R(5): G(t),
            R(1) / R(5): G(1) / G(t),
            R(-5): G(-t),
            R(-5)**(-1): G(-t)**(-1),
            R(5)**2: G(t)**2,
            R(5)**(-2): G(t)**(-2)
        }

    raise NotImplementedError(target)
Beispiel #21
0
def enumerate_totallyreal_fields_rel(F,
                                     m,
                                     B,
                                     a=[],
                                     verbose=0,
                                     return_seqs=False,
                                     return_pari_objects=True):
    r"""
    This function enumerates (primitive) totally real field extensions of
    degree `m>1` of the totally real field F with discriminant `d \leq B`;
    optionally one can specify the first few coefficients, where the sequence ``a``
    corresponds to a polynomial by

    ::

        a[d]*x^n + ... + a[0]*x^(n-d)

    if ``length(a) = d+1``, so in particular always ``a[d] = 1``.

    .. note::

        This is guaranteed to give all primitive such fields, and
        seems in practice to give many imprimitive ones.

    INPUT:

    - ``F`` -- number field, the base field
    - ``m`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``a`` -- list (default: []), the coefficient list to begin with
    - ``verbose`` -- boolean or nonnegative integer or string (default: 0)
      give a verbose description of the computations being performed. If
      ``verbose`` is set to ``2`` or more then it outputs some extra
      information. If ``verbose`` is a string then it outputs to a file
      specified by ``verbose``
    - ``return_seqs`` -- (boolean, default False) If ``True``, then return
      the polynomials as sequences (for easier exporting to a file). This
      also returns a list of four numbers, as explained in the OUTPUT
      section below.
    - ``return_pari_objects`` -- (boolean, default: True) if
      both ``return_seqs`` and ``return_pari_objects`` are ``False`` then
      it returns the elements as Sage objects; otherwise it returns pari
      objects.

    OUTPUT:

    - the list of fields with entries ``[d,fabs,f]``, where ``d`` is the
      discriminant, ``fabs`` is an absolute defining polynomial, and ``f``
      is a defining polynomial relative to ``F``, sorted by discriminant.

    - if ``return_seqs`` is ``True``, then the first field of the list is
      a list containing the count of four items as explained below

      - the first entry gives the number of polynomials tested
      - the second entry gives the number of polynomials with its
        discriminant having a large enough square divisor
      - the third entry is the number of irreducible polynomials
      - the fourth entry is the number of irreducible polynomials with
        discriminant at most ``B``

    EXAMPLES::

        sage: ZZx = ZZ['x']
        sage: F.<t> = NumberField(x^2-2)
        sage: enumerate_totallyreal_fields_rel(F, 1, 2000)
        [[1, [-2, 0, 1], xF - 1]]
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
        [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)
        [[9, 6, 5, 0], [[1600, [4, 0, -6, 0, 1], [-1, 1, 1]]]]

    TESTS:

    Each of the outputs must be elements of Sage if ``return_pari_objects``
    is set to ``False``::

        sage: type(enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1])
        <type 'sage.libs.cypari2.gen.Gen'>
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent()
        Integer Ring
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent()
        Univariate Polynomial Ring in x over Rational Field
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][2].parent()
        Univariate Polynomial Ring in xF over Number Field in t with defining polynomial x^2 - 2
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)[1][0][1][0].parent()
        Rational Field

    AUTHORS:

    - John Voight (2007-11-01)
    """

    if not isinstance(m, Integer):
        try:
            m = Integer(m)
        except TypeError:
            raise TypeError("cannot coerce m (= %s) to an integer" % m)
    if (m < 1):
        raise ValueError("m must be at least 1.")

    n = F.degree() * m

    # Initialize
    S = {}  # dictionary of the form {(d, fabs): f, ...}
    dB_odlyzko = odlyzko_bound_totallyreal(n)
    dB = math.ceil(40000 * dB_odlyzko**n)
    counts = [0, 0, 0, 0]

    # Trivial case
    if m == 1:
        g = pari(F.defining_polynomial()).polrecip().Vec()
        if return_seqs:
            return [[0, 0, 0, 0], [1, [-1, 1], g]]
        elif return_pari_objects:
            return [[1, g, pari('xF-1')]]
        else:
            Px = PolynomialRing(QQ, 'xF')
            return [[ZZ(1), [QQ(_) for _ in g], Px.gen() - 1]]

    if verbose:
        saveout = sys.stdout
        if isinstance(verbose, str):
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
    f_out = [0] * m + [1]
    T = tr_data_rel(F, m, B, a)
    if verbose == 2:
        T.incr(f_out, verbose)
    else:
        T.incr(f_out)

    Fx = PolynomialRing(F, 'xF')

    nfF = pari(
        str(F.defining_polynomial()).replace('x', str(F.primitive_element())))
    parit = pari(str(F.primitive_element()))

    while f_out[m] != 0:
        counts[0] += 1
        if verbose:
            print("==>", f_out, end="")

        f_str = ''
        for i in range(len(f_out)):
            f_str += '(' + str(f_out[i]) + ')*x^' + str(i)
            if i < len(f_out) - 1:
                f_str += '+'
        nf = pari(f_str)
        if nf.poldegree('t') == 0:
            nf = nf.subst('x', 'x-t')
        nf = nf.polresultant(nfF, parit)
        d = nf.poldisc()
        #counts[0] += 1
        if d > 0 and nf.polsturm() == n:
            da = int_has_small_square_divisor(Integer(d))
            if d > dB or d <= B * da:
                counts[1] += 1
                if nf.polisirreducible():
                    counts[2] += 1
                    [zk, d] = nf.nfbasis_d()

                    if d <= B:
                        if verbose:
                            print("has discriminant", d, end="")

                        # Find a minimal lattice element
                        counts[3] += 1
                        ng = pari([nf, zk]).polredabs()

                        # Check if K is contained in the list.
                        if (d, ng) in S:
                            if verbose:
                                print("but is not new")
                        else:
                            if verbose:
                                print("and is new!")
                            S[(d, ng)] = Fx(f_out)
                    else:
                        if verbose:
                            print("has discriminant", abs(d), "> B")
                else:
                    if verbose:
                        print("is not absolutely irreducible")
            else:
                if verbose:
                    print("has discriminant", abs(d),
                          "with no large enough square divisor")
        else:
            if verbose:
                if d == 0:
                    print("is not squarefree")
                else:
                    print("is not totally real")
        if verbose == 2:
            T.incr(f_out, verbose=verbose)
        else:
            T.incr(f_out)

    # In the application of Smyth's theorem above, we exclude finitely
    # many possibilities which we must now throw back in.
    if m == 2:
        if Fx([-1, 1, 1]).is_irreducible():
            K = F.extension(Fx([-1, 1, 1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                S[(d, ng)] = Fx([-1, 1, 1])
        elif F.degree() == 2:
            for ff in [[1, -7, 13, -7, 1], [1, -8, 14, -7, 1]]:
                f = Fx(ff).factor()[0][0]
                K = F.extension(f, 'tK')
                Kabs = K.absolute_field('tKabs')
                Kabs_pari = pari(Kabs.defining_polynomial())
                d = K.absolute_discriminant()
                if abs(d) <= B:
                    ng = Kabs_pari.polredabs()
                    S[(d, ng)] = f
    elif m == 3:
        if Fx([-1, 6, -5, 1]).is_irreducible():
            K = F.extension(Fx([-1, 6, -5, 1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                S[(d, ng)] = Fx([-1, 6, -5, 1])

    # Convert S to a sorted list of triples [d, fabs, f], taking care
    # to use cmp() and not the comparison operators on PARI polynomials.
    S = [[s[0], s[1], t] for s, t in S.items()]
    S.sort(cmp=lambda x, y: cmp(x[0], y[0]) or cmp(x[1], y[1]))

    # Now check for isomorphic fields
    weed_fields(S)

    # Output.
    if verbose:
        print("=" * 80)
        print("Polynomials tested: {}".format(counts[0]))
        print("Polynomials with discriminant with large enough square"
              " divisor: {}".format(counts[1]))
        print("Irreducible polynomials: {}".format(counts[2]))
        print("Polynomials with nfdisc <= B: {}".format(counts[3]))
        for i in range(len(S)):
            print(S[i])
        if isinstance(verbose, str):
            fsock.close()
        sys.stdout = saveout

    # Make sure to return elements that belong to Sage
    if return_seqs:
        return [[ZZ(x) for x in counts],
                [[
                    s[0], [QQ(x) for x in s[1].polrecip().Vec()],
                    s[2].coefficients(sparse=False)
                ] for s in S]]
    elif return_pari_objects:
        return S
    else:
        Px = PolynomialRing(QQ, 'x')
        return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S]
Beispiel #22
0
def egros_get_j(S=[], proof=None, verbose=False):
    r"""
    Returns a list of rational `j` such that all elliptic curves
    defined over `Q` with good reduction outside `S` have
    `j`-invariant in the list, sorted by height.

    INPUT:

        -  ``S`` - list of primes (default: empty list).

        - ``proof`` - True/False (default True): the MW basis for
          auxiliary curves will be computed with this proof flag.

        - ``verbose`` - True/False (default False): if True, some
          details of the computation will be output.

    .. note::

        Proof flag: The algorithm used requires determining all
        S-integral points on several auxiliary curves, which in turn
        requires the computation of their generators.  This is not
        always possible (even in theory) using current knowledge.

        The value of this flag is passed to the function which
        computes generators of various auxiliary elliptic curves, in
        order to find their S-integral points.  Set to False if the
        default (True) causes warning messages, but note that you can
        then not rely on the set of invariants returned being
        complete.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.ell_egros import egros_get_j
        sage: egros_get_j([])
        [1728]
        sage: egros_get_j([2])
        [128, 432, -864, 1728, 3375/2, -3456, 6912, 8000, 10976, -35937/4, 287496, -784446336, -189613868625/128]
        sage: egros_get_j([3])
        [0, -576, 1536, 1728, -5184, -13824, 21952/9, -41472, 140608/3, -12288000]
        sage: jlist=egros_get_j([2,3]); len(jlist) # long time (30s)
        83

    """
    if not all([p.is_prime() for p in S]):
        raise ValueError, "Elements of S must be prime."

        if proof is None:
            from sage.structure.proof.proof import get_flag
            proof = get_flag(proof, "elliptic_curve")
        else:
            proof = bool(proof)

    if verbose:
        import sys  # so we can flush stdout for debugging

    SS = [-1] + S

    jlist = []
    wcount = 0
    nw = 6**len(S) * 2

    if verbose:
        print "Finding possible j invariants for S = ", S
        print "Using ", nw, " twists of base curve"
        sys.stdout.flush()

    for ei in xmrange([6] * len(S) + [2]):
        w = prod([p**e for p, e in zip(reversed(SS), ei)], QQ(1))
        wcount += 1
        if verbose:
            print "Curve #", wcount, "/", nw, ":"
            print "w = ", w, "=", w.factor()
            sys.stdout.flush()
        a6 = -1728 * w
        d2 = 0
        d3 = 0
        u0 = (2**d2) * (3**d3)
        E = EllipticCurve([0, 0, 0, 0, a6])
        # This curve may not be minimal at 2 or 3, but the
        # S-integral_points function requires minimality at primes in
        # S, so we find a new model which is p-minimal at both 2 and 3
        # if they are in S.  Note that the isomorphism between models
        # will preserve S-integrality of points.
        E2 = E.local_minimal_model(2) if 2 in S else E
        E23 = E2.local_minimal_model(3) if 3 in S else E2
        urst = E23.isomorphism_to(E)

        try:
            pts = E23.S_integral_points(S, proof=proof)
        except RuntimeError:
            pts = []
            print "Failed to find S-integral points on ", E23.ainvs()
            if proof:
                if verbose:
                    print "--trying again with proof=False"
                    sys.stdout.flush()
                pts = E23.S_integral_points(S, proof=False)
                if verbose:
                    print "--done"
        if verbose:
            print len(pts), " S-integral points: ", pts
            sys.stdout.flush()
        for P in pts:
            P = urst(P)
            x = P[0]
            y = P[1]
            j = x**3 / w
            assert j - 1728 == y**2 / w
            if is_possible_j(j, S):
                if not j in jlist:
                    if verbose:
                        print "Adding possible j = ", j
                        sys.stdout.flush()
                    jlist += [j]
            else:
                if True:  #verbose:
                    print "Discarding illegal j = ", j
                    sys.stdout.flush()
    height_cmp = lambda j1, j2: cmp(j1.height(), j2.height())
    jlist.sort(cmp=height_cmp)
    return jlist
Beispiel #23
0
    def next_state(self, height):
        r"""
        Build the next state for type `A_{2n}^{(2)\dagger}`.

        TESTS::

            sage: RC = RiggedConfigurations(CartanType(['A', 4, 2]).dual(), [[2,1]])
            sage: from sage.combinat.rigged_configurations.bij_type_A2_dual import RCToKRTBijectionTypeA2Dual
            sage: bijection = RCToKRTBijectionTypeA2Dual(RC(partition_list=[[2],[2,2]]))
            sage: bijection.next_state(2)
            -1
        """
        height -= 1  # indexing
        n = self.n
        ell = [None] * (2 * n)
        case_S = [False] * n
        case_Q = False
        b = None

        # Calculate the rank and ell values

        last_size = 0
        for a in range(height, n - 1):
            ell[a] = self._find_singular_string(self.cur_partitions[a],
                                                last_size)

            if ell[a] is None:
                b = a + 1
                break
            else:
                last_size = self.cur_partitions[a][ell[a]]

        if b is None:
            partition = self.cur_partitions[n - 1]
            # Special case for n
            for i in reversed(range(len(partition))):
                if partition[i] >= last_size:
                    if partition.vacancy_numbers[i] == partition.rigging[i]:
                        last_size = partition[i]
                        case_S[n - 1] = True
                        ell[2 * n - 1] = i
                        break
                    elif partition.vacancy_numbers[i] - QQ(1) / QQ(
                            2) == partition.rigging[i] and not case_Q:
                        case_Q = True
                        # This will never be singular
                        last_size = partition[i] + 1
                        ell[n - 1] = i

            if ell[2 * n - 1] is None:
                if not case_Q:
                    b = n
                else:
                    b = 0

        if b is None:
            # Now go back
            for a in reversed(range(n - 1)):
                if a >= height and self.cur_partitions[a][ell[a]] == last_size:
                    ell[n + a] = ell[a]
                    case_S[a] = True
                else:
                    ell[n + a] = self._find_singular_string(
                        self.cur_partitions[a], last_size)

                    if ell[n + a] is None:
                        b = -(a + 2)
                        break
                    else:
                        last_size = self.cur_partitions[a][ell[n + a]]

        if b is None:
            b = -1

        # Determine the new rigged configuration by removing boxes from the
        #   selected string and then making the new string singular
        if n > 1:
            if case_S[0]:
                row_num = None
                row_num_bar = self.cur_partitions[0].remove_cell(ell[n], 2)
            else:
                row_num = self.cur_partitions[0].remove_cell(ell[0])
                row_num_bar = self.cur_partitions[0].remove_cell(ell[n])
        for a in range(1, n - 1):
            if case_S[a]:
                row_num_next = None
                row_num_bar_next = self.cur_partitions[a].remove_cell(
                    ell[n + a], 2)
            else:
                row_num_next = self.cur_partitions[a].remove_cell(ell[a])
                row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n +
                                                                          a])

            self._update_vacancy_numbers(a - 1)
            if row_num is not None:
                self.cur_partitions[a -
                                    1].rigging[row_num] = self.cur_partitions[
                                        a - 1].vacancy_numbers[row_num]
            if row_num_bar is not None:
                self.cur_partitions[
                    a - 1].rigging[row_num_bar] = self.cur_partitions[
                        a - 1].vacancy_numbers[row_num_bar]
            row_num = row_num_next
            row_num_bar = row_num_bar_next

        if case_Q:
            row_num_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1])
            if case_S[n - 1]:
                row_num_bar_next = self.cur_partitions[n - 1].remove_cell(
                    ell[2 * n - 1])
            else:
                row_num_bar_next = None
        elif case_S[n - 1]:
            row_num_next = None
            row_num_bar_next = self.cur_partitions[n - 1].remove_cell(
                ell[2 * n - 1], 2)
        else:
            row_num_next = None
            row_num_bar_next = None

        if n > 1:
            self._update_vacancy_numbers(n - 2)
            if row_num is not None:
                self.cur_partitions[n -
                                    2].rigging[row_num] = self.cur_partitions[
                                        n - 2].vacancy_numbers[row_num]
            if row_num_bar is not None:
                self.cur_partitions[
                    n - 2].rigging[row_num_bar] = self.cur_partitions[
                        n - 2].vacancy_numbers[row_num_bar]

        self._update_vacancy_numbers(n - 1)
        if row_num_next is not None:
            self.cur_partitions[n -
                                1].rigging[row_num_next] = self.cur_partitions[
                                    n - 1].vacancy_numbers[row_num_next]
        if row_num_bar_next is not None:
            if case_Q:
                # This will always be the largest value
                self.cur_partitions[
                    n - 1].rigging[row_num_bar_next] = self.cur_partitions[
                        n -
                        1].vacancy_numbers[row_num_bar_next] - QQ(1) / QQ(2)
            else:
                self.cur_partitions[
                    n - 1].rigging[row_num_bar_next] = self.cur_partitions[
                        n - 1].vacancy_numbers[row_num_bar_next]

        return (b)
Beispiel #24
0
def parse_NFelt(K, s):
    r"""
    Returns an element of K defined by the string s.
    """
    return K([QQ(c) for c in s.split(",")])
Beispiel #25
0
    def __init__(self, a, b=None, parent=None, check=True):
        r"""
        Create the cusp a/b in `\mathbb{P}^1(\QQ)`, where if b=0
        this is the cusp at infinity.

        When present, b must either be Infinity or coercible to an
        Integer.

        EXAMPLES::

            sage: Cusp(2,3)
            2/3
            sage: Cusp(3,6)
            1/2
            sage: Cusp(1,0)
            Infinity
            sage: Cusp(infinity)
            Infinity
            sage: Cusp(5)
            5
            sage: Cusp(1/2)
            1/2
            sage: Cusp(1.5)
            3/2
            sage: Cusp(int(7))
            7
            sage: Cusp(1, 2, check=False)
            1/2
            sage: Cusp('sage', 2.5, check=False)          # don't do this!
            sage/2.50000000000000

        ::

            sage: I**2
            -1
            sage: Cusp(I)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert I to a cusp

        ::

            sage: a = Cusp(2,3)
            sage: loads(a.dumps()) == a
            True

        ::

            sage: Cusp(1/3,0)
            Infinity
            sage: Cusp((1,0))
            Infinity

        TESTS::

            sage: Cusp("1/3", 5)
            1/15
            sage: Cusp(Cusp(3/5), 7)
            3/35
            sage: Cusp(5/3, 0)
            Infinity
            sage: Cusp(3,oo)
            0
            sage: Cusp((7,3), 5)
            7/15
            sage: Cusp(int(5), 7)
            5/7

        ::

            sage: Cusp(0,0)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert (0, 0) to a cusp

        ::

            sage: Cusp(oo,oo)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert (+Infinity, +Infinity) to a cusp

        ::

            sage: Cusp(Cusp(oo),oo)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert (Infinity, +Infinity) to a cusp
        """
        if parent is None:
            parent = Cusps
        Element.__init__(self, parent)

        if not check:
            self.__a = a
            self.__b = b
            return

        if b is None:
            if isinstance(a, Integer):
                self.__a = a
                self.__b = ZZ.one()
            elif isinstance(a, Rational):
                self.__a = a.numer()
                self.__b = a.denom()
            elif is_InfinityElement(a):
                self.__a = ZZ.one()
                self.__b = ZZ.zero()
            elif isinstance(a, Cusp):
                self.__a = a.__a
                self.__b = a.__b
            elif isinstance(a, integer_types):
                self.__a = ZZ(a)
                self.__b = ZZ.one()
            elif isinstance(a, (tuple, list)):
                if len(a) != 2:
                    raise TypeError("unable to convert %r to a cusp" % a)
                if ZZ(a[1]) == 0:
                    self.__a = ZZ.one()
                    self.__b = ZZ.zero()
                    return
                try:
                    r = QQ((a[0], a[1]))
                    self.__a = r.numer()
                    self.__b = r.denom()
                except (ValueError, TypeError):
                    raise TypeError("unable to convert %r to a cusp" % a)
            else:
                try:
                    r = QQ(a)
                    self.__a = r.numer()
                    self.__b = r.denom()
                except (ValueError, TypeError):
                    raise TypeError("unable to convert %r to a cusp" % a)
            return

        if is_InfinityElement(b):
            if is_InfinityElement(a) or (isinstance(a, Cusp) and a.is_infinity()):
                raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
            self.__a = ZZ.zero()
            self.__b = ZZ.one()
            return
        elif not b:
            if not a:
                raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
            self.__a = ZZ.one()
            self.__b = ZZ.zero()
            return

        if isinstance(a, Integer) or isinstance(a, Rational):
            r = a / ZZ(b)
        elif is_InfinityElement(a):
            self.__a = ZZ.one()
            self.__b = ZZ.zero()
            return
        elif isinstance(a, Cusp):
            if a.__b:
                r = a.__a / (a.__b * b)
            else:
                self.__a = ZZ.one()
                self.__b = ZZ.zero()
                return
        elif isinstance(a, integer_types):
            r = ZZ(a) / b
        elif isinstance(a, (tuple, list)):
            if len(a) != 2:
                raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))
            r = ZZ(a[0]) / (ZZ(a[1]) * b)
        else:
            try:
                r = QQ(a) / b
            except (ValueError, TypeError):
                raise TypeError("unable to convert (%r, %r) to a cusp" % (a, b))

        self.__a = r.numer()
        self.__b = r.denom()
Beispiel #26
0
def NFelt_list(a):
    r"""
    Return the list representation of the NFelt string.
    """
    return [QorZ_list(QQ(c)) for c in a.split(",")]
Beispiel #27
0
import collections

from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.all import NumberField
from sage.rings.all import ZZ, QQ, AA, RIF, RR
from ore_algebra import DifferentialOperators

IVP = collections.namedtuple("IVP", ["dop", "ini"])

DiffOps_a, a, Da = DifferentialOperators(QQ, 'a')
koutschan1 = IVP(
    dop = (1315013644371957611900*a**2+263002728874391522380*a+13150136443719576119)*Da**3
        + (2630027288743915223800*a**2+16306169190212274387560*a+1604316646133788286518)*Da**2
        + (1315013644371957611900*a**2-39881765316802329075320*a+35449082663034775873349)*Da
        + (-278967152068515080896550+6575068221859788059500*a),
    ini = [ QQ(5494216492395559)/3051757812500000000000000000000,
            QQ(6932746783438351)/610351562500000000000000000000,
            1/QQ(2) * QQ(1142339612827789)/19073486328125000000000000000 ]
)

y, z = PolynomialRing(QQ, ['y', 'z']).gens()
salvy1_pol = (16*y**6*z**2 + 8*y**5*z**3 + y**4*z**4 + 128*y**5*z**2 + 48*y**4*z**3 +
        4*y**3*z**4 + 32*y**5* z + 372*y**4*z**2 + 107*y**3*z**3 + 6*y**2*z**4 +
        88*y**4*z + 498*y**3*z**2 + 113*y**2*z**3 + 4*y*z**4 + 16*y**4 + 43*y**3*z +
        311*y**2*z**2 + 57*y*z**3 + z**4 + 24*y**3 - 43*y**2*z + 72*y*z **2 + 11*z**3 +
        12*y**2 - 30*y*z - z**2 + 2*y)
DiffOps_z, z, Dz = DifferentialOperators(QQ, 'z')
salvy1_dop = ((71820*z**41 + 22638420*z**40 + 706611850*z**39 - 27125189942*z**38 -
        1014313164418*z**37 - 2987285491626*z**36 + 143256146804484*z**35 +
        595033302717820*z**34 - 8471861990006953*z**33 + 22350994766224977*z**32 +
        199821041784996648*z**31 - 11402401137364528368*z**30 -
Beispiel #28
0
    def simplify(self, x, error=None, force=False, size_heuristic_bound=32):
        r"""
        Return a simplified version of ``x``.

        Produce an element which differs from ``x`` by an element of
        valuation strictly greater than the valuation of ``x`` (or strictly
        greater than ``error`` if set.)

        INPUT:

        - ``x`` -- an element in the domain of this valuation

        - ``error`` -- a rational, infinity, or ``None`` (default: ``None``),
          the error allowed to introduce through the simplification

        - ``force`` -- ignored

        - ``size_heuristic_bound`` -- when ``force`` is not set, the expected
          factor by which the ``x`` need to shrink to perform an actual
          simplification (default: 32)

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: v.simplify(6, force=True)
            2
            sage: v.simplify(6, error=0, force=True)
            0

        """
        if not force and self._relative_size(x) <= size_heuristic_bound:
            return x

        x = self.domain().coerce(x)

        v = self(x)
        if error is None:
            error = v
        from sage.rings.all import infinity
        if error is infinity:
            return x
        if error < v:
            return self.domain().zero()
        from sage.rings.all import QQ
        error = QQ(error).ceil()

        from sage.rings.all import Qp
        precision_ring = Qp(self.p(), error + 1 - v)
        reduced = precision_ring(x)
        if error - v >= 5:
            # If there is not much relative precision left, it is better to
            # just go with the integer/rational lift. The rational
            # reconstruction is likely not smaller.
            try:
                reconstruction = reduced.rational_reconstruction()
                if reconstruction in self.domain():
                    return self.domain()(reconstruction)
            except ArithmeticError:
                pass

        return self.domain()(reduced.lift())
Beispiel #29
0
    def __call__(self, Q, P):
        """
        Compute and return the :class:`ReductionData` corresponding to
        the genus 2 curve `y^2 + Q(x) y = P(x)`.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: genus2reduction(x^3 - 2*x^2 - 2*x + 1, -5*x^5)
            Reduction data about this proper smooth genus 2 curve:
                    y^2 + (x^3 - 2*x^2 - 2*x + 1)*y = -5*x^5
            A Minimal Equation (away from 2):
                    y^2 = x^6 - 240*x^4 - 2550*x^3 - 11400*x^2 - 24100*x - 19855
            Minimal Discriminant (away from 2):  56675000
            Conductor (away from 2): 1416875
            Local Data:
                    p=2
                    (potential) stable reduction:  (II), j=1
                    p=5
                    (potential) stable reduction:  (I)
                    reduction at p: [V] page 156, (3), f=4
                    p=2267
                    (potential) stable reduction:  (II), j=432
                    reduction at p: [I{1-0-0}] page 170, (1), f=1

        ::

            sage: genus2reduction(x^2 + 1, -5*x^5)
            Reduction data about this proper smooth genus 2 curve:
                    y^2 + (x^2 + 1)*y = -5*x^5
            A Minimal Equation (away from 2):
                    y^2 = -20*x^5 + x^4 + 2*x^2 + 1
            Minimal Discriminant (away from 2):  48838125
            Conductor: 32025
            Local Data:
                    p=3
                    (potential) stable reduction:  (II), j=1
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
                    p=5
                    (potential) stable reduction:  (IV)
                    reduction at p: [I{1-1-2}] page 182, (5), f=2
                    p=7
                    (potential) stable reduction:  (II), j=4
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
                    p=61
                    (potential) stable reduction:  (II), j=57
                    reduction at p: [I{2-0-0}] page 170, (2), f=1

        Verify that we fix :trac:`5573`::

            sage: genus2reduction(x^3 + x^2 + x,-2*x^5 + 3*x^4 - x^3 - x^2 - 6*x - 2)
            Reduction data about this proper smooth genus 2 curve:
                    y^2 + (x^3 + x^2 + x)*y = -2*x^5 + 3*x^4 - x^3 - x^2 - 6*x - 2
            A Minimal Equation (away from 2):
                    y^2 = x^6 + 18*x^3 + 36*x^2 - 27
            Minimal Discriminant (away from 2):  1520984142
            Conductor: 954
            Local Data:
                    p=2
                    (potential) stable reduction:  (II), j=1
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
                    p=3
                    (potential) stable reduction:  (I)
                    reduction at p: [II] page 155, (1), f=2
                    p=53
                    (potential) stable reduction:  (II), j=12
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
        """
        R = PolynomialRing(QQ, 'x')
        P = R(P)
        Q = R(Q)
        if P.degree() > 6:
            raise ValueError("P (=%s) must have degree at most 6"%P)
        if Q.degree() >=4:
            raise ValueError("Q (=%s) must have degree at most 3"%Q)

        res = pari.genus2red([P,Q])

        conductor = ZZ(res[0])
        minimal_equation = R(res[2])

        minimal_disc = QQ(res[2].poldisc()).abs()
        if minimal_equation.degree() == 5:
            minimal_disc *= minimal_equation[5]**2
        # Multiply with suitable power of 2 of the form 2^(2*(d-1) - 12)
        b = 2 * (minimal_equation.degree() - 1)
        k = QQ((12 - minimal_disc.valuation(2), b)).ceil()
        minimal_disc >>= 12 - b*k
        minimal_disc = ZZ(minimal_disc)

        local_data = {}
        for red in res[3]:
            p = ZZ(red[0])

            t = red[1]
            data = "(potential) stable reduction:  (%s)" % roman_numeral[int(t[0])]
            t = t[1]
            if len(t) == 1:
                data += ", j=%s" % t[0].lift()
            elif len(t) == 2:
                data += ", j1+j2=%s, j1*j2=%s" % (t[0].lift(), t[1].lift())

            t = red[2]
            if t:
                data += "\nreduction at p: %s, " % str(t[0]).replace('"', '').replace("(tame) ", "")
                data += divisors_to_string(t[1]) + ", f=" + str(res[0].valuation(red[0]))

            local_data[p] = data

        prime_to_2_conductor_only = (-1 in res[1].component(2))
        return ReductionData(res, P, Q, minimal_equation, minimal_disc, local_data,
                             conductor, prime_to_2_conductor_only)
Beispiel #30
0
def kneading_sequence(theta):
    r"""
    Determines the kneading sequence for an angle theta in RR/ZZ which
    is periodic under doubling. We use the definition for the kneading
    sequence given in Definition 3.2 of [LS1994]_.

    INPUT:

    - ``theta`` -- a rational number with odd denominator

    OUTPUT:

    a string representing the kneading sequence of theta in RR/ZZ

    REFERENCES:

    [LS1994]_

    EXAMPLES::

        sage: kneading_sequence(0)
        '*'

    ::

        sage: kneading_sequence(1/3)
        '1*'

    Since 1/3 and 7/3 are the same in RR/ZZ, they have the same kneading sequence::

        sage: kneading_sequence(7/3)
        '1*'

    We can also use (finite) decimal inputs, as long as the denominator in reduced form is odd::

        sage: kneading_sequence(1.2)
        '110*'

    Since rationals with even denominator are not periodic under doubling, we have not implemented kneading sequences for such rationals::

        sage: kneading_sequence(1/4)
        Traceback (most recent call last):
        ...
        ValueError: input must be a rational number with odd denominator
    """

    if theta not in QQ:
        raise TypeError('input must be a rational number with odd denominator')
    elif QQ(theta).valuation(2) < 0:
        raise ValueError(
            'input must be a rational number with odd denominator')
    else:
        theta = QQ(theta)
        theta = theta - floor(theta)
        KS = []
        not_done = True
        left = theta / 2
        right = (theta + 1) / 2
        y = theta
        while not_done:
            if ((y < left) or (y > right)):
                KS.append('0')
            elif ((y > left) and (y < right)):
                KS.append('1')
            else:
                not_done = False
            y = 2 * y - floor(2 * y)
        KS_str = ''.join(KS) + '*'
    return KS_str