Skip to content

Commit 7a921c8

Browse files
Release Managervbraun
Release Manager
authored andcommitted
Trac #18461: Implement Field._gcd_univariate_polynomial()
The goal of this ticket is to implement a Cython method `Field._gcd_univariate_polynomial()` using the standard Euclidean algorithm. This is much faster than `Fields.ParentMethods._gcd_univariate_polynomial()`, which calls `EuclideanDomains.ElementMethods.gcd()`, since both are Python methods. (The `_gcd_univariate_polynomial` mechanism was introduced in #13442.) The following bug can then be fixed by just removing `PolynomialRealDense.gcd()`, which does not take into account the case where one of the arguments of `gcd` is zero: {{{ sage: R.<x> = RR[] sage: x.gcd(R.zero()) Traceback (most recent call last): ... TypeError: 'MinusInfinity' object cannot be interpreted as an index }}} Removing this method ''without'' implementing `Field._gcd_univariate_polynomial()` (falling back on Python code) is about twice as slow; with this ticket there is no slowdown. Similarly, to make `CC` and `QQbar` use the new method instead of Python code, we also remove the now obsolete `Polynomial_generic_field.gcd()`. URL: http://trac.sagemath.org/18461 Reported by: pbruin Ticket author(s): Peter Bruin Reviewer(s): Bruno Grenet
2 parents ebd5f4f + 908ace7 commit 7a921c8

File tree

4 files changed

+48
-74
lines changed

4 files changed

+48
-74
lines changed

src/doc/en/thematic_tutorials/coercion_and_categories.rst

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ This base class provides a lot more methods than a general parent::
122122
'_coerce_self',
123123
'_coerce_try',
124124
'_default_category',
125+
'_gcd_univariate_polynomial',
125126
'_gens',
126127
'_has_coerce_map_from',
127128
'_ideal_class_',

src/sage/rings/polynomial/polynomial_element_generic.py

-31
Original file line numberDiff line numberDiff line change
@@ -726,37 +726,6 @@ def quo_rem(self, other):
726726
R = R[:R.degree()] - (aaa*B[:B.degree()]).shift(diff_deg)
727727
return (Q, R)
728728

729-
@coerce_binop
730-
def gcd(self, other):
731-
"""
732-
Return the greatest common divisor of this polynomial and ``other``, as
733-
a monic polynomial.
734-
735-
INPUT:
736-
737-
- ``other`` -- a polynomial defined over the same ring as ``self``
738-
739-
EXAMPLES::
740-
741-
sage: R.<x> = QQbar[]
742-
sage: (2*x).gcd(2*x^2)
743-
x
744-
745-
sage: zero = R.zero()
746-
sage: zero.gcd(2*x)
747-
x
748-
sage: (2*x).gcd(zero)
749-
x
750-
sage: zero.gcd(zero)
751-
0
752-
"""
753-
from sage.categories.euclidean_domains import EuclideanDomains
754-
g = EuclideanDomains().ElementMethods().gcd(self, other)
755-
c = g.leading_coefficient()
756-
if c.is_unit():
757-
return (1/c)*g
758-
return g
759-
760729
@coerce_binop
761730
def xgcd(self, other):
762731
r"""

src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx

-43
Original file line numberDiff line numberDiff line change
@@ -612,49 +612,6 @@ cdef class PolynomialRealDense(Polynomial):
612612
r._normalize()
613613
return q, r * leading
614614

615-
@coerce_binop
616-
def gcd(self, other):
617-
"""
618-
Returns the gcd of self and other as a monic polynomial. Due to the
619-
inherit instability of division in this inexact ring, the results may
620-
not be entirely stable.
621-
622-
EXAMPLES::
623-
624-
sage: R.<x> = RR[]
625-
sage: (x^3).gcd(x^5+1)
626-
1.00000000000000
627-
sage: (x^3).gcd(x^5+x^2)
628-
x^2
629-
sage: f = (x+3)^2 * (x-1)
630-
sage: g = (x+3)^5
631-
sage: f.gcd(g)
632-
x^2 + 6.00000000000000*x + 9.00000000000000
633-
634-
Unless the division is exact (i.e. no rounding occurs) the returned gcd is
635-
almost certain to be 1. ::
636-
637-
sage: f = (x+RR.pi())^2 * (x-1)
638-
sage: g = (x+RR.pi())^5
639-
sage: f.gcd(g)
640-
1.00000000000000
641-
642-
"""
643-
aval = self.valuation()
644-
a = self >> aval
645-
bval = other.valuation()
646-
b = other >> bval
647-
if b.degree() > a.degree():
648-
a, b = b, a
649-
while b: # this will be exactly zero when the previous b is degree 0
650-
q, r = a.quo_rem(b)
651-
a, b = b, r
652-
if a.degree() == 0:
653-
# make sure gcd of "relatively prime" things is exactly 1
654-
return self._parent(1) << min(aval, bval)
655-
else:
656-
return a * ~a[a.degree()] << min(aval, bval)
657-
658615
def __call__(self, *args, **kwds):
659616
"""
660617
EXAMPLES::

src/sage/rings/ring.pyx

+47
Original file line numberDiff line numberDiff line change
@@ -2182,6 +2182,53 @@ cdef class Field(PrincipalIdealDomain):
21822182
"""
21832183
raise NotImplementedError, "Algebraic closures of general fields not implemented."
21842184

2185+
def _gcd_univariate_polynomial(self, a, b):
2186+
"""
2187+
Return the gcd of ``a`` and ``b`` as a monic polynomial.
2188+
2189+
.. WARNING:
2190+
2191+
If the base ring is inexact, the results may not be
2192+
entirely stable.
2193+
2194+
TESTS::
2195+
2196+
sage: for A in (RR, CC, QQbar):
2197+
....: g = A._gcd_univariate_polynomial
2198+
....: R.<x> = A[]
2199+
....: z = R.zero()
2200+
....: assert(g(2*x, 2*x^2) == x and
2201+
....: g(z, 2*x) == x and
2202+
....: g(2*x, z) == x and
2203+
....: g(z, z) == z)
2204+
2205+
sage: R.<x> = RR[]
2206+
sage: (x^3).gcd(x^5+1)
2207+
1.00000000000000
2208+
sage: (x^3).gcd(x^5+x^2)
2209+
x^2
2210+
sage: f = (x+3)^2 * (x-1)
2211+
sage: g = (x+3)^5
2212+
sage: f.gcd(g)
2213+
x^2 + 6.00000000000000*x + 9.00000000000000
2214+
2215+
The following example illustrates the fact that for inexact
2216+
base rings, the returned gcd is often 1 due to rounding::
2217+
2218+
sage: f = (x+RR.pi())^2 * (x-1)
2219+
sage: g = (x+RR.pi())^5
2220+
sage: f.gcd(g)
2221+
1.00000000000000
2222+
2223+
"""
2224+
while b:
2225+
q, r = a.quo_rem(b)
2226+
a, b = b, r
2227+
if a:
2228+
a = a.monic()
2229+
return a
2230+
2231+
21852232
cdef class Algebra(Ring):
21862233
"""
21872234
Generic algebra

0 commit comments

Comments
 (0)