Пример #1
0
 def _test(self):
     from sage.all import QQ, PolynomialRing, GaussValuation
     R = PolynomialRing(QQ, 'x')
     x = R.gen()
     v = QQ.valuation(2)
     v = GaussValuation(R, v).augmentation(x + 1, QQ(1) / 2)
     f = x**4 - 30 * x**2 - 75
     v.mac_lane_step(f)
Пример #2
0
def factor_with_slope(f, vK, s, precision, reduce_function):
    r"""
    Return the factor with slope `s`.

    INPUT:

    - ``f`` -- a monic polynomial over a field `K`
    - ``vK`` -- a discrete valuation on `K` such that `f` for which `f` is integral
    - ``s`` -- a nonpositive **integer**
    - ``precision`` -- a positive integer
    - ``reduce_function`` -- a function which takes as input an element of `K`
      and returns a simpler approximation; the approximation is with relative
      precision ``precision``

    OUTPUT: a monic and integral polynomial `g` which approximates the factor
    of `f` with slope `s`. We assume that `s` is a slope of `f` (hence `g`)
    will be nonconstant. The precision of the approximation is such that the
    relative precision of the coefficients of `g` is at least ``precision``.

    """
    vK = vK.scale(1 / vK(vK.uniformizer()))
    R = f.parent()
    x = R.gen()
    pi = vK.uniformizer()
    v0 = GaussValuation(R, vK)
    f1 = f(pi**ZZ(-s) * x)
    f2 = reduce_function(f1 * pi**(-v0(f1)))
    g = factor_with_slope_zero(f2, vK, precision, reduce_function)
    g = reduce_function(g)
    return g(pi**ZZ(s) * x).monic()
Пример #3
0
 def _test(self):
     from sage.all import QQ, PolynomialRing, GaussValuation, FunctionField
     R = PolynomialRing(QQ, 'x')
     x = R.gen()
     v = GaussValuation(R, QQ.valuation(2))
     K = FunctionField(QQ, 'x')
     x = K.gen()
     v = K.valuation(v)
     K.valuation((v, K.hom(x/2), K.hom(2*x)))
Пример #4
0
 def _test(self):
     from sage.all import PolynomialRing, QQ, NumberField, GaussValuation, FunctionField
     R = PolynomialRing(QQ, 'x')
     x = R.gen()
     K = NumberField(x**6 + 126 * x**3 + 126, 'pi')
     v = K.valuation(2)
     R = PolynomialRing(K, 'x')
     x = R.gen()
     v = GaussValuation(R, v).augmentation(x, QQ(2) / 3)
     F = FunctionField(K, 'x')
     x = F.gen()
     v = F.valuation(v)
     S = PolynomialRing(F, 'y')
     y = S.gen()
     w0 = GaussValuation(S, v)
     G = y**2 - x**3 - 3
     w1 = w0.mac_lane_step(G)[0]
     w1.mac_lane_step(G)
Пример #5
0
    def __init__(self, Y, vK):

        p = vK.residue_field().characteristic()
        assert p == Y.covering_degree()
        assert isinstance(Y, SuperellipticCurve)
        f = Y.polynomial()
        R = f.parent()
        assert R.base_ring() is vK.domain(
        ), "the domain of vK must be the base field of f"
        assert p == vK.residue_field().characteristic(
        ), "the exponent p must be the residue characteristic of vK"
        assert not p.divides(f.degree()), "the degree of f must be prime to p"
        self._p = p
        self._base_valuation = vK
        v0 = GaussValuation(R, vK)
        phi, psi, f1 = v0.monic_integral_model(f)
        # now f1 = phi(f).monic()
        if f1 != f.monic():
            print(
                "We make the coordinate change (x --> %s) in order to work with an integral polynomial f"
                % phi(R.gen()))
            self._f = f1
            a = phi(f).leading_coefficient()
            pi = vK.uniformizer()
            m = (vK(a) / p).floor()
            a = pi**(-p * m) * a
            self._a = a
            FX = FunctionField(vK.domain(), R.variable_name())
            S = PolynomialRing(FX, 'T')
            T = S.gen()
            FY = FX.extension(T**p - FX(a * f1), 'y')
            self._FX = FX
            self._FY = FY
            Y = SmoothProjectiveCurve(FY)
            self._curve = Y
        else:
            self._f = f.monic()
            self._a = vK.domain().one()
            self._FY = Y.function_field()
            self._FX = Y.rational_function_field()
            self._curve = Y
        X = BerkovichLine(self._FX, vK)
        self._X = X
Пример #6
0
 def __init__(self, K, L, approximation=None):
     if isinstance(approximation, MacLaneLimitValuation):
         # v = apprximation determines phi uniquely
         v = approximation
         assert v(K.polynomial()) == Infinity
     else:
         if approximation == None:
             R = PolynomialRing(L.number_field(), 'x')
             v0 = GaussValuation(R, L.valuation())
         else:
             v0 = approximation
         # now we have to find a limit valuation v such that v(P_K)=infinity
         # which is approximated by v0
         P = R(K.polynomial())
         V = [v0]
         done = False
         while len(V) > 0 and not done > 0:
             V_new = []
             for v in V:
                 if v.phi().degree() == 1:
                     if v.effective_degree(P) == 1 or v.mu() == Infinity:
                         V_new = [v]
                         done = True
                         break
                     else:
                         V_new += v.mac_lane_step(P,
                                                  assume_squarefree=True,
                                                  check=False)
             V = V_new
         if len(V) == 0:
             raise AssertionError("no embedding exists")
         else:
             v = V[0]
     # now v is an approximation of an irreducible factor of P of degree 1
     v = LimitValuation(v, P)
     self._domain = K
     self._target = L
     self._limit_valuation = v
Пример #7
0
def factor_with_slope_zero(f, vK, N, reduce_function):
    r"""
    Return the factor of `f` with slope zero.

    INPUT:

    - ``f`` -- a nonconstant polynomial over a field `K` (not necessarily monic)
        which is integral wrt to `v_K` and whose reduction to the residue field of
        `v_K` is nonconstant.
    - ``vK`` -- a normalized discrete valuation on `K` for which `f` is integral
    - ``N`` -- a positive integer
    - ``reduce_function`` -- a function which takes as input an element of `K`
      and returns a simpler approximation; the approximation is with relative
      precision ``precision``

    OUTPUT: a pair `(f_1,f_2)` of polynomials such that `f_1` has slope zero,
    `f_2` has only nonzero slopes, and

    .. MATH::

            v_K( f - f_1\cdot f_2 ) > N.


    EXAMPLES::

        sage: from mclf.padic_extensions.slope_factors import factor_with_slope_zero
        sage: R.<x> = QQ[]
        sage: v2 = QQ.valuation(2)
        sage: f = (2*x - 1)*(x + 1)
        sage: reduce_function = lambda g: g
        sage: factor_with_slope_zero(f, v2, 3, reduce_function)
        x + 1

    """
    R = f.parent()
    pi = vK.uniformizer()
    v0 = GaussValuation(R, vK)
    Kb = vK.residue_field()
    fb = f.map_coefficients(lambda c: vK.reduce(c), Kb)
    k = min([i for i in range(fb.degree() + 1) if fb[i] != 0])
    gb = fb.shift(-k).monic()
    g = R([vK.lift(gb[i]) for i in range(gb.degree() + 1)])
    q, r0 = f.quo_rem(g)
    if r0.is_zero():  # we are done
        return g
    qb = q.map_coefficients(lambda c: vK.reduce(c), Kb)
    assert qb != 0
    m = v0(r0)
    r = r0 * pi**(-m)

    while m <= N:
        # we have f = q*g + pi^m*r
        rb = r.map_coefficients(lambda c: vK.reduce(c), Kb)
        ab, bb = pol_linear_combination(rb, qb, gb)
        # now  rb = ab*qb + bb*gb and deg(ab) < deg(gb)
        a = R([vK.lift(ab[i]) for i in range(ab.degree() + 1)])
        b = R([vK.lift(bb[i]) for i in range(bb.degree() + 1)])
        r0 = r - (a * q + b * g + pi**m * a * b)
        g = g + pi**m * a
        q = q + pi**m * b
        r = r0 * pi**(-1)
        m = m + 1
    return g
Пример #8
0
    def weak_splitting_field(self, F):
        r"""
        Return the weak splitting field of a list of polynomials.

        INPUT:

        - ``F`` -- a polynomial over the underlying number field `K_0`,
          or a list of polynomials

        OUTPUT:

        A weak splitting field `L/K` of ``F``.

        This means that `F` splits over an unramified extension of `L`.

        Note:

        This function works at the moment only for the base field `\mathbb{Q}_p`.

        TODO:

        The following trick should give a massive improvement for large examples:
        Instead of calling ``K.approximate_factorization(F)`` one should calling
        a new version of ``K.approximate_irreducible_factor(F, *options*)``.

        The function ``approximate_irreducible_factor(..)`` would do a
        MacLane approximation with ``require_maximal_degree=True``. From the
        resulting v's one can then select (according to the options) one which,
        after enough MacLane steps, gives an approximate irreducible factor.

        The point is that the test for being an approximate factor seems to be
        the most time consuming for large examples. A further speedup could be
        obtained by

        - either finding a more clever way to test,
        - or by simply doing several MacLane steps before testing.

        The options should be set such that factors are chosen accoring to the
        following rules:

        1. one prefers purely ramified factors over factors with inertia
        2. one prefers purely wild factors over mixed factors
        3. one prefers mixed factors over tame factors

        Note that for tame factors the inertia may be ignored, hence they
        may be considered as purely ramified. However, it is better to leave
        them until the end, because doing a tame extension is almost trivial.
        It is not clear to me whether a purely wild factor with inertia is better
        than a mixed unramified factor.

        EXAMPLES:

        The following example created an error in a previous version ::

            sage: from mclf import *
            sage: v_2 = QQ.valuation(2)
            sage: Q2 = FakepAdicCompletion(QQ, v_2)
            sage: R.<x> = QQ[]
            sage: f = x^12 + 192*x^9 - 5352*x^6 + 33344*x^3 - 293568
            sage: L = Q2.weak_splitting_field(f)
            sage: L.ramification_degree()
            4

        Check that non-integral polynomials are allowed as well ::

            sage: Q2.weak_splitting_field(2*x^2 + 1)
            2-adic completion of Number Field in pi2 with defining polynomial x^2 + 2

        """
        if not isinstance(F, Polynomial):
            F = prod(F).radical()
        else:
            F = F.radical()
        K = self
        assert F.parent().base_ring() == QQ, "For the time being, F has to be defined over QQ"
        if F.is_constant():
            return K
        v0 = GaussValuation(F.parent(), self.valuation())
        F = v0.monic_integral_model(F)[0](F).monic()
        first_step = True
        while True:
            g = K.approximate_irreducible_factor(F)
            # here the base field of F needs to coerce into the number
            # field K0 underlying K. When we replace K by an extension, we can
            # guaranteee that this holds only if the base field of F is QQ
            if isinstance(g, Integer):
                e = g
                # e is the tame ramification index needed to obtain a weak
                # splitting field of F
                if e == 1:
                    return K
                else:
                    return K.ramified_extension(e)
            else:
                # now g is an approximate irreducible factor of F
                # which will give a wildly ramified extension of K
                if first_step and F.degree() == g.degree():
                    # it is often advantagous to replace F by the defining
                    # polynomial of the extension generated by F, because it
                    # is close to being Eisenstein
                    K = K.extension(g)
                    F = K.polynomial()
                else:
                    K = K.extension(g)
            first_step = False
Пример #9
0
    def subfield(self, alpha, e):
        r"""
        Return a subfield approximated by a given element.

        INPUT:

        - ``alpha`` -- an element of the number field `K_0` underlying `K`
        - ``e`` -- a divisor of the absolute degree of `K_0`

        OUTPUT:

        A `p`-adic number field `L` with ramification index `e` which has an
        embedding into `K`, or ``None`` if no such field can be found.

        If `L` is a subfield of `K` with ramification index `e` and `\alpha_i`
        is a sequence of element of `K_0` converging to a generator of `L`, then
        calling ``K.subfield(alpha_i,e)`` will find the subfield `L` for `i`
        sufficiently large.

        TODO:

        One easy improvement could be to not try to embed L into K after every
        MacLane step, but only for the last step before the degree of v jumps.

        """
        from mclf.padic_extensions.fake_padic_embeddings import FakepAdicEmbedding
        K = self
        v_p = K.base_valuation()
        if e == 1:
            return FakepAdicCompletion(QQ, v_p)
        n = K.degree()
        assert e.divides(n), "e must be a divisor of the degree of K"
        alpha = K.number_field()(alpha)
        f = alpha.minpoly()
        R = f.parent()
        v = GaussValuation(R, v_p)
        while True:
            d = v.phi().degree()
            v1 = v
            while v1.phi().degree() == d and v.mu() < Infinity:
                v = v1
                if v.mu() < Infinity:
                    V = v.mac_lane_step(f, assume_squarefree=True, check=False)
                    if len(V) > 1:
                        # print("len(V) > 1")
                        return None
                    v1 = V[0]
            # now v.phi().degree() = d, and either v1.phi().degree() > d
            # or v.mu() = Infinity
            g = v.phi()
            if g.degree() > 1:
                L = FakepAdicCompletion(QQ, v_p).extension(g)
                if L.ramification_degree() == e:
                    try:
                        FakepAdicEmbedding(L, K)
                        # this can be very slow, but so far it is the only
                        # conclusive test I know
                        # print("found subfield of degree %s and ramification degree %s"%(L.degree(), L.ramification_degree()))
                        return L
                    except AssertionError:
                        pass
                        # print("no embedding into L!")
            if v.mu() == Infinity:
                # print("v.mu() = Infinity")
                return None
            else:
                v = v1  # we go to a larger degree