diff --git a/src/flint/flint_base/flint_base.pyi b/src/flint/flint_base/flint_base.pyi index 784cddba..f1c27b06 100644 --- a/src/flint/flint_base/flint_base.pyi +++ b/src/flint/flint_base/flint_base.pyi @@ -1,84 +1,142 @@ # # # -from typing import Generic, TypeVar, Iterator, Iterable, Any, Final, Self, Mapping, Sequence +from typing import ( + Generic, + TypeVar, + Iterator, + Iterable, + Any, + Final, + Self, + Mapping, + Sequence, + overload, +) from abc import abstractmethod import enum - FLINT_VERSION: Final[str] FLINT_RELEASE: Final[int] +Telem = TypeVar("Telem", bound=flint_scalar) +Telem_coerce = TypeVar("Telem_coerce", contravariant=True) +Tmpoly = TypeVar("Tmpoly", bound=flint_mpoly) +Tctx = TypeVar("Tctx", bound=flint_mpoly_context) -Telem = TypeVar('Telem', bound=flint_scalar) -Telem_coerce = TypeVar('Telem_coerce', contravariant=True) -Tmpoly = TypeVar('Tmpoly', bound=flint_mpoly) -Tctx = TypeVar('Tctx', bound=flint_mpoly_context) - -Sctx = TypeVar('Sctx', bound=flint_mpoly_context) +Sctx = TypeVar("Sctx", bound=flint_mpoly_context) _str = str - class flint_elem: - pass - + def str(self) -> _str: ... + def repr(self) -> _str: ... class flint_scalar(flint_elem): def is_zero(self) -> bool: ... - + def __pos__(self) -> Self: ... + def __neg__(self) -> Self: ... + def __add__(self, other: Self | int, /) -> Self: ... + def __radd__(self, other: int, /) -> Self: ... + def __sub__(self, other: Self | int, /) -> Self: ... + def __rsub__(self, other: int, /) -> Self: ... + def __mul__(self, other: Self | int, /) -> Self: ... + def __rmul__(self, other: int, /) -> Self: ... + def __truediv__(self, other: Self | int, /) -> Self: ... + def __rtruediv__(self, other: int, /) -> Self: ... + def __pow__(self, other: int, /) -> Self: ... + def __rpow__(self, other: int, /) -> Self: ... class flint_poly(flint_elem, Generic[Telem]): + def str( + self, ascending: bool = False, var: str = "x", *args: Any, **kwargs: Any + ) -> str: ... def __iter__(self) -> Iterator[Telem]: ... def __getitem__(self, index: int, /) -> Telem: ... + def __setitem__(self, index: int, value: Telem | int, /) -> None: ... + def __len__(self) -> int: ... + def length(self) -> int: ... + def degree(self) -> int: ... def coeffs(self) -> list[Telem]: ... - def str(self, ascending: bool = False, var: str = "x", *args: Any, **kwargs: Any): ... + @overload + def __call__(self, other: Telem | int, /) -> Telem: ... + @overload + def __call__(self, other: Self, /) -> Self: ... + def __pos__(self) -> Self: ... + def __neg__(self) -> Self: ... + def __add__(self, other: Telem | int | Self, /) -> Self: ... + def __radd__(self, other: Telem | int, /) -> Self: ... + def __sub__(self, other: Telem | int | Self, /) -> Self: ... + def __rsub__(self, other: Telem | int, /) -> Self: ... + def __mul__(self, other: Telem | int | Self, /) -> Self: ... + def __rmul__(self, other: Telem | int, /) -> Self: ... + def __truediv__(self, other: Telem | int | Self, /) -> Self: ... + def __rtruediv__(self, other: Telem | int, /) -> Self: ... + def __floordiv__(self, other: Telem | int | Self, /) -> Self: ... + def __rfloordiv__(self, other: Telem | int, /) -> Self: ... + def __mod__(self, other: Telem | int | Self, /) -> Self: ... + def __rmod__(self, other: Telem | int, /) -> Self: ... + def __divmod__(self, other: Telem | int | Self, /) -> tuple[Self, Self]: ... + def __rdivmod__(self, other: Telem | int, /) -> tuple[Self, Self]: ... + def __pow__(self, other: int, /) -> Self: ... + def is_zero(self) -> bool: ... + def is_one(self) -> bool: ... + def is_constant(self) -> bool: ... + def is_gen(self) -> bool: ... def roots(self) -> list[tuple[Telem, int]]: ... # Should be list[arb]: def real_roots(self) -> list[Any]: ... # Should be list[acb]: def complex_roots(self) -> list[Any]: ... + def derivative(self) -> Self: ... +class _flint_poly_exact(flint_poly[Telem]): + def sqrt(self) -> Self: ... + def gcd(self, other: Self | Telem, /) -> Self: ... + def xgcd(self, other: Self | Telem, /) -> tuple[Self, Self, Self]: ... + def factor(self) -> tuple[Telem, list[tuple[Self, int]]]: ... + def factor_squarefree(self) -> tuple[Telem, list[tuple[Self, int]]]: ... + def resultant(self, other: Self | Telem, /) -> Telem: ... + def deflation(self) -> tuple[Self, int]: ... class Ordering(enum.Enum): lex = "lex" deglex = "deglex" degrevlex = "degrevlex" - class flint_mpoly(flint_elem, Generic[Tctx, Telem, Telem_coerce]): - def __init__(self, - val: Self | Telem | Telem_coerce | int | dict[tuple[int, ...], Telem | Telem_coerce | int] | str = 0, - ctx: Tctx | None = None + def __init__( + self, + val: Self + | Telem + | Telem_coerce + | int + | dict[tuple[int, ...], Telem | Telem_coerce | int] + | str = 0, + ctx: Tctx | None = None, ) -> None: ... - def str(self) -> _str: ... def repr(self) -> _str: ... - def context(self) -> Tctx: ... - def degrees(self) -> tuple[int, ...]: ... def total_degree(self) -> int: ... - def leading_coefficient(self) -> Telem: ... def to_dict(self) -> dict[tuple[int, ...], Telem]: ... - def is_one(self) -> bool: ... def is_zero(self) -> bool: ... def is_constant(self) -> bool: ... - def __len__(self) -> int: ... def __getitem__(self, index: tuple[int, ...]) -> Telem: ... - def __setitem__(self, index: tuple[int, ...], coeff: Telem | Telem_coerce | int) -> None: ... + def __setitem__( + self, index: tuple[int, ...], coeff: Telem | Telem_coerce | int + ) -> None: ... def __iter__(self) -> Iterable[tuple[int, ...]]: ... def __contains__(self, index: tuple[int, ...]) -> bool: ... - def coefficient(self, i: int) -> Telem: ... def monomial(self, i: int) -> tuple[int, ...]: ... def terms(self) -> Iterable[tuple[tuple[int, ...], Telem]]: ... def monoms(self) -> list[tuple[int, ...]]: ... def coeffs(self) -> list[Telem]: ... - def __pos__(self) -> Self: ... def __neg__(self) -> Self: ... def __add__(self, other: Self | Telem | Telem_coerce | int) -> Self: ... @@ -93,80 +151,66 @@ class flint_mpoly(flint_elem, Generic[Tctx, Telem, Telem_coerce]): def __rfloordiv__(self, other: Telem | Telem_coerce | int) -> Self: ... def __mod__(self, other: Self | Telem | Telem_coerce | int) -> Self: ... def __rmod__(self, other: Telem | Telem_coerce | int) -> Self: ... - def __divmod__(self, other: Self | Telem | Telem_coerce | int) -> tuple[Self, Self]: ... + def __divmod__( + self, other: Self | Telem | Telem_coerce | int + ) -> tuple[Self, Self]: ... def __rdivmod__(self, other: Telem | Telem_coerce | int) -> tuple[Self, Self]: ... def __pow__(self, other: Telem | Telem_coerce | int) -> Self: ... def __rpow__(self, other: Telem | Telem_coerce | int) -> Self: ... - def iadd(self, other: Telem | Telem_coerce | int) -> None: ... def isub(self, other: Telem | Telem_coerce | int) -> None: ... def imul(self, other: Telem | Telem_coerce | int) -> None: ... - def gcd(self, other: Self) -> Self: ... def term_content(self) -> Self: ... - def factor(self) -> tuple[Telem, Sequence[tuple[Self, int]]]: ... def factor_squarefree(self) -> tuple[Telem, Sequence[tuple[Self, int]]]: ... - def sqrt(self) -> Self: ... - def resultant(self, other: Self, var: _str | int) -> Self: ... def discriminant(self, var: _str | int) -> Self: ... - def deflation_index(self) -> tuple[list[int], list[int]]: ... def deflation(self) -> tuple[Self, list[int]]: ... def deflation_monom(self) -> tuple[Self, list[int], Self]: ... - def inflate(self, N: list[int]) -> Self: ... def deflate(self, N: list[int]) -> Self: ... - def subs(self, mapping: dict[_str | int, Telem | Telem_coerce | int]) -> Self: ... def compose(self, *args: Self, ctx: Tctx | None = None) -> Self: ... def __call__(self, *args: Telem | Telem_coerce) -> Telem: ... - def derivative(self, var: _str | int) -> Self: ... - def unused_gens(self) -> tuple[_str, ...]: ... - def project_to_context( - self, - other_ctx: Tctx, - mapping: dict[_str | int, _str | int] | None = None + self, other_ctx: Tctx, mapping: dict[_str | int, _str | int] | None = None ) -> Self: ... - class flint_mpoly_context(flint_elem, Generic[Tmpoly, Telem, Telem_coerce]): - def nvars(self) -> int: ... def ordering(self) -> Ordering: ... - def gen(self, i: int, /) -> Tmpoly: ... def from_dict(self, d: Mapping[tuple[int, ...], Telem_coerce], /) -> Tmpoly: ... def constant(self, z: Telem_coerce, /) -> Tmpoly: ... - def name(self, i: int, /) -> str: ... def names(self) -> tuple[str]: ... def gens(self) -> tuple[Tmpoly, ...]: ... def variable_to_index(self, var: str, /) -> int: ... - def term(self, coeff: Telem_coerce | None = None, exp_vec: Iterable[int] | None = None) -> Tmpoly: ... + def term( + self, coeff: Telem_coerce | None = None, exp_vec: Iterable[int] | None = None + ) -> Tmpoly: ... def drop_gens(self, gens: Iterable[str | int], /) -> Self: ... def append_gens(self, gens: Iterable[str | int], /) -> Self: ... - def infer_generator_mapping(self, ctx: flint_mpoly_context, /) -> dict[int, int]: ... - + def infer_generator_mapping( + self, ctx: flint_mpoly_context, / + ) -> dict[int, int]: ... @classmethod - def from_context(cls, + def from_context( + cls, ctx: Sctx, names: str | Iterable[str | tuple[str, int]] | tuple[str, int] | None = None, ordering: Ordering | str = Ordering.lex, - ) -> Sctx: - ... - + ) -> Sctx: ... class flint_mod_mpoly_context(flint_mpoly_context[Tmpoly, Telem, Telem_coerce]): @abstractmethod def modulus(self) -> int: ... - class flint_series(flint_elem, Generic[Telem]): """Base class for power series.""" def __iter__(self) -> Iterator[Telem]: ... diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index cdd3f06d..2fb6ed72 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import Any, Callable, TypeVar, Iterable, Protocol, TYPE_CHECKING +from typing import Any, Callable, Sequence, TypeVar, Iterable, Protocol, TYPE_CHECKING import math import operator @@ -26,10 +26,13 @@ def raises(f, exception) -> bool: if TYPE_CHECKING: from typing import TypeIs + from flint.flint_base.flint_base import _flint_poly_exact Tscalar = TypeVar('Tscalar', bound=flint_base.flint_scalar) Tscalar_co = TypeVar('Tscalar_co', bound=flint_base.flint_scalar, covariant=True) +Tscalar_contra = TypeVar('Tscalar_contra', bound=flint_base.flint_scalar, contravariant=True) +Tpoly = TypeVar("Tpoly", bound='_flint_poly_exact') Tmpoly = TypeVar('Tmpoly', bound=flint_base.flint_mpoly) Tmpolyctx_co = TypeVar('Tmpolyctx_co', bound=flint_base.flint_mpoly_context, covariant=True) @@ -768,7 +771,7 @@ def set_bad(): assert raises(lambda: Z([0,2,1]).reversion(), ValueError) -def test_fmpq(): +def test_fmpq() -> None: Q = flint.fmpq assert Q() == Q(0) assert Q(0) != Q(1) @@ -940,8 +943,8 @@ def test_fmpq(): ] is_exception = lambda v: isinstance(v, type) and issubclass(v, Exception) - for func2, values in cases2: - for n, val in enumerate(values, -1): + for func2, values2 in cases2: + for n, val in enumerate(values2, -1): if is_exception(val): assert raises(lambda: func2(n), val) else: @@ -1409,15 +1412,15 @@ def test_nmod_poly(): assert P([1,2,3],17) != P([1,2,4],15) assert P([1,2,3],17) != 1 assert P([1,2,3],17) != Z([1,2,3]) - assert raises(lambda: P([1,2],3) < P([1,2],3), TypeError) + assert raises(lambda: P([1,2],3) < P([1,2],3), TypeError) # type: ignore assert P(Z([1,2,3]),17) == P([1,2,3],17) assert P([1,2,N(3,17)],17) == P([1,2,3],17) assert P(P([1,2],17),17) == P([1,2],17) assert raises(lambda: P(P([1,2],17),13), ValueError) - assert raises(lambda: P([1,2,[]],17), TypeError) + assert raises(lambda: P([1,2,[]],17), TypeError) # type: ignore assert raises(lambda: P([1,2,flint.nmod(3,15)],17), ValueError) assert raises(lambda: P([1,2],0), ValueError) - assert raises(lambda: P({},3), TypeError) + assert raises(lambda: P({},3), TypeError) # type: ignore assert P([1,2,3],17).degree() == 2 assert P([1,2,3],17).length() == 3 assert len(P([1,2,3],17)) == 3 @@ -1454,31 +1457,31 @@ def test_nmod_poly(): assert raises(lambda: s2 * s, ValueError) assert raises(lambda: s2 // s, ValueError) assert raises(lambda: s2 % s, ValueError) - assert raises(lambda: s + [], TypeError) - assert raises(lambda: s - [], TypeError) - assert raises(lambda: s * [], TypeError) - assert raises(lambda: s // [], TypeError) - assert raises(lambda: s % [], TypeError) - assert raises(lambda: [] + s, TypeError) - assert raises(lambda: [] - s, TypeError) - assert raises(lambda: [] * s, TypeError) - assert raises(lambda: [] // s, TypeError) - assert raises(lambda: [] % s, TypeError) - assert raises(lambda: [] % s, TypeError) + assert raises(lambda: s + [], TypeError) # type: ignore + assert raises(lambda: s - [], TypeError) # type: ignore + assert raises(lambda: s * [], TypeError) # type: ignore + assert raises(lambda: s // [], TypeError) # type: ignore + assert raises(lambda: s % [], TypeError) # type: ignore + assert raises(lambda: [] + s, TypeError) # type: ignore + assert raises(lambda: [] - s, TypeError) # type: ignore + assert raises(lambda: [] * s, TypeError) # type: ignore + assert raises(lambda: [] // s, TypeError) # type: ignore + assert raises(lambda: [] % s, TypeError) # type: ignore + assert raises(lambda: [] % s, TypeError) # type: ignore assert raises(lambda: s.reverse(-1), ValueError) - assert raises(lambda: s.compose("A"), TypeError) - assert raises(lambda: s.compose_mod(s, "A"), TypeError) - assert raises(lambda: s.compose_mod("A", P([3,6,9],17)), TypeError) + assert raises(lambda: s.compose("A"), TypeError) # type: ignore + assert raises(lambda: s.compose_mod(s, "A"), TypeError) # type: ignore + assert raises(lambda: s.compose_mod("A", P([3,6,9],17)), TypeError) # type: ignore assert raises(lambda: s.compose_mod(s, P([0], 17)), ZeroDivisionError) assert raises(lambda: pow(s, -1, P([3,6,9],17)), ValueError) - assert raises(lambda: pow(s, 1, "A"), TypeError) - assert raises(lambda: pow(s, "A", P([3,6,9],17)), TypeError) + assert raises(lambda: pow(s, 1, "A"), TypeError) # type: ignore + assert raises(lambda: pow(s, "A", P([3,6,9],17)), TypeError) # type: ignore assert str(P([1,2,3],17)) == "3*x^2 + 2*x + 1" assert P([1,2,3],17).repr() == "nmod_poly([1, 2, 3], 17)" p = P([3,4,5],17) assert p(14) == N(2,17) assert p(P([1,2,3],17)) == P([12,11,11,9,11],17) - assert raises(lambda: p({}), TypeError) + assert raises(lambda: p({}), TypeError) # type: ignore p2 = P([3,4,5],17) assert p2[1] == N(4,17) assert p2[-1] == N(0,17) @@ -1491,14 +1494,14 @@ def set_bad1(): p2[-1] = 3 def set_bad2(): - p2[2] = [] + p2[2] = [] # type: ignore assert raises(set_bad1, ValueError) assert raises(set_bad2, TypeError) assert bool(P([], 5)) is False assert bool(P([1], 5)) is True assert P([1,2,1],3).gcd(P([1,1],3)) == P([1,1],3) - raises(lambda: P([1,2],3).gcd([]), TypeError) + raises(lambda: P([1,2],3).gcd([]), TypeError) # type: ignore raises(lambda: P([1,2],3).gcd(P([1,2],5)), ValueError) p3 = P([1,2,3,4,5,6],7) f3 = (N(6,7), [(P([6, 1],7), 5)]) @@ -1962,8 +1965,8 @@ def test_fmpz_mod_poly(): assert f.is_irreducible() assert f.is_monic() assert raises(lambda: R1.random_element(degree=-123), ValueError) - assert raises(lambda: R1.random_element(monic="A"), ValueError) - assert raises(lambda: R1.random_element(irreducible="A"), ValueError) + assert raises(lambda: R1.random_element(monic="A"), TypeError) # type: ignore + assert raises(lambda: R1.random_element(irreducible="A"), TypeError) # type: ignore # Conversion tests F = fmpz_mod_ctx(11) @@ -1975,8 +1978,9 @@ def test_fmpz_mod_poly(): assert raises(lambda: R(R_other([1,2,3])), ValueError) # moduli must match assert raises(lambda: R(F_other(2)), ValueError) # moduli must match assert raises(lambda: R([F(1), F_other(2)]), ValueError) # moduli must match - assert raises(lambda: R([F(1), "A"]), TypeError) # need to be able to cast to fmpz_mod + assert raises(lambda: R([F(1), "A"]), TypeError) # type: ignore + R.__call__ f1 = R([-1, -2, -3]) f2 = R([fmpz(-1),fmpz(-2),fmpz(-3)]) f3 = R([F(-1),F(-2),F(-3)]) @@ -2018,7 +2022,7 @@ def test_fmpz_mod_poly(): assert f[-1] == 0 assert raises(lambda: f.__setitem__(-1, 1), ValueError) - assert raises(lambda: f.__setitem__(1, "A"), TypeError) + assert raises(lambda: f.__setitem__(1, "A"), TypeError) # type: ignore # Comparisons f1 = R([1,2,3]) @@ -2031,10 +2035,10 @@ def test_fmpz_mod_poly(): assert (f1 != "1") is True assert (f4 == 3) is True assert (hash(f1) == hash(f2)) is True - assert raises(lambda: f1 > f2, TypeError) - assert raises(lambda: f1 >= f2, TypeError) - assert raises(lambda: f1 < f2, TypeError) - assert raises(lambda: f1 <= f2, TypeError) + assert raises(lambda: f1 > f2, TypeError) # type: ignore + assert raises(lambda: f1 >= f2, TypeError) # type: ignore + assert raises(lambda: f1 < f2, TypeError) # type: ignore + assert raises(lambda: f1 <= f2, TypeError) # type: ignore assert len(f1) == f1.length() == 3 assert f1.degree() == 2 @@ -2076,8 +2080,8 @@ def test_fmpz_mod_poly(): # add assert raises(lambda: f + f_cmp, ValueError) - assert raises(lambda: f + "AAA", TypeError) - assert raises(lambda: "AAA" + f, TypeError) + assert raises(lambda: f + "AAA", TypeError) # type: ignore + assert raises(lambda: "AAA" + f, TypeError) # type: ignore assert f + g == R_test([-4,-6]) assert f + 1 == R_test([0,-2]) assert f + fmpz(1) == R_test([0,-2]) @@ -2088,8 +2092,8 @@ def test_fmpz_mod_poly(): # sub assert raises(lambda: f - f_cmp, ValueError) - assert raises(lambda: f - "AAA", TypeError) - assert raises(lambda: "AAA" - f, TypeError) + assert raises(lambda: f - "AAA", TypeError) # type: ignore + assert raises(lambda: "AAA" - f, TypeError) # type: ignore assert f - g == R_test([2, 2]) assert f - 1 == R_test([-2,-2]) assert f - fmpz(1) == R_test([-2,-2]) @@ -2100,8 +2104,8 @@ def test_fmpz_mod_poly(): # mul assert raises(lambda: f * f_cmp, ValueError) - assert raises(lambda: f * "AAA", TypeError) - assert raises(lambda: "AAA" * f, TypeError) + assert raises(lambda: f * "AAA", TypeError) # type: ignore + assert raises(lambda: "AAA" * f, TypeError) # type: ignore assert f * g == R_test([3, 4 + 6, 8]) assert f * 2 == R_test([-2,-4]) assert f * fmpz(2) == R_test([-2,-4]) @@ -2112,18 +2116,18 @@ def test_fmpz_mod_poly(): # scalar_mul assert 2 * f == f.scalar_mul(2) - assert raises(lambda: f.scalar_mul("AAA"), TypeError) + assert raises(lambda: f.scalar_mul("AAA"), TypeError) # type: ignore # Exact division assert raises(lambda: f.exact_division(f_cmp), ValueError) - assert raises(lambda: f.exact_division("AAA"), TypeError) + assert raises(lambda: f.exact_division("AAA"), TypeError) # type: ignore assert raises(lambda: f.exact_division(0), ZeroDivisionError) assert (f * g).exact_division(g) == f assert raises(lambda: f.exact_division(g), DomainError) # true div - assert raises(lambda: f / "AAA", TypeError) + assert raises(lambda: f / "AAA", TypeError) # type: ignore assert raises(lambda: f / 0, ZeroDivisionError) assert raises(lambda: f_cmp / 2, DomainError) @@ -2134,8 +2138,8 @@ def test_fmpz_mod_poly(): # floor div assert raises(lambda: 1 // f_bad, DomainError) assert raises(lambda: f // f_cmp, ValueError) - assert raises(lambda: f // "AAA", TypeError) - assert raises(lambda: "AAA" // f, TypeError) + assert raises(lambda: f // "AAA", TypeError) # type: ignore + assert raises(lambda: "AAA" // f, TypeError) # type: ignore assert (f * g) // g == f assert (f + f) // 2 == f assert (f + f) // fmpz(2) == f @@ -2156,9 +2160,9 @@ def test_fmpz_mod_poly(): # Check other typechecks for pow_mod assert raises(lambda: pow(f, -2, g), ValueError) - assert raises(lambda: pow(f, 1, "A"), TypeError) - assert raises(lambda: pow(f, "A", g), TypeError) - assert raises(lambda: f.pow_mod(2**32, g, mod_rev_inv="A"), TypeError) + assert raises(lambda: pow(f, 1, "A"), TypeError) # type: ignore + assert raises(lambda: pow(f, "A", g), TypeError) # type: ignore + assert raises(lambda: f.pow_mod(2**32, g, mod_rev_inv="A"), TypeError) # type: ignore # Shifts assert raises(lambda: R_test([1,2,3]).left_shift(-1), ValueError) @@ -2169,8 +2173,8 @@ def test_fmpz_mod_poly(): # Mod assert raises(lambda: f % f_bad, ValueError) assert raises(lambda: 123 % f_bad, DomainError) - assert raises(lambda: f % "AAA", TypeError) - assert raises(lambda: tuple() % f, TypeError) + assert raises(lambda: f % "AAA", TypeError) # type: ignore + assert raises(lambda: tuple() % f, TypeError) # type: ignore assert f % 1 == 0 assert R_test.one() % 1 == 0 @@ -2185,17 +2189,17 @@ def test_fmpz_mod_poly(): assert h(-1) == R_test.modulus() - 1 h = R_test([0, 0, 1]) assert h(1) == h(-1) - assert raises(lambda: h("AAA"), TypeError) + assert raises(lambda: h("AAA"), TypeError) # type: ignore assert f([-1,-2,-3]) == [f(x) for x in [-1, -2, -3]] # compose - assert raises(lambda: h.compose("AAA"), TypeError) + assert raises(lambda: h.compose("AAA"), TypeError) # type: ignore # compose mod mod = R_test([1,2,3,4]) assert f.compose(h) % mod == f.compose_mod(h, mod) - assert raises(lambda: h.compose_mod("AAA", mod), TypeError) - assert raises(lambda: h.compose_mod(f, "AAA"), TypeError) + assert raises(lambda: h.compose_mod("AAA", mod), TypeError) # type: ignore + assert raises(lambda: h.compose_mod(f, "AAA"), TypeError) # type: ignore assert raises(lambda: h.compose_mod(f, R_test(0)), ZeroDivisionError) # Reverse @@ -2212,26 +2216,26 @@ def test_fmpz_mod_poly(): # mulmod assert f.mul_mod(f, g) == (f*f) % g - assert raises(lambda: f.mul_mod(f, "AAA"), TypeError) - assert raises(lambda: f.mul_mod("AAA", g), TypeError) + assert raises(lambda: f.mul_mod(f, "AAA"), TypeError) # type: ignore + assert raises(lambda: f.mul_mod("AAA", g), TypeError) # type: ignore # pow_mod assert f.pow_mod(2, g) == (f*f) % g - assert raises(lambda: f.pow_mod(2, "AAA"), TypeError) + assert raises(lambda: f.pow_mod(2, "AAA"), TypeError) # type: ignore # divmod S, T = f.divmod(g) assert S*g + T == f - assert raises(lambda: f.divmod("AAA"), TypeError) + assert raises(lambda: f.divmod("AAA"), TypeError) # type: ignore assert raises(lambda: f_bad.divmod(f_bad), ValueError) # gcd assert raises(lambda: f_cmp.gcd(f_cmp), DomainError) - assert raises(lambda: f.gcd("f"), TypeError) + assert raises(lambda: f.gcd("f"), TypeError) # type: ignore # xgcd assert raises(lambda: (f_cmp).xgcd(f_cmp), ValueError) - assert raises(lambda: (f).xgcd("f_cmp"), TypeError) + assert raises(lambda: (f).xgcd("f_cmp"), TypeError) # type: ignore # disc. assert raises(lambda: (f_cmp).discriminant(), NotImplementedError) @@ -2242,7 +2246,7 @@ def test_fmpz_mod_poly(): # inverse_mod f_inv = f.inverse_mod(g) assert (f * f_inv) % g == 1 - assert raises(lambda: f.inverse_mod("AAA"), TypeError) + assert raises(lambda: f.inverse_mod("AAA"), TypeError) # type: ignore assert raises(lambda: (f_cmp).inverse_mod(f_cmp), ValueError) f_inv = f.inverse_series_trunc(2) @@ -2253,7 +2257,7 @@ def test_fmpz_mod_poly(): f1 = R_test([-3, 1]) f2 = R_test([-5, 1]) assert f1.resultant(f2) == (3 - 5) - assert raises(lambda: f.resultant("AAA"), TypeError) + assert raises(lambda: f.resultant("AAA"), TypeError) # type: ignore # sqrt f1 = R_test.random_element(irreducible=True) @@ -2291,12 +2295,12 @@ def test_fmpz_mod_poly(): # minpoly assert raises(lambda: R_cmp.minpoly([1,2,3,4]), NotImplementedError) - assert raises(lambda: R_test.minpoly(1), ValueError) - assert raises(lambda: R_test.minpoly([1,2,3,"AAA"]), ValueError) + assert raises(lambda: R_test.minpoly(1), TypeError) # type: ignore + assert raises(lambda: R_test.minpoly([1,2,3,"AAA"]), TypeError) # type: ignore # multipoint_evaluation - assert raises(lambda: R_test([1,2,3]).multipoint_evaluate([1,2,3,"AAA"]), ValueError) - assert raises(lambda: R_test([1,2,3]).multipoint_evaluate("AAA"), ValueError) + assert raises(lambda: R_test([1,2,3]).multipoint_evaluate([1,2,3,"AAA"]), TypeError) # type: ignore + assert raises(lambda: R_test([1,2,3]).multipoint_evaluate("AAA"), TypeError) # type: ignore f = R_test([1,2,3]) ell = [-1,-2,-3,-4,-5] @@ -2315,16 +2319,16 @@ def test_fmpz_mod_poly(): assert not f.equal_trunc("A", 3) assert not f.equal_trunc(f_cmp, 3) - assert raises(lambda: f.add_trunc("A", 1), TypeError) + assert raises(lambda: f.add_trunc("A", 1), TypeError) # type: ignore assert raises(lambda: f.add_trunc(f_cmp, 1), ValueError) assert f.add_trunc(g, 3) == (f + g) % x**3 - assert raises(lambda: f.sub_trunc("A", 1), TypeError) + assert raises(lambda: f.sub_trunc("A", 1), TypeError) # type: ignore assert raises(lambda: f.sub_trunc(f_cmp, 1), ValueError) assert f.sub_trunc(g, 3) == (f - g) % x**3 - assert raises(lambda: f.mul_low("A", h), TypeError) - assert raises(lambda: f.mul_low(g, "A"), TypeError) + assert raises(lambda: f.mul_low("A", h), TypeError) # type: ignore + assert raises(lambda: f.mul_low(g, "A"), TypeError) # type: ignore assert f.mul_low(g, 3) == (f * g) % x**3 assert raises(lambda: f.pow_trunc(-1, 5), ValueError) @@ -2587,307 +2591,433 @@ def _all_polys() -> list[tuple[Any, Any, bool, flint.fmpz]]: ] -def test_polys(): +class _TPoly(Protocol[Tpoly, Tscalar_contra]): + def __call__( + self, x: Sequence[Tscalar_contra | int] | Tpoly | Tscalar_contra | int, / + ) -> Tpoly: ... + + +class _Telem(Protocol[Tscalar]): + def __call__(self, x: int | Tscalar, /) -> Tscalar: ... + + +_PolyTestCase = tuple[_TPoly[Tpoly, Tscalar], _Telem[Tscalar], bool, flint.fmpz] + + +def _for_all_polys(test: Callable[[_PolyTestCase], None]) -> None: + """Test all mpoly types with the given test function.""" + # Spell it out like this so that a type checker can understand the types + # in the generics for each call of test(). + + fmpz: _Telem[flint.fmpz] = flint.fmpz + fmpq: _Telem[flint.fmpq] = flint.fmpq + fmpz_poly: _TPoly[flint.fmpz_poly, flint.fmpz] = flint.fmpz_poly + fmpq_poly: _TPoly[flint.fmpq_poly, flint.fmpq] = flint.fmpq_poly + + def nmod_poly( + p: int, + ) -> tuple[_TPoly[flint.nmod_poly, flint.nmod], _Telem[flint.nmod]]: + """Make nmod poly and scalar constructors for modulus p.""" + + def poly( + x: Sequence[flint.nmod | int] | flint.nmod_poly | flint.nmod | int, / + ) -> flint.nmod_poly: + return flint.nmod_poly(x, p) + + def elem(x: int | flint.nmod = 0, /) -> flint.nmod: + return flint.nmod(x, p) + + return poly, elem + + def fmpz_mod_poly( + p: int, + ) -> tuple[_TPoly[flint.fmpz_mod_poly, flint.fmpz_mod], _Telem[flint.fmpz_mod]]: + """Make fmpz_mod poly and scalar constructors for modulus p.""" + ectx = flint.fmpz_mod_ctx(p) + pctx = flint.fmpz_mod_poly_ctx(ectx) + + def poly( + x: Sequence[flint.fmpz_mod | int] + | flint.fmpz_mod_poly + | flint.fmpz_mod + | int, + /, + ) -> flint.fmpz_mod_poly: + return flint.fmpz_mod_poly(x, pctx) + + def elem(x: int | flint.fmpz_mod = 0, /) -> flint.fmpz_mod: + return flint.fmpz_mod(x, ectx) + + return poly, elem + + def fq_default_poly( + p: int, k: int | None = None + ) -> tuple[ + _TPoly[flint.fq_default_poly, flint.fq_default], _Telem[flint.fq_default] + ]: + """Make fq_default poly and scalar constructors for field p^k.""" + if k is None: + ectx = flint.fq_default_ctx(p) + else: + ectx = flint.fq_default_ctx(p, k) + pctx = flint.fq_default_poly_ctx(ectx) + + def poly( + x: Sequence[flint.fq_default | int] + | flint.fq_default_poly + | flint.fq_default + | int, + /, + ) -> flint.fq_default_poly: + return flint.fq_default_poly(x, pctx) + + def elem(x: int | flint.fq_default = 0, /) -> flint.fq_default: + return flint.fq_default(x, ectx) + + return poly, elem + + # Z and Q + test((fmpz_poly, fmpz, False, flint.fmpz(0))) + test((fmpq_poly, fmpq, True, flint.fmpz(0))) + + # Z/pZ (p prime) + test((*nmod_poly(17), True, flint.fmpz(17))) + test((*fmpz_mod_poly(163), True, flint.fmpz(163))) + test((*fmpz_mod_poly(2**127 - 1), True, flint.fmpz(2**127 - 1))) + test((*fmpz_mod_poly(2**255 - 19), True, flint.fmpz(2**255 - 19))) + + # Z/nZ (n composite) + test((*nmod_poly(16), False, flint.fmpz(16))) + test((*fmpz_mod_poly(164), False, flint.fmpz(164))) + test((*fmpz_mod_poly(2**127), False, flint.fmpz(2**127))) + test((*fmpz_mod_poly(2**255), False, flint.fmpz(2**255))) + + # GF(p^k) + test((*fq_default_poly(2**127 - 1), True, flint.fmpz(2**127 - 1))) + test((*fq_default_poly(2**127 - 1, 2), True, flint.fmpz(2**127 - 1))) + test((*fq_default_poly(65537), True, flint.fmpz(65537))) + test((*fq_default_poly(65537, 5), True, flint.fmpz(65537))) + test((*fq_default_poly(11), True, flint.fmpz(11))) + test((*fq_default_poly(11, 5), True, flint.fmpz(11))) + + +def all_polys(f: Callable[[_PolyTestCase], None]) -> Callable[[], None]: + """Decorator to run a test function for all mpoly types.""" + def wrapper(): + _for_all_polys(f) + wrapper.__name__ = f.__name__ + return wrapper + + +@all_polys +def test_polys(args: _PolyTestCase[Tpoly, Tscalar]) -> None: # To test type annotations, uncomment: # P: type[flint.fmpq_poly] # S: type[flint.fmpq] # is_field: bool # characteristic: flint.fmpz + P, S, is_field, characteristic = args - for P, S, is_field, characteristic in _all_polys(): + composite_characteristic = characteristic != 0 and not characteristic.is_prime() + # nmod_poly crashes for many operations with non-prime modulus + # https://github.com/flintlib/python-flint/issues/124 + # so we can't even test it... + nmod_poly_will_crash = type(P(1)) is flint.nmod_poly and composite_characteristic - composite_characteristic = characteristic != 0 and not characteristic.is_prime() - # nmod_poly crashes for many operations with non-prime modulus - # https://github.com/flintlib/python-flint/issues/124 - # so we can't even test it... - nmod_poly_will_crash = type(P(1)) is flint.nmod_poly and composite_characteristic - - assert P([S(1)]) == P([1]) == P(P([1])) == P(1) - - assert raises(lambda: P([None]), TypeError) # type: ignore - assert raises(lambda: P(object()), TypeError) # type: ignore - assert raises(lambda: P(None), TypeError) # type: ignore - assert raises(lambda: P(None, None), TypeError) # type: ignore - assert raises(lambda: P([1,2], None), TypeError) # type: ignore - assert raises(lambda: P(1, None), TypeError) # type: ignore - - assert len(P([])) == P([]).length() == 0 - assert len(P([1])) == P([1]).length() == 1 - assert len(P([1,2])) == P([1,2]).length() == 2 - assert len(P([1,2,3])) == P([1,2,3]).length() == 3 - - assert P([]).degree() == -1 - assert P([1]).degree() == 0 - assert P([1,2]).degree() == 1 - assert P([1,2,3]).degree() == 2 - - assert (P([1]) == P([1])) is True - assert (P([1]) != P([1])) is False - assert (P([1]) == P([2])) is False - assert (P([1]) != P([2])) is True - - assert (P([1]) == 1) is True - assert (P([1]) != 1) is False - assert (P([1]) == 2) is False - assert (P([1]) != 2) is True - - assert (1 == P([1])) is True - assert (1 != P([1])) is False - assert (2 == P([1])) is False - assert (2 != P([1])) is True - - s1, s2 = S(1), S(2) - - assert (P([s1]) == s1) is True - assert (P([s1]) != s1) is False - assert (P([s1]) == s2) is False - assert (P([s1]) != s2) is True - - assert (s1 == P([s1])) is True - assert (s1 != P([s1])) is False - assert (s1 == P([s2])) is False - assert (s1 != P([s2])) is True - - assert (P([1]) == None) is False - assert (P([1]) != None) is True - assert (None == P([1])) is False - assert (None != P([1])) is True - - assert raises(lambda: P([1]) < P([1]), TypeError) # type: ignore - assert raises(lambda: P([1]) <= P([1]), TypeError) # type: ignore - assert raises(lambda: P([1]) > P([1]), TypeError) # type: ignore - assert raises(lambda: P([1]) >= P([1]), TypeError) # type: ignore - assert raises(lambda: P([1]) < None, TypeError) # type: ignore - assert raises(lambda: P([1]) <= None, TypeError) # type: ignore - assert raises(lambda: P([1]) > None, TypeError) # type: ignore - assert raises(lambda: P([1]) >= None, TypeError) # type: ignore - assert raises(lambda: None < P([1]), TypeError) # type: ignore - assert raises(lambda: None <= P([1]), TypeError) # type: ignore - assert raises(lambda: None > P([1]), TypeError) # type: ignore - assert raises(lambda: None >= P([1]), TypeError) # type: ignore - - assert P([1, 2, 3])[1] == S(2) - assert P([1, 2, 3])[-1] == S(0) - assert P([1, 2, 3])[3] == S(0) - - p = P([1, 2, 3]) - p[1] = S(4) - assert p == P([1, 4, 3]) - - def setbad(obj, i, val): - obj[i] = val - - assert raises(lambda: setbad(p, 2, None), TypeError) - assert raises(lambda: setbad(p, -1, 1), ValueError) - - for v in [], [1], [1, 2]: - p = P(v) - if type(p) == flint.fmpz_poly: - assert P(v).repr() == f'fmpz_poly({v!r})' - elif type(p) == flint.fmpq_poly: - assert P(v).repr() == f'fmpq_poly({v!r})' - elif type(p) == flint.nmod_poly: - assert P(v).repr() == f'nmod_poly({v!r}, {p.modulus()})' - elif type(p) == flint.fmpz_mod_poly: - pass # fmpz_mod_poly does not have .repr() ... - elif type(p) == flint.fq_default_poly: - pass # fq_default_poly does not have .repr() ... - else: - assert False + assert P([S(1)]) == P([1]) == P(P([1])) == P(1) + + assert raises(lambda: P([None]), TypeError) # type: ignore + assert raises(lambda: P(object()), TypeError) # type: ignore + assert raises(lambda: P(None), TypeError) # type: ignore + assert raises(lambda: P(None, None), TypeError) # type: ignore + assert raises(lambda: P([1,2], None), TypeError) # type: ignore + assert raises(lambda: P(1, None), TypeError) # type: ignore + + assert len(P([])) == P([]).length() == 0 + assert len(P([1])) == P([1]).length() == 1 + assert len(P([1,2])) == P([1,2]).length() == 2 + assert len(P([1,2,3])) == P([1,2,3]).length() == 3 + + assert P([]).degree() == -1 + assert P([1]).degree() == 0 + assert P([1,2]).degree() == 1 + assert P([1,2,3]).degree() == 2 + + assert (P([1]) == P([1])) is True + assert (P([1]) != P([1])) is False + assert (P([1]) == P([2])) is False + assert (P([1]) != P([2])) is True + + assert (P([1]) == 1) is True + assert (P([1]) != 1) is False + assert (P([1]) == 2) is False + assert (P([1]) != 2) is True + + assert (1 == P([1])) is True + assert (1 != P([1])) is False + assert (2 == P([1])) is False + assert (2 != P([1])) is True + + s1, s2 = S(1), S(2) + + assert (P([s1]) == s1) is True + assert (P([s1]) != s1) is False + assert (P([s1]) == s2) is False + assert (P([s1]) != s2) is True + + assert (s1 == P([s1])) is True + assert (s1 != P([s1])) is False + assert (s1 == P([s2])) is False + assert (s1 != P([s2])) is True + + assert (P([1]) == None) is False + assert (P([1]) != None) is True + assert (None == P([1])) is False + assert (None != P([1])) is True + + assert raises(lambda: P([1]) < P([1]), TypeError) # type: ignore + assert raises(lambda: P([1]) <= P([1]), TypeError) # type: ignore + assert raises(lambda: P([1]) > P([1]), TypeError) # type: ignore + assert raises(lambda: P([1]) >= P([1]), TypeError) # type: ignore + assert raises(lambda: P([1]) < None, TypeError) # type: ignore + assert raises(lambda: P([1]) <= None, TypeError) # type: ignore + assert raises(lambda: P([1]) > None, TypeError) # type: ignore + assert raises(lambda: P([1]) >= None, TypeError) # type: ignore + assert raises(lambda: None < P([1]), TypeError) # type: ignore + assert raises(lambda: None <= P([1]), TypeError) # type: ignore + assert raises(lambda: None > P([1]), TypeError) # type: ignore + assert raises(lambda: None >= P([1]), TypeError) # type: ignore + + assert P([1, 2, 3])[1] == S(2) + assert P([1, 2, 3])[-1] == S(0) + assert P([1, 2, 3])[3] == S(0) + + p = P([1, 2, 3]) + p[1] = S(4) + assert p == P([1, 4, 3]) + + def setbad(obj, i, val): + obj[i] = val + + assert raises(lambda: setbad(p, 2, None), TypeError) + assert raises(lambda: setbad(p, -1, 1), ValueError) + + for v in [], [1], [1, 2]: + p = P(v) + if type(p) == flint.fmpz_poly: + assert p.repr() == f'fmpz_poly({v!r})' + elif type(p) == flint.fmpq_poly: + assert p.repr() == f'fmpq_poly({v!r})' + elif type(p) == flint.nmod_poly: + assert p.repr() == f'nmod_poly({v!r}, {p.modulus()})' + elif type(p) == flint.fmpz_mod_poly: + assert p.repr() == f'fmpz_mod_poly({v!r}, {p.context()!r})' + elif type(p) == flint.fq_default_poly: + assert p.repr() == f'fq_default_poly({v!r}, {p.context()!r})' + else: + assert False - assert repr(P([])) == '0' - assert repr(P([1])) == '1' - assert repr(P([1, 2])) == '2*x + 1' - assert repr(P([1, 2, 3])) == '3*x^2 + 2*x + 1' + assert repr(P([])) == '0' + assert repr(P([1])) == '1' + assert repr(P([1, 2])) == '2*x + 1' + assert repr(P([1, 2, 3])) == '3*x^2 + 2*x + 1' - p = P([1, 2, 3]) - assert p(0) == p(S(0)) == S(1) == 1 - assert p(1) == p(S(1)) == S(6) == 6 - assert p(p) == P([6, 16, 36, 36, 27]) - assert raises(lambda: p(None), TypeError) # type: ignore + p = P([1, 2, 3]) + assert p(0) == p(S(0)) == S(1) == 1 + assert p(1) == p(S(1)) == S(6) == 6 + assert p(p) == P([6, 16, 36, 36, 27]) + assert raises(lambda: p(None), TypeError) # type: ignore - assert bool(P([])) is False - assert bool(P([1])) is True + assert bool(P([])) is False + assert bool(P([1])) is True - assert P([]).is_zero() is True - assert P([1]).is_zero() is False + assert P([]).is_zero() is True + assert P([1]).is_zero() is False - assert P([]).is_one() is False - assert P([1]).is_one() is True + assert P([]).is_one() is False + assert P([1]).is_one() is True - assert +P([1, 2, 3]) == P([1, 2, 3]) - assert -P([1, 2, 3]) == P([-1, -2, -3]) + assert +P([1, 2, 3]) == P([1, 2, 3]) + assert -P([1, 2, 3]) == P([-1, -2, -3]) - assert P([1, 2, 3]) + P([4, 5, 6]) == P([5, 7, 9]) + assert P([1, 2, 3]) + P([4, 5, 6]) == P([5, 7, 9]) - for T in [int, S, flint.fmpz]: - assert P([1, 2, 3]) + T(1) == P([2, 2, 3]) - assert T(1) + P([1, 2, 3]) == P([2, 2, 3]) + for T in [int, S, flint.fmpz]: + assert P([1, 2, 3]) + T(1) == P([2, 2, 3]) + assert T(1) + P([1, 2, 3]) == P([2, 2, 3]) - assert raises(lambda: P([1, 2, 3]) + None, TypeError) # type: ignore - assert raises(lambda: None + P([1, 2, 3]), TypeError) # type: ignore + assert raises(lambda: P([1, 2, 3]) + None, TypeError) # type: ignore + assert raises(lambda: None + P([1, 2, 3]), TypeError) # type: ignore - assert P([1, 2, 3]) - P([4, 5, 6]) == P([-3, -3, -3]) + assert P([1, 2, 3]) - P([4, 5, 6]) == P([-3, -3, -3]) - for T in [int, S, flint.fmpz]: - assert P([1, 2, 3]) - T(1) == P([0, 2, 3]) - assert T(1) - P([1, 2, 3]) == P([0, -2, -3]) + for T in [int, S, flint.fmpz]: + assert P([1, 2, 3]) - T(1) == P([0, 2, 3]) + assert T(1) - P([1, 2, 3]) == P([0, -2, -3]) - assert raises(lambda: P([1, 2, 3]) - None, TypeError) # type: ignore - assert raises(lambda: None - P([1, 2, 3]), TypeError) # type: ignore + assert raises(lambda: P([1, 2, 3]) - None, TypeError) # type: ignore + assert raises(lambda: None - P([1, 2, 3]), TypeError) # type: ignore - assert P([1, 2, 3]) * P([4, 5, 6]) == P([4, 13, 28, 27, 18]) + assert P([1, 2, 3]) * P([4, 5, 6]) == P([4, 13, 28, 27, 18]) - for T in [int, S, flint.fmpz]: - assert P([1, 2, 3]) * T(2) == P([2, 4, 6]) - assert T(2) * P([1, 2, 3]) == P([2, 4, 6]) + for T in [int, S, flint.fmpz]: + assert P([1, 2, 3]) * T(2) == P([2, 4, 6]) + assert T(2) * P([1, 2, 3]) == P([2, 4, 6]) - assert raises(lambda: P([1, 2, 3]) * None, TypeError) # type: ignore - assert raises(lambda: None * P([1, 2, 3]), TypeError) # type: ignore + assert raises(lambda: P([1, 2, 3]) * None, TypeError) # type: ignore + assert raises(lambda: None * P([1, 2, 3]), TypeError) # type: ignore - assert P([1, 2, 1]) // P([1, 1]) == P([1, 1]) - assert P([1, 2, 1]) % P([1, 1]) == P([0]) - assert divmod(P([1, 2, 1]), P([1, 1])) == (P([1, 1]), P([0])) + assert P([1, 2, 1]) // P([1, 1]) == P([1, 1]) + assert P([1, 2, 1]) % P([1, 1]) == P([0]) + assert divmod(P([1, 2, 1]), P([1, 1])) == (P([1, 1]), P([0])) - if is_field: - assert P([1, 1]) // 2 == P([S(1)/2, S(1)/2]) - assert P([1, 1]) % 2 == P([0]) - elif characteristic == 0: - assert P([1, 1]) // 2 == P([0, 0]) - assert P([1, 1]) % 2 == P([1, 1]) - elif nmod_poly_will_crash: - pass + if is_field: + assert P([1, 1]) // 2 == P([S(1)/2, S(1)/2]) + assert P([1, 1]) % 2 == P([0]) + elif characteristic == 0: + assert P([1, 1]) // 2 == P([0, 0]) + assert P([1, 1]) % 2 == P([1, 1]) + elif nmod_poly_will_crash: + pass + else: + # Z/nZ for n not prime + if characteristic % 2 == 0: + assert raises(lambda: P([1, 1]) // 2, DomainError) + assert raises(lambda: P([1, 1]) % 2, DomainError) else: - # Z/nZ for n not prime - if characteristic % 2 == 0: - assert raises(lambda: P([1, 1]) // 2, DomainError) - assert raises(lambda: P([1, 1]) % 2, DomainError) - else: - assert False + assert False - assert 1 // P([1, 1]) == P([0]) - assert 1 % P([1, 1]) == P([1]) - assert divmod(1, P([1, 1])) == (P([0]), P([1])) + assert 1 // P([1, 1]) == P([0]) + assert 1 % P([1, 1]) == P([1]) + assert divmod(1, P([1, 1])) == (P([0]), P([1])) - assert raises(lambda: P([1, 2, 1]) // None, TypeError) # type: ignore - assert raises(lambda: P([1, 2, 1]) % None, TypeError) # type: ignore - assert raises(lambda: divmod(P([1, 2, 1]), None), TypeError) # type: ignore + assert raises(lambda: P([1, 2, 1]) // None, TypeError) # type: ignore + assert raises(lambda: P([1, 2, 1]) % None, TypeError) # type: ignore + assert raises(lambda: divmod(P([1, 2, 1]), None), TypeError) # type: ignore - assert raises(lambda: None // P([1, 1]), TypeError) # type: ignore - assert raises(lambda: None % P([1, 1]), TypeError) # type: ignore - assert raises(lambda: divmod(None, P([1, 1])), TypeError) # type: ignore + assert raises(lambda: None // P([1, 1]), TypeError) # type: ignore + assert raises(lambda: None % P([1, 1]), TypeError) # type: ignore + assert raises(lambda: divmod(None, P([1, 1])), TypeError) # type: ignore - assert raises(lambda: P([1, 2, 1]) // 0, ZeroDivisionError) - assert raises(lambda: P([1, 2, 1]) % 0, ZeroDivisionError) - assert raises(lambda: divmod(P([1, 2, 1]), 0), ZeroDivisionError) + assert raises(lambda: P([1, 2, 1]) // 0, ZeroDivisionError) + assert raises(lambda: P([1, 2, 1]) % 0, ZeroDivisionError) + assert raises(lambda: divmod(P([1, 2, 1]), 0), ZeroDivisionError) - assert raises(lambda: P([1, 2, 1]) // P([0]), ZeroDivisionError) - assert raises(lambda: P([1, 2, 1]) % P([0]), ZeroDivisionError) - assert raises(lambda: divmod(P([1, 2, 1]), P([0])), ZeroDivisionError) + assert raises(lambda: P([1, 2, 1]) // P([0]), ZeroDivisionError) + assert raises(lambda: P([1, 2, 1]) % P([0]), ZeroDivisionError) + assert raises(lambda: divmod(P([1, 2, 1]), P([0])), ZeroDivisionError) - # Exact/field scalar division - if is_field: - assert P([2, 2]) / 2 == P([1, 1]) - assert P([1, 2]) / 2 == P([S(1)/2, 1]) - elif characteristic == 0: - assert P([2, 2]) / 2 == P([1, 1]) - assert raises(lambda: P([1, 2]) / 2, DomainError) - elif nmod_poly_will_crash: - pass - else: - # Z/nZ for n not prime - assert raises(lambda: P([2, 2]) / 2, DomainError) - assert raises(lambda: P([1, 2]) / 2, DomainError) - - assert raises(lambda: P([1, 2]) / 0, ZeroDivisionError) - - if not nmod_poly_will_crash: - assert P([1, 2, 1]) / P([1, 1]) == P([1, 1]) - assert raises(lambda: 1 / P([1, 1]), DomainError) - assert raises(lambda: P([1, 2, 1]) / P([1, 2]), DomainError) - - assert P([1, 1]) ** 0 == P([1]) - assert P([1, 1]) ** 1 == P([1, 1]) - assert P([1, 1]) ** 2 == P([1, 2, 1]) - assert raises(lambda: P([1, 1]) ** -1, DomainError) - assert raises(lambda: P([1, 1]) ** None, TypeError) # type: ignore - - # XXX: Not sure what this should do in general: - p = P([1, 1]) - mod = P([1, 1]) - if type(p) not in [flint.fmpz_mod_poly, flint.nmod_poly, flint.fq_default_poly]: - assert raises(lambda: pow(p, 2, mod), NotImplementedError) # type: ignore - else: - assert p * p % mod == pow(p, 2, mod) + # Exact/field scalar division + if is_field: + assert P([2, 2]) / 2 == P([1, 1]) + assert P([1, 2]) / 2 == P([S(1)/2, 1]) + elif characteristic == 0: + assert P([2, 2]) / 2 == P([1, 1]) + assert raises(lambda: P([1, 2]) / 2, DomainError) + elif nmod_poly_will_crash: + pass + else: + # Z/nZ for n not prime + assert raises(lambda: P([2, 2]) / 2, DomainError) + assert raises(lambda: P([1, 2]) / 2, DomainError) - if not composite_characteristic: - assert P([1, 2, 1]).gcd(P([1, 1])) == P([1, 1]) - assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError) # type: ignore - elif nmod_poly_will_crash: - pass - else: - # Z/nZ for n not prime - assert raises(lambda: P([1, 2, 1]).gcd(P([1, 1])), DomainError) - assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError) # type: ignore + assert raises(lambda: P([1, 2]) / 0, ZeroDivisionError) - if is_field: - p1 = P([1, 0, 1]) - p2 = P([2, 1]) - g, s, t = P([1]), P([1])/5, P([2, -1])/5 - assert p1.xgcd(p2) == (g, s, t) - assert raises(lambda: p1.xgcd(None), TypeError) # type: ignore + if not composite_characteristic: + assert P([1, 2, 1]) / P([1, 1]) == P([1, 1]) + assert raises(lambda: 1 / P([1, 1]), DomainError) + assert raises(lambda: P([1, 2, 1]) / P([1, 2]), DomainError) + + assert P([1, 1]) ** 0 == P([1]) + assert P([1, 1]) ** 1 == P([1, 1]) + assert P([1, 1]) ** 2 == P([1, 2, 1]) + assert raises(lambda: P([1, 1]) ** -1, DomainError) + assert raises(lambda: P([1, 1]) ** None, TypeError) # type: ignore + + # XXX: Not sure what this should do in general: + p = P([1, 1]) + mod = P([1, 1]) + if isinstance(p, flint.fmpz_mod_poly) and isinstance(mod, flint.fmpz_mod_poly): + assert p * p % mod == pow(p, 2, mod) + elif isinstance(p, flint.nmod_poly) and isinstance(mod, flint.nmod_poly): + assert p * p % mod == pow(p, 2, mod) + elif isinstance(p, flint.fq_default_poly) and isinstance(mod, flint.fq_default_poly): + assert p * p % mod == pow(p, 2, mod) + else: + assert raises(lambda: pow(p, 2, mod), NotImplementedError) # type: ignore - if not composite_characteristic: - assert P([1, 2, 1]).factor() == (S(1), [(P([1, 1]), 2)]) - elif nmod_poly_will_crash: - pass - else: - assert raises(lambda: P([1, 2, 1]).factor(), DomainError) + if not composite_characteristic: + assert P([1, 2, 1]).gcd(P([1, 1])) == P([1, 1]) + assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError) # type: ignore + elif nmod_poly_will_crash: + pass + else: + # Z/nZ for n not prime + assert raises(lambda: P([1, 2, 1]).gcd(P([1, 1])), DomainError) + assert raises(lambda: P([1, 2, 1]).gcd(None), TypeError) # type: ignore - if not composite_characteristic: - assert P([1, 2, 1]).sqrt() == P([1, 1]) - assert raises(lambda: P([1, 2, 2]).sqrt(), DomainError) - elif nmod_poly_will_crash: - pass - else: - assert raises(lambda: P([1, 2, 1]).sqrt(), DomainError) + if is_field: + p1 = P([1, 0, 1]) + p2 = P([2, 1]) + g, s, t = P([1]), P([1])/5, P([2, -1])/5 + assert p1.xgcd(p2) == (g, s, t) + assert raises(lambda: p1.xgcd(None), TypeError) # type: ignore + + if not composite_characteristic: + assert P([1, 2, 1]).factor() == (S(1), [(P([1, 1]), 2)]) + elif nmod_poly_will_crash: + pass + else: + assert raises(lambda: P([1, 2, 1]).factor(), DomainError) - if P == flint.fmpq_poly: - assert raises(lambda: P([1, 2, 1], 3).sqrt(), ValueError) - assert P([1, 2, 1], 4).sqrt() == P([1, 1], 2) + if not composite_characteristic: + assert P([1, 2, 1]).sqrt() == P([1, 1]) + assert raises(lambda: P([1, 2, 2]).sqrt(), DomainError) + elif nmod_poly_will_crash: + pass + else: + assert raises(lambda: P([1, 2, 1]).sqrt(), DomainError) + + if P == flint.fmpq_poly: + assert raises(lambda: (P([1, 2, 1])/3).sqrt(), ValueError) + assert (P([1, 2, 1])/4).sqrt() == P([1, 1])/2 - assert P([]).deflation() == (P([]), 1) - assert P([1, 2]).deflation() == (P([1, 2]), 1) - assert P([1, 0, 2]).deflation() == (P([1, 2]), 2) + assert P([]).deflation() == (P([]), 1) + assert P([1, 2]).deflation() == (P([1, 2]), 1) + assert P([1, 0, 2]).deflation() == (P([1, 2]), 2) - assert P([1, 2, 1]).derivative() == P([2, 2]) + assert P([1, 2, 1]).derivative() == P([2, 2]) + if is_field: p = P([1, 2, 1]) - if is_field and type(p) != flint.fq_default_poly: + if isinstance(p, (flint.fmpq_poly, flint.nmod_poly, flint.fmpz_mod_poly)): assert p.integral() == P([0, 1, 1, S(1)/3]) - if type(p) == flint.fq_default_poly: - assert raises(lambda: p.integral(), NotImplementedError) - - # resultant checks. - x = P([0, 1]) - - if composite_characteristic and type(x) in [flint.fmpz_mod_poly, flint.nmod_poly]: - # Flint sometimes crashes in this case, even though the resultant - # could be computed. - divisor = characteristic.factor()[0][0] - assert raises(lambda: x.resultant(x + divisor), ValueError) - elif type(x) == flint.fq_default_poly: - # Flint does not implement resultants over GF(q) for nonprime q, so - # there's nothing for us to check. - pass + elif isinstance(p, flint.fq_default_poly): + assert raises(lambda: p.integral(), NotImplementedError) # type: ignore else: - assert x.resultant(x) == 0 - assert x.resultant(x**2 + x - x) == 0 - assert x.resultant(x**10 - x**5 + 1) == S(1) - assert (x - 1).resultant(x**5 + 1) == S(2) + assert False + + # resultant checks. + x = P([0, 1]) + + if composite_characteristic and type(x) in [flint.fmpz_mod_poly, flint.nmod_poly]: + # Flint sometimes crashes in this case, even though the resultant + # could be computed. + divisor = characteristic.factor()[0][0] + assert raises(lambda: x.resultant(x + divisor), ValueError) + elif type(x) == flint.fq_default_poly: + # Flint does not implement resultants over GF(q) for nonprime q, so + # there's nothing for us to check. + pass + else: + assert x.resultant(x) == 0 + assert x.resultant(x**2 + x - x) == 0 + assert x.resultant(x**10 - x**5 + 1) == S(1) + assert (x - 1).resultant(x**5 + 1) == S(2) + + for k in range(-10, 10): + assert x.resultant(x + S(k)) == S(k) - for k in range(-10, 10): - assert x.resultant(x + S(k)) == S(k) def test_poly_resultants(): # Check that the resultant of two cyclotomic polynomials is right. @@ -4535,7 +4665,7 @@ def test_fq_default(): assert raises(lambda: flint.fq_default_ctx(5, fq_type="A"), ValueError) assert raises(lambda: flint.fq_default_ctx(5, fq_type=[]), TypeError) assert raises(lambda: flint.fq_default_ctx(5, fq_type=-1), ValueError) - assert raises(lambda: flint.fq_default_ctx("ABC"), TypeError) + assert raises(lambda: flint.fq_default_ctx("ABC"), TypeError) # type: ignore # var must be one character assert raises(lambda: flint.fq_default_ctx(5, var="XXX"), ValueError) @@ -4614,8 +4744,8 @@ def test_fq_default(): assert gf_5.gen() == gf_5(R.gen()) assert gf_5.gen() == gf_5(flint.nmod_poly([0, 1], 5)) assert gf_5(flint.fmpz(2**64)) == gf_5(2**64) - assert raises(lambda: flint.fq_default(1, "AAA"), TypeError) - assert raises(lambda: flint.fq_default.__init__(1, "AAA"), TypeError) + assert raises(lambda: flint.fq_default(1, "AAA"), TypeError) # type: ignore + assert raises(lambda: flint.fq_default.__init__(1, "AAA"), TypeError) # type: ignore assert raises(lambda: flint.fq_default("AAA", gf_5), TypeError) assert raises(lambda: gf_5.one() + gf_5_2.one(), ValueError) # testing various equalties between types @@ -4682,10 +4812,10 @@ def test_fq_default(): assert (gf(0) != gf.zero()) is False assert (gf(1) == gf.zero()) is False assert (gf(1) != gf.zero()) is True - assert raises(lambda: gf.zero() > gf.zero(), TypeError) - assert raises(lambda: gf.zero() >= gf.zero(), TypeError) - assert raises(lambda: gf.zero() < gf.zero(), TypeError) - assert raises(lambda: gf.zero() <= gf.zero(), TypeError) + assert raises(lambda: gf.zero() > gf.zero(), TypeError) # type: ignore + assert raises(lambda: gf.zero() >= gf.zero(), TypeError) # type: ignore + assert raises(lambda: gf.zero() < gf.zero(), TypeError) # type: ignore + assert raises(lambda: gf.zero() <= gf.zero(), TypeError) # type: ignore assert gf.zero().is_zero() is True assert gf.one().is_zero() is False @@ -4719,7 +4849,7 @@ def test_fq_default(): assert raises(lambda: a / 0, ZeroDivisionError) assert raises(lambda: ~gf.zero(), ZeroDivisionError) assert raises(lambda: pow(gf.zero(), -1), ZeroDivisionError) - assert raises(lambda: pow(gf.zero(), "A"), TypeError) + assert raises(lambda: pow(gf.zero(), "A"), TypeError) # type: ignore assert 1/a == pow(a, -1) == ~a assert gf.one() == pow(a, 0) @@ -4742,7 +4872,7 @@ def test_fq_default_poly(): R2 = flint.fq_default_poly_ctx(11, 3) R3 = flint.fq_default_poly_ctx(13, 5) - assert raises(lambda: flint.fq_default_poly_ctx("AAA"), TypeError) + assert raises(lambda: flint.fq_default_poly_ctx("AAA"), TypeError) # type: ignore assert (R1 == R1) is True assert hash(R1) == hash(R2) assert (R1 != R1) is False @@ -4760,10 +4890,10 @@ def test_fq_default_poly(): # random element failure f = R1.random_element(not_zero=True) assert not f.is_zero() - assert raises(lambda: R1.random_element(monic="AAA"), TypeError) + assert raises(lambda: R1.random_element(monic="AAA"), TypeError) # type: ignore assert raises(lambda: R1.random_element(degree=-1), ValueError) - assert raises(lambda: flint.fq_default_poly([1,2,3], "AAA"), TypeError) + assert raises(lambda: flint.fq_default_poly([1,2,3], "AAA"), TypeError) # type: ignore assert R1(0).leading_coefficient() == 0 assert raises(lambda: R1.random_element().reverse(degree=-1), ValueError) @@ -4827,8 +4957,8 @@ def test_fq_default_poly(): assert pow(R_gen, 2**60, g) == pow(pow(R_gen, 2**30, g), 2**30, g) assert raises(lambda: pow(f, -2, g), ValueError) assert raises(lambda: pow(f, 1, "A"), TypeError) - assert raises(lambda: pow(f, "A", g), TypeError) - assert raises(lambda: f.pow_mod(2**32, g, mod_rev_inv="A"), TypeError) + assert raises(lambda: pow(f, "A", g), TypeError) # type: ignore + assert raises(lambda: f.pow_mod(2**32, g, mod_rev_inv="A"), TypeError) # type: ignore # Shifts assert raises(lambda: R_test([1,2,3]).left_shift(-1), ValueError) @@ -4905,7 +5035,7 @@ def test_fq_default_poly(): assert f.sub_trunc(g, 3) == (f - g) % x**3 assert raises(lambda: f.mul_low("A", 1), TypeError) - assert raises(lambda: f.mul_low(g, "A"), TypeError) + assert raises(lambda: f.mul_low(g, "A"), TypeError) # type: ignore assert raises(lambda: f.mul_low(f_cmp, 1), ValueError) assert f.mul_low(g, 3) == (f * g) % x**3 diff --git a/src/flint/types/fmpq_poly.pyi b/src/flint/types/fmpq_poly.pyi index 8ff1d09d..b0207367 100644 --- a/src/flint/types/fmpq_poly.pyi +++ b/src/flint/types/fmpq_poly.pyi @@ -1,5 +1,5 @@ -from typing import overload, Any -from flint.flint_base.flint_base import flint_poly +from typing import overload, Any, Sequence +from flint.flint_base.flint_base import _flint_poly_exact from flint.types.fmpz import fmpz, ifmpz from flint.types.fmpq import fmpq, ifmpq from flint.types.fmpz_poly import fmpz_poly, ifmpz_poly @@ -8,20 +8,14 @@ from flint.types.fmpz_poly import fmpz_poly, ifmpz_poly ifmpq_poly = fmpq_poly | ifmpq | ifmpz_poly -class fmpq_poly(flint_poly[fmpq]): +class fmpq_poly(_flint_poly_exact[fmpq]): """ The *fmpq_poly* type represents dense univariate polynomials over the rational numbers. For efficiency reasons, an *fmpq_poly* is structurally an integer polynomial with a single common denominator. """ - @overload - def __init__(self) -> None: ... - @overload - def __init__(self, other: fmpq_poly | fmpz_poly | list[int] | list[ifmpq] | ifmpq, /) -> None: ... - @overload - def __init__(self, other: fmpq_poly | fmpz_poly | list[int] | list[ifmpq] | ifmpq, - den: ifmpz, /) -> None: ... + def __init__(self, other: Sequence[ifmpq] | ifmpq_poly = ..., den: ifmpz = ..., /) -> None: ... def __len__(self) -> int: ... def length(self) -> int: ... @@ -44,6 +38,7 @@ class fmpq_poly(flint_poly[fmpq]): def is_zero(self) -> bool: ... def is_one(self) -> bool: ... def is_constant(self) -> bool: ... + def is_gen(self) -> bool: ... def leading_coefficient(self) -> fmpq: ... diff --git a/src/flint/types/fmpq_poly.pyx b/src/flint/types/fmpq_poly.pyx index 389ad6ad..9116f90a 100644 --- a/src/flint/types/fmpq_poly.pyx +++ b/src/flint/types/fmpq_poly.pyx @@ -194,6 +194,21 @@ cdef class fmpq_poly(flint_poly): """ return fmpq_poly_degree(self.val) <= 0 + def is_gen(self): + """ + Return ``True`` if the polynomial is the generator + of the polynomial, `x`, and ``False`` otherwise + + >>> x = fmpq_poly([0, 1]) + >>> x + x + >>> x.is_gen() + True + >>> (x + 1).is_gen() + False + """ + return fmpq_poly_is_gen(self.val) + def leading_coefficient(self): """ Returns the leading coefficient of the polynomial. diff --git a/src/flint/types/fmpz_mod_poly.pyi b/src/flint/types/fmpz_mod_poly.pyi new file mode 100644 index 00000000..ea81ab2f --- /dev/null +++ b/src/flint/types/fmpz_mod_poly.pyi @@ -0,0 +1,149 @@ +from typing import Literal, Sequence, overload + +from flint.flint_base.flint_base import _flint_poly_exact +from flint.types.fmpz import fmpz +from flint.types.fmpz_poly import fmpz_poly +from flint.types.fmpz_mod import fmpz_mod, fmpz_mod_ctx, ifmpz, ifmpz_mod + +ifmpz_mod_poly = ifmpz_mod | fmpz_mod_poly | fmpz_poly + +class fmpz_mod_poly_ctx: + r""" + Context object for creating :class:`~.fmpz_mod_poly` initialised + with a modulus :math:`N`. + + >>> fmpz_mod_poly_ctx(2**127 - 1) + fmpz_mod_poly_ctx(170141183460469231731687303715884105727) + + """ + def __init__(self, mod: fmpz_mod_ctx | ifmpz): ... + def modulus(self) -> fmpz: ... + def is_prime(self) -> bool: ... + def zero(self) -> fmpz_mod_poly: ... + def one(self) -> fmpz_mod_poly: ... + def gen(self) -> fmpz_mod_poly: ... + def random_element( + self, degree: int = 3, monic: bool = False, irreducible: bool = False + ) -> fmpz_mod_poly: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def __str__(self) -> str: ... + def __repr__(self) -> str: ... + def __call__(self, val: ifmpz_mod_poly | list[ifmpz_mod]) -> fmpz_mod_poly: ... + def minpoly(self, vals: Sequence[ifmpz_mod]) -> fmpz_mod_poly: ... + +class fmpz_mod_poly(_flint_poly_exact[fmpz_mod]): + """ + The *fmpz_mod_poly* type represents univariate polynomials + over integer modulo an arbitrary-size modulus. + For wordsize modulus, see :class:`~.nmod_poly`. + + An *fmpz_mod_poly* element is constructed from an :class:`~.fmpz_mod_poly_ctx` + either by passing it as an argument to the type, or + by directly calling the context: + + >>> fmpz_mod_poly([1,-2,3], fmpz_mod_poly_ctx(2**127 - 1)) + 3*x^2 + 170141183460469231731687303715884105725*x + 1 + >>> R = fmpz_mod_poly_ctx(2**127 - 1) + >>> R([4,5,6]) + 6*x^2 + 5*x + 4 + + """ + def __init__(self, val: Sequence[ifmpz_mod] | ifmpz_mod_poly, ctx): ... + def context(self) -> fmpz_mod_poly_ctx: ... + def modulus(self) -> fmpz: ... + def __pos__(self) -> fmpz_mod_poly: ... + def __neg__(self) -> fmpz_mod_poly: ... + def __add__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __radd__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __sub__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __rsub__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __mul__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __rmul__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __truediv__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __rtruediv__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __floordiv__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __rfloordiv__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __mod__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __rmod__(self, other: ifmpz_mod_poly, /) -> fmpz_mod_poly: ... + def __pow__( + self, e: ifmpz, mod: ifmpz_mod_poly | None = None, / + ) -> fmpz_mod_poly: ... + def scalar_mul(self, other: ifmpz_mod) -> fmpz_mod_poly: ... + def exact_division(self, right: ifmpz_mod_poly) -> fmpz_mod_poly: ... + def left_shift(self, n: int, /) -> fmpz_mod_poly: ... + def right_shift(self, n: int, /) -> fmpz_mod_poly: ... + def __getitem__(self, i: int, /) -> fmpz_mod: ... + def __setitem__(self, i: int, x: ifmpz_mod, /) -> None: ... + def __len__(self) -> int: ... + def __hash__(self) -> int: ... + @overload + def __call__(self, input: ifmpz_mod) -> fmpz_mod: ... + @overload + def __call__(self, input: fmpz_mod_poly) -> fmpz_mod_poly: ... + @overload + def __call__( + self, input: list[ifmpz_mod] | tuple[ifmpz_mod, ...] + ) -> list[fmpz_mod]: ... + def evaluate(self, input: ifmpz_mod) -> fmpz_mod: ... + def multipoint_evaluate(self, vals: Sequence[ifmpz_mod]) -> list[fmpz_mod]: ... + def compose(self, other: fmpz_mod_poly) -> fmpz_mod_poly: ... + def compose_mod( + self, other: ifmpz_mod_poly, modulus: ifmpz_mod_poly + ) -> fmpz_mod_poly: ... + def length(self) -> int: ... + def degree(self) -> int: ... + def is_zero(self) -> bool: ... + def is_one(self) -> bool: ... + def is_gen(self) -> bool: ... + def is_constant(self) -> bool: ... + def constant_coefficient(self) -> fmpz_mod: ... + def leading_coefficient(self) -> fmpz_mod: ... + def reverse(self, degree: int | None = None) -> fmpz_mod_poly: ... + def truncate(self, n: int) -> fmpz_mod_poly: ... + def is_monic(self) -> bool: ... + def monic(self, check: bool = True) -> fmpz_mod_poly: ... + def is_irreducible(self) -> bool: ... + def is_squarefree(self) -> bool: ... + def square(self) -> fmpz_mod_poly: ... + def mul_mod( + self, other: ifmpz_mod_poly, modulus: ifmpz_mod_poly + ) -> fmpz_mod_poly: ... + def pow_mod( + self, e: int, modulus: ifmpz_mod_poly | None = None, / + ) -> fmpz_mod_poly: ... + def divmod(self, other: ifmpz_mod_poly) -> tuple[fmpz_mod, fmpz_mod_poly]: ... + def __divmod__(self, other: ifmpz_mod_poly) -> tuple[fmpz_mod_poly, fmpz_mod_poly]: ... + def __rdivmod__(self, other: ifmpz_mod_poly) -> tuple[fmpz_mod_poly, fmpz_mod_poly]: ... + def gcd(self, other: ifmpz_mod_poly) -> fmpz_mod_poly: ... + def xgcd( + self, other: ifmpz_mod_poly + ) -> tuple[fmpz_mod_poly, fmpz_mod_poly, fmpz_mod_poly]: ... + def derivative(self) -> fmpz_mod_poly: ... + def integral(self) -> fmpz_mod_poly: ... + def discriminant(self) -> fmpz_mod: ... + def radical(self) -> fmpz_mod_poly: ... + def inverse_mod(self, other: ifmpz_mod_poly) -> fmpz_mod_poly: ... + def inverse_series_trunc(self, n: int) -> fmpz_mod_poly: ... + def resultant(self, other: ifmpz_mod_poly) -> fmpz_mod: ... + def sqrt(self) -> fmpz_mod_poly: ... + def sqrt_trunc(self, n: int) -> fmpz_mod_poly: ... + def inverse_sqrt_trunc(self, n: int) -> fmpz_mod_poly: ... + def equal_trunc(self, other: object, n: int) -> bool: ... + def add_trunc(self, other: fmpz_mod_poly, n: int) -> fmpz_mod_poly: ... + def sub_trunc(self, other: fmpz_mod_poly, n: int) -> fmpz_mod_poly: ... + def mul_low(self, other: fmpz_mod_poly, n: int) -> fmpz_mod_poly: ... + def pow_trunc(self, e: int, n: int) -> fmpz_mod_poly: ... + def inflate(self, n: int) -> fmpz_mod_poly: ... + def deflate(self, n: int) -> fmpz_mod_poly: ... + def deflation(self) -> tuple[fmpz_mod_poly, int]: ... + def factor_squarefree(self) -> tuple[fmpz_mod, list[tuple[fmpz_mod_poly, int]]]: ... + def factor( + self, algorithm: str | None = None + ) -> tuple[fmpz_mod, list[tuple[fmpz_mod_poly, int]]]: ... + @overload + def roots( + self, multiplicities: Literal[True] = ... + ) -> list[tuple[fmpz_mod, int]]: ... + @overload + def roots(self, multiplicities: Literal[False]) -> list[fmpz_mod]: ... diff --git a/src/flint/types/fmpz_mod_poly.pyx b/src/flint/types/fmpz_mod_poly.pyx index d854dc26..dd3e7c58 100644 --- a/src/flint/types/fmpz_mod_poly.pyx +++ b/src/flint/types/fmpz_mod_poly.pyx @@ -130,7 +130,7 @@ cdef class fmpz_mod_poly_ctx: """ cdef slong length if not (isinstance(monic, bool) and isinstance(irreducible, bool)): - raise ValueError("Both 'monic' and 'irreducible' must be of type bool") + raise TypeError("Both 'monic' and 'irreducible' must be of type bool") length = degree + 1 if length <= 0: @@ -285,14 +285,14 @@ cdef class fmpz_mod_poly_ctx: raise NotImplementedError("minpoly algorithm assumes that the modulus is prime") if not isinstance(vals, (list, tuple)): - raise ValueError("Input must be a list or tuple of points") + raise TypeError("Input must be a list or tuple of points") n = len(vals) xs = fmpz_vec(n) for i in range(n): check = self.mod.set_any_as_fmpz_mod(&xs.val[i], vals[i]) if check is NotImplemented: - raise ValueError(f"Unable to cast {vals[i]} to an 'fmpz_mod'") + raise TypeError(f"Unable to cast {vals[i]} to an 'fmpz_mod'") res = self.new_ctype_poly() fmpz_mod_poly_minpoly(res.val, xs.val, n, self.mod.val) @@ -335,6 +335,16 @@ cdef class fmpz_mod_poly(flint_poly): if check is NotImplemented: raise TypeError + def modulus(self): + return self.ctx.modulus() + + def context(self): + return self.ctx + + def repr(self): + coeffs_str = ", ".join(map(str, self.coeffs())) + return f"fmpz_mod_poly([{coeffs_str}], fmpz_mod_poly_ctx({self.ctx.modulus()}))" + def __pos__(self): return self @@ -759,14 +769,14 @@ cdef class fmpz_mod_poly(flint_poly): cdef fmpz_mod f if not isinstance(vals, (list, tuple)): - raise ValueError("Input must be a list of points") + raise TypeError("Input must be a list of points") n = len(vals) xs = fmpz_vec(n) for i in range(n): check = self.ctx.mod.set_any_as_fmpz_mod(&xs.val[i], vals[i]) if check is NotImplemented: - raise ValueError(f"Unable to cast {vals[i]} to an 'fmpz_mod'") + raise TypeError(f"Unable to cast {vals[i]} to an 'fmpz_mod'") # Call for multipoint eval, iterative horner will be used # for small arrays (len < 32) and a fast eval for larger ones diff --git a/src/flint/types/fmpz_poly.pyi b/src/flint/types/fmpz_poly.pyi index 32b7d296..d3628b33 100644 --- a/src/flint/types/fmpz_poly.pyi +++ b/src/flint/types/fmpz_poly.pyi @@ -1,40 +1,30 @@ -from typing import overload, Any -from flint.flint_base.flint_base import flint_poly +from typing import overload, Any, Sequence +from flint.flint_base.flint_base import _flint_poly_exact from flint.types.fmpz import fmpz, ifmpz from flint.types.fmpq import fmpq from flint.types.fmpq_poly import fmpq_poly - ifmpz_poly = fmpz_poly | ifmpz - -class fmpz_poly(flint_poly[fmpz]): +class fmpz_poly(_flint_poly_exact[fmpz]): """ The *fmpz_poly* type represents dense univariate polynomials over the integers. """ - @overload - def __init__(self) -> None: ... - @overload - def __init__(self, arg: list[int] | list[ifmpz] | ifmpz | fmpz_poly, /) -> None: ... - + def __init__(self, arg: Sequence[ifmpz] | ifmpz_poly = ..., /) -> None: ... def __len__(self) -> int: ... def length(self) -> int: ... def degree(self) -> int: ... - def __getitem__(self, i: int, /) -> fmpz: ... def __setitem__(self, i: int, x: ifmpz, /) -> None: ... - def repr(self) -> str: ... - def __bool__(self) -> bool: ... def is_zero(self) -> bool: ... def is_one(self) -> bool: ... def is_constant(self) -> bool: ... - + def is_gen(self) -> bool: ... def leading_coefficient(self) -> fmpz: ... - @overload def __call__(self, other: ifmpz, /) -> fmpz: ... @overload @@ -43,14 +33,11 @@ class fmpz_poly(flint_poly[fmpz]): def __call__(self, other: fmpz_poly, /) -> fmpz_poly: ... @overload def __call__(self, other: fmpq_poly, /) -> fmpq_poly: ... - #@overload - #def __call__(self, other: arb, /) -> acb: ... - #@overload - #def __call__(self, other: acb, /) -> acb: ... - - + # @overload + # def __call__(self, other: arb, /) -> acb: ... + # @overload + # def __call__(self, other: acb, /) -> acb: ... def derivative(self) -> fmpz_poly: ... - def __pos__(self) -> fmpz_poly: ... def __neg__(self) -> fmpz_poly: ... def __add__(self, other: ifmpz_poly, /) -> fmpz_poly: ... @@ -68,15 +55,12 @@ class fmpz_poly(flint_poly[fmpz]): def __divmod__(self, other: ifmpz_poly, /) -> tuple[fmpz_poly, fmpz_poly]: ... def __rdivmod__(self, other: ifmpz, /) -> tuple[fmpz_poly, fmpz_poly]: ... def __pow__(self, other: int, /) -> fmpz_poly: ... - def gcd(self, other: ifmpz_poly, /) -> fmpz_poly: ... def content(self) -> fmpz: ... - - def resultant(self, other: ifmpz_poly, /) -> fmpz_poly: ... - def factor(self) -> tuple[fmpz_poly, list[tuple[fmpz_poly, int]]]: ... - def factor_squarefree(self) -> tuple[fmpz_poly, list[tuple[fmpz_poly, int]]]: ... + def resultant(self, other: ifmpz_poly, /) -> fmpz: ... + def factor(self) -> tuple[fmpz, list[tuple[fmpz_poly, int]]]: ... + def factor_squarefree(self) -> tuple[fmpz, list[tuple[fmpz_poly, int]]]: ... def sqrt(self) -> fmpz_poly: ... - def deflation(self) -> tuple[fmpz_poly, int]: ... def deflation_monom(self) -> tuple[fmpz_poly, int, fmpz_poly]: ... def inflate(self, n: int, /) -> fmpz_poly: ... @@ -85,25 +69,17 @@ class fmpz_poly(flint_poly[fmpz]): # XXX acb def complex_roots(self, verbose: bool = False) -> list[Any]: ... - @staticmethod def cyclotomic(n: int, /) -> fmpz_poly: ... - def is_cyclotomic(self) -> int: ... - @staticmethod def cos_minpoly(n: int, /) -> fmpz_poly: ... - @staticmethod def chebyshev_t(n: int, /) -> fmpz_poly: ... - @staticmethod def chebyshev_u(n: int, /) -> fmpz_poly: ... - @staticmethod def swinnerton_dyer(n: int, /, use_arb: bool = True) -> fmpz_poly: ... - @staticmethod def hilbert_class_poly(D: int, /) -> fmpz_poly: ... - def height_bits(self, signed: bool = False) -> int: ... diff --git a/src/flint/types/fmpz_poly.pyx b/src/flint/types/fmpz_poly.pyx index 74037cba..6cc05fa0 100644 --- a/src/flint/types/fmpz_poly.pyx +++ b/src/flint/types/fmpz_poly.pyx @@ -171,6 +171,21 @@ cdef class fmpz_poly(flint_poly): """ return fmpz_poly_degree(self.val) <= 0 + def is_gen(self): + """ + Return ``True`` if the polynomial is the generator + of the polynomial, `x`, and ``False`` otherwise + + >>> x = fmpz_poly([0, 1]) + >>> x + x + >>> x.is_gen() + True + >>> (x + 1).is_gen() + False + """ + return fmpz_poly_is_gen(self.val) + def leading_coefficient(self): """ Returns the leading coefficient of the polynomial. diff --git a/src/flint/types/fq_default.pyi b/src/flint/types/fq_default.pyi new file mode 100644 index 00000000..c2993511 --- /dev/null +++ b/src/flint/types/fq_default.pyi @@ -0,0 +1,74 @@ +from enum import Enum +from ..flint_base.flint_base import flint_scalar +from .fmpz import fmpz +from .fmpz_mod import fmpz_mod, ifmpz +from .fmpz_poly import fmpz_poly +from .nmod_poly import nmod_poly +from .fmpz_mod_poly import fmpz_mod_poly + +class fq_default_type(Enum): + DEFAULT = 0 + FQ_ZECH = 1 + FQ_NMOD = 2 + FQ = 3 + NMOD = 4 + FMPZ_MOD = 5 + +ifmpz_mod = ifmpz | fmpz_mod +ifq_default = fq_default | fmpz_mod_poly | nmod_poly | fmpz_poly | ifmpz_mod + +class fq_default_ctx: + r"""Context object for creating :class:`~.fq_default`.""" + + def __init__( + self, + p: ifmpz | None = None, + degree: int | None = None, + var: str | None = None, + modulus: fmpz_mod_poly | fmpz_poly | None = None, + fq_type: str | int | fq_default_type = fq_default_type.DEFAULT, + check_prime: bool = True, + check_modulus: bool = True, + ): ... + @property + def fq_type(self) -> fq_default_type: ... + def degree(self) -> int: ... + def characteristic(self) -> fmpz: ... + def prime(self) -> fmpz: ... + def order(self) -> fmpz: ... + def multiplicative_order(self) -> fmpz: ... + def modulus(self) -> fmpz_mod_poly: ... + def zero(self) -> fq_default: ... + def one(self) -> fq_default: ... + def gen(self) -> fq_default: ... + def random_element(self, not_zero: bool = False) -> fq_default: ... + def __call__(self, val: ifq_default) -> fq_default: ... + +class fq_default(flint_scalar): + def __init__(self, val: list[ifmpz] | ifq_default, ctx: fq_default_ctx): ... + def __int__(self) -> int: ... + def polynomial(self) -> fmpz_mod_poly: ... + def to_list(self) -> list[ifmpz]: ... + def str(self) -> str: ... + def __hash__(self) -> int: ... + def is_zero(self) -> bool: ... + def is_one(self) -> bool: ... + def inverse(self) -> fq_default: ... + def square(self) -> fq_default: ... + def __neg__(self) -> fq_default: ... + def __add__(self, other: ifq_default, /) -> fq_default: ... + def __radd__(self, other: ifq_default, /) -> fq_default: ... + def __sub__(self, other: ifq_default, /) -> fq_default: ... + def __rsub__(self, other: ifq_default, /) -> fq_default: ... + def __mul__(self, other: ifq_default, /) -> fq_default: ... + def __rmul__(self, other: ifq_default, /) -> fq_default: ... + def __truediv__(self, other: ifq_default, /) -> fq_default: ... + def __rtruediv__(self, other: ifq_default, /) -> fq_default: ... + def __invert__(self) -> fq_default: ... + def __pow__(self, e: ifmpz) -> fq_default: ... + def sqrt(self) -> fq_default: ... + def is_square(self) -> bool: ... + def pth_root(self) -> fq_default: ... + def trace(self) -> fmpz: ... + def norm(self) -> fmpz: ... + def frobenius(self, e: int = ...) -> fq_default: ... diff --git a/src/flint/types/fq_default_poly.pyi b/src/flint/types/fq_default_poly.pyi new file mode 100644 index 00000000..839909ab --- /dev/null +++ b/src/flint/types/fq_default_poly.pyi @@ -0,0 +1,143 @@ +from typing import overload, Sequence +from flint.flint_base.flint_base import _flint_poly_exact +from .fmpz import fmpz, ifmpz +from .fmpz_mod import fmpz_mod +from .fmpz_poly import fmpz_poly, ifmpz_poly +from .fmpz_mod_poly import fmpz_mod_poly +from .fq_default import fq_default_type, fq_default_ctx, fq_default, ifq_default + +ifmpz_mod = int | fmpz | fmpz_mod +ifq_default_poly = fq_default_poly | ifq_default | ifmpz_poly + +class fq_default_poly_ctx: + r"""Context object for creating :class:`~.fq_default_poly` initialised + with a finite field `GF(p^d)`. + """ + + @overload + def __init__(self, p: fq_default_ctx, /) -> None: ... + @overload + def __init__( + self, + p: fq_default_ctx | ifmpz | None = None, + degree: int | None = None, + var: str | None = None, + modulus: fmpz_mod_poly | fmpz_poly | None = None, + fq_type: str | int | fq_default_type = fq_default_type.DEFAULT, + check_prime: bool = True, + check_modulus: bool = True, + ): ... + def base_field(self) -> fq_default_ctx: ... + def characteristic(self) -> fmpz: ... + def prime(self) -> fmpz: ... + def zero(self) -> fq_default_poly: ... + def one(self) -> fq_default_poly: ... + def gen(self) -> fq_default_poly: ... + def random_element( + self, + degree: int = 3, + not_zero: bool = False, + monic: bool = False, + irreducible: bool = False, + ) -> fq_default_poly: ... + def __str__(self) -> str: ... + def __repr__(self) -> str: ... + def __call__(self, val: ifq_default_poly) -> fq_default_poly: ... + +class fq_default_poly(_flint_poly_exact[fq_default]): + """ + The *fq_default_poly* type represents univariate polynomials + over a finite field. + """ + + def __init__( + self, + other: Sequence[ifq_default] | ifq_default_poly, + ctx: fq_default_poly_ctx, + /, + ) -> None: ... + def context(self) -> fq_default_poly_ctx: ... + def __getitem__(self, i: int, /) -> fq_default: ... + def __setitem__(self, i: int, x: ifq_default, /) -> None: ... + def __len__(self) -> int: ... + def length(self) -> int: ... + def degree(self) -> int: ... + def constant_coefficient(self) -> fq_default: ... + def leading_coefficient(self) -> fq_default: ... + def reverse(self, degree: int | None = None) -> fq_default_poly: ... + def truncate(self, n: int) -> fq_default_poly: ... + def monic(self) -> fq_default_poly: ... + def is_zero(self) -> bool: ... + def is_one(self) -> bool: ... + def is_gen(self) -> bool: ... + def is_constant(self) -> bool: ... + def is_monic(self) -> bool: ... + def is_irreducible(self) -> bool: ... + def is_squarefree(self) -> bool: ... + def __pos__(self) -> fq_default_poly: ... + def __neg__(self) -> fq_default_poly: ... + def __add__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __radd__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __sub__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __rsub__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __mul__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __rmul__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __floordiv__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __rfloordiv__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __mod__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __rmod__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __divmod__( + self, other: ifq_default_poly, / + ) -> tuple[fq_default_poly, fq_default_poly]: ... + def __rdivmod__( + self, other: ifq_default_poly, / + ) -> tuple[fq_default_poly, fq_default_poly]: ... + def __truediv__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __rtruediv__(self, other: ifq_default_poly, /) -> fq_default_poly: ... + def __pow__( + self, e: int, mod: ifq_default_poly | None = None + ) -> fq_default_poly: ... + def pow_mod(self, e: int, modulus: ifq_default_poly) -> fq_default_poly: ... + def divmod( + self, other: ifq_default_poly + ) -> tuple[fq_default_poly, fq_default_poly]: ... + def exact_division(self, other: ifq_default_poly) -> fq_default_poly: ... + def gcd(self, other: ifq_default_poly) -> fq_default_poly: ... + def xgcd( + self, other: ifq_default_poly, / + ) -> tuple[fq_default_poly, fq_default_poly, fq_default_poly]: ... + def square(self) -> fq_default_poly: ... + def left_shift(self, n: int) -> fq_default_poly: ... + def right_shift(self, n: int) -> fq_default_poly: ... + def sqrt(self) -> fq_default_poly: ... + def mul_mod( + self, other: ifq_default_poly, modulus: ifq_default_poly + ) -> fq_default_poly: ... + def equal_trunc(self, other: ifq_default_poly, n: int) -> bool: ... + def add_trunc(self, other: ifq_default_poly, n: int) -> fq_default_poly: ... + def sub_trunc(self, other: ifq_default_poly, n: int) -> fq_default_poly: ... + def mul_low(self, other: ifq_default_poly, n: int) -> fq_default_poly: ... + def pow_trunc(self, e: int, n: int) -> fq_default_poly: ... + def sqrt_trunc(self, n: int) -> fq_default_poly: ... + def inv_sqrt_trunc(self, n: int) -> fq_default_poly: ... + def inverse_series_trunc(self, n: int) -> fq_default_poly: ... + def inverse_mod(self, other: ifq_default_poly) -> fq_default_poly: ... + def derivative(self) -> fq_default_poly: ... + def radical(self) -> fq_default_poly: ... + def inflate(self, n: int) -> fq_default_poly: ... + def deflate(self, n: int) -> fq_default_poly: ... + def deflation(self) -> tuple[fq_default_poly, int]: ... + @overload + def __call__(self, input: ifq_default) -> fq_default: ... + @overload + def __call__(self, input: fq_default_poly) -> fq_default_poly: ... + def evaluate(self, input: ifq_default) -> fq_default_poly: ... + def compose(self, other: ifq_default_poly) -> fq_default_poly: ... + def compose_mod( + self, other: ifq_default_poly, modulus: ifq_default_poly + ) -> fq_default_poly: ... + def factor_squarefree( + self, + ) -> tuple[fq_default, list[tuple[fq_default_poly, int]]]: ... + def factor(self) -> tuple[fq_default, list[tuple[fq_default_poly, int]]]: ... + def roots(self, multiplicities=True) -> list[tuple[fq_default, int]]: ... diff --git a/src/flint/types/fq_default_poly.pyx b/src/flint/types/fq_default_poly.pyx index c5dcd3bc..58405f47 100644 --- a/src/flint/types/fq_default_poly.pyx +++ b/src/flint/types/fq_default_poly.pyx @@ -278,6 +278,13 @@ cdef class fq_default_poly(flint_poly): if check is NotImplemented: raise TypeError + def context(self): + return self.ctx + + def repr(self): + coeffs_str = ", ".join(map(str, self.coeffs())) + return f"fq_default_poly([{coeffs_str}], {self.ctx!r})" + def __getitem__(self, long i): cdef fq_default x x = self.ctx.field.new_ctype_fq_default() diff --git a/src/flint/types/nmod_poly.pyi b/src/flint/types/nmod_poly.pyi new file mode 100644 index 00000000..8a7c6342 --- /dev/null +++ b/src/flint/types/nmod_poly.pyi @@ -0,0 +1,69 @@ +from typing import overload, Iterator, Sequence +from flint.flint_base.flint_base import _flint_poly_exact +from flint.types.nmod import inmod, nmod +from flint.types.fmpz_poly import fmpz_poly + +inmod_poly = nmod_poly | fmpz_poly | inmod + +class nmod_poly(_flint_poly_exact[nmod]): + """Dense univariate polynomials over Z/nZ for word-size n.""" + + @overload + def __init__(self, val: nmod_poly) -> None: ... + @overload + def __init__(self, val: Sequence[inmod] | inmod_poly, mod: int) -> None: ... + def __len__(self) -> int: ... + def length(self) -> int: ... + def degree(self) -> int: ... + def modulus(self) -> int: ... + def __iter__(self) -> Iterator[nmod]: ... + def coeffs(self) -> list[nmod]: ... + def repr(self) -> str: ... + def __getitem__(self, i: int) -> nmod: ... + def __setitem__(self, i: int, x: inmod) -> None: ... + def __bool__(self) -> bool: ... + def is_zero(self) -> bool: ... + def is_one(self) -> bool: ... + def is_constant(self) -> bool: ... + def is_gen(self) -> bool: ... + def reverse(self, degree: int | None = None) -> nmod_poly: ... + def leading_coefficient(self) -> nmod: ... + def inverse_series_trunc(self, n: int) -> nmod_poly: ... + def compose(self, other: inmod_poly) -> nmod_poly: ... + def compose_mod(self, other: inmod_poly, modulus: inmod_poly) -> nmod_poly: ... + @overload + def __call__(self, other: inmod) -> nmod: ... + @overload + def __call__(self, other: nmod_poly | fmpz_poly) -> nmod_poly: ... + def derivative(self) -> nmod_poly: ... + def integral(self) -> nmod_poly: ... + def __pos__(self) -> nmod_poly: ... + def __neg__(self) -> nmod_poly: ... + def __add__(self, other: inmod_poly) -> nmod_poly: ... + def __radd__(self, other: inmod_poly) -> nmod_poly: ... + def __sub__(self, other: inmod_poly) -> nmod_poly: ... + def __rsub__(self, other: inmod_poly) -> nmod_poly: ... + def __mul__(self, other: inmod_poly) -> nmod_poly: ... + def __rmul__(self, other: inmod_poly) -> nmod_poly: ... + def __truediv__(self, other: inmod_poly) -> nmod_poly: ... + def __rtruediv__(self, other: inmod_poly) -> nmod_poly: ... + def __floordiv__(self, other: inmod_poly) -> nmod_poly: ... + def __rfloordiv__(self, other: inmod_poly) -> nmod_poly: ... + def __mod__(self, other: inmod_poly) -> nmod_poly: ... + def __rmod__(self, other: inmod_poly) -> nmod_poly: ... + def __divmod__(self, other: inmod_poly) -> tuple[nmod_poly, nmod_poly]: ... + def __rdivmod__(self, other: inmod_poly) -> tuple[nmod_poly, nmod_poly]: ... + def __pow__(self, other: int, mod: inmod_poly | None = None) -> nmod_poly: ... + def pow_mod( + self, e: int, modulus: inmod_poly, mod_rev_inv: inmod_poly | None = None + ) -> nmod_poly: ... + def gcd(self, other: inmod_poly) -> nmod_poly: ... + def resultant(self, other: inmod_poly) -> nmod: ... + def xgcd(self, other: inmod_poly) -> tuple[nmod_poly, nmod_poly, nmod_poly]: ... + def factor( + self, algorithm: str | None = None + ) -> tuple[nmod, list[tuple[nmod_poly, int]]]: ... + def factor_squarefree(self) -> tuple[nmod, list[tuple[nmod_poly, int]]]: ... + def sqrt(self) -> nmod_poly: ... + def deflation(self) -> tuple[nmod_poly, int]: ... + def roots(self) -> list[tuple[nmod, int]]: ...