197 lines
6.3 KiB
Python
197 lines
6.3 KiB
Python
|
from sympy.core.symbol import symbols
|
||
|
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||
|
from sympy.polys import QQ, ZZ
|
||
|
from sympy.polys.polytools import Poly
|
||
|
from sympy.polys.polyerrors import NotInvertible
|
||
|
from sympy.polys.agca.extensions import FiniteExtension
|
||
|
from sympy.polys.domainmatrix import DomainMatrix
|
||
|
|
||
|
from sympy.testing.pytest import raises
|
||
|
|
||
|
from sympy.abc import x, y, t
|
||
|
|
||
|
|
||
|
def test_FiniteExtension():
|
||
|
# Gaussian integers
|
||
|
A = FiniteExtension(Poly(x**2 + 1, x))
|
||
|
assert A.rank == 2
|
||
|
assert str(A) == 'ZZ[x]/(x**2 + 1)'
|
||
|
i = A.generator
|
||
|
assert i.parent() is A
|
||
|
|
||
|
assert i*i == A(-1)
|
||
|
raises(TypeError, lambda: i*())
|
||
|
|
||
|
assert A.basis == (A.one, i)
|
||
|
assert A(1) == A.one
|
||
|
assert i**2 == A(-1)
|
||
|
assert i**2 != -1 # no coercion
|
||
|
assert (2 + i)*(1 - i) == 3 - i
|
||
|
assert (1 + i)**8 == A(16)
|
||
|
assert A(1).inverse() == A(1)
|
||
|
raises(NotImplementedError, lambda: A(2).inverse())
|
||
|
|
||
|
# Finite field of order 27
|
||
|
F = FiniteExtension(Poly(x**3 - x + 1, x, modulus=3))
|
||
|
assert F.rank == 3
|
||
|
a = F.generator # also generates the cyclic group F - {0}
|
||
|
assert F.basis == (F(1), a, a**2)
|
||
|
assert a**27 == a
|
||
|
assert a**26 == F(1)
|
||
|
assert a**13 == F(-1)
|
||
|
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))
|
||
|
assert K.rank == 2
|
||
|
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
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_eq_hash():
|
||
|
# Test eq and hash
|
||
|
p1 = Poly(x**2 - 2, x, domain=ZZ)
|
||
|
p2 = Poly(x**2 - 2, x, domain=QQ)
|
||
|
K1 = FiniteExtension(p1)
|
||
|
K2 = FiniteExtension(p2)
|
||
|
assert K1 == FiniteExtension(Poly(x**2 - 2))
|
||
|
assert K2 != FiniteExtension(Poly(x**2 - 2))
|
||
|
assert len({K1, K2, FiniteExtension(p1)}) == 2
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_mod():
|
||
|
# Test mod
|
||
|
K = FiniteExtension(Poly(x**3 + 1, x, domain=QQ))
|
||
|
xf = K(x)
|
||
|
assert (xf**2 - 1) % 1 == K.zero
|
||
|
assert 1 % (xf**2 - 1) == K.zero
|
||
|
assert (xf**2 - 1) / (xf - 1) == xf + 1
|
||
|
assert (xf**2 - 1) // (xf - 1) == xf + 1
|
||
|
assert (xf**2 - 1) % (xf - 1) == K.zero
|
||
|
raises(ZeroDivisionError, lambda: (xf**2 - 1) % 0)
|
||
|
raises(TypeError, lambda: xf % [])
|
||
|
raises(TypeError, lambda: [] % xf)
|
||
|
|
||
|
# Test mod over ring
|
||
|
K = FiniteExtension(Poly(x**3 + 1, x, domain=ZZ))
|
||
|
xf = K(x)
|
||
|
assert (xf**2 - 1) % 1 == K.zero
|
||
|
raises(NotImplementedError, lambda: (xf**2 - 1) % (xf - 1))
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_from_sympy():
|
||
|
# Test to_sympy/from_sympy
|
||
|
K = FiniteExtension(Poly(x**3 + 1, x, domain=ZZ))
|
||
|
xf = K(x)
|
||
|
assert K.from_sympy(x) == xf
|
||
|
assert K.to_sympy(xf) == x
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_set_domain():
|
||
|
KZ = FiniteExtension(Poly(x**2 + 1, x, domain='ZZ'))
|
||
|
KQ = FiniteExtension(Poly(x**2 + 1, x, domain='QQ'))
|
||
|
assert KZ.set_domain(QQ) == KQ
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_exquo():
|
||
|
# Test exquo
|
||
|
K = FiniteExtension(Poly(x**4 + 1))
|
||
|
xf = K(x)
|
||
|
assert K.exquo(xf**2 - 1, xf - 1) == xf + 1
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_convert():
|
||
|
# Test from_MonogenicFiniteExtension
|
||
|
K1 = FiniteExtension(Poly(x**2 + 1))
|
||
|
K2 = QQ[x]
|
||
|
x1, x2 = K1(x), K2(x)
|
||
|
assert K1.convert(x2) == x1
|
||
|
assert K2.convert(x1) == x2
|
||
|
|
||
|
K = FiniteExtension(Poly(x**2 - 1, domain=QQ))
|
||
|
assert K.convert_from(QQ(1, 2), QQ) == K.one/2
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_division_ring():
|
||
|
# Test division in FiniteExtension over a ring
|
||
|
KQ = FiniteExtension(Poly(x**2 - 1, x, domain=QQ))
|
||
|
KZ = FiniteExtension(Poly(x**2 - 1, x, domain=ZZ))
|
||
|
KQt = FiniteExtension(Poly(x**2 - 1, x, domain=QQ[t]))
|
||
|
KQtf = FiniteExtension(Poly(x**2 - 1, x, domain=QQ.frac_field(t)))
|
||
|
assert KQ.is_Field is True
|
||
|
assert KZ.is_Field is False
|
||
|
assert KQt.is_Field is False
|
||
|
assert KQtf.is_Field is True
|
||
|
for K in KQ, KZ, KQt, KQtf:
|
||
|
xK = K.convert(x)
|
||
|
assert xK / K.one == xK
|
||
|
assert xK // K.one == xK
|
||
|
assert xK % K.one == K.zero
|
||
|
raises(ZeroDivisionError, lambda: xK / K.zero)
|
||
|
raises(ZeroDivisionError, lambda: xK // K.zero)
|
||
|
raises(ZeroDivisionError, lambda: xK % K.zero)
|
||
|
if K.is_Field:
|
||
|
assert xK / xK == K.one
|
||
|
assert xK // xK == K.one
|
||
|
assert xK % xK == K.zero
|
||
|
else:
|
||
|
raises(NotImplementedError, lambda: xK / xK)
|
||
|
raises(NotImplementedError, lambda: xK // xK)
|
||
|
raises(NotImplementedError, lambda: xK % xK)
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_Poly():
|
||
|
K = FiniteExtension(Poly(x**2 - 2))
|
||
|
p = Poly(x, y, domain=K)
|
||
|
assert p.domain == K
|
||
|
assert p.as_expr() == x
|
||
|
assert (p**2).as_expr() == 2
|
||
|
|
||
|
K = FiniteExtension(Poly(x**2 - 2, x, domain=QQ))
|
||
|
K2 = FiniteExtension(Poly(t**2 - 2, t, domain=K))
|
||
|
assert str(K2) == 'QQ[x]/(x**2 - 2)[t]/(t**2 - 2)'
|
||
|
|
||
|
eK = K2.convert(x + t)
|
||
|
assert K2.to_sympy(eK) == x + t
|
||
|
assert K2.to_sympy(eK ** 2) == 4 + 2*x*t
|
||
|
p = Poly(x + t, y, domain=K2)
|
||
|
assert p**2 == Poly(4 + 2*x*t, y, domain=K2)
|
||
|
|
||
|
|
||
|
def test_FiniteExtension_sincos_jacobian():
|
||
|
# Use FiniteExtensino to compute the Jacobian of a matrix involving sin
|
||
|
# and cos of different symbols.
|
||
|
r, p, t = symbols('rho, phi, theta')
|
||
|
elements = [
|
||
|
[sin(p)*cos(t), r*cos(p)*cos(t), -r*sin(p)*sin(t)],
|
||
|
[sin(p)*sin(t), r*cos(p)*sin(t), r*sin(p)*cos(t)],
|
||
|
[ cos(p), -r*sin(p), 0],
|
||
|
]
|
||
|
|
||
|
def make_extension(K):
|
||
|
K = FiniteExtension(Poly(sin(p)**2+cos(p)**2-1, sin(p), domain=K[cos(p)]))
|
||
|
K = FiniteExtension(Poly(sin(t)**2+cos(t)**2-1, sin(t), domain=K[cos(t)]))
|
||
|
return K
|
||
|
|
||
|
Ksc1 = make_extension(ZZ[r])
|
||
|
Ksc2 = make_extension(ZZ)[r]
|
||
|
|
||
|
for K in [Ksc1, Ksc2]:
|
||
|
elements_K = [[K.convert(e) for e in row] for row in elements]
|
||
|
J = DomainMatrix(elements_K, (3, 3), K)
|
||
|
det = J.charpoly()[-1] * (-K.one)**3
|
||
|
assert det == K.convert(r**2*sin(p))
|