Coverage for /usr/lib/python3/dist-packages/sympy/polys/domains/finitefield.py: 50%
70 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""Implementation of :class:`FiniteField` class. """
4from sympy.polys.domains.field import Field
6from sympy.polys.domains.modularinteger import ModularIntegerFactory
7from sympy.polys.domains.simpledomain import SimpleDomain
8from sympy.polys.polyerrors import CoercionFailed
9from sympy.utilities import public
10from sympy.polys.domains.groundtypes import SymPyInteger
12@public
13class FiniteField(Field, SimpleDomain):
14 r"""Finite field of prime order :ref:`GF(p)`
16 A :ref:`GF(p)` domain represents a `finite field`_ `\mathbb{F}_p` of prime
17 order as :py:class:`~.Domain` in the domain system (see
18 :ref:`polys-domainsintro`).
20 A :py:class:`~.Poly` created from an expression with integer
21 coefficients will have the domain :ref:`ZZ`. However, if the ``modulus=p``
22 option is given then the domain will be a finite field instead.
24 >>> from sympy import Poly, Symbol
25 >>> x = Symbol('x')
26 >>> p = Poly(x**2 + 1)
27 >>> p
28 Poly(x**2 + 1, x, domain='ZZ')
29 >>> p.domain
30 ZZ
31 >>> p2 = Poly(x**2 + 1, modulus=2)
32 >>> p2
33 Poly(x**2 + 1, x, modulus=2)
34 >>> p2.domain
35 GF(2)
37 It is possible to factorise a polynomial over :ref:`GF(p)` using the
38 modulus argument to :py:func:`~.factor` or by specifying the domain
39 explicitly. The domain can also be given as a string.
41 >>> from sympy import factor, GF
42 >>> factor(x**2 + 1)
43 x**2 + 1
44 >>> factor(x**2 + 1, modulus=2)
45 (x + 1)**2
46 >>> factor(x**2 + 1, domain=GF(2))
47 (x + 1)**2
48 >>> factor(x**2 + 1, domain='GF(2)')
49 (x + 1)**2
51 It is also possible to use :ref:`GF(p)` with the :py:func:`~.cancel`
52 and :py:func:`~.gcd` functions.
54 >>> from sympy import cancel, gcd
55 >>> cancel((x**2 + 1)/(x + 1))
56 (x**2 + 1)/(x + 1)
57 >>> cancel((x**2 + 1)/(x + 1), domain=GF(2))
58 x + 1
59 >>> gcd(x**2 + 1, x + 1)
60 1
61 >>> gcd(x**2 + 1, x + 1, domain=GF(2))
62 x + 1
64 When using the domain directly :ref:`GF(p)` can be used as a constructor
65 to create instances which then support the operations ``+,-,*,**,/``
67 >>> from sympy import GF
68 >>> K = GF(5)
69 >>> K
70 GF(5)
71 >>> x = K(3)
72 >>> y = K(2)
73 >>> x
74 3 mod 5
75 >>> y
76 2 mod 5
77 >>> x * y
78 1 mod 5
79 >>> x / y
80 4 mod 5
82 Notes
83 =====
85 It is also possible to create a :ref:`GF(p)` domain of **non-prime**
86 order but the resulting ring is **not** a field: it is just the ring of
87 the integers modulo ``n``.
89 >>> K = GF(9)
90 >>> z = K(3)
91 >>> z
92 3 mod 9
93 >>> z**2
94 0 mod 9
96 It would be good to have a proper implementation of prime power fields
97 (``GF(p**n)``) but these are not yet implemented in SymPY.
99 .. _finite field: https://en.wikipedia.org/wiki/Finite_field
100 """
102 rep = 'FF'
103 alias = 'FF'
105 is_FiniteField = is_FF = True
106 is_Numerical = True
108 has_assoc_Ring = False
109 has_assoc_Field = True
111 dom = None
112 mod = None
114 def __init__(self, mod, symmetric=True):
115 from sympy.polys.domains import ZZ
116 dom = ZZ
118 if mod <= 0:
119 raise ValueError('modulus must be a positive integer, got %s' % mod)
121 self.dtype = ModularIntegerFactory(mod, dom, symmetric, self)
122 self.zero = self.dtype(0)
123 self.one = self.dtype(1)
124 self.dom = dom
125 self.mod = mod
127 def __str__(self):
128 return 'GF(%s)' % self.mod
130 def __hash__(self):
131 return hash((self.__class__.__name__, self.dtype, self.mod, self.dom))
133 def __eq__(self, other):
134 """Returns ``True`` if two domains are equivalent. """
135 return isinstance(other, FiniteField) and \
136 self.mod == other.mod and self.dom == other.dom
138 def characteristic(self):
139 """Return the characteristic of this domain. """
140 return self.mod
142 def get_field(self):
143 """Returns a field associated with ``self``. """
144 return self
146 def to_sympy(self, a):
147 """Convert ``a`` to a SymPy object. """
148 return SymPyInteger(int(a))
150 def from_sympy(self, a):
151 """Convert SymPy's Integer to SymPy's ``Integer``. """
152 if a.is_Integer:
153 return self.dtype(self.dom.dtype(int(a)))
154 elif a.is_Float and int(a) == a:
155 return self.dtype(self.dom.dtype(int(a)))
156 else:
157 raise CoercionFailed("expected an integer, got %s" % a)
159 def from_FF(K1, a, K0=None):
160 """Convert ``ModularInteger(int)`` to ``dtype``. """
161 return K1.dtype(K1.dom.from_ZZ(a.val, K0.dom))
163 def from_FF_python(K1, a, K0=None):
164 """Convert ``ModularInteger(int)`` to ``dtype``. """
165 return K1.dtype(K1.dom.from_ZZ_python(a.val, K0.dom))
167 def from_ZZ(K1, a, K0=None):
168 """Convert Python's ``int`` to ``dtype``. """
169 return K1.dtype(K1.dom.from_ZZ_python(a, K0))
171 def from_ZZ_python(K1, a, K0=None):
172 """Convert Python's ``int`` to ``dtype``. """
173 return K1.dtype(K1.dom.from_ZZ_python(a, K0))
175 def from_QQ(K1, a, K0=None):
176 """Convert Python's ``Fraction`` to ``dtype``. """
177 if a.denominator == 1:
178 return K1.from_ZZ_python(a.numerator)
180 def from_QQ_python(K1, a, K0=None):
181 """Convert Python's ``Fraction`` to ``dtype``. """
182 if a.denominator == 1:
183 return K1.from_ZZ_python(a.numerator)
185 def from_FF_gmpy(K1, a, K0=None):
186 """Convert ``ModularInteger(mpz)`` to ``dtype``. """
187 return K1.dtype(K1.dom.from_ZZ_gmpy(a.val, K0.dom))
189 def from_ZZ_gmpy(K1, a, K0=None):
190 """Convert GMPY's ``mpz`` to ``dtype``. """
191 return K1.dtype(K1.dom.from_ZZ_gmpy(a, K0))
193 def from_QQ_gmpy(K1, a, K0=None):
194 """Convert GMPY's ``mpq`` to ``dtype``. """
195 if a.denominator == 1:
196 return K1.from_ZZ_gmpy(a.numerator)
198 def from_RealField(K1, a, K0):
199 """Convert mpmath's ``mpf`` to ``dtype``. """
200 p, q = K0.to_rational(a)
202 if q == 1:
203 return K1.dtype(K1.dom.dtype(p))
206FF = GF = FiniteField