From ad8fa4df9d48c328c64f4e562e64f96fe8e040c8 Mon Sep 17 00:00:00 2001 From: Kalevi Suominen Date: Sun, 7 Jan 2018 23:08:01 +0200 Subject: [PATCH 1/5] Division in a finite extension --- sympy/polys/agca/extensions.py | 50 ++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/sympy/polys/agca/extensions.py b/sympy/polys/agca/extensions.py index 7755906d1578..8b5584aeb560 100644 --- a/sympy/polys/agca/extensions.py +++ b/sympy/polys/agca/extensions.py @@ -2,7 +2,7 @@ from __future__ import print_function, division -from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.polyerrors import CoercionFailed, NotInvertible from sympy.polys.polytools import Poly class ExtensionElement(object): @@ -70,11 +70,57 @@ def __mul__(f, g): __rmul__ = __mul__ + def inverse(f): + """Multiplicative inverse. + + Raises + ====== + NotInvertible + If the element is a zero divisor. + + """ + if not f.ext.domain.is_Field: + raise NotImplementedError("base field expected") + return ExtElem(f.rep.invert(f.ext.mod), f.ext) + + def _invrep(f, g): + rep = f._get_rep(g) + if rep is not None: + return rep.invert(f.ext.mod) + else: + return None + + def __truediv__(f, g): + if not f.ext.domain.is_Field: + return NotImplemented + try: + rep = f._invrep(g) + except NotInvertible: + raise ZeroDivisionError + + if rep is not None: + return f*ExtElem(rep, f.ext) + else: + return NotImplemented + + __div__ = __truediv__ + + def __rtruediv__(f, g): + try: + return f.ext.convert(g)/f + except CoercionFailed: + return NotImplemented + + __rdiv__ = __rtruediv__ + def __pow__(f, n): if not isinstance(n, int): raise TypeError("exponent of type 'int' expected") if n < 0: - raise ValueError("negative powers are not defined") + try: + f, n = f.inverse(), -n + except NotImplementedError: + raise ValueError("negative powers are not defined") b = f.rep m = f.ext.mod From 8df77d147c173dd3545b754e66fe0de4533d22e6 Mon Sep 17 00:00:00 2001 From: Gilles Schintgen Date: Sat, 20 Jun 2020 12:27:15 +0000 Subject: [PATCH 2/5] agca-extensions: convert to python3 --- sympy/polys/agca/extensions.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sympy/polys/agca/extensions.py b/sympy/polys/agca/extensions.py index e32e7e331381..38ccf8b9c5d9 100644 --- a/sympy/polys/agca/extensions.py +++ b/sympy/polys/agca/extensions.py @@ -1,7 +1,5 @@ """Finite extensions of ring domains.""" -from __future__ import print_function, division - from sympy.polys.polyerrors import CoercionFailed, NotInvertible from sympy.polys.polytools import Poly @@ -103,7 +101,7 @@ def __truediv__(f, g): else: return NotImplemented - __div__ = __truediv__ + __floordiv__ = __truediv__ def __rtruediv__(f, g): try: @@ -111,7 +109,7 @@ def __rtruediv__(f, g): except CoercionFailed: return NotImplemented - __rdiv__ = __rtruediv__ + __rfloordiv__ = __rtruediv__ def __pow__(f, n): if not isinstance(n, int): From 69f0b5aae7fe541396c583bdda580b12c126390c Mon Sep 17 00:00:00 2001 From: Gilles Schintgen Date: Sat, 20 Jun 2020 12:29:45 +0000 Subject: [PATCH 3/5] agca-extensions: add tests for inverse/division --- sympy/polys/agca/tests/test_extensions.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sympy/polys/agca/tests/test_extensions.py b/sympy/polys/agca/tests/test_extensions.py index a995f701ca4a..432687e2cf20 100644 --- a/sympy/polys/agca/tests/test_extensions.py +++ b/sympy/polys/agca/tests/test_extensions.py @@ -1,5 +1,7 @@ from sympy.polys.polytools import Poly +from sympy.polys.polyerrors import NotInvertible from sympy.polys.agca.extensions import FiniteExtension +from sympy.testing.pytest import raises from sympy.abc import x, t def test_FiniteExtension(): @@ -14,6 +16,7 @@ def test_FiniteExtension(): assert i**2 != -1 # no coercion assert (2 + i)*(1 - i) == 3 - i assert (1 + i)**8 == A(16) + raises(NotImplementedError, lambda: A(1).inverse()) # Finite field of order 27 F = FiniteExtension(Poly(x**3 - x + 1, x, modulus=3)) @@ -26,6 +29,14 @@ def test_FiniteExtension(): assert a**9 == a + 1 assert a**3 == a - 1 assert a**6 == a**2 + a + 1 + assert F(x**2 + x).inverse() == 1 - a + assert F(x + 2)**(-1) == F(x + 2).inverse() + assert a**19 * a**(-19) == F(1) + assert (a - 1) / (2*a**2 - 1) == a**2 + 1 + assert (a - 1) // (2*a**2 - 1) == a**2 + 1 + assert 2/(a**2 + 1) == a**2 - a + 1 + assert (a**2 + 1)/2 == -a**2 - 1 + raises(NotInvertible, lambda: F(0).inverse()) # Function field of an elliptic curve K = FiniteExtension(Poly(t**2 - x**3 - x + 1, t, field=True)) @@ -33,4 +44,5 @@ def test_FiniteExtension(): assert str(K) == 'ZZ(x)[t]/(t**2 - x**3 - x + 1)' y = K.generator c = 1/(x**3 - x**2 + x - 1) + assert ((y + x)*(y - x)).inverse() == K(c) assert (y + x)*(y - x)*c == K(1) # explicit inverse of y + x From 28d484fbf7d932d602a74bb329b416e599e605a7 Mon Sep 17 00:00:00 2001 From: Gilles Schintgen Date: Sun, 21 Jun 2020 11:57:13 +0000 Subject: [PATCH 4/5] agca-extensions: add public documentation The main exposition in agca.rst is the commit message of 077a9daca657b5c65b138ebe1716de8d3c6cb6f9 (by @jksuom). --- doc/src/modules/polys/agca.rst | 25 +++++++++++++++++++++ sympy/polys/agca/extensions.py | 41 +++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/doc/src/modules/polys/agca.rst b/doc/src/modules/polys/agca.rst index 9800fa0e0fa1..032416d26405 100644 --- a/doc/src/modules/polys/agca.rst +++ b/doc/src/modules/polys/agca.rst @@ -309,3 +309,28 @@ Finally, here is the detailed reference of the actual homomorphism class: .. autoclass:: ModuleHomomorphism :members: + +Finite Extensions +----------------- + +Let $A$ be a (commutative) ring and $B$ an extension ring of $A$. +An element $t$ of $B$ is a generator of $B$ (over $A$) if all elements +of $B$ can be represented as polynomials in $t$ with coefficients +in $A$. The representation is unique if and only if $t$ satisfies no +non-trivial polynomial relation, in which case $B$ can be identified +with a (univariate) polynomial ring over $A$. + +The polynomials having $t$ as a root form a non-zero ideal in general. +The most important case in practice is that of an ideal generated by +a single monic polynomial. If $t$ satisfies such a polynomial relation, +then its highest power $t^n$ can be written as linear combination of +lower powers. It follows, inductively, that all higher powers of $t$ +also have such a representation. Hence the lower powers $t^i$ +($i = 0, \dots, n-1$) form a basis of $B$, which is then called a finite +extension of $A$, or, more precisely, a monogenic finite extension +as it is generated by a single element $t$. + +.. currentmodule:: sympy.polys.agca.extensions + +.. autoclass:: MonogenicFiniteExtension + :members: diff --git a/sympy/polys/agca/extensions.py b/sympy/polys/agca/extensions.py index 38ccf8b9c5d9..e0f6e41b2f24 100644 --- a/sympy/polys/agca/extensions.py +++ b/sympy/polys/agca/extensions.py @@ -153,12 +153,51 @@ def __str__(f): class MonogenicFiniteExtension(object): - """ + r""" Finite extension generated by an integral element. The generator is defined by a monic univariate polynomial derived from the argument ``mod``. + A shorter alias is ``FiniteExtension``. + + Examples + ======== + + Quadratic integer ring $\mathbb{Z}[\sqrt2]$: + + >>> from sympy import Symbol, Poly + >>> from sympy.polys.agca.extensions import FiniteExtension + >>> x = Symbol('x') + >>> R = FiniteExtension(Poly(x**2 - 2)); R + ZZ[x]/(x**2 - 2) + >>> R.rank + 2 + >>> R(1 + x)*(3 - 2*x) + x - 1 + + Finite field $GF(5^3)$ defined by the primitive + polynomial $x^3 + x^2 + 2$ (over $\mathbb{Z}_5$). + + >>> F = FiniteExtension(Poly(x**3 + x**2 + 2, modulus=5)); F + GF(5)[x]/(x**3 + x**2 + 2) + >>> F.basis + (1, x, x**2) + >>> F(x + 3)/(x**2 + 2) + -2*x**2 + x + 2 + + Function field of an elliptic curve: + + >>> t = Symbol('t') + >>> FiniteExtension(Poly(t**2 - x**3 - x + 1, t, field=True)) + ZZ(x)[t]/(t**2 - x**3 - x + 1) + + Notes + ===== + + It's not possible to use a ``FiniteExtension`` as ``domain`` for the + :class:`~.Poly` class. + """ def __init__(self, mod): if not (isinstance(mod, Poly) and mod.is_univariate): From 775921b7f31b2959c7bbcdfbf6baa4c9cd9546c8 Mon Sep 17 00:00:00 2001 From: Gilles Schintgen Date: Mon, 22 Jun 2020 13:34:39 +0000 Subject: [PATCH 5/5] agca.extensions: reword note concerning Domain --- sympy/polys/agca/extensions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sympy/polys/agca/extensions.py b/sympy/polys/agca/extensions.py index e0f6e41b2f24..28d95f39b73f 100644 --- a/sympy/polys/agca/extensions.py +++ b/sympy/polys/agca/extensions.py @@ -195,7 +195,8 @@ class MonogenicFiniteExtension(object): Notes ===== - It's not possible to use a ``FiniteExtension`` as ``domain`` for the + ``FiniteExtension`` is not a subclass of :class:`~.Domain`. Consequently, + a ``FiniteExtension`` can't currently be used as ``domain`` for the :class:`~.Poly` class. """