Skip to content

Commit 8eacd3e

Browse files
committed
improve fq_default and raise coverage of tests
1 parent 6c93c62 commit 8eacd3e

File tree

3 files changed

+76
-52
lines changed

3 files changed

+76
-52
lines changed

src/flint/test/test_all.py

+54-7
Original file line numberDiff line numberDiff line change
@@ -3671,15 +3671,44 @@ def test_matrices_transpose():
36713671

36723672
def test_fq_default():
36733673
# test fq_default context creation
3674-
# TODO
3674+
3675+
# fq_type parsing
3676+
assert raises(lambda: flint.fq_default_ctx(5, fq_type="A"), ValueError)
3677+
assert raises(lambda: flint.fq_default_ctx(5, fq_type=[]), TypeError)
3678+
assert raises(lambda: flint.fq_default_ctx(5, fq_type=-1), ValueError)
3679+
3680+
# var must be one character
3681+
assert raises(lambda: flint.fq_default_ctx(5, var="XXX"), ValueError)
3682+
3683+
# p must be set if modulus has no characteristic / modulus
3684+
assert raises(lambda: flint.fq_default_ctx(modulus=[0,1,0]), ValueError)
3685+
3686+
# prime must be prime when setting from modulus
3687+
assert raises(lambda: flint.fq_default_ctx(10, modulus=[0,1,0]), ValueError)
3688+
mod_not_prime = flint.fmpz_mod_poly_ctx(10)([1,0,1])
3689+
assert raises(lambda: flint.fq_default_ctx(modulus=mod_not_prime), ValueError)
3690+
mod_not_irr = flint.fmpz_mod_poly_ctx(11)([0,0,1])
3691+
assert raises(lambda: flint.fq_default_ctx(modulus=mod_not_irr), ValueError)
3692+
3693+
# modulus must be able to be cast to fmpz_mod_poly
3694+
assert raises(lambda: flint.fq_default_ctx(11, modulus="AAA"), TypeError)
3695+
3696+
# either p or modulus must be set
3697+
assert raises(lambda: flint.fq_default_ctx(p=None, modulus=None), ValueError)
3698+
3699+
# p must be prime
3700+
assert raises(lambda: flint.fq_default_ctx(10), ValueError)
3701+
3702+
# degree must be positive
3703+
assert raises(lambda: flint.fq_default_ctx(11, -1), ValueError)
36753704

36763705
# GF(5)
3677-
gf_5 = flint.fq_default_ctx(5)
3678-
gf_5_ = flint.fq_default_ctx(5)
3706+
gf_5 = flint.fq_default_ctx(5, fq_type='NMOD')
3707+
gf_5_ = flint.fq_default_ctx(5, fq_type='NMOD')
36793708

36803709
# GF(5^2)
3681-
gf_5_2 = flint.fq_default_ctx(5, 2)
3682-
gf_5_2_ = flint.fq_default_ctx(5, 2)
3710+
gf_5_2 = flint.fq_default_ctx(5, 2, fq_type='FQ_ZECH')
3711+
gf_5_2_ = flint.fq_default_ctx(5, 2, fq_type='FQ_ZECH')
36833712

36843713
# GF((2**127 - 1)^2)
36853714
gf_127 = flint.fq_default_ctx(2**127 - 1, 2)
@@ -3689,6 +3718,8 @@ def test_fq_default():
36893718
assert (gf_5 != gf_5_) is False
36903719
assert (gf_5 == gf_5_2) is False
36913720
assert (gf_5 != gf_5_2) is True
3721+
assert (gf_5 == "a") is False
3722+
assert (gf_5 != "a") is True
36923723

36933724
assert gf_5.prime() == gf_5_2.prime() == 5
36943725
assert gf_5_2.order() == 5*5
@@ -3702,7 +3733,11 @@ def test_fq_default():
37023733
assert str(gf_5) == "Context for fq_default in GF(5)"
37033734
assert str(gf_5_2) == "Context for fq_default in GF(5^2)[z]/(z^2 + 4*z + 2)"
37043735

3736+
assert repr(gf_5) == "fq_default_ctx(5, var='z' type='NMOD')"
3737+
assert repr(gf_5_2) == "fq_default_ctx(5, 2, 'z', x^2 + 4*x + 2, 'FQ_ZECH')"
3738+
37053739
# coercision
3740+
assert gf_5.one() == flint.fq_default(1, gf_5)
37063741
assert gf_5(1) == gf_5.one()
37073742
assert gf_5(flint.fmpz(1)) == gf_5.one()
37083743
assert gf_5(-1) == -gf_5.one()
@@ -3717,7 +3752,10 @@ def test_fq_default():
37173752
R = flint.fmpz_mod_poly_ctx(5)
37183753
assert gf_5.gen() == gf_5(R.gen())
37193754
assert gf_5.gen() == gf_5(flint.nmod_poly([0, 1], 5))
3720-
3755+
assert gf_5(flint.fmpz(2**64)) == gf_5(2**64)
3756+
assert raises(lambda: flint.fq_default(1, "AAA"), TypeError)
3757+
assert raises(lambda: flint.fq_default.__init__(1, "AAA"), TypeError)
3758+
assert raises(lambda: flint.fq_default("AAA", gf_5), TypeError)
37213759

37223760
# testing various equalties between types
37233761

@@ -3809,6 +3847,7 @@ def test_fq_default():
38093847
assert (a / b) / c == a / (b * c)
38103848

38113849
assert a + 0 == 0 + a == a
3850+
assert a - 0 == -(0 - a) == a
38123851
assert a + gf.zero() == a
38133852
assert a * 1 == 1 * a == a
38143853
assert a * gf.one() == a
@@ -3818,13 +3857,21 @@ def test_fq_default():
38183857
assert raises(lambda: a / 0, ZeroDivisionError)
38193858
assert raises(lambda: ~gf.zero(), ZeroDivisionError)
38203859
assert raises(lambda: pow(gf.zero(), -1), ZeroDivisionError)
3860+
assert raises(lambda: pow(gf.zero(), "A"), TypeError)
38213861

38223862
assert 1/a == pow(a, -1) == ~a
38233863
assert gf.one() == pow(a, 0)
38243864
assert gf.zero() == pow(gf.zero(), 2**64)
38253865
assert a == pow(a, 1)
3826-
3866+
assert pow(a, flint.fmpz(2**64)) == pow(a, 2**64)
38273867
assert (a*a).is_square()
3868+
assert (a*a).sqrt() in [a, -a]
3869+
3870+
while True:
3871+
nqr = gf.random_element()
3872+
if not nqr.is_square():
3873+
break
3874+
assert raises(lambda: nqr.sqrt(), ValueError)
38283875

38293876

38303877
def test_fq_default_poly():

src/flint/types/fq_default.pxd

+1-4
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@ cdef class fq_default_ctx:
3434
cdef any_as_fq_default(self, obj)
3535

3636
cdef _set_from_order(self, p, d, var, fq_type=*, check_prime=*)
37-
cdef _set_from_modulus(self, modulus, var, fq_type=*, check_modulus=*)
38-
39-
cdef _c_set_from_order(self, fmpz p, int d, char *var, fq_default_type fq_type=*)
40-
cdef _c_set_from_modulus(self, modulus, char *var, fq_default_type fq_type=*)
37+
cdef _set_from_modulus(self, modulus, var, fq_type=*, check_prime=*, check_modulus=*)
4138

4239
cdef class fq_default(flint_scalar):
4340
cdef fq_default_ctx ctx

src/flint/types/fq_default.pyx

+21-41
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,11 @@ cdef class fq_default_ctx:
7676

7777
return var
7878

79-
def __init__(self, p=None, degree=None, var=None, modulus=None, fq_type=fq_default_type.DEFAULT):
79+
def __init__(self, p=None, degree=None, var=None, modulus=None, fq_type=fq_default_type.DEFAULT,
80+
check_prime=True, check_modulus=True):
8081
# Ensure the var used for the generator of GF(p^d) is a single byte
81-
# TODO: this var is meaningless for GF(p) -- we could handle this somehow?
8282
var = self._parse_input_var(var)
83+
self.var = var
8384

8485
# Ensure the fq_type is an integer between 0, 5 -- we allow users to
8586
# input a string which is converted as an enum
@@ -89,16 +90,17 @@ cdef class fq_default_ctx:
8990
if modulus is not None:
9091
# If the polynomial has no known characteristic, we can try and create one
9192
# using the supplied prime
92-
if not (typecheck(modulus, fmpz_mod_poly) or typecheck(modulus, nmod_poly)):
93+
if not typecheck(modulus, fmpz_mod_poly):
9394
if p is None:
9495
raise ValueError("cannot create from modulus if no characteristic is known")
95-
9696
ring_ctx = fmpz_mod_poly_ctx(p)
97+
if not ring_ctx.is_prime():
98+
raise ValueError("characteristic is not prime")
9799
modulus = ring_ctx.any_as_fmpz_mod_poly(modulus)
98100
if modulus is NotImplemented:
99101
raise TypeError("modulus cannot be cast to fmpz_mod_poly")
100102

101-
self._set_from_modulus(modulus, var, fq_type)
103+
self._set_from_modulus(modulus, var, fq_type, check_prime=check_prime, check_modulus=check_modulus)
102104
return
103105

104106
# If there's no modulus and no prime, we can't continue
@@ -110,23 +112,16 @@ cdef class fq_default_ctx:
110112
degree = 1
111113

112114
# Construct the field from the prime and degree GF(p^d)
113-
self._set_from_order(p, degree, var, fq_type)
115+
self._set_from_order(p, degree, var, fq_type, check_prime=check_prime)
114116

115-
cdef _c_set_from_order(self, fmpz p, int d, char *var,
116-
fq_default_type fq_type=fq_default_type.DEFAULT):
117-
self.var = var
118-
fq_default_ctx_init_type(self.val, p.val, d, self.var, fq_type)
119-
self._initialized = True
120-
121-
cdef _set_from_order(self, p, d, var,
122-
fq_type=fq_default_type.DEFAULT, check_prime=True):
117+
cdef _set_from_order(self, p, d, var, fq_type=fq_default_type.DEFAULT, check_prime=True):
123118
"""
124119
Construct a context for the finite field GF(p^d).
125120
126121
`var` is a name for the ring generator of this field over GF(p).
127122
128123
The optional parameter `type` select the implementation. For more
129-
information about the types available, see :class:`~.fq_default_type`
124+
information about the types available, see :class:`~.fq_default_type`
130125
for possible types.
131126
"""
132127
# c_from_order expects the characteristic to be fmpz type
@@ -141,24 +136,11 @@ cdef class fq_default_ctx:
141136
if d < 1:
142137
raise ValueError(f"the degree must be positive, got {d = }")
143138

144-
# Cython type conversion and context initalisation
145-
self._c_set_from_order(prime, d, var, fq_type)
146-
147-
cdef _c_set_from_modulus(self, modulus, char *var,
148-
fq_default_type fq_type=fq_default_type.DEFAULT):
149-
self.var = var
150-
if typecheck(modulus, fmpz_mod_poly):
151-
fq_default_ctx_init_modulus_type(self.val, (<fmpz_mod_poly>modulus).val,
152-
(<fmpz_mod_poly>modulus).ctx.mod.val, self.var, fq_type)
153-
elif typecheck(modulus, nmod_poly):
154-
fq_default_ctx_init_modulus_nmod_type(self.val, (<nmod_poly>modulus).val,
155-
self.var, fq_type)
156-
else:
157-
raise TypeError(f"modulus must be fmpz_mod_poly or nmod_poly, got {modulus!r}")
139+
fq_default_ctx_init_type(self.val, (<fmpz>prime).val, d, self.var, <fq_default_type>fq_type)
158140
self._initialized = True
159141

160-
cdef _set_from_modulus(self, modulus, var,
161-
fq_type=fq_default_type.DEFAULT, check_modulus=True):
142+
cdef _set_from_modulus(self, modulus, var, fq_type=fq_default_type.DEFAULT,
143+
check_prime=True, check_modulus=True):
162144
"""
163145
Construct a context for a finite field from an irreducible polynomial.
164146
@@ -167,14 +149,18 @@ cdef class fq_default_ctx:
167149
`var` is a name for the ring generator of this field over the prime field.
168150
169151
The optional parameter `type` select the implementation. For more
170-
information about the types available, see :class:`~.fq_default_type`
152+
information about the types available, see :class:`~.fq_default_type`
171153
for possible types.
172154
"""
155+
if check_prime and not (<fmpz_mod_poly>modulus).ctx.is_prime():
156+
raise ValueError("characteristic is not prime")
157+
173158
if check_modulus and not modulus.is_irreducible():
174159
raise ValueError("modulus must be irreducible")
175160

176-
# Cython type conversion and context initalisation
177-
self._c_set_from_modulus(modulus, var, fq_type)
161+
fq_default_ctx_init_modulus_type(self.val, (<fmpz_mod_poly>modulus).val,
162+
(<fmpz_mod_poly>modulus).ctx.mod.val, self.var, <fq_default_type>fq_type)
163+
self._initialized = True
178164

179165
@property
180166
def fq_type(self):
@@ -517,9 +503,6 @@ cdef class fq_default(flint_scalar):
517503
def str(self):
518504
return self.polynomial().str(var=self.ctx.var.decode())
519505

520-
def repr(self):
521-
return f"fq_default({self.to_list(), self.ctx.__repr__()})"
522-
523506
def __hash__(self):
524507
return hash((self.polynomial(), hash(self.ctx)))
525508

@@ -741,11 +724,8 @@ cdef class fq_default(flint_scalar):
741724
fq_default_pow_ui(res.val, res.val, <ulong>e, self.ctx.val)
742725
return res
743726

744-
# Attempt to cast the exponent to an fmpz type then exponentiate
727+
# Cast the exponent to fmpz type
745728
e_fmpz = any_as_fmpz(e)
746-
if e_fmpz is NotImplemented:
747-
raise TypeError(f"exponent {e = } cannot be cast to fmpz")
748-
749729
fq_default_pow(res.val, res.val, (<fmpz>e_fmpz).val, self.ctx.val)
750730

751731
return res

0 commit comments

Comments
 (0)