Example #1
0
    def mac_lane_approximants(self,
                              G,
                              assume_squarefree=False,
                              require_final_EF=True,
                              required_precision=-1,
                              require_incomparability=False,
                              require_maximal_degree=False,
                              algorithm="serial"):
        r"""
        Return approximants on `K[x]` for the extensions of this valuation to
        `L=K[x]/(G)`.

        If `G` is an irreducible polynomial, then this corresponds to
        extensions of this valuation to the completion of `L`.

        INPUT:

        - ``G`` -- a monic squarefree integral polynomial defined over a
          univariate polynomial ring over the :meth:`domain` of this valuation.

        - ``assume_squarefree`` -- a boolean (default: ``False``), whether to
          assume that ``G`` is squarefree. If ``True``, the squafreeness of
          ``G`` is not verified though it is necessary when
          ``require_final_EF`` is set for the algorithm to terminate.

        - ``require_final_EF`` -- a boolean (default: ``True``); whether to
          require the returned key polynomials to be in one-to-one
          correspondance to the extensions of this valuation to ``L`` and
          require them to have the ramification index and residue degree of the
          valuations they correspond to.

        - ``required_precision`` -- a number or infinity (default: -1); whether
          to require the last key polynomial of the returned valuations to have
          at least that valuation.

        - ``require_incomparability`` -- a boolean (default: ``False``);
          whether to require require the returned valuations to be incomparable
          (with respect to the partial order on valuations defined by comparing
          them pointwise.)

        - ``require_maximal_degree`` -- a boolean (deault: ``False``); whether
          to require the last key polynomial of the returned valuation to have
          maximal degree. This is most relevant when using this algorithm to
          compute approximate factorizations of ``G``, when set to ``True``,
          the last key polynomial has the same degree as the corresponding
          factor.

        - ``algorithm`` -- one of ``"serial"`` or ``"parallel"`` (default:
          ``"serial"``); whether or not to parallelize the algorithm

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: v = pAdicValuation(QQ, 2)
            sage: R.<x> = QQ[]
            sage: v.mac_lane_approximants(x^2 + 1)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]]
            sage: v.mac_lane_approximants(x^2 + 1, required_precision=infinity)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2, v(x^2 + 1) = +Infinity ]]
            sage: v.mac_lane_approximants(x^2 + x + 1)
            [[ Gauss valuation induced by 2-adic valuation, v(x^2 + x + 1) = +Infinity ]]

        Note that ``G`` does not need to be irreducible. Here, we detect a
        factor `x + 1` and an approximate factor `x + 1` (which is an
        approximation to `x - 1`)::

            sage: v.mac_lane_approximants(x^2 - 1)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = +Infinity ],
             [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ]]

        However, it needs to be squarefree::

            sage: v.mac_lane_approximants(x^2)
            Traceback (most recent call last):
            ...
            ValueError: G must be squarefree

        TESTS:

        Some difficult cases provided by Mark van Hoeij::

            sage: k = GF(2)
            sage: K.<x> = FunctionField(k)
            sage: R.<y> = K[]
            sage: F = y^21 + x*y^20 + (x^3 + x + 1)*y^18 + (x^3 + 1)*y^17 + (x^4 + x)*y^16 + (x^7 + x^6 + x^3 + x + 1)*y^15 + x^7*y^14 + (x^8 + x^7 + x^6 + x^4 + x^3 + 1)*y^13 + (x^9 + x^8 + x^4 + 1)*y^12 + (x^11 + x^9 + x^8 + x^5 + x^4 + x^3 + x^2)*y^11 + (x^12 + x^9 + x^8 + x^7 + x^5 + x^3 + x + 1)*y^10 + (x^14 + x^13 + x^10 + x^9 + x^8 + x^7 + x^6 + x^3 + x^2 + 1)*y^9 + (x^13 + x^9 + x^8 + x^6 + x^4 + x^3 + x)*y^8 + (x^16 + x^15 + x^13 + x^12 + x^11 + x^7 + x^3 + x)*y^7 + (x^17 + x^16 + x^13 + x^9 + x^8 + x)*y^6 + (x^17 + x^16 + x^12 + x^7 + x^5 + x^2 + x + 1)*y^5 + (x^19 + x^16 + x^15 + x^12 + x^6 + x^5 + x^3 + 1)*y^4 + (x^18 + x^15 + x^12 + x^10 + x^9 + x^7 + x^4 + x)*y^3 + (x^22 + x^21 + x^20 + x^18 + x^13 + x^12 + x^9 + x^8 + x^7 + x^5 + x^4 + x^3)*y^2 + (x^23 + x^22 + x^20 + x^17 + x^15 + x^14 + x^12 + x^9)*y + x^25 + x^23 + x^19 + x^17 + x^15 + x^13 + x^11 + x^5
            sage: x = K._ring.gen()
            sage: v0 = FunctionFieldValuation(K, GaussValuation(K._ring, TrivialValuation(k)).augmentation(x,1))
            sage: v0.mac_lane_approximants(F, assume_squarefree=True) # optional: integrated; assumes squarefree for speed
            [[ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x) = 1 ], v(y + x + 1) = 3/2 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x) = 1 ], v(y) = 4/3, v(y^3 + x^4) = 13/3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x) = 1 ], v(y + x) = 2 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x) = 1 ], v(y^15 + y^13 + (x + 1)*y^12 + x*y^11 + (x + 1)*y^10 + y^9 + y^8 + x*y^6 + x*y^5 + y^4 + y^3 + y^2 + (x + 1)*y + x + 1) = 2 ]]
            sage: v0 = FunctionFieldValuation(K, GaussValuation(K._ring, TrivialValuation(k)).augmentation(x+1,1))
            sage: v0.mac_lane_approximants(F, assume_squarefree=True) # optional: integrated; assumes squarefree for speed
            [[ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x + 1) = 1 ], v(y) = 7/2, v(y^2 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) = 15/2 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x + 1) = 1 ], v(y + x^2 + 1) = 7/2 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x + 1) = 1 ], v(y) = 3/4, v(y^4 + x^3 + x^2 + x + 1) = 15/4 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x + 1) = 1 ], v(y^13 + x*y^12 + y^10 + (x + 1)*y^9 + (x + 1)*y^8 + x*y^7 + x*y^6 + (x + 1)*y^4 + y^3 + (x + 1)*y^2 + 1) = 2 ]]
            sage: v0 = FunctionFieldValuation(K, GaussValuation(K._ring, TrivialValuation(k)).augmentation(x^3+x^2+1,1))
            sage: v0.mac_lane_approximants(F, assume_squarefree=True) # optional: integrated; assumes squarefree for speed
            [[ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x^3 + x^2 + 1) = 1 ], v(y + x^3 + x^2 + x) = 2, v(y^2 + (x^6 + x^4 + 1)*y + x^14 + x^10 + x^9 + x^8 + x^5 + x^4 + x^3 + x^2 + x) = 5 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x^3 + x^2 + 1) = 1 ], v(y^2 + (x^7 + x^5 + x^4 + x^3 + x^2 + x)*y + x^7 + x^5 + x + 1) = 3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x^3 + x^2 + 1) = 1 ], v(y^3 + (x^8 + x^5 + x^4 + x^3 + x + 1)*y^2 + (x^7 + x^6 + x^5)*y + x^8 + x^5 + x^4 + x^3 + 1) = 3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x^3 + x^2 + 1) = 1 ], v(y^3 + (x^8 + x^4 + x^3 + x + 1)*y^2 + (x^4 + x^3 + 1)*y + x^8 + x^7 + x^4 + x + 1) = 3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x^3 + x^2 + 1) = 1 ], v(y^4 + (x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1)*y^3 + (x^8 + x^5 + x^4 + x^3 + x^2 + x + 1)*y^2 + (x^8 + x^7 + x^6 + x^5 + x^3 + x^2 + 1)*y + x^8 + x^7 + x^6 + x^5 + x^3 + 1) = 3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by Trivial valuation, v(x^3 + x^2 + 1) = 1 ], v(y^7 + (x^8 + x^5 + x^4 + x)*y^6 + (x^7 + 1)*y^5 + (x^4 + x^2)*y^4 + (x^8 + x^3 + x + 1)*y^3 + (x^7 + x^6 + x^4 + x^2 + x + 1)*y^2 + (x^8 + x^7 + x^5 + x^3 + 1)*y + x^7 + x^6 + x^5 + x^4 + x^3 + x^2) = 3 ]]

        Cases with trivial residue field extensions::

            sage: K.<x> = FunctionField(QQ)
            sage: S.<y> = K[]
            sage: F = y^2 - x^2 - x^3 - 3
            sage: v0 = GaussValuation(K._ring,pAdicValuation(QQ,3))
            sage: v1 = v0.augmentation(K._ring.gen(),1/3)
            sage: mu0 = FunctionFieldValuation(K, v1)
            sage: sorted(mu0.mac_lane_approximants(F), key=str)
            [[ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by 3-adic valuation, v(x) = 1/3 ], v(y + 2*x) = 2/3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by 3-adic valuation, v(x) = 1/3 ], v(y + x) = 2/3 ]]

        Over a complete base field::

            sage: k=Qp(2,10)
            sage: v = pAdicValuation(k)

            sage: R.<x>=k[]
            sage: G = x
            sage: v.mac_lane_approximants(G)
            [Gauss valuation induced by 2-adic valuation]
            sage: v.mac_lane_approximants(G, required_precision = infinity)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = +Infinity ]]

            sage: G = x^2 + 1
            sage: v.mac_lane_approximants(G) # optional: integrated
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + (1 + O(2^10))) = 1/2 ]]
            sage: v.mac_lane_approximants(G, required_precision = infinity) # optional: integrated
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + (1 + O(2^10))) = 1/2, v((1 + O(2^10))*x^2 + (1 + O(2^10))) = +Infinity ]]

            sage: G = x^4 + 2*x^3 + 2*x^2 - 2*x + 2
            sage: v.mac_lane_approximants(G)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4 ]]
            sage: v.mac_lane_approximants(G, required_precision=infinity)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4, v((1 + O(2^10))*x^4 + (2 + O(2^11))*x^3 + (2 + O(2^11))*x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + O(2^11))*x + (2 + O(2^11))) = +Infinity ]]

        The factorization of primes in the Gaussian integers can be read off
        the Mac Lane approximants::

            sage: v0 = pAdicValuation(QQ, 2)
            sage: R.<x> = QQ[]
            sage: G = x^2 + 1
            sage: v0.mac_lane_approximants(G)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]]

            sage: v0 = pAdicValuation(QQ, 3)
            sage: v0.mac_lane_approximants(G)
            [[ Gauss valuation induced by 3-adic valuation, v(x^2 + 1) = +Infinity ]]

            sage: v0 = pAdicValuation(QQ, 5)
            sage: v0.mac_lane_approximants(G)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ],
             [ Gauss valuation induced by 5-adic valuation, v(x + 3) = 1 ]]
            sage: sorted(v0.mac_lane_approximants(G, required_precision = 10), key=str)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 3626068) = 10 ],
             [ Gauss valuation induced by 5-adic valuation, v(x + 6139557) = 10 ]]

        The same example over the 5-adic numbers. In the quadratic extension
        `\QQ[x]/(x^2+1)`, 5 factors `-(x - 2)(x + 2)`, this behaviour can be
        read off the Mac Lane approximants::

            sage: k=Qp(5,4)
            sage: v = pAdicValuation(k)
            sage: R.<x>=k[]
            sage: G = x^2 + 1
            sage: v1,v2 = v.mac_lane_approximants(G); sorted([v1,v2], key=str)
            [[ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + (2 + O(5^4))) = 1 ],
             [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + (3 + O(5^4))) = 1 ]]
            sage: w1, w2 = v.mac_lane_approximants(G, required_precision = 2); sorted([w1,w2], key=str)
            [[ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + (2 + 5 + O(5^4))) = 2 ],
             [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + (3 + 3*5 + O(5^4))) = 2 ]]

        Note how the latter give a better approximation to the factors of `x^2 + 1`::

            sage: v1.phi() * v2.phi() - G # optional: integrated
            (5 + O(5^4))*x + 5 + O(5^4)
            sage: w1.phi() * w2.phi() - G # optional: integrated
            (5^3 + O(5^4))*x + 5^3 + O(5^4)

        In this example, the process stops with a factorization of `x^2 + 1`::

            sage: sorted(v.mac_lane_approximants(G, required_precision=infinity), key=str)
            [[ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + (2 + 5 + 2*5^2 + 5^3 + O(5^4))) = +Infinity ],
             [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + (3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4))) = +Infinity ]]

        This obviously cannot happen over the rationals where we only get an
        approximate factorization::

            sage: v = pAdicValuation(QQ, 5)
            sage: R.<x>=QQ[]
            sage: G = x^2 + 1
            sage: v.mac_lane_approximants(G)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ], [ Gauss valuation induced by 5-adic valuation, v(x + 3) = 1 ]]
            sage: sorted(v.mac_lane_approximants(G, required_precision=5), key=str)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 1068) = 6 ],
             [ Gauss valuation induced by 5-adic valuation, v(x + 2057) = 5 ]]

        Initial versions ran into problems with the trivial residue field
        extensions in this case::

            sage: K = Qp(3,20)
            sage: R.<T> = K[]

            sage: alpha = T^3/4
            sage: G = 3^3*T^3*(alpha^4 - alpha)^2 - (4*alpha^3 - 1)^3
            sage: G = G/G.leading_coefficient()
            sage: pAdicValuation(K).mac_lane_approximants(G) # optional: integrated
            [[ Gauss valuation induced by 3-adic valuation, v((1 + O(3^20))*T + (2 + O(3^20))) = 1/9, v((1 + O(3^20))*T^9 + (2*3 + 2*3^2 + O(3^21))*T^8 + (3 + 3^5 + O(3^21))*T^7 + (2*3 + 2*3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + O(3^21))*T^6 + (2*3 + 2*3^2 + 3^4 + 3^6 + 2*3^7 + O(3^21))*T^5 + (3 + 3^2 + 3^3 + 2*3^6 + 2*3^7 + 3^8 + O(3^21))*T^4 + (2*3 + 2*3^2 + 3^3 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + O(3^21))*T^3 + (2*3 + 2*3^2 + 3^3 + 2*3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + O(3^21))*T^2 + (3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^7 + 3^8 + O(3^21))*T + (2 + 2*3 + 2*3^2 + 2*3^4 + 2*3^5 + 3^7 + O(3^20))) = 55/27 ]]

        A similar example::

            sage: R.<x> = QQ[]
            sage: v = pAdicValuation(QQ, 3)
            sage: G = (x^3 + 3)^3 - 81
            sage: v.mac_lane_approximants(G) # optional: integrated
            [[ Gauss valuation induced by 3-adic valuation, v(x) = 1/3, v(x^3 + 3*x + 3) = 13/9 ]]

        Another problematic case::

            sage: R.<x> = QQ[] 
            sage: Delta = x^12 + 20*x^11 + 154*x^10 + 664*x^9 + 1873*x^8 + 3808*x^7 + 5980*x^6 + 7560*x^5 + 7799*x^4 + 6508*x^3 + 4290*x^2 + 2224*x + 887 
            sage: K.<theta> = NumberField(x^6 + 108) 
            sage: K.is_galois()
            True
            sage: vK = pAdicValuation(QQ, 2).extension(K)
            sage: vK(2) 
            1 
            sage: vK(theta) 
            1/3
            sage: G=Delta.change_ring(K) 
            sage: sorted(vK.mac_lane_approximants(G), key=str) # long time
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 2*x^2 + 1/2*theta^4 + theta^3 + 5*theta + 1) = 5/3 ],
             [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 2*x^2 + 3/2*theta^4 + theta^3 + 5*theta + 1) = 5/3 ],
             [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 2*x^2 + theta^4 + theta^3 + 1) = 5/3 ]]

        An easy case that produced the wrong error at some point::

            sage: R.<x> = QQ[]
            sage: v = pAdicValuation(QQ, 2)
            sage: v.mac_lane_approximants(x^2 - 1/2)
            Traceback (most recent call last):
            ...
            ValueError: G must be integral

        """
        R = G.parent()
        if R.base_ring() is not self.domain():
            raise ValueError(
                "G must be defined over the domain of this valuation")

        from sage.misc.misc import verbose
        verbose("Approximants of %r on %r towards %r" %
                (self, self.domain(), G),
                level=3)

        from sage.rings.all import infinity
        from gauss_valuation import GaussValuation

        if not all([self(c) >= 0 for c in G.coefficients()]):
            raise ValueError("G must be integral")

        if require_maximal_degree:
            # we can only assert maximality of degrees when E and F are final
            require_final_EF = True

        if not assume_squarefree:
            if require_final_EF and not G.is_squarefree():
                raise ValueError("G must be squarefree")
            else:
                # if only required_precision is set, we do not need to check
                # whether G is squarefree. If G is not squarefree, we compute
                # valuations corresponding to approximants for all the
                # squarefree factors of G (up to required_precision.)
                pass

        def is_sufficient(leaf, others):
            if leaf.valuation.mu() < required_precision:
                return False
            if require_final_EF and not leaf.ef:
                return False
            if require_maximal_degree and leaf.valuation.phi().degree(
            ) != leaf.valuation.E() * leaf.valuation.F():
                return False
            if require_incomparability:
                if any(leaf.valuation <= o.valuation for o in others):
                    return False
            return True

        # Leaves in the computation of the tree of approximants. Each vertex
        # consists of a tuple (v,ef,p,coeffs,vals) where v is an approximant, i.e., a
        # valuation, ef is a boolean, p is the parent of this vertex, and
        # coeffs and vals are cached values. (Only v and ef are relevant,
        # everything else are caches/debug info.)
        # The boolean ef denotes whether v already has the final ramification
        # index E and residue degree F of this approximant.
        # An edge V -- P represents the relation P.v ≤ V.v (pointwise on the
        # polynomial ring K[x]) between the valuations.
        class Node(object):
            def __init__(self, valuation, parent, ef, principal_part_bound,
                         coefficients, valuations):
                self.valuation = valuation
                self.parent = parent
                self.ef = ef
                self.principal_part_bound = principal_part_bound
                self.coefficients = coefficients
                self.valuations = valuations
                self.forced_leaf = False

        import mac_lane
        mac_lane.valuation.Node = Node

        seed = Node(GaussValuation(R, self), None,
                    G.degree() == 1, G.degree(), None, None)
        seed.forced_leaf = is_sufficient(seed, [])

        def create_children(node):
            new_leafs = []
            if node.forced_leaf:
                return new_leafs
            augmentations = node.valuation.mac_lane_step(
                G,
                report_degree_bounds_and_caches=True,
                coefficients=node.coefficients,
                valuations=node.valuations,
                check=False,
                principal_part_bound=node.principal_part_bound)
            for w, bound, principal_part_bound, coefficients, valuations in augmentations:
                ef = bound == w.E() * w.F()
                new_leafs.append(
                    Node(w, node, ef, principal_part_bound, coefficients,
                         valuations))
            for leaf in new_leafs:
                if is_sufficient(leaf,
                                 [l for l in new_leafs if l is not leaf]):
                    leaf.forced_leaf = True
            return new_leafs

        def reduce_tree(v, w):
            return v + w

        from sage.all import RecursivelyEnumeratedSet
        tree = RecursivelyEnumeratedSet([seed],
                                        successors=create_children,
                                        structure='forest',
                                        enumeration='breadth')
        # this is a tad faster but annoying for profiling / debugging
        if algorithm == 'parallel':
            nodes = tree.map_reduce(map_function=lambda x: [x], reduce_init=[])
        elif algorithm == 'serial':
            from sage.parallel.map_reduce import RESetMapReduce
            nodes = RESetMapReduce(forest=tree,
                                   map_function=lambda x: [x],
                                   reduce_init=[]).run_serial()
        else:
            raise NotImplementedError(algorithm)
        leafs = set([node.valuation for node in nodes])
        for node in nodes:
            if node.parent is None:
                continue
            v = node.parent.valuation
            if v in leafs:
                leafs.remove(v)

        return list(leafs)
Example #2
0
    def mac_lane_approximants(self,
                              G,
                              assume_squarefree=False,
                              require_final_EF=True,
                              required_precision=-1,
                              require_incomparability=False,
                              require_maximal_degree=False,
                              algorithm="serial"):
        r"""
        Return approximants on `K[x]` for the extensions of this valuation to
        `L=K[x]/(G)`.

        If `G` is an irreducible polynomial, then this corresponds to
        extensions of this valuation to the completion of `L`.

        INPUT:

        - ``G`` -- a monic squarefree integral polynomial in a
          univariate polynomial ring over the domain of this valuation

        - ``assume_squarefree`` -- a boolean (default: ``False``), whether to
          assume that ``G`` is squarefree. If ``True``, the squafreeness of
          ``G`` is not verified though it is necessary when
          ``require_final_EF`` is set for the algorithm to terminate.

        - ``require_final_EF`` -- a boolean (default: ``True``); whether to
          require the returned key polynomials to be in one-to-one
          correspondance to the extensions of this valuation to ``L`` and
          require them to have the ramification index and residue degree of the
          valuations they correspond to.

        - ``required_precision`` -- a number or infinity (default: -1); whether
          to require the last key polynomial of the returned valuations to have
          at least that valuation.

        - ``require_incomparability`` -- a boolean (default: ``False``);
          whether to require require the returned valuations to be incomparable
          (with respect to the partial order on valuations defined by comparing
          them pointwise.)

        - ``require_maximal_degree`` -- a boolean (deault: ``False``); whether
          to require the last key polynomial of the returned valuation to have
          maximal degree. This is most relevant when using this algorithm to
          compute approximate factorizations of ``G``, when set to ``True``,
          the last key polynomial has the same degree as the corresponding
          factor.

        - ``algorithm`` -- one of ``"serial"`` or ``"parallel"`` (default:
          ``"serial"``); whether or not to parallelize the algorithm

        EXAMPLES::

            sage: v = QQ.valuation(2)
            sage: R.<x> = QQ[]
            sage: v.mac_lane_approximants(x^2 + 1)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]]
            sage: v.mac_lane_approximants(x^2 + 1, required_precision=infinity)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2, v(x^2 + 1) = +Infinity ]]
            sage: v.mac_lane_approximants(x^2 + x + 1)
            [[ Gauss valuation induced by 2-adic valuation, v(x^2 + x + 1) = +Infinity ]]

        Note that ``G`` does not need to be irreducible. Here, we detect a
        factor `x + 1` and an approximate factor `x + 1` (which is an
        approximation to `x - 1`)::

            sage: v.mac_lane_approximants(x^2 - 1)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = +Infinity ],
             [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1 ]]

        However, it needs to be squarefree::

            sage: v.mac_lane_approximants(x^2)
            Traceback (most recent call last):
            ...
            ValueError: G must be squarefree

        TESTS:

        Some difficult cases provided by Mark van Hoeij::

            sage: k = GF(2)
            sage: K.<x> = FunctionField(k)
            sage: R.<y> = K[]
            sage: F = y^21 + x*y^20 + (x^3 + x + 1)*y^18 + (x^3 + 1)*y^17 + (x^4 + x)*y^16 + (x^7 + x^6 + x^3 + x + 1)*y^15 + x^7*y^14 + (x^8 + x^7 + x^6 + x^4 + x^3 + 1)*y^13 + (x^9 + x^8 + x^4 + 1)*y^12 + (x^11 + x^9 + x^8 + x^5 + x^4 + x^3 + x^2)*y^11 + (x^12 + x^9 + x^8 + x^7 + x^5 + x^3 + x + 1)*y^10 + (x^14 + x^13 + x^10 + x^9 + x^8 + x^7 + x^6 + x^3 + x^2 + 1)*y^9 + (x^13 + x^9 + x^8 + x^6 + x^4 + x^3 + x)*y^8 + (x^16 + x^15 + x^13 + x^12 + x^11 + x^7 + x^3 + x)*y^7 + (x^17 + x^16 + x^13 + x^9 + x^8 + x)*y^6 + (x^17 + x^16 + x^12 + x^7 + x^5 + x^2 + x + 1)*y^5 + (x^19 + x^16 + x^15 + x^12 + x^6 + x^5 + x^3 + 1)*y^4 + (x^18 + x^15 + x^12 + x^10 + x^9 + x^7 + x^4 + x)*y^3 + (x^22 + x^21 + x^20 + x^18 + x^13 + x^12 + x^9 + x^8 + x^7 + x^5 + x^4 + x^3)*y^2 + (x^23 + x^22 + x^20 + x^17 + x^15 + x^14 + x^12 + x^9)*y + x^25 + x^23 + x^19 + x^17 + x^15 + x^13 + x^11 + x^5
            sage: x = K._ring.gen()
            sage: v0 = K.valuation(GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x,1))
            sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed
            [[ Gauss valuation induced by (x)-adic valuation, v(y + x + 1) = 3/2 ],
             [ Gauss valuation induced by (x)-adic valuation, v(y) = 1 ],
             [ Gauss valuation induced by (x)-adic valuation, v(y) = 4/3 ],
             [ Gauss valuation induced by (x)-adic valuation, v(y^15 + y^13 + y^12 + y^10 + y^9 + y^8 + y^4 + y^3 + y^2 + y + 1) = 1 ]]
            sage: v0 = K.valuation(GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x+1,1))
            sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed
            [[ Gauss valuation induced by (x + 1)-adic valuation, v(y + x^2 + 1) = 7/2 ],
             [ Gauss valuation induced by (x + 1)-adic valuation, v(y) = 3/4 ],
             [ Gauss valuation induced by (x + 1)-adic valuation, v(y) = 7/2 ],
             [ Gauss valuation induced by (x + 1)-adic valuation, v(y^13 + y^12 + y^10 + y^7 + y^6 + y^3 + 1) = 1 ]]
            sage: v0 = valuations.FunctionFieldValuation(K, GaussValuation(K._ring, valuations.TrivialValuation(k)).augmentation(x^3+x^2+1,1))
            sage: v0.mac_lane_approximants(F, assume_squarefree=True) # assumes squarefree for speed
            [[ Gauss valuation induced by (x^3 + x^2 + 1)-adic valuation, v(y + x^3 + x^2 + x) = 2, v(y^2 + (x^6 + x^4 + 1)*y + x^14 + x^10 + x^9 + x^8 + x^5 + x^4 + x^3 + x^2 + x) = 5 ],
             [ Gauss valuation induced by (x^3 + x^2 + 1)-adic valuation, v(y^2 + (x^2 + x)*y + 1) = 1 ],
             [ Gauss valuation induced by (x^3 + x^2 + 1)-adic valuation, v(y^3 + (x + 1)*y^2 + (x + 1)*y + x^2 + x + 1) = 1 ],
             [ Gauss valuation induced by (x^3 + x^2 + 1)-adic valuation, v(y^3 + x^2*y + x) = 1 ],
             [ Gauss valuation induced by (x^3 + x^2 + 1)-adic valuation, v(y^4 + (x + 1)*y^3 + x^2*y^2 + (x^2 + x)*y + x) = 1 ],   
             [ Gauss valuation induced by (x^3 + x^2 + 1)-adic valuation, v(y^7 + x^2*y^6 + (x + 1)*y^4 + x^2*y^3 + (x^2 + x + 1)*y^2 + x^2*y + x) = 1 ]]

        Cases with trivial residue field extensions::

            sage: K.<x> = FunctionField(QQ)
            sage: S.<y> = K[]
            sage: F = y^2 - x^2 - x^3 - 3
            sage: v0 = GaussValuation(K._ring, QQ.valuation(3))
            sage: v1 = v0.augmentation(K._ring.gen(),1/3)
            sage: mu0 = valuations.FunctionFieldValuation(K, v1)
            sage: mu0.mac_lane_approximants(F)
            [[ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by 3-adic valuation, v(x) = 1/3 ], v(y + 2*x) = 2/3 ],
             [ Gauss valuation induced by Valuation on rational function field induced by [ Gauss valuation induced by 3-adic valuation, v(x) = 1/3 ], v(y + x) = 2/3 ]]

        Over a complete base field::

            sage: k=Qp(2,10)
            sage: v = k.valuation()

            sage: R.<x>=k[]
            sage: G = x
            sage: v.mac_lane_approximants(G)
            [Gauss valuation induced by 2-adic valuation]
            sage: v.mac_lane_approximants(G, required_precision = infinity)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = +Infinity ]]

            sage: G = x^2 + 1
            sage: v.mac_lane_approximants(G)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2 ]]
            sage: v.mac_lane_approximants(G, required_precision = infinity)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x + 1 + O(2^10)) = 1/2, v((1 + O(2^10))*x^2 + 1 + O(2^10)) = +Infinity ]]

            sage: G = x^4 + 2*x^3 + 2*x^2 - 2*x + 2
            sage: v.mac_lane_approximants(G)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4 ]]
            sage: v.mac_lane_approximants(G, required_precision=infinity)
            [[ Gauss valuation induced by 2-adic valuation, v((1 + O(2^10))*x) = 1/4, v((1 + O(2^10))*x^4 + (2 + O(2^11))*x^3 + (2 + O(2^11))*x^2 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + 2^10 + O(2^11))*x + 2 + O(2^11)) = +Infinity ]]

        The factorization of primes in the Gaussian integers can be read off
        the Mac Lane approximants::

            sage: v0 = QQ.valuation(2)
            sage: R.<x> = QQ[]
            sage: G = x^2 + 1
            sage: v0.mac_lane_approximants(G)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 ]]

            sage: v0 = QQ.valuation(3)
            sage: v0.mac_lane_approximants(G)
            [[ Gauss valuation induced by 3-adic valuation, v(x^2 + 1) = +Infinity ]]

            sage: v0 = QQ.valuation(5)
            sage: v0.mac_lane_approximants(G)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ],
             [ Gauss valuation induced by 5-adic valuation, v(x + 3) = 1 ]]
            sage: v0.mac_lane_approximants(G, required_precision = 10)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 3116/237) = 10 ],
             [ Gauss valuation induced by 5-adic valuation, v(x - 3116/237) = 10 ]]

        The same example over the 5-adic numbers. In the quadratic extension
        `\QQ[x]/(x^2+1)`, 5 factors `-(x - 2)(x + 2)`, this behaviour can be
        read off the Mac Lane approximants::

            sage: k=Qp(5,4)
            sage: v = k.valuation()
            sage: R.<x>=k[]
            sage: G = x^2 + 1
            sage: v1,v2 = v.mac_lane_approximants(G); v1,v2
            ([ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + O(5^4)) = 1 ],
             [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 3 + O(5^4)) = 1 ])
            sage: w1, w2 = v.mac_lane_approximants(G, required_precision = 2); w1,w2
            ([ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + 5 + O(5^4)) = 2 ],
             [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 3 + 3*5 + O(5^4)) = 2 ])

        Note how the latter give a better approximation to the factors of `x^2 + 1`::

            sage: v1.phi() * v2.phi() - G
            O(5^4)*x^2 + (5 + O(5^4))*x + 5 + O(5^4)
            sage: w1.phi() * w2.phi() - G
            O(5^4)*x^2 + (5^2 + O(5^4))*x + 5^3 + O(5^4)

        In this example, the process stops with a factorization of `x^2 + 1`::

            sage: v.mac_lane_approximants(G, required_precision=infinity)
            [[ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 2 + 5 + 2*5^2 + 5^3 + O(5^4)) = +Infinity ],
             [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x + 3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4)) = +Infinity ]]

        This obviously cannot happen over the rationals where we only get an
        approximate factorization::

            sage: v = QQ.valuation(5)
            sage: R.<x>=QQ[]
            sage: G = x^2 + 1
            sage: v.mac_lane_approximants(G)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 2) = 1 ],
             [ Gauss valuation induced by 5-adic valuation, v(x + 3) = 1 ]]
            sage: v.mac_lane_approximants(G, required_precision=5)
            [[ Gauss valuation induced by 5-adic valuation, v(x + 79/3) = 5 ],
             [ Gauss valuation induced by 5-adic valuation, v(x - 79/3) = 5 ]]

        Initial versions ran into problems with the trivial residue field
        extensions in this case::

            sage: K = Qp(3, 20, print_mode='digits')
            sage: R.<T> = K[]

            sage: alpha = T^3/4
            sage: G = 3^3*T^3*(alpha^4 - alpha)^2 - (4*alpha^3 - 1)^3
            sage: G = G/G.leading_coefficient()
            sage: K.valuation().mac_lane_approximants(G)
            [[ Gauss valuation induced by 3-adic valuation, v(...1*T + ...2) = 1/9, v(...1*T^9 + ...20*T^8 + ...210*T^7 + ...20*T^6 + ...20*T^5 + ...10*T^4 + ...220*T^3 + ...20*T^2 + ...110*T + ...122) = 55/27 ]]

        A similar example::

            sage: R.<x> = QQ[]
            sage: v = QQ.valuation(3)
            sage: G = (x^3 + 3)^3 - 81
            sage: v.mac_lane_approximants(G)
            [[ Gauss valuation induced by 3-adic valuation, v(x) = 1/3, v(x^3 + 3*x + 3) = 13/9 ]]

        Another problematic case::

            sage: R.<x> = QQ[] 
            sage: Delta = x^12 + 20*x^11 + 154*x^10 + 664*x^9 + 1873*x^8 + 3808*x^7 + 5980*x^6 + 7560*x^5 + 7799*x^4 + 6508*x^3 + 4290*x^2 + 2224*x + 887 
            sage: K.<theta> = NumberField(x^6 + 108) 
            sage: K.is_galois()
            True
            sage: vK = QQ.valuation(2).extension(K)
            sage: vK(2) 
            1 
            sage: vK(theta) 
            1/3
            sage: G=Delta.change_ring(K) 
            sage: vK.mac_lane_approximants(G)
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 1/2*theta^4 + 3*theta + 1) = 3/2 ],
             [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 1/2*theta^4 + theta + 1) = 3/2 ],
             [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/4, v(x^4 + 2*theta + 1) = 3/2 ]]

        An easy case that produced the wrong error at some point::

            sage: R.<x> = QQ[]
            sage: v = QQ.valuation(2)
            sage: v.mac_lane_approximants(x^2 - 1/2)
            Traceback (most recent call last):
            ...
            ValueError: G must be integral

        Some examples that Sebastian Pauli used in a talk at Sage Days 87.

        ::

            sage: R = ZpFM(3, 7, print_mode='terse')
            sage: S.<x> = R[]
            sage: v = R.valuation()
            sage: f = x^4 + 234
            sage: len(v.mac_lane_approximants(f, assume_squarefree=True)) # is_squarefree() is not properly implemented yet
            2

        ::

            sage: R = ZpFM(2, 50, print_mode='terse')
            sage: S.<x> = R[]
            sage: f = (x^32 + 16)*(x^32 + 16 + 2^16*x^2) + 2^34
            sage: v = R.valuation()
            sage: len(v.mac_lane_approximants(f, assume_squarefree=True)) # is_squarefree() is not properly implemented yet
            2

        A case that triggered an assertion at some point::

            sage: v = QQ.valuation(3)
            sage: R.<x> = QQ[]
            sage: f = x^36 + 60552000*x^33 + 268157412*x^30 + 173881701*x^27 + 266324841*x^24 + 83125683*x^21 + 111803814*x^18 + 31925826*x^15 + 205726716*x^12 +17990262*x^9 + 351459648*x^6 + 127014399*x^3 + 359254116
            sage: v.mac_lane_approximants(f)
            [[ Gauss valuation induced by 3-adic valuation, v(x) = 1/3, v(x^3 - 3) = 3/2, v(x^12 - 3*x^9 + 54*x^6 + 27/2*x^3 + 405/2) = 13/2, v(x^36 + 60552000*x^33 + 268157412*x^30 + 173881701*x^27 + 266324841*x^24 + 83125683*x^21 + 111803814*x^18 + 31925826*x^15 + 205726716*x^12 + 17990262*x^9 + 351459648*x^6 + 127014399*x^3 + 359254116) = +Infinity ]]

        """
        R = G.parent()
        if R.base_ring() is not self.domain():
            raise ValueError(
                "G must be defined over the domain of this valuation")

        from sage.misc.misc import verbose
        verbose("Approximants of %r on %r towards %r" %
                (self, self.domain(), G),
                level=3)

        from sage.rings.valuation.gauss_valuation import GaussValuation

        if not all([self(c) >= 0 for c in G.coefficients()]):
            raise ValueError("G must be integral")

        if require_maximal_degree:
            # we can only assert maximality of degrees when E and F are final
            require_final_EF = True

        if not assume_squarefree:
            if require_final_EF and not G.is_squarefree():
                raise ValueError("G must be squarefree")
            else:
                # if only required_precision is set, we do not need to check
                # whether G is squarefree. If G is not squarefree, we compute
                # valuations corresponding to approximants for all the
                # squarefree factors of G (up to required_precision.)
                pass

        def is_sufficient(leaf, others):
            if leaf.valuation.mu() < required_precision:
                return False
            if require_final_EF and not leaf.ef:
                return False
            if require_maximal_degree and leaf.valuation.phi().degree(
            ) != leaf.valuation.E() * leaf.valuation.F():
                return False
            if require_incomparability:
                if any(leaf.valuation <= o.valuation for o in others):
                    return False
            return True

        seed = MacLaneApproximantNode(GaussValuation(R, self), None,
                                      G.degree() == 1, G.degree(), None, None)
        seed.forced_leaf = is_sufficient(seed, [])

        def create_children(node):
            new_leafs = []
            if node.forced_leaf:
                return new_leafs
            augmentations = node.valuation.mac_lane_step(
                G,
                report_degree_bounds_and_caches=True,
                coefficients=node.coefficients,
                valuations=node.valuations,
                check=False,
                # We do not want to see augmentations that are
                # already part of other branches of the tree of
                # valuations for obvious performance reasons and
                # also because the principal_part_bound would be
                # incorrect for these.
                allow_equivalent_key=node.valuation.is_gauss_valuation(),
                # The length of an edge in the Newton polygon in
                # one MacLane step bounds the length of the
                # principal part (i.e., the part with negative
                # slopes) of the Newton polygons in the next
                # MacLane step. Therefore, mac_lane_step does not
                # need to compute valuations for coefficients
                # beyond that bound as they do not contribute any
                # augmentations.
                principal_part_bound=node.principal_part_bound)
            for w, bound, principal_part_bound, coefficients, valuations in augmentations:
                ef = bound == w.E() * w.F()
                new_leafs.append(
                    MacLaneApproximantNode(w, node, ef, principal_part_bound,
                                           coefficients, valuations))
            for leaf in new_leafs:
                if is_sufficient(leaf,
                                 [l for l in new_leafs if l is not leaf]):
                    leaf.forced_leaf = True
            return new_leafs

        def reduce_tree(v, w):
            return v + w

        from sage.all import RecursivelyEnumeratedSet
        tree = RecursivelyEnumeratedSet([seed],
                                        successors=create_children,
                                        structure='forest',
                                        enumeration='breadth')
        # this is a tad faster but annoying for profiling / debugging
        if algorithm == 'parallel':
            nodes = tree.map_reduce(map_function=lambda x: [x], reduce_init=[])
        elif algorithm == 'serial':
            from sage.parallel.map_reduce import RESetMapReduce
            nodes = RESetMapReduce(forest=tree,
                                   map_function=lambda x: [x],
                                   reduce_init=[]).run_serial()
        else:
            raise NotImplementedError(algorithm)
        leafs = set([node.valuation for node in nodes])
        for node in nodes:
            if node.parent is None:
                continue
            v = node.parent.valuation
            if v in leafs:
                leafs.remove(v)

        # The order of the leafs is not predictable in parallel mode and in
        # serial mode it depends on the hash functions and so on the underlying
        # architecture (32/64 bit). There is no natural ordering on these
        # valuations but it is very convenient for doctesting to return them in
        # some stable order, so we just order them by their string
        # representation which should be very fast.
        try:
            ret = sorted(leafs, key=str)
        except Exception:
            # if for some reason the valuation can not be printed, we leave them unsorted
            ret = list(leafs)

        return ret