Skip to content

Commit c89ae73

Browse files
committed
Include composite modulus in poly tests
1 parent 01e6418 commit c89ae73

File tree

2 files changed

+96
-28
lines changed

2 files changed

+96
-28
lines changed

src/flint/test/test_all.py

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,14 +2072,14 @@ def test_fmpz_mod_poly():
20722072
# true div
20732073
assert raises(lambda: f / "AAA", TypeError)
20742074
assert raises(lambda: f / 0, ZeroDivisionError)
2075-
assert raises(lambda: f_cmp / 2, ZeroDivisionError)
2075+
assert raises(lambda: f_cmp / 2, DomainError)
20762076

20772077
assert (f + f) / 2 == f
20782078
assert (f + f) / fmpz(2) == f
20792079
assert (f + f) / F_test(2) == f
20802080

20812081
# floor div
2082-
assert raises(lambda: 1 // f_bad, ZeroDivisionError)
2082+
assert raises(lambda: 1 // f_bad, DomainError)
20832083
assert raises(lambda: f // f_cmp, ValueError)
20842084
assert raises(lambda: f // "AAA", TypeError)
20852085
assert raises(lambda: "AAA" // f, TypeError)
@@ -2115,7 +2115,7 @@ def test_fmpz_mod_poly():
21152115

21162116
# Mod
21172117
assert raises(lambda: f % f_bad, ValueError)
2118-
assert raises(lambda: 123 % f_bad, ValueError)
2118+
assert raises(lambda: 123 % f_bad, DomainError)
21192119
assert raises(lambda: f % "AAA", TypeError)
21202120
assert raises(lambda: tuple() % f, TypeError), f'{"AAA" % f = }'
21212121

@@ -2229,8 +2229,8 @@ def test_fmpz_mod_poly():
22292229
assert raises(lambda: R_test([0,0,1]).complex_roots(), DomainError)
22302230

22312231
# composite moduli not supported
2232-
assert raises(lambda: R_cmp([0,0,1]).factor(), NotImplementedError)
2233-
assert raises(lambda: R_cmp([0,0,1]).factor_squarefree(), NotImplementedError)
2232+
assert raises(lambda: R_cmp([0,0,1]).factor(), DomainError)
2233+
assert raises(lambda: R_cmp([0,0,1]).factor_squarefree(), DomainError)
22342234
assert raises(lambda: R_cmp([0,0,1]).roots(), NotImplementedError)
22352235
assert raises(lambda: R_cmp([0,0,1]).complex_roots(), DomainError)
22362236

@@ -2511,11 +2511,28 @@ def _all_polys():
25112511
(lambda *a: flint.fq_default_poly(*a, flint.fq_default_poly_ctx(11, 5)),
25122512
lambda x: flint.fq_default(x, flint.fq_default_ctx(11, 5)),
25132513
True, flint.fmpz(11)),
2514+
(lambda *a: flint.nmod_poly(*a, 16), lambda x: flint.nmod(x, 16), False, flint.fmpz(16)),
2515+
(lambda *a: flint.fmpz_mod_poly(*a, flint.fmpz_mod_poly_ctx(164)),
2516+
lambda x: flint.fmpz_mod(x, flint.fmpz_mod_ctx(164)),
2517+
False, flint.fmpz(164)),
2518+
(lambda *a: flint.fmpz_mod_poly(*a, flint.fmpz_mod_poly_ctx(2**127)),
2519+
lambda x: flint.fmpz_mod(x, flint.fmpz_mod_ctx(2**127)),
2520+
False, flint.fmpz(2**127)),
2521+
(lambda *a: flint.fmpz_mod_poly(*a, flint.fmpz_mod_poly_ctx(2**255)),
2522+
lambda x: flint.fmpz_mod(x, flint.fmpz_mod_ctx(2**255)),
2523+
False, flint.fmpz(2**255)),
25142524
]
25152525

25162526

25172527
def test_polys():
25182528
for P, S, is_field, characteristic in _all_polys():
2529+
2530+
composite_characteristic = characteristic != 0 and not characteristic.is_prime()
2531+
# nmod_poly crashes for many operations with non-prime modulus
2532+
# https://github.com/flintlib/python-flint/issues/124
2533+
# so we can't even test it...
2534+
nmod_poly_will_crash = type(P(1)) is flint.nmod_poly and composite_characteristic
2535+
25192536
assert P([S(1)]) == P([1]) == P(P([1])) == P(1)
25202537

25212538
assert raises(lambda: P([None]), TypeError)
@@ -2601,7 +2618,7 @@ def setbad(obj, i, val):
26012618
elif type(p) == flint.fmpq_poly:
26022619
assert P(v).repr() == f'fmpq_poly({v!r})'
26032620
elif type(p) == flint.nmod_poly:
2604-
assert P(v).repr() == f'nmod_poly({v!r}, 17)'
2621+
assert P(v).repr() == f'nmod_poly({v!r}, {p.modulus()})'
26052622
elif type(p) == flint.fmpz_mod_poly:
26062623
pass # fmpz_mod_poly does not have .repr() ...
26072624
elif type(p) == flint.fq_default_poly:
@@ -2666,9 +2683,18 @@ def setbad(obj, i, val):
26662683
if is_field:
26672684
assert P([1, 1]) // 2 == P([S(1)/2, S(1)/2])
26682685
assert P([1, 1]) % 2 == P([0])
2669-
else:
2686+
elif characteristic == 0:
26702687
assert P([1, 1]) // 2 == P([0, 0])
26712688
assert P([1, 1]) % 2 == P([1, 1])
2689+
elif nmod_poly_will_crash:
2690+
pass
2691+
else:
2692+
# Z/nZ for n not prime
2693+
if characteristic % 2 == 0:
2694+
assert raises(lambda: P([1, 1]) // 2, DomainError)
2695+
assert raises(lambda: P([1, 1]) % 2, DomainError)
2696+
else:
2697+
1/0
26722698

26732699
assert 1 // P([1, 1]) == P([0])
26742700
assert 1 % P([1, 1]) == P([1])
@@ -2694,14 +2720,22 @@ def setbad(obj, i, val):
26942720
if is_field:
26952721
assert P([2, 2]) / 2 == P([1, 1])
26962722
assert P([1, 2]) / 2 == P([S(1)/2, 1])
2697-
else:
2723+
elif characteristic == 0:
26982724
assert P([2, 2]) / 2 == P([1, 1])
26992725
assert raises(lambda: P([1, 2]) / 2, DomainError)
2726+
elif nmod_poly_will_crash:
2727+
pass
2728+
else:
2729+
# Z/nZ for n not prime
2730+
assert raises(lambda: P([2, 2]) / 2, DomainError)
2731+
assert raises(lambda: P([1, 2]) / 2, DomainError)
2732+
27002733
assert raises(lambda: P([1, 2]) / 0, ZeroDivisionError)
27012734

2702-
assert P([1, 2, 1]) / P([1, 1]) == P([1, 1])
2703-
assert raises(lambda: 1 / P([1, 1]), DomainError)
2704-
assert raises(lambda: P([1, 2, 1]) / P([1, 2]), DomainError)
2735+
if not nmod_poly_will_crash:
2736+
assert P([1, 2, 1]) / P([1, 1]) == P([1, 1])
2737+
assert raises(lambda: 1 / P([1, 1]), DomainError)
2738+
assert raises(lambda: P([1, 2, 1]) / P([1, 2]), DomainError)
27052739

27062740
assert P([1, 1]) ** 0 == P([1])
27072741
assert P([1, 1]) ** 1 == P([1, 1])
@@ -2717,8 +2751,15 @@ def setbad(obj, i, val):
27172751
else:
27182752
assert p * p % mod == pow(p, 2, mod)
27192753

2720-
assert P([1, 2, 1]).gcd(P([1, 1])) == P([1, 1])
2721-
assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError)
2754+
if not composite_characteristic:
2755+
assert P([1, 2, 1]).gcd(P([1, 1])) == P([1, 1])
2756+
assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError)
2757+
elif nmod_poly_will_crash:
2758+
pass
2759+
else:
2760+
# Z/nZ for n not prime
2761+
assert raises(lambda: P([1, 2, 1]).gcd(P([1, 1])), NotImplementedError)
2762+
assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError)
27222763

27232764
if is_field:
27242765
p1 = P([1, 0, 1])
@@ -2727,10 +2768,22 @@ def setbad(obj, i, val):
27272768
assert p1.xgcd(p2) == (g, s, t)
27282769
assert raises(lambda: p1.xgcd(None), TypeError)
27292770

2730-
assert P([1, 2, 1]).factor() == (S(1), [(P([1, 1]), 2)])
2771+
if not composite_characteristic:
2772+
assert P([1, 2, 1]).factor() == (S(1), [(P([1, 1]), 2)])
2773+
elif nmod_poly_will_crash:
2774+
pass
2775+
else:
2776+
assert raises(lambda: P([1, 2, 1]).factor(), DomainError)
27312777

2732-
assert P([1, 2, 1]).sqrt() == P([1, 1])
2733-
assert raises(lambda: P([1, 2, 2]).sqrt(), ValueError), f"{P}, {P([1, 2, 2]).sqrt()}"
2778+
if not composite_characteristic:
2779+
assert P([1, 2, 1]).sqrt() == P([1, 1])
2780+
assert raises(lambda: P([1, 2, 2]).sqrt(), ValueError), f"{P}, {P([1, 2, 2]).sqrt()}"
2781+
elif nmod_poly_will_crash:
2782+
pass
2783+
else:
2784+
# fmpz_mod_poly.sqrt() also crashes here:
2785+
# GR_MUST_SUCCEED failure: src/fmpz_mod_poly/sqrt_series.c
2786+
assert raises(lambda: P([1, 2, 1]).sqrt(), DomainError)
27342787

27352788
if P == flint.fmpq_poly:
27362789
assert raises(lambda: P([1, 2, 1], 3).sqrt(), ValueError)
@@ -2748,6 +2801,7 @@ def setbad(obj, i, val):
27482801
if type(p) == flint.fq_default_poly:
27492802
assert raises(lambda: p.integral(), NotImplementedError)
27502803

2804+
27512805
def _all_mpolys():
27522806
return [
27532807
(flint.fmpz_mpoly, flint.fmpz_mpoly_ctx.get_context, flint.fmpz, False, flint.fmpz(0)),
@@ -3280,7 +3334,15 @@ def factor(p):
32803334
for P, S, [x, y], is_field, characteristic in _all_polys_mpolys():
32813335

32823336
if characteristic != 0 and not characteristic.is_prime():
3283-
assert raises(lambda: x.factor(), DomainError)
3337+
# nmod_poly crashes for many operations with non-prime modulus
3338+
# https://github.com/flintlib/python-flint/issues/124
3339+
# so we can't even test it...
3340+
nmod_poly_will_crash = type(x) is flint.nmod_poly
3341+
3342+
if not nmod_poly_will_crash:
3343+
assert raises(lambda: x.factor(), DomainError)
3344+
3345+
# All tests below would raise
32843346
continue
32853347

32863348
assert factor(0*x) == (S(0), [])

src/flint/types/fmpz_mod_poly.pyx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,8 @@ cdef class fmpz_mod_poly(flint_poly):
439439

440440
if other == 0:
441441
raise ZeroDivisionError(f"Cannot divide by zero")
442-
443-
if not other.is_unit():
444-
raise ZeroDivisionError(f"Cannot divide by {other} modulo {self.ctx.modulus()}")
442+
elif not other.is_unit():
443+
raise DomainError(f"Cannot divide by {other} modulo {self.ctx.modulus()}")
445444

446445
res = self.ctx.new_ctype_poly()
447446
fmpz_mod_poly_scalar_div_fmpz(
@@ -520,8 +519,12 @@ cdef class fmpz_mod_poly(flint_poly):
520519
if left is NotImplemented:
521520
return NotImplemented
522521

523-
if not right.leading_coefficient().is_unit():
524-
raise ZeroDivisionError(f"The leading term of {right} must be a unit modulo N")
522+
lc = right.leading_coefficient()
523+
524+
if lc.is_zero():
525+
raise ZeroDivisionError(f"Cannot divide by zero")
526+
elif not lc.is_unit():
527+
raise DomainError(f"The leading term of {right} must be a unit modulo N")
525528

526529
res = (<fmpz_mod_poly>left).ctx.new_ctype_poly()
527530
fmpz_mod_poly_div(
@@ -648,7 +651,7 @@ cdef class fmpz_mod_poly(flint_poly):
648651
)
649652
if not fmpz_is_one(f):
650653
fmpz_clear(f)
651-
raise ValueError(
654+
raise DomainError(
652655
f"Cannot compute remainder of {left} modulo {right}"
653656
)
654657

@@ -1266,13 +1269,13 @@ cdef class fmpz_mod_poly(flint_poly):
12661269
"""
12671270
cdef fmpz_mod_poly res
12681271

1269-
if not self.ctx.is_prime():
1270-
raise NotImplementedError("gcd algorithm assumes that the modulus is prime")
1271-
12721272
other = self.ctx.any_as_fmpz_mod_poly(other)
12731273
if other is NotImplemented:
12741274
raise TypeError(f"Cannot interpret {other} as a polynomial")
12751275

1276+
if not self.ctx.is_prime():
1277+
raise NotImplementedError("gcd algorithm assumes that the modulus is prime")
1278+
12761279
res = self.ctx.new_ctype_poly()
12771280
fmpz_mod_poly_gcd(
12781281
res.val, self.val, (<fmpz_mod_poly>other).val, self.ctx.mod.val
@@ -1485,6 +1488,9 @@ cdef class fmpz_mod_poly(flint_poly):
14851488
cdef fmpz_mod_poly res
14861489
cdef int check
14871490

1491+
if not self.ctx.is_prime():
1492+
raise DomainError("sqrt algorithm assumes that the modulus is prime")
1493+
14881494
res = self.ctx.new_ctype_poly()
14891495
check = fmpz_mod_poly_sqrt(
14901496
res.val, self.val, res.ctx.mod.val
@@ -1762,7 +1768,7 @@ cdef class fmpz_mod_poly(flint_poly):
17621768
cdef int i
17631769

17641770
if not self.ctx.is_prime():
1765-
raise NotImplementedError("factor_squarefree algorithm assumes that the modulus is prime")
1771+
raise DomainError("factor_squarefree algorithm assumes that the modulus is prime")
17661772

17671773
fmpz_mod_poly_factor_init(fac, self.ctx.mod.val)
17681774
fmpz_mod_poly_factor_squarefree(fac, self.val, self.ctx.mod.val)
@@ -1796,7 +1802,7 @@ cdef class fmpz_mod_poly(flint_poly):
17961802
cdef int i
17971803

17981804
if not self.ctx.is_prime():
1799-
raise NotImplementedError("factor algorithm assumes that the modulus is prime")
1805+
raise DomainError("factor algorithm assumes that the modulus is prime")
18001806

18011807
# XXX: fmpz_mod_poly_factor with modulus 163 crashes on the zero poly:
18021808
#

0 commit comments

Comments
 (0)