{"action":"created","comment":{"url":"https://api.github.com/repos/saraedum/mac_lane/pulls/comments/129038576","pull_request_review_id":51771819,"id":129038576,"diff_hunk":"@@ -0,0 +1,1526 @@\n+# -*- coding: utf-8 -*-\n+r\"\"\"\n+Inductive valuations on polynomial rings\n+\n+This module provides functionality for inductive valuations, i.e., finite\n+chains of :class:`AugmentedValuation`s on top of a :class:`GaussValuation`.\n+\n+AUTHORS:\n+\n+- Julian Rüth (2016-11-01): initial version\n+\n+REFERENCES:\n+\n+.. [ML1936] Mac Lane, S. (1936). A construction for prime ideals as absolute\n+values of an algebraic field. Duke Mathematical Journal, 2(3), 492-510.\n+\n+.. [ML1936'] MacLane, S. (1936). A construction for absolute values in\n+polynomial rings. Transactions of the American Mathematical Society, 40(3),\n+363-395.\n+\n+\"\"\"\n+#*****************************************************************************\n+#       Copyright (C) 2016-2017 Julian Rüth <julian.rueth@fsfe.org>\n+#\n+#  Distributed under the terms of the GNU General Public License (GPL)\n+#  as published by the Free Software Foundation; either version 2 of\n+#  the License, or (at your option) any later version.\n+#                  http://www.gnu.org/licenses/\n+#*****************************************************************************\n+from valuation import DiscreteValuation, InfiniteDiscretePseudoValuation\n+from developing_valuation import DevelopingValuation\n+\n+from sage.misc.cachefunc import cached_method\n+from sage.misc.abstract_method import abstract_method\n+\n+class InductiveValuation(DevelopingValuation):\n+    r\"\"\"\n+    Abstract base class for iterated :class:`AugmentedValuation` on top of a\n+    :class:`GaussValuation`.\n+\n+    EXAMPLES::\n+\n+        sage: R.<x> = QQ[]\n+        sage: v = GaussValuation(R, QQ.valuation(5))\n+\n+    TESTS::\n+\n+        sage: TestSuite(v).run() # long time\n+\n+    \"\"\"\n+    def is_equivalence_unit(self, f, valuations=None):\n+        r\"\"\"\n+        Return whether ``f`` is an equivalence unit, i.e., an element of\n+        :meth:`effective_degree` zero (see [ML1936'] p.497.)\n+\n+        INPUT:\n+\n+        - ``f`` -- a polynomial in the domain of this valuation\n+\n+        EXAMPLES::\n+\n+            sage: R = Zp(2,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v.is_equivalence_unit(x)\n+            False\n+            sage: v.is_equivalence_unit(S.zero())\n+            False\n+            sage: v.is_equivalence_unit(2*x + 1)\n+            True\n+\n+        \"\"\"\n+        f = self.domain().coerce(f)\n+\n+        if f.is_zero():\n+            return False\n+        return self.effective_degree(f, valuations=valuations) == 0\n+\n+    def equivalence_reciprocal(self, f, coefficients=None, valuations=None, check=True):\n+        r\"\"\"\n+        Return an equivalence reciprocal of ``f``.\n+\n+        An equivalence reciprocal of `f` is a polynomial `h` such that `f\\cdot\n+        h` is equivalent to 1 modulo this valuation (see [ML1936'] p.497.)\n+\n+        INPUT:\n+\n+        - ``f`` -- a polynomial in the domain of this valuation which is an\n+          :meth:`equivalence_unit`\n+\n+        - ``coefficients`` -- the coefficients of ``f`` in the :meth:`phi`-adic\n+          expansion if known (default: ``None``)\n+\n+        - ``valuations`` -- the valuations of ``coefficients`` if known\n+          (default: ``None``)\n+\n+        - ``check`` -- whether or not to check the validity of ``f`` (default:\n+          ``True``)\n+\n+        EXAMPLES::\n+\n+            sage: R = Zp(3,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: f = 3*x + 2\n+            sage: h = v.equivalence_reciprocal(f); h # optional: integrated (needs xgcd for polynomials with p-adic coefficients)\n+            2 + 3 + 3^2 + 3^3 + 3^4 + O(3^5)\n+            sage: v.is_equivalent(f*h, 1) # optional: integrated\n+            True\n+\n+        In an extended valuation over an extension field::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v = v.augmentation(x^2 + x + u, 1)\n+            sage: f = 2*x + u\n+            sage: h = v.equivalence_reciprocal(f); h\n+            (u + 1) + O(2^5)\n+            sage: v.is_equivalent(f*h, 1)\n+            True\n+\n+        Extending the valuation once more::\n+\n+            sage: v = v.augmentation((x^2 + x + u)^2 + 2*x*(x^2 + x + u) + 4*x, 3)\n+            sage: h = v.equivalence_reciprocal(f); h\n+            (u + 1) + O(2^5)\n+            sage: v.is_equivalent(f*h, 1)\n+            True\n+\n+        TESTS:\n+\n+        A case that caused problems at some point::\n+\n+            sage: K = Qp(2, 4)\n+            sage: R.<x> = K[]\n+            sage: L.<a> = K.extension(x^4 + 4*x^3 + 6*x^2 + 4*x + 2)\n+            sage: R.<t> = L[]\n+            sage: v = GaussValuation(R)\n+            sage: w = v.augmentation(t + 1, 5/16)\n+            sage: w = w.augmentation(t^4 + (a^8 + a^12 + a^14 + a^16 + a^17 + a^19 + a^20 + a^23)*t^3 + (a^6 + a^9 + a^13 + a^15 + a^18 + a^19 + a^21)*t^2 + a^10*t + 1 + a^4 + a^5 + a^8 + a^13 + a^14 + a^15, 17/8)\n+            sage: f = a^-15*t^2 + (a^-11 + a^-9 + a^-6 + a^-5 + a^-3 + a^-2)*t + a^-15\n+            sage: f_ = w.equivalence_reciprocal(f)\n+            sage: w.reduce(f*f_)\n+            1\n+            sage: f = f.parent()([f[0], f[1].add_bigoh(1), f[2]])\n+            sage: f_ = w.equivalence_reciprocal(f)\n+            sage: w.reduce(f*f_)\n+            1\n+\n+        \"\"\"\n+        f = self.domain().coerce(f)\n+\n+        from sage.categories.fields import Fields\n+        if not self.domain().base_ring() in Fields():\n+            # the xgcd does in general not work, i.e., return 1, unless over a field\n+            raise NotImplementedError(\"only implemented for polynomial rings over fields\")\n+\n+        if check:\n+            if coefficients is None:\n+                coefficients = list(self.coefficients(f))\n+            if valuations is None:\n+                valuations = list(self.valuations(f, coefficients=coefficients))\n+            if not self.is_equivalence_unit(f, valuations=valuations):\n+                raise ValueError(\"f must be an equivalence unit but %r is not\"%(f,))\n+\n+        if coefficients is None:\n+            e0 = self.coefficients(f).next()\n+        else:\n+            e0 = coefficients[0]\n+        \n+        # f is an equivalence unit, its valuation is given by the constant coefficient\n+        if valuations is None:\n+            vf = self(e0)\n+        else:\n+            vf = valuations[0]\n+\n+        e0 = self.simplify(e0, error=vf)\n+        s_ = self.equivalence_unit(-vf)\n+        residue = self.reduce(e0 * s_)\n+        if not isinstance(self, FinalInductiveValuation):\n+            assert residue.is_constant()\n+            residue = residue[0]\n+        h = self.lift(~residue) * s_\n+\n+        h = self.simplify(h, -vf)\n+\n+        # it might be the case that f*h has non-zero valuation because h has\n+        # insufficient precision, so we must not assert that here but only\n+        # until we lifted to higher precision\n+\n+        # We do not actually need g*phi + h*e0 = 1, it is only important that\n+        # the RHS is 1 in reduction.\n+        # This allows us to do two things:\n+        # - we may lift h to arbitrary precision\n+        # - we can add anything which times e0 has positive valuation, e.g., we\n+        # may drop coefficients of positive valuation\n+        h = h.map_coefficients(lambda c:_lift_to_maximal_precision(c))\n+\n+        return h\n+\n+    @cached_method\n+    def mu(self):\n+        r\"\"\"\n+        Return the valuation of :meth:`phi`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = GaussValuation(R, QQ.valuation(2))\n+            sage: v.mu()\n+            0\n+\n+        \"\"\"\n+        return self(self.phi())\n+\n+    @abstract_method\n+    def equivalence_unit(self, s, reciprocal=False):\n+        \"\"\"\n+        Return an equivalence unit of valuation ``s``.\n+\n+        INPUT:\n+\n+        - ``s`` -- an element of the :meth:`value_group`\n+\n+        - ``reciprocal`` -- a boolean (default: ``False``); whether or not to\n+          return the equivalence unit as the :meth:`equivalence_reciprocal` of\n+          the equivalence unit of valuation ``-s``.\n+\n+        EXAMPLES::\n+\n+            sage: S.<x> = Qp(3,5)[]\n+            sage: v = GaussValuation(S)\n+            sage: v.equivalence_unit(2)\n+            (3^2 + O(3^7))\n+            sage: v.equivalence_unit(-2)\n+            (3^-2 + O(3^3))\n+\n+        Note that this might fail for negative ``s`` if the domain is not\n+        defined over a field::\n+\n+            sage: v = ZZ.valuation(2)\n+            sage: R.<x> = ZZ[]\n+            sage: w = GaussValuation(R, v)\n+            sage: w.equivalence_unit(1)\n+            2\n+            sage: w.equivalence_unit(-1)\n+            Traceback (most recent call last):\n+            ...\n+            ValueError: s must be in the value semigroup of this valuation but -1 is not in Additive Abelian Semigroup generated by 1\n+\n+        \"\"\"\n+        \n+    @abstract_method\n+    def augmentation_chain(self):\n+        r\"\"\"\n+        Return a list with the chain of augmentations down to the underlying\n+        :class:`GaussValuation`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v.augmentation_chain()\n+            [Gauss valuation induced by 2-adic valuation]\n+\n+        \"\"\"\n+\n+    @abstract_method\n+    def is_gauss_valuation(self):\n+        r\"\"\"\n+        Return whether this valuation is a Gauss valuation over the domain.\n+\n+        EXAMPLES::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v.is_gauss_valuation()\n+            True\n+\n+        \"\"\"\n+\n+    @abstract_method\n+    def E(self):\n+        \"\"\"\n+        Return the ramification index of this valuation over its underlying\n+        Gauss valuation.\n+\n+        EXAMPLES::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v.E()\n+            1\n+\n+        \"\"\"\n+\n+    @abstract_method\n+    def F(self):\n+        \"\"\"\n+        Return the residual degree of this valuation over its Gauss extension.\n+\n+        EXAMPLES::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v.F()\n+            1\n+\n+        \"\"\"\n+\n+    @abstract_method\n+    def monic_integral_model(self, G):\n+        r\"\"\"\n+        Return a monic integral irreducible polynomial which defines the same\n+        extension of the base ring of the domain as the irreducible polynomial\n+        ``G`` together with maps between the old and the new polynomial.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = GaussValuation(R, QQ.valuation(2))\n+            sage: v.monic_integral_model(5*x^2 + 1/2*x + 1/4)\n+            (Ring endomorphism of Univariate Polynomial Ring in x over Rational Field\n+               Defn: x |--> 1/2*x,\n+             Ring endomorphism of Univariate Polynomial Ring in x over Rational Field\n+               Defn: x |--> 2*x,\n+            x^2 + 1/5*x + 1/5)\n+\n+        \"\"\"\n+\n+    @abstract_method\n+    def element_with_valuation(self, s):\n+        r\"\"\"\n+        Return a polynomial of minimal degree with valuation ``s``.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = GaussValuation(R, QQ.valuation(2))\n+            sage: v.element_with_valuation(-2)\n+            1/4\n+\n+        Depending on the base ring, an element of valuation ``s`` might not\n+        exist::\n+\n+            sage: R.<x> = ZZ[]\n+            sage: v = GaussValuation(R, ZZ.valuation(2))\n+            sage: v.element_with_valuation(-2)\n+            Traceback (most recent call last):\n+            ...\n+            ValueError: s must be in the value semigroup of this valuation but -2 is not in Additive Abelian Semigroup generated by 1\n+            \n+        \"\"\"\n+\n+    def _test_element_with_valuation_inductive_valuation(self, **options):\n+        r\"\"\"\n+        Test the correctness of :meth:`element_with_valuation`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = GaussValuation(R, QQ.valuation(2))\n+            sage: v._test_element_with_valuation_inductive_valuation()\n+\n+        \"\"\"\n+        tester = self._tester(**options)\n+        chain = self.augmentation_chain()\n+        for s in tester.some_elements(self.value_group().some_elements()):\n+            try:\n+                R = self.element_with_valuation(s)\n+            except (ValueError, NotImplementedError):\n+                # this is often not possible unless the underlying ring of\n+                # constants is a field\n+                from sage.categories.fields import Fields\n+                if self.domain().base() not in Fields():\n+                    continue\n+                raise\n+            tester.assertEqual(self(R), s)\n+            if chain != [self]:\n+                base = chain[1]\n+                if s in base.value_group():\n+                    S = base.element_with_valuation(s)\n+                    tester.assertEqual(self(S), s)\n+                    tester.assertGreaterEqual(S.degree(), R.degree())\n+\n+    def _test_EF(self, **options):\n+        r\"\"\"\n+        Test the correctness of :meth:`E` and :meth:`F`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = GaussValuation(S)\n+            sage: v._test_EF()\n+\n+        \"\"\"\n+        tester = self._tester(**options)\n+        chain = self.augmentation_chain()\n+        for w,v in zip(chain, chain[1:]):\n+            from sage.rings.all import infinity, ZZ\n+            if w(w.phi()) is infinity:\n+                tester.assertEqual(w.E(), v.E())\n+            tester.assertIn(w.E(), ZZ)\n+            tester.assertIn(w.F(), ZZ)\n+            tester.assertGreaterEqual(w.E(), v.E())\n+            tester.assertGreaterEqual(w.F(), v.F())\n+\n+    def _test_augmentation_chain(self, **options):\n+        r\"\"\"\n+        Test the correctness of :meth:`augmentation_chain`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+            sage: v._test_augmentation_chain()\n+            \n+        \"\"\"\n+        tester = self._tester(**options)\n+        chain = self.augmentation_chain()\n+        tester.assertIs(chain[0], self)\n+        tester.assertTrue(chain[-1].is_gauss_valuation())\n+        for w,v in zip(chain, chain[1:]):\n+            tester.assertGreaterEqual(w, v)\n+\n+    def _test_equivalence_unit(self, **options):\n+        r\"\"\"\n+        Test the correctness of :meth:`lift_to_key`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+            sage: v._test_equivalence_unit()\n+\n+        \"\"\"\n+        tester = self._tester(**options)\n+\n+        if self.is_gauss_valuation():\n+            value_group = self.value_group()\n+        else:\n+            value_group = self.augmentation_chain()[1].value_group()\n+\n+        for s in tester.some_elements(value_group.some_elements()):\n+            try:\n+                R = self.equivalence_unit(s)\n+            except (ValueError, NotImplementedError):\n+                # this is often not possible unless the underlying ring of\n+                # constants is a field\n+                from sage.categories.fields import Fields\n+                if self.domain().base() not in Fields():\n+                    continue\n+                raise\n+            tester.assertIs(R.parent(), self.domain())\n+            tester.assertEqual(self(R), s)\n+            tester.assertTrue(self.is_equivalence_unit(R))\n+\n+    def _test_is_equivalence_unit(self, **options):\n+        r\"\"\"\n+        Test the correctness of :meth:`is_equivalence_unit`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+            sage: v._test_is_equivalence_unit()\n+\n+        \"\"\"\n+        tester = self._tester(**options)\n+        tester.assertFalse(self.is_equivalence_unit(self.phi()))\n+\n+    def _test_equivalence_reciprocal(self, **options):\n+        r\"\"\"\n+        Test the correctness of :meth:`equivalence_reciprocal`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+            sage: v._test_equivalence_reciprocal()\n+\n+        \"\"\"\n+        tester = self._tester(**options)\n+        S = tester.some_elements(self.domain().some_elements())\n+        for f in S:\n+            if self.is_equivalence_unit(f):\n+                try:\n+                    g = self.equivalence_reciprocal(f)\n+                except (ValueError, NotImplementedError):\n+                    # this is often not possible unless the underlying ring of\n+                    # constants is a field\n+                    from sage.categories.fields import Fields\n+                    if self.domain().base() not in Fields():\n+                        continue\n+                    raise\n+                tester.assertEqual(self.reduce(f*g), 1)\n+\n+    def _test_inductive_valuation_inheritance(self, **options):\n+        r\"\"\"\n+        Test that every instance that is a :class:`InductiveValuation` is\n+        either a :class:`FiniteInductiveValuation` or a\n+        :class:`InfiniteInductiveValuation`. Same for\n+        :class:`FinalInductiveValuation` and\n+        :class:`NonFinalInductiveValuation`.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+            sage: v._test_inductive_valuation_inheritance()\n+\n+        \"\"\"\n+        tester = self._tester(**options)\n+        tester.assertTrue(isinstance(self, InfiniteInductiveValuation) != isinstance(self, FiniteInductiveValuation))\n+        tester.assertTrue(isinstance(self, FinalInductiveValuation) != isinstance(self, NonFinalInductiveValuation))\n+\n+\n+class FiniteInductiveValuation(InductiveValuation, DiscreteValuation):\n+    r\"\"\"\n+    Abstract base class for iterated :class:`AugmentedValuation` on top of a\n+    :class:`GaussValuation` which is a discrete valuation, i.e., the last key\n+    polynomial has finite valuation.\n+\n+    EXAMPLES::\n+\n+        sage: R.<x> = QQ[]\n+        sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+\n+    \"\"\"\n+    def __init__(self, parent, phi):\n+        r\"\"\"\n+        TESTS::\n+\n+            sage: R.<x> = QQ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(QQ))\n+            sage: from sage.rings.valuation.inductive_valuation import FiniteInductiveValuation\n+            sage: isinstance(v, FiniteInductiveValuation)\n+            True\n+\n+        \"\"\"\n+        InductiveValuation.__init__(self, parent, phi)\n+        DiscreteValuation.__init__(self, parent)\n+\n+    def extensions(self, other):\n+        r\"\"\"\n+        Return the extensions of this valuation to ``other``.\n+\n+        EXAMPLES::\n+\n+            sage: R.<x> = ZZ[]\n+            sage: v = valuations.GaussValuation(R, valuations.TrivialValuation(ZZ))\n+            sage: K.<x> = FunctionField(QQ)\n+            sage: v.extensions(K)\n+            [Trivial valuation on Rational Field]\n+\n+        \"\"\"\n+        from sage.categories.function_fields import FunctionFields\n+        if other in FunctionFields() and other.ngens() == 1:\n+            # extend to K[x] and from there to K(x)\n+            v = self.extension(self.domain().change_ring(self.domain().base().fraction_field()))\n+            return [other.valuation(v)]\n+        return super(FiniteInductiveValuation, self).extensions(other)\n+\n+\n+class NonFinalInductiveValuation(FiniteInductiveValuation, DiscreteValuation):\n+    r\"\"\"\n+    Abstract base class for iterated :class:`AugmentedValuation` on top of a\n+    :class:`GaussValuation` which can be extended further through\n+    :meth:`augmentation`.\n+\n+    EXAMPLES::\n+\n+        sage: R.<u> = Qq(4,5)\n+        sage: S.<x> = R[]\n+        sage: v = valuations.GaussValuation(S)\n+        sage: v = v.augmentation(x^2 + x + u, 1)\n+\n+    \"\"\"\n+    def __init__(self, parent, phi):\n+        r\"\"\"\n+        TESTS::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = valuations.GaussValuation(S)\n+            sage: v = v.augmentation(x^2 + x + u, 1)\n+            sage: from sage.rings.valuation.inductive_valuation import NonFinalInductiveValuation\n+            sage: isinstance(v, NonFinalInductiveValuation)\n+            True\n+\n+        \"\"\"\n+        FiniteInductiveValuation.__init__(self, parent, phi)\n+        DiscreteValuation.__init__(self, parent)\n+\n+    def augmentation(self, phi, mu, check=True):\n+        r\"\"\"\n+        Return the inductive valuation which extends this valuation by mapping\n+        ``phi`` to ``mu``.\n+\n+        INPUT:\n+\n+        - ``phi`` -- a polynomial in the domain of this valuation; this must be\n+          a key polynomial, see :meth:`is_key` for properties of key\n+          polynomials.\n+\n+        - ``mu`` -- a rational number or infinity, the valuation of ``phi`` in\n+          the extended valuation\n+\n+        - ``check`` -- a boolean (default: ``True``), whether or not to check\n+          the correctness of the parameters\n+\n+        EXAMPLES::\n+\n+            sage: R.<u> = Qq(4,5)\n+            sage: S.<x> = R[]\n+            sage: v = valuations.GaussValuation(S)\n+            sage: v = v.augmentation(x^2 + x + u, 1)\n+            sage: v = v.augmentation((x^2 + x + u)^2 + 2*x*(x^2 + x + u) + 4*x, 3)\n+            sage: v\n+            [ Gauss valuation induced by 2-adic valuation,\n+              v((1 + O(2^5))*x^2 + (1 + O(2^5))*x + u + O(2^5)) = 1,\n+              v((1 + O(2^5))*x^4 + (2^2 + O(2^6))*x^3 + (1 + (u + 1)*2 + O(2^5))*x^2 + ((u + 1)*2^2 + O(2^6))*x + (u + 1) + (u + 1)*2 + (u + 1)*2^2 + (u + 1)*2^3 + (u + 1)*2^4 + O(2^5)) = 3 ]\n+\n+        TESTS:\n+\n+        Make sure that we do not make the assumption that the degrees of the\n+        key polynomials are strictly increasing::\n+            \n+            sage: v_K = QQ.valuation(3)\n+            sage: A.<t> = QQ[]\n+            sage: v0 = valuations.GaussValuation(A,v_K)\n+\n+            sage: v1 = v0.augmentation(t, 1/12)\n+            sage: v2 = v1.augmentation(t^12 + 3, 7/6)\n+            sage: v3 = v2.augmentation(t^12 + 3*t^2 + 3, 9/4)\n+            sage: v4 = v1.augmentation(t^12 + 3*t^2 + 3, 9/4)\n+            sage: v3 <= v4 and v3 >= v4 \n+            True\n+\n+        .. SEEALSO::\n+\n+            :meth:`AugmentedValuation`\n+\n+        \"\"\"\n+        from augmented_valuation import AugmentedValuation\n+        return AugmentedValuation(self, phi, mu, check)\n+\n+    def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, assume_equivalence_irreducible=False, report_degree_bounds_and_caches=False, coefficients=None, valuations=None, check=True):\n+        r\"\"\"\n+        Perform an approximation step towards the squarefree monic non-constant\n+        integral polynomial ``G`` which is not an :meth:`equivalence_unit`.\n+\n+        This performs the individual steps that are used in\n+        :meth:`mac_lane_approximants`.\n+\n+        INPUT:\n+\n+        - ``G`` -- a sqaurefree monic non-constant integral polynomial ``G``\n+          which is not an :meth:`equivalence_unit`\n+\n+        - ``principal_part_bound`` -- an integer or ``None`` (default:\n+          ``None``), a bound on the length of the principal part, i.e., the\n+          section of negative slope, of the Newton polygon of ``G``\n+\n+        - ``assume_squarefree`` -- whether or not to assume that ``G`` is\n+          squarefree (default: ``False``)\n+\n+        - ``assume_equivalence_irreducible`` -- whether or not to assume that\n+          ``G`` is equivalence irreducible (default: ``False``)\n+\n+        - ``report_degree_bounds_and_caches`` -- whether or not to include internal state with the returned value (used by :meth:`mac_lane_approximants` to speed up sequential calls)\n+\n+         - ``coefficients`` -- the coefficients of ``G`` in the\n+           :meth:`phi`-adic expansion if known (default: ``None``)\n+\n+        - ``valauations`` -- the valuations of ``coefficients`` if known\n+          (default: ``None``)\n+\n+        - ``check`` -- whether to check that ``G`` is a squarefree monic\n+          non-constant  integral polynomial and not an :meth:`equivalence_unit`\n+          (default: ``True``)\n+\n+        TESTS::\n+\n+            sage: K.<x> = FunctionField(QQ)\n+            sage: S.<y> = K[]\n+            sage: F = y^2 - x^2 - x^3 - 3\n+            sage: v0 = valuations.GaussValuation(K._ring, QQ.valuation(3))\n+            sage: v1 = v0.augmentation(K._ring.gen(), 1/3)\n+            sage: mu0 = K.valuation(v1)\n+            sage: eta0 = valuations.GaussValuation(S, mu0)\n+            sage: eta1 = eta0.mac_lane_step(F)[0]\n+            sage: eta2 = eta1.mac_lane_step(F)[0]\n+            sage: eta2\n+            [ 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 ]\n+\n+        \"\"\"\n+        G = self.domain().coerce(G)\n+\n+        if G.is_constant():\n+            raise ValueError(\"G must not be constant\")\n+\n+        from itertools import islice\n+        from sage.misc.misc import verbose\n+        verbose(\"Augmenting %s towards %s\"%(self, G), level=10)\n+\n+        if not G.is_monic():\n+            raise ValueError(\"G must be monic\")\n+\n+        if coefficients is None:\n+            coefficients = self.coefficients(G)\n+            if principal_part_bound:\n+                coefficients = islice(coefficients, 0, principal_part_bound + 1, 1)\n+            coefficients = list(coefficients)\n+        if valuations is None:\n+            valuations = self.valuations(G, coefficients=coefficients)\n+            if principal_part_bound:\n+                valuations = islice(valuations, 0, principal_part_bound + 1, 1)\n+            valuations = list(valuations)\n+\n+        if check and min(valuations) < 0:\n+            raise ValueError(\"G must be integral\")\n+\n+        if check and self.is_equivalence_unit(G, valuations=valuations):\n+            raise ValueError(\"G must not be an equivalence-unit\")\n+\n+        if check and not assume_squarefree and not G.is_squarefree():\n+            raise ValueError(\"G must be squarefree\")\n+\n+        from sage.rings.all import infinity\n+        assert self(G) is not infinity # this is a valuation and G is non-zero\n+\n+        ret = []\n+\n+        F = self.equivalence_decomposition(G, assume_not_equivalence_unit=True, coefficients=coefficients, valuations=valuations, compute_unit=False, degree_bound=principal_part_bound)\n+        assert len(F), \"%s equivalence-decomposes as an equivalence-unit %s\"%(G, F)\n+        if len(F) == 1 and F[0][1] == 1 and F[0][0].degree() == G.degree():\n+            assert self.is_key(G, assume_equivalence_irreducible=assume_equivalence_irreducible)\n+            ret.append((self.augmentation(G, infinity, check=False), G.degree(), principal_part_bound, None, None))\n+        else:\n+            for phi,e in F:\n+                if G == phi:\n+                    # Something strange happened here:\n+                    # G is not a key (we checked that before) but phi==G is; so phi must have less precision than G\n+                    # this can happen if not all coefficients of G have the same precision\n+                    # if we drop some precision of G then it will be a key (but is\n+                    # that really what we should do?)\n+                    assert not G.base_ring().is_exact()\n+                    prec = min([c.precision_absolute() for c in phi.list()])\n+                    g = G.map_coefficients(lambda c:c.add_bigoh(prec))\n+                    assert self.is_key(g)\n+                    ret.append((self.augmentation(g, infinity, check=False), g.degree(), principal_part_bound, None, None))\n+                    assert len(F) == 1\n+                    break\n+\n+                if phi == self.phi():\n+                    # a factor phi in the equivalence decomposition means that we\n+                    # found an actual factor of G, i.e., we can set\n+                    # v(phi)=infinity\n+                    # However, this should already have happened in the last step\n+                    # (when this polynomial had -infinite slope in the Newton\n+                    # polygon.)\n+                    if self.is_gauss_valuation(): # unless in the first step\n+                        pass\n+                    else:\n+                        continue\n+\n+                verbose(\"Determining the augmentation of %s for %s\"%(self, phi), level=11)\n+                old_mu = self(phi)\n+                w = self.augmentation(phi, old_mu, check=False)\n+\n+                # we made some experiments here: instead of computing the\n+                # coefficients again from scratch, update the coefficients when\n+                # phi - self.phi() is a constant.\n+                # It turned out to be slightly slower than just recomputing the\n+                # coefficients. The main issue with the approach was that we\n+                # needed to keep track of all the coefficients and not just of\n+                # the coefficients up to principal_part_bound.\n+\n+                w_coefficients = w.coefficients(G)\n+                if principal_part_bound:\n+                    w_coefficients = islice(w_coefficients, 0, principal_part_bound + 1, 1)\n+                w_coefficients = list(w_coefficients)\n+\n+                w_valuations = w.valuations(G, coefficients=w_coefficients)\n+                if principal_part_bound:\n+                    w_valuations = islice(w_valuations, 0, principal_part_bound + 1, 1)\n+                w_valuations = list(w_valuations)\n+\n+                from sage.geometry.newton_polygon import NewtonPolygon\n+                NP = NewtonPolygon(w.newton_polygon(G, valuations=w_valuations).vertices(), last_slope=0)\n+\n+                verbose(\"Newton-Polygon for v(phi)=%s : %s\"%(self(phi), NP), level=11)\n+                slopes = NP.slopes(repetition=True)\n+                multiplicities = {slope : len([s for s in slopes if s == slope]) for slope in slopes}\n+                slopes = multiplicities.keys()\n+                if NP.vertices()[0][0] != 0:\n+                    slopes = [-infinity] + slopes\n+                    multiplicities[-infinity] = 1\n+\n+                if not slopes:\n+                    q,r = G.quo_rem(phi)\n+                    assert not r.is_zero()\n+                    phi = phi.coefficients(sparse=False)\n+                    for i,c in enumerate(r.coefficients(sparse=False)):\n+                        if not c.is_zero():\n+                            v = w(c)\n+                            # for a correct result we need to add O(pi^v) in degree i\n+                            # we try to find the coefficient of phi where such an\n+                            # error can be introduced without losing much absolute\n+                            # precision on phi\n+                            best = i\n+                            for j in range(i):\n+                                if w(q[j]) < w(q[best]):\n+                                    best = j\n+                            # now add the right O() to phi in degree i - best\n+                            phi[i-best] = phi[i-best].add_bigoh(w(c)-w(q[best]))\n+\n+                    phi = G.parent()(phi)\n+                    w = self._base_valuation.augmentation(phi, infinity, check=False)\n+                    ret.append((w, phi.degree(), principal_part_bound, None, None))\n+                    continue\n+\n+                for i, slope in enumerate(slopes):\n+                    slope = slopes[i]\n+                    verbose(\"Slope = %s\"%slope, level=12)\n+                    new_mu = old_mu - slope\n+                    new_valuations = [val - (j*slope if slope is not -infinity else (0 if j == 0 else -infinity)) for j,val in enumerate(w_valuations)]\n+                    base = self\n+                    if phi.degree() == base.phi().degree():\n+                        assert new_mu > self(phi)\n+                        if not base.is_gauss_valuation():\n+                            base = base._base_valuation","path":"src/sage/rings/valuation/inductive_valuation.py","position":838,"original_position":839,"commit_id":"acfe38f722ed73a9df5debc8ad552dffeb92e479","original_commit_id":"45286d752986084a57f1d6248f9bab5fd0f69094","user":{"login":"saraedum","id":373765,"avatar_url":"https://avatars1.githubusercontent.com/u/373765?v=4","gravatar_id":"","url":"https://api.github.com/users/saraedum","html_url":"https://github.com/saraedum","followers_url":"https://api.github.com/users/saraedum/followers","following_url":"https://api.github.com/users/saraedum/following{/other_user}","gists_url":"https://api.github.com/users/saraedum/gists{/gist_id}","starred_url":"https://api.github.com/users/saraedum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saraedum/subscriptions","organizations_url":"https://api.github.com/users/saraedum/orgs","repos_url":"https://api.github.com/users/saraedum/repos","events_url":"https://api.github.com/users/saraedum/events{/privacy}","received_events_url":"https://api.github.com/users/saraedum/received_events","type":"User","site_admin":false},"body":"Yes, this is a very common case. I'll add a comment.","created_at":"2017-07-24T13:44:29Z","updated_at":"2017-07-24T13:44:29Z","html_url":"https://github.com/saraedum/mac_lane/pull/4#discussion_r129038576","pull_request_url":"https://api.github.com/repos/saraedum/mac_lane/pulls/4","_links":{"self":{"href":"https://api.github.com/repos/saraedum/mac_lane/pulls/comments/129038576"},"html":{"href":"https://github.com/saraedum/mac_lane/pull/4#discussion_r129038576"},"pull_request":{"href":"https://api.github.com/repos/saraedum/mac_lane/pulls/4"}}},"pull_request":{"url":"https://api.github.com/repos/saraedum/mac_lane/pulls/4","id":131255938,"html_url":"https://github.com/saraedum/mac_lane/pull/4","diff_url":"https://github.com/saraedum/mac_lane/pull/4.diff","patch_url":"https://github.com/saraedum/mac_lane/pull/4.patch","issue_url":"https://api.github.com/repos/saraedum/mac_lane/issues/4","number":4,"state":"open","locked":false,"title":"Review https://trac.sagemath.org/ticket/21869","user":{"login":"saraedum","id":373765,"avatar_url":"https://avatars1.githubusercontent.com/u/373765?v=4","gravatar_id":"","url":"https://api.github.com/users/saraedum","html_url":"https://github.com/saraedum","followers_url":"https://api.github.com/users/saraedum/followers","following_url":"https://api.github.com/users/saraedum/following{/other_user}","gists_url":"https://api.github.com/users/saraedum/gists{/gist_id}","starred_url":"https://api.github.com/users/saraedum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saraedum/subscriptions","organizations_url":"https://api.github.com/users/saraedum/orgs","repos_url":"https://api.github.com/users/saraedum/repos","events_url":"https://api.github.com/users/saraedum/events{/privacy}","received_events_url":"https://api.github.com/users/saraedum/received_events","type":"User","site_admin":false},"body":"","created_at":"2017-07-19T07:40:56Z","updated_at":"2017-07-24T13:44:29Z","closed_at":null,"merged_at":null,"merge_commit_sha":"11bb4a038b89b810c8fe84e073e9e17f89a106c1","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/saraedum/mac_lane/pulls/4/commits","review_comments_url":"https://api.github.com/repos/saraedum/mac_lane/pulls/4/comments","review_comment_url":"https://api.github.com/repos/saraedum/mac_lane/pulls/comments{/number}","comments_url":"https://api.github.com/repos/saraedum/mac_lane/issues/4/comments","statuses_url":"https://api.github.com/repos/saraedum/mac_lane/statuses/acfe38f722ed73a9df5debc8ad552dffeb92e479","head":{"label":"saraedum:sage","ref":"sage","sha":"acfe38f722ed73a9df5debc8ad552dffeb92e479","user":{"login":"saraedum","id":373765,"avatar_url":"https://avatars1.githubusercontent.com/u/373765?v=4","gravatar_id":"","url":"https://api.github.com/users/saraedum","html_url":"https://github.com/saraedum","followers_url":"https://api.github.com/users/saraedum/followers","following_url":"https://api.github.com/users/saraedum/following{/other_user}","gists_url":"https://api.github.com/users/saraedum/gists{/gist_id}","starred_url":"https://api.github.com/users/saraedum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saraedum/subscriptions","organizations_url":"https://api.github.com/users/saraedum/orgs","repos_url":"https://api.github.com/users/saraedum/repos","events_url":"https://api.github.com/users/saraedum/events{/privacy}","received_events_url":"https://api.github.com/users/saraedum/received_events","type":"User","site_admin":false},"repo":{"id":74326173,"name":"mac_lane","full_name":"saraedum/mac_lane","owner":{"login":"saraedum","id":373765,"avatar_url":"https://avatars1.githubusercontent.com/u/373765?v=4","gravatar_id":"","url":"https://api.github.com/users/saraedum","html_url":"https://github.com/saraedum","followers_url":"https://api.github.com/users/saraedum/followers","following_url":"https://api.github.com/users/saraedum/following{/other_user}","gists_url":"https://api.github.com/users/saraedum/gists{/gist_id}","starred_url":"https://api.github.com/users/saraedum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saraedum/subscriptions","organizations_url":"https://api.github.com/users/saraedum/orgs","repos_url":"https://api.github.com/users/saraedum/repos","events_url":"https://api.github.com/users/saraedum/events{/privacy}","received_events_url":"https://api.github.com/users/saraedum/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/saraedum/mac_lane","description":"Mac Lane Infrastructure for Discrete Valuations in Sage","fork":false,"url":"https://api.github.com/repos/saraedum/mac_lane","forks_url":"https://api.github.com/repos/saraedum/mac_lane/forks","keys_url":"https://api.github.com/repos/saraedum/mac_lane/keys{/key_id}","collaborators_url":"https://api.github.com/repos/saraedum/mac_lane/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/saraedum/mac_lane/teams","hooks_url":"https://api.github.com/repos/saraedum/mac_lane/hooks","issue_events_url":"https://api.github.com/repos/saraedum/mac_lane/issues/events{/number}","events_url":"https://api.github.com/repos/saraedum/mac_lane/events","assignees_url":"https://api.github.com/repos/saraedum/mac_lane/assignees{/user}","branches_url":"https://api.github.com/repos/saraedum/mac_lane/branches{/branch}","tags_url":"https://api.github.com/repos/saraedum/mac_lane/tags","blobs_url":"https://api.github.com/repos/saraedum/mac_lane/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/saraedum/mac_lane/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/saraedum/mac_lane/git/refs{/sha}","trees_url":"https://api.github.com/repos/saraedum/mac_lane/git/trees{/sha}","statuses_url":"https://api.github.com/repos/saraedum/mac_lane/statuses/{sha}","languages_url":"https://api.github.com/repos/saraedum/mac_lane/languages","stargazers_url":"https://api.github.com/repos/saraedum/mac_lane/stargazers","contributors_url":"https://api.github.com/repos/saraedum/mac_lane/contributors","subscribers_url":"https://api.github.com/repos/saraedum/mac_lane/subscribers","subscription_url":"https://api.github.com/repos/saraedum/mac_lane/subscription","commits_url":"https://api.github.com/repos/saraedum/mac_lane/commits{/sha}","git_commits_url":"https://api.github.com/repos/saraedum/mac_lane/git/commits{/sha}","comments_url":"https://api.github.com/repos/saraedum/mac_lane/comments{/number}","issue_comment_url":"https://api.github.com/repos/saraedum/mac_lane/issues/comments{/number}","contents_url":"https://api.github.com/repos/saraedum/mac_lane/contents/{+path}","compare_url":"https://api.github.com/repos/saraedum/mac_lane/compare/{base}...{head}","merges_url":"https://api.github.com/repos/saraedum/mac_lane/merges","archive_url":"https://api.github.com/repos/saraedum/mac_lane/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/saraedum/mac_lane/downloads","issues_url":"https://api.github.com/repos/saraedum/mac_lane/issues{/number}","pulls_url":"https://api.github.com/repos/saraedum/mac_lane/pulls{/number}","milestones_url":"https://api.github.com/repos/saraedum/mac_lane/milestones{/number}","notifications_url":"https://api.github.com/repos/saraedum/mac_lane/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/saraedum/mac_lane/labels{/name}","releases_url":"https://api.github.com/repos/saraedum/mac_lane/releases{/id}","deployments_url":"https://api.github.com/repos/saraedum/mac_lane/deployments","created_at":"2016-11-21T04:29:41Z","updated_at":"2016-11-21T19:39:58Z","pushed_at":"2017-07-22T21:45:45Z","git_url":"git://github.com/saraedum/mac_lane.git","ssh_url":"git@github.com:saraedum/mac_lane.git","clone_url":"https://github.com/saraedum/mac_lane.git","svn_url":"https://github.com/saraedum/mac_lane","homepage":"","size":98484,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":4,"forks":0,"open_issues":4,"watchers":0,"default_branch":"master"}},"base":{"label":"saraedum:develop","ref":"develop","sha":"b63a0d211a58c050a15ec47b1ecda6f877324072","user":{"login":"saraedum","id":373765,"avatar_url":"https://avatars1.githubusercontent.com/u/373765?v=4","gravatar_id":"","url":"https://api.github.com/users/saraedum","html_url":"https://github.com/saraedum","followers_url":"https://api.github.com/users/saraedum/followers","following_url":"https://api.github.com/users/saraedum/following{/other_user}","gists_url":"https://api.github.com/users/saraedum/gists{/gist_id}","starred_url":"https://api.github.com/users/saraedum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saraedum/subscriptions","organizations_url":"https://api.github.com/users/saraedum/orgs","repos_url":"https://api.github.com/users/saraedum/repos","events_url":"https://api.github.com/users/saraedum/events{/privacy}","received_events_url":"https://api.github.com/users/saraedum/received_events","type":"User","site_admin":false},"repo":{"id":74326173,"name":"mac_lane","full_name":"saraedum/mac_lane","owner":{"login":"saraedum","id":373765,"avatar_url":"https://avatars1.githubusercontent.com/u/373765?v=4","gravatar_id":"","url":"https://api.github.com/users/saraedum","html_url":"https://github.com/saraedum","followers_url":"https://api.github.com/users/saraedum/followers","following_url":"https://api.github.com/users/saraedum/following{/other_user}","gists_url":"https://api.github.com/users/saraedum/gists{/gist_id}","starred_url":"https://api.github.com/users/saraedum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saraedum/subscriptions","organizations_url":"https://api.github.com/users/saraedum/orgs","repos_url":"https://api.github.com/users/saraedum/repos","events_url":"https://api.github.com/users/saraedum/events{/privacy}","received_events_url":"https://api.github.com/users/saraedum/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/saraedum/mac_lane","description":"Mac Lane Infrastructure for Discrete Valuations in Sage","fork":false,"url":"https://api.github.com/repos/saraedum/mac_lane","forks_url":"https://api.github.com/repos/saraedum/mac_lane/forks","keys_url":"https://api.github.com/repos/saraedum/mac_lane/keys{/key_id}","collaborators_url":"https://api.github.com/repos/saraedum/mac_lane/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/saraedum/mac_lane/teams","hooks_url":"https://api.github.com/repos/saraedum/mac_lane/hooks","issue_events_url":"https://api.github.com/repos/saraedum/mac_lane/issues/events{/number}","events_url":"https://api.github.com/repos/saraedum/mac_lane/events","assignees_url":"https://api.github.com/repos/saraedum/mac_lane/assignees{/user}","branches_url":"https://api.github.com/repos/saraedum/mac_lane/branches{/branch}","tags_url":"https://api.github.com/repos/saraedum/mac_lane/tags","blobs_url":"https://api.github.com/repos/saraedum/mac_lane/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/saraedum/mac_lane/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/saraedum/mac_lane/git/refs{/sha}","trees_url":"https://api.github.com/repos/saraedum/mac_lane/git/trees{/sha}","statuses_url":"https://api.github.com/repos/saraedum/mac_lane/statuses/{sha}","languages_url":"https://api.github.com/repos/saraedum/mac_lane/languages","stargazers_url":"https://api.github.com/repos/saraedum/mac_lane/stargazers","contributors_url":"https://api.github.com/repos/saraedum/mac_lane/contributors","subscribers_url":"https://api.github.com/repos/saraedum/mac_lane/subscribers","subscription_url":"https://api.github.com/repos/saraedum/mac_lane/subscription","commits_url":"https://api.github.com/repos/saraedum/mac_lane/commits{/sha}","git_commits_url":"https://api.github.com/repos/saraedum/mac_lane/git/commits{/sha}","comments_url":"https://api.github.com/repos/saraedum/mac_lane/comments{/number}","issue_comment_url":"https://api.github.com/repos/saraedum/mac_lane/issues/comments{/number}","contents_url":"https://api.github.com/repos/saraedum/mac_lane/contents/{+path}","compare_url":"https://api.github.com/repos/saraedum/mac_lane/compare/{base}...{head}","merges_url":"https://api.github.com/repos/saraedum/mac_lane/merges","archive_url":"https://api.github.com/repos/saraedum/mac_lane/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/saraedum/mac_lane/downloads","issues_url":"https://api.github.com/repos/saraedum/mac_lane/issues{/number}","pulls_url":"https://api.github.com/repos/saraedum/mac_lane/pulls{/number}","milestones_url":"https://api.github.com/repos/saraedum/mac_lane/milestones{/number}","notifications_url":"https://api.github.com/repos/saraedum/mac_lane/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/saraedum/mac_lane/labels{/name}","releases_url":"https://api.github.com/repos/saraedum/mac_lane/releases{/id}","deployments_url":"https://api.github.com/repos/saraedum/mac_lane/deployments","created_at":"2016-11-21T04:29:41Z","updated_at":"2016-11-21T19:39:58Z","pushed_at":"2017-07-22T21:45:45Z","git_url":"git://github.com/saraedum/mac_lane.git","ssh_url":"git@github.com:saraedum/mac_lane.git","clone_url":"https://github.com/saraedum/mac_lane.git","svn_url":"https://github.com/saraedum/mac_lane","homepage":"","size":98484,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":4,"forks":0,"open_issues":4,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/saraedum/mac_lane/pulls/4"},"html":{"href":"https://github.com/saraedum/mac_lane/pull/4"},"issue":{"href":"https://api.github.com/repos/saraedum/mac_lane/issues/4"},"comments":{"href":"https://api.github.com/repos/saraedum/mac_lane/issues/4/comments"},"review_comments":{"href":"https://api.github.com/repos/saraedum/mac_lane/pulls/4/comments"},"review_comment":{"href":"https://api.github.com/repos/saraedum/mac_lane/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/saraedum/mac_lane/pulls/4/commits"},"statuses":{"href":"https://api.github.com/repos/saraedum/mac_lane/statuses/acfe38f722ed73a9df5debc8ad552dffeb92e479"}}}}
{"actor":{"display_login":"saraedum"}}