diff --git a/src/flint/flint_base/flint_base.pyi b/src/flint/flint_base/flint_base.pyi index f1c27b06..0aea4f6e 100644 --- a/src/flint/flint_base/flint_base.pyi +++ b/src/flint/flint_base/flint_base.pyi @@ -36,13 +36,13 @@ 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 __add__(self, other: int, /) -> Self: ... def __radd__(self, other: int, /) -> Self: ... - def __sub__(self, other: Self | int, /) -> Self: ... + def __sub__(self, other: int, /) -> Self: ... def __rsub__(self, other: int, /) -> Self: ... - def __mul__(self, other: Self | int, /) -> Self: ... + def __mul__(self, other: int, /) -> Self: ... def __rmul__(self, other: int, /) -> Self: ... - def __truediv__(self, other: Self | int, /) -> Self: ... + def __truediv__(self, other: int, /) -> Self: ... def __rtruediv__(self, other: int, /) -> Self: ... def __pow__(self, other: int, /) -> Self: ... def __rpow__(self, other: int, /) -> Self: ... @@ -90,15 +90,6 @@ class flint_poly(flint_elem, Generic[Telem]): 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" diff --git a/src/flint/flint_base/meson.build b/src/flint/flint_base/meson.build index 6c6943d7..f69d99f2 100644 --- a/src/flint/flint_base/meson.build +++ b/src/flint/flint_base/meson.build @@ -2,6 +2,7 @@ pkgdir = 'flint/flint_base' pyfiles = [ '__init__.py', + 'flint_base.pyi', ] exts = [ diff --git a/src/flint/meson.build b/src/flint/meson.build index 4ed3dc99..061ed3c7 100644 --- a/src/flint/meson.build +++ b/src/flint/meson.build @@ -2,6 +2,8 @@ thisdir = 'flint' pyfiles = [ '__init__.py', + 'typing.py', + 'py.typed', ] exts = [ diff --git a/src/flint/py.typed b/src/flint/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index 59d1c46a..8325b8ab 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -8,6 +8,7 @@ import random import flint +import flint.typing as typ import flint.flint_base.flint_base as flint_base from flint.utils.flint_exceptions import DomainError, IncompatibleContextError @@ -26,13 +27,10 @@ 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) @@ -2621,17 +2619,11 @@ def _all_polys() -> list[tuple[Any, Any, bool, flint.fmpz]]: ] -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] +Tpoly = TypeVar("Tpoly", bound=typ.epoly_p) +Tc = TypeVar("Tc", bound=flint_base.flint_scalar) +TS = Callable[[Tc | int], Tc] +TP = Callable[[Tpoly | Sequence[Tc | int] | Tc | int], Tpoly] +_PolyTestCase = tuple[TP[Tpoly,Tc], TS[Tc], bool, flint.fmpz] def _for_all_polys(test: Callable[[_PolyTestCase], None]) -> None: @@ -2639,14 +2631,14 @@ def _for_all_polys(test: Callable[[_PolyTestCase], None]) -> None: # 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 + fmpz: TS[flint.fmpz] = flint.fmpz + fmpq: TS[flint.fmpq] = flint.fmpq + fmpz_poly: TP[flint.fmpz_poly, flint.fmpz] = flint.fmpz_poly + fmpq_poly: TP[flint.fmpq_poly, flint.fmpq] = flint.fmpq_poly def nmod_poly( p: int, - ) -> tuple[_TPoly[flint.nmod_poly, flint.nmod], _Telem[flint.nmod]]: + ) -> tuple[TP[flint.nmod_poly, flint.nmod], TS[flint.nmod]]: """Make nmod poly and scalar constructors for modulus p.""" def poly( @@ -2661,7 +2653,7 @@ def elem(x: int | flint.nmod = 0, /) -> flint.nmod: def fmpz_mod_poly( p: int, - ) -> tuple[_TPoly[flint.fmpz_mod_poly, flint.fmpz_mod], _Telem[flint.fmpz_mod]]: + ) -> tuple[TP[flint.fmpz_mod_poly, flint.fmpz_mod], TS[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) @@ -2683,7 +2675,7 @@ def elem(x: int | flint.fmpz_mod = 0, /) -> flint.fmpz_mod: def fq_default_poly( p: int, k: int | None = None ) -> tuple[ - _TPoly[flint.fq_default_poly, flint.fq_default], _Telem[flint.fq_default] + TP[flint.fq_default_poly, flint.fq_default], TS[flint.fq_default] ]: """Make fq_default poly and scalar constructors for field p^k.""" if k is None: @@ -2740,7 +2732,7 @@ def wrapper(): @all_polys -def test_polys(args: _PolyTestCase[Tpoly, Tscalar]) -> None: +def test_polys(args: _PolyTestCase[typ.epoly_p[Tc], Tc]) -> None: # To test type annotations, uncomment: # P: type[flint.fmpq_poly] # S: type[flint.fmpq] @@ -2872,7 +2864,7 @@ def setbad(obj, i, val): assert P([1, 2, 3]) + P([4, 5, 6]) == P([5, 7, 9]) - for T in [int, S, flint.fmpz]: + 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]) @@ -2881,7 +2873,7 @@ def setbad(obj, i, val): assert P([1, 2, 3]) - P([4, 5, 6]) == P([-3, -3, -3]) - for T in [int, S, flint.fmpz]: + 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]) @@ -2890,7 +2882,7 @@ def setbad(obj, i, val): assert P([1, 2, 3]) * P([4, 5, 6]) == P([4, 13, 28, 27, 18]) - for T in [int, S, flint.fmpz]: + 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]) diff --git a/src/flint/types/fmpq_poly.pyi b/src/flint/types/fmpq_poly.pyi index b0207367..eeaeb45f 100644 --- a/src/flint/types/fmpq_poly.pyi +++ b/src/flint/types/fmpq_poly.pyi @@ -1,5 +1,5 @@ from typing import overload, Any, Sequence -from flint.flint_base.flint_base import _flint_poly_exact +from flint.flint_base.flint_base import flint_poly 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,7 +8,7 @@ from flint.types.fmpz_poly import fmpz_poly, ifmpz_poly ifmpq_poly = fmpq_poly | ifmpq | ifmpz_poly -class fmpq_poly(_flint_poly_exact[fmpq]): +class fmpq_poly(flint_poly[fmpq]): """ The *fmpq_poly* type represents dense univariate polynomials over the rational numbers. For efficiency reasons, an *fmpq_poly* is diff --git a/src/flint/types/fmpq_series.pyi b/src/flint/types/fmpq_series.pyi index 678c81b9..8ac0c3ee 100644 --- a/src/flint/types/fmpq_series.pyi +++ b/src/flint/types/fmpq_series.pyi @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Sequence from flint.flint_base.flint_base import flint_series from flint.types.fmpz import fmpz, ifmpz from flint.types.fmpq import fmpq, ifmpq @@ -13,7 +13,7 @@ class fmpq_series(flint_series[fmpq]): """Approximate truncated power series with rational coefficients.""" def __init__(self, - val: list[int] | list[ifmpq] | ifmpq | ifmpq_series | None = None, + val: Sequence[ifmpq] | ifmpq | ifmpq_series | None = None, den: ifmpz | None = None, prec: int | None = None): ... diff --git a/src/flint/types/fmpz_mod_poly.pyi b/src/flint/types/fmpz_mod_poly.pyi index ea81ab2f..bd863ba6 100644 --- a/src/flint/types/fmpz_mod_poly.pyi +++ b/src/flint/types/fmpz_mod_poly.pyi @@ -1,6 +1,6 @@ from typing import Literal, Sequence, overload -from flint.flint_base.flint_base import _flint_poly_exact +from flint.flint_base.flint_base import flint_poly 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 @@ -32,7 +32,7 @@ class fmpz_mod_poly_ctx: 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]): +class fmpz_mod_poly(flint_poly[fmpz_mod]): """ The *fmpz_mod_poly* type represents univariate polynomials over integer modulo an arbitrary-size modulus. diff --git a/src/flint/types/fmpz_poly.pyi b/src/flint/types/fmpz_poly.pyi index d3628b33..98cac647 100644 --- a/src/flint/types/fmpz_poly.pyi +++ b/src/flint/types/fmpz_poly.pyi @@ -1,12 +1,12 @@ from typing import overload, Any, Sequence -from flint.flint_base.flint_base import _flint_poly_exact +from flint.flint_base.flint_base import flint_poly 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_exact[fmpz]): +class fmpz_poly(flint_poly[fmpz]): """ The *fmpz_poly* type represents dense univariate polynomials over the integers. diff --git a/src/flint/types/fmpz_series.pyi b/src/flint/types/fmpz_series.pyi index a34d5bd5..c4f7f91c 100644 --- a/src/flint/types/fmpz_series.pyi +++ b/src/flint/types/fmpz_series.pyi @@ -10,7 +10,7 @@ ifmpz_series = fmpz_series | ifmpz_poly class fmpz_series(flint_series[fmpz]): def __init__(self, - val: list[int] | list[ifmpz] | fmpz_series | fmpz_poly | ifmpz | None = None, + val: Sequence[ifmpz] | fmpz_series | fmpz_poly | ifmpz | None = None, prec: int | None = None): ... @property diff --git a/src/flint/types/fq_default_poly.pyi b/src/flint/types/fq_default_poly.pyi index 839909ab..855143a0 100644 --- a/src/flint/types/fq_default_poly.pyi +++ b/src/flint/types/fq_default_poly.pyi @@ -1,5 +1,5 @@ from typing import overload, Sequence -from flint.flint_base.flint_base import _flint_poly_exact +from flint.flint_base.flint_base import flint_poly from .fmpz import fmpz, ifmpz from .fmpz_mod import fmpz_mod from .fmpz_poly import fmpz_poly, ifmpz_poly @@ -44,7 +44,7 @@ class fq_default_poly_ctx: def __repr__(self) -> str: ... def __call__(self, val: ifq_default_poly) -> fq_default_poly: ... -class fq_default_poly(_flint_poly_exact[fq_default]): +class fq_default_poly(flint_poly[fq_default]): """ The *fq_default_poly* type represents univariate polynomials over a finite field. diff --git a/src/flint/types/meson.build b/src/flint/types/meson.build index b5c2f953..cd8cc022 100644 --- a/src/flint/types/meson.build +++ b/src/flint/types/meson.build @@ -2,17 +2,63 @@ thisdir = 'flint/types' pyfiles = [ '__init__.py', + + 'fmpz.pyi', + 'fmpz_poly.pyi', + 'fmpz_series.pyi', + 'fmpz_mpoly.pyi', + # 'fmpz_mat.pyi', + # 'fmpz_vec.pyi', + + 'fmpq.pyi', + 'fmpq_poly.pyi', + 'fmpq_series.pyi', + 'fmpq_mpoly.pyi', + # 'fmpq_mat.pyi', + # 'fmpq_vec.pyi', + + 'nmod.pyi', + 'nmod_poly.pyi', + 'nmod_mpoly.pyi', + # 'nmod_mat.pyi', + # 'nmod_series.pyi', + + 'fmpz_mod.pyi', + 'fmpz_mod_poly.pyi', + 'fmpz_mod_mpoly.pyi', + # 'fmpz_mod_mat.pyi', + + 'fq_default.pyi', + 'fq_default_poly.pyi', + + # 'arf.pyi', + # + # 'arb.pyi', + # 'arb_poly.pyi', + # 'arb_mat.pyi', + # 'arb_series.pyi', + # + # 'acb.pyi', + # 'acb_poly.pyi', + # 'acb_mat.pyi', + # 'acb_series.pyi', + # + # 'dirichlet.pyi', + # + # '_gr.pyi', ] exts = [ 'fmpz', 'fmpz_poly', + 'fmpz_mpoly', 'fmpz_mat', 'fmpz_series', 'fmpz_vec', 'fmpq', 'fmpq_poly', + 'fmpq_mpoly', 'fmpq_mat', 'fmpq_series', 'fmpq_vec', @@ -25,6 +71,7 @@ exts = [ 'fmpz_mod', 'fmpz_mod_poly', + 'fmpz_mod_mpoly', 'fmpz_mod_mat', 'fq_default', @@ -44,10 +91,6 @@ exts = [ 'dirichlet', - 'fmpz_mpoly', - 'fmpz_mod_mpoly', - 'fmpq_mpoly', - '_gr', ] diff --git a/src/flint/types/nmod_poly.pyi b/src/flint/types/nmod_poly.pyi index 8a7c6342..a3941515 100644 --- a/src/flint/types/nmod_poly.pyi +++ b/src/flint/types/nmod_poly.pyi @@ -1,11 +1,11 @@ from typing import overload, Iterator, Sequence -from flint.flint_base.flint_base import _flint_poly_exact +from flint.flint_base.flint_base import flint_poly 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]): +class nmod_poly(flint_poly[nmod]): """Dense univariate polynomials over Z/nZ for word-size n.""" @overload diff --git a/src/flint/typing.py b/src/flint/typing.py new file mode 100644 index 00000000..76c71358 --- /dev/null +++ b/src/flint/typing.py @@ -0,0 +1,288 @@ +# +# +# +from typing import ( + TYPE_CHECKING, + Protocol, + TypeVar, + Iterator, + Iterable, + Any, + Self, + Mapping, + Sequence, + overload, +) + +from .flint_base.flint_base import ( + flint_elem, + flint_scalar, + flint_poly, + flint_mpoly, + flint_mpoly_context, + flint_series, + Ordering, +) + +from flint.types.fmpz import fmpz + +__all__ = [ + # Abstract base classes + "flint_elem", + "flint_scalar", + "flint_poly", + "flint_mpoly", + "flint_mpoly_context", + "flint_series", + + # Protocols + "elem_p", + "scalar_p", + "poly_p", + # "mpoly_p", + # "mpoly_context_p", + # "series_p", + + # Types + "Ordering", + "fmpz", + "ifmpz", +] + + +if TYPE_CHECKING: + import flint as _flint + + +_Telem = TypeVar("_Telem", bound=flint_scalar) +_Telem_co = TypeVar("_Telem_co", bound=flint_scalar, covariant=True) +_Telem_coerce = TypeVar("_Telem_coerce") +_Telem_coerce_contra = TypeVar("_Telem_coerce_contra", contravariant=True) +_Tmpoly = TypeVar("_Tmpoly", bound=flint_mpoly, covariant=True) +_Tctx = TypeVar("_Tctx", bound=flint_mpoly_context) +_Sctx = TypeVar("_Sctx", bound=flint_mpoly_context) + +_str = str + + +ifmpz = fmpz | int + + +class elem_p(Protocol): + """FLINT element Protocol.""" + def str(self) -> _str: ... + def repr(self) -> _str: ... + + +class scalar_p(elem_p, Protocol): + """FLINT scalar Protocol.""" + 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: ... + + +_Tscalar = TypeVar("_Tscalar", bound=scalar_p) + + +class poly_p(elem_p, Protocol[_Tscalar]): + """FLINT univariate polynomial Protocol.""" + def str( + self, ascending: bool = False, var: str = "x", *args: Any, **kwargs: Any + ) -> str: ... + def __iter__(self) -> Iterator[_Tscalar]: ... + def __getitem__(self, index: int, /) -> _Tscalar: ... + def __setitem__(self, index: int, value: _Tscalar | int, /) -> None: ... + def __len__(self) -> int: ... + def length(self) -> int: ... + def degree(self) -> int: ... + def coeffs(self) -> list[_Tscalar]: ... + @overload + def __call__(self, other: _Tscalar | ifmpz, /) -> _Tscalar: ... + @overload + def __call__(self, other: Self, /) -> Self: ... # pyright: ignore[reportOverlappingOverload] + + def __pos__(self) -> Self: ... + def __neg__(self) -> Self: ... + def __add__(self, other: _Tscalar | ifmpz | Self, /) -> Self: ... + def __radd__(self, other: _Tscalar | ifmpz, /) -> Self: ... + def __sub__(self, other: _Tscalar | ifmpz | Self, /) -> Self: ... + def __rsub__(self, other: _Tscalar | ifmpz, /) -> Self: ... + def __mul__(self, other: _Tscalar | ifmpz | Self, /) -> Self: ... + def __rmul__(self, other: _Tscalar | ifmpz, /) -> Self: ... + def __truediv__(self, other: _Tscalar | ifmpz | Self, /) -> Self: ... + def __rtruediv__(self, other: _Tscalar | ifmpz, /) -> Self: ... + def __floordiv__(self, other: _Tscalar | ifmpz | Self, /) -> Self: ... + def __rfloordiv__(self, other: _Tscalar | ifmpz, /) -> Self: ... + def __mod__(self, other: _Tscalar | ifmpz | Self, /) -> Self: ... + def __rmod__(self, other: _Tscalar | ifmpz, /) -> Self: ... + def __divmod__(self, other: _Tscalar | ifmpz | Self, /) -> tuple[Self, Self]: ... + def __rdivmod__(self, other: _Tscalar | ifmpz, /) -> 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[_Tscalar, 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 epoly_p(poly_p[_Tscalar], Protocol): + """FLINT exact univariate polynomial Protocol.""" + def sqrt(self) -> Self: ... + def gcd(self, other: Self | _Tscalar, /) -> Self: ... + def factor(self) -> tuple[_Tscalar, list[tuple[Self, int]]]: ... + def factor_squarefree(self) -> tuple[_Tscalar, list[tuple[Self, int]]]: ... + def deflation(self) -> tuple[Self, int]: ... + + +class _mpoly_p(elem_p, Protocol[_Tctx, _Telem, _Telem_coerce]): + """FLINT multivariate polynomial Protocol.""" + 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 __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: ... + def __radd__(self, other: _Telem | _Telem_coerce | int) -> Self: ... + def __sub__(self, other: Self | _Telem | _Telem_coerce | int) -> Self: ... + def __rsub__(self, other: _Telem | _Telem_coerce | int) -> Self: ... + def __mul__(self, other: Self | _Telem | _Telem_coerce | int) -> Self: ... + def __rmul__(self, other: _Telem | _Telem_coerce | int) -> Self: ... + def __truediv__(self, other: Self | _Telem | _Telem_coerce | int) -> Self: ... + def __rtruediv__(self, other: _Telem | _Telem_coerce | int) -> Self: ... + def __floordiv__(self, other: Self | _Telem | _Telem_coerce | int) -> Self: ... + 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 __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: ... + + +class _mpoly_context_p( + elem_p, Protocol[_Tmpoly, _Telem_co, _Telem_coerce_contra] +): + """FLINT multivariate polynomial context protocol.""" + def nvars(self) -> int: ... + def ordering(self) -> Ordering: ... + def gen(self, i: int, /) -> _Tmpoly: ... + def from_dict(self, d: Mapping[tuple[int, ...], _Telem_coerce_contra], /) -> _Tmpoly: ... + def constant(self, z: _Telem_coerce_contra, /) -> _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_contra | 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]: ... + @classmethod + def from_context( + cls, + ctx: _Sctx, + names: str | Iterable[str | tuple[str, int]] | tuple[str, int] | None = None, + ordering: Ordering | str = Ordering.lex, + ) -> _Sctx: ... + + +class _series_p(elem_p, Protocol[_Telem]): + """FLINT univariate power series.""" + + def __iter__(self) -> Iterator[_Telem]: ... + def coeffs(self) -> list[_Telem]: ... + + +if TYPE_CHECKING: + + _x1: scalar_p = _flint.fmpz(1) + _x2: scalar_p = _flint.fmpq(1, 2) + _x3: scalar_p = _flint.nmod(1, 2) + _x4: scalar_p = _flint.fmpz_mod(1, _flint.fmpz_mod_ctx(2)) + _x5: scalar_p = _flint.fq_default(1, _flint.fq_default_ctx(2)) + # XXX: Add arf, acf, arb, acb, ... + + _y1: poly_p[_flint.fmpz] = _flint.fmpz_poly([1, 2]) + _y2: poly_p[_flint.fmpq] = _flint.fmpq_poly([1, 2]) + _y3: poly_p[_flint.nmod] = _flint.nmod_poly(1, 2) + _y4: poly_p[_flint.fmpz_mod] = _flint.fmpz_mod_poly(1, _flint.fmpz_mod_poly_ctx(2)) + _y5: poly_p[_flint.fq_default] = _flint.fq_default_poly(1, _flint.fq_default_poly_ctx(2)) + # XXX: Add arb_poly, acb_poly, ... + + _z1: epoly_p[_flint.fmpz] = _flint.fmpz_poly([1, 2]) + _z2: epoly_p[_flint.fmpq] = _flint.fmpq_poly([1, 2]) + _z3: epoly_p[_flint.nmod] = _flint.nmod_poly(1, 2) + _z4: epoly_p[_flint.fmpz_mod] = _flint.fmpz_mod_poly(1, _flint.fmpz_mod_poly_ctx(2)) + _z5: epoly_p[_flint.fq_default] = _flint.fq_default_poly(1, _flint.fq_default_poly_ctx(2))