diff --git a/quaddtype/meson.build b/quaddtype/meson.build index 04b506b..75e9e38 100644 --- a/quaddtype/meson.build +++ b/quaddtype/meson.build @@ -35,7 +35,7 @@ if openmp_dep.found() dependencies += openmp_dep endif -# compiler flags for QBLAS compatibility +# compiler flags for QBLAS compatibility if not is_windows # QBLAS requires extended numeric literals for Q suffix support # if compiler supports (usually gcc) @@ -61,14 +61,14 @@ foreach optional_attr: optional_variable_attributes code = ''' #pragma GCC diagnostic error "-Wattributes" #pragma clang diagnostic error "-Wattributes" - + int @0@ foo; - + int main() { return 0; } '''.format(attr) - + if c.compiles(code, name: optional_attr[0]) cdata.set10(optional_attr[1], true) message('Thread-local storage support found: @0@'.format(attr)) @@ -122,6 +122,9 @@ srcs = [ py.install_sources( [ 'numpy_quaddtype/__init__.py', + 'numpy_quaddtype/__init__.pyi', + 'numpy_quaddtype/_quaddtype_main.pyi', + 'numpy_quaddtype/py.typed', ], subdir: 'numpy_quaddtype', pure: false @@ -134,4 +137,4 @@ py.extension_module('_quaddtype_main', install: true, subdir: 'numpy_quaddtype', include_directories: [includes, build_includes], -) \ No newline at end of file +) diff --git a/quaddtype/numpy_quaddtype/__init__.pyi b/quaddtype/numpy_quaddtype/__init__.pyi new file mode 100644 index 0000000..ae9aa25 --- /dev/null +++ b/quaddtype/numpy_quaddtype/__init__.pyi @@ -0,0 +1,56 @@ +from typing import Final + +from ._quaddtype_main import ( + QuadPrecDType, + QuadPrecision, + _IntoQuad, # type-check only # pyright: ignore[reportPrivateUsage] + get_num_threads, + get_quadblas_version, + is_longdouble_128, + set_num_threads, +) + +__all__ = [ + "QuadPrecision", + "QuadPrecDType", + "SleefQuadPrecision", + "LongDoubleQuadPrecision", + "SleefQuadPrecDType", + "LongDoubleQuadPrecDType", + "is_longdouble_128", + "pi", + "e", + "log2e", + "log10e", + "ln2", + "ln10", + "max_value", + "epsilon", + "smallest_normal", + "smallest_subnormal", + "bits", + "precision", + "resolution", + "set_num_threads", + "get_num_threads", + "get_quadblas_version", +] + +def SleefQuadPrecision(value: _IntoQuad) -> QuadPrecision: ... +def LongDoubleQuadPrecision(value: _IntoQuad) -> QuadPrecision: ... +def SleefQuadPrecDType() -> QuadPrecDType: ... +def LongDoubleQuadPrecDType() -> QuadPrecDType: ... + +pi: Final[QuadPrecision] = ... +e: Final[QuadPrecision] = ... +log2e: Final[QuadPrecision] = ... +log10e: Final[QuadPrecision] = ... +ln2: Final[QuadPrecision] = ... +ln10: Final[QuadPrecision] = ... +max_value: Final[QuadPrecision] = ... +epsilon: Final[QuadPrecision] = ... +smallest_normal: Final[QuadPrecision] = ... +smallest_subnormal: Final[QuadPrecision] = ... +resolution: Final[QuadPrecision] = ... +bits: Final = 128 +precision: Final = 33 diff --git a/quaddtype/numpy_quaddtype/_quaddtype_main.pyi b/quaddtype/numpy_quaddtype/_quaddtype_main.pyi new file mode 100644 index 0000000..72c334b --- /dev/null +++ b/quaddtype/numpy_quaddtype/_quaddtype_main.pyi @@ -0,0 +1,134 @@ +from typing import Any, Literal, TypeAlias, final + +import numpy as np +from typing_extensions import Never, Self, override + +_Backend: TypeAlias = Literal["sleef", "longdouble"] +_IntoQuad: TypeAlias = QuadPrecision | float | str +_CastsQuad: TypeAlias = _IntoQuad | np.floating[Any] | np.integer[Any] | np.bool_ + +@final +class QuadPrecDType(np.dtype[QuadPrecision]): # type: ignore[misc, type-var] # pyright: ignore[reportGeneralTypeIssues, reportInvalidTypeArguments] + def __new__(cls, /, backend: _Backend = "sleef") -> Self: ... + + # `numpy.dtype` overrides + names: None # pyright: ignore[reportIncompatibleVariableOverride] + @property + @override + def alignment(self) -> Literal[16]: ... + @property + @override + def itemsize(self) -> Literal[16]: ... + @property + @override + def name(self) -> Literal["QuadPrecDType128"]: ... + @property + @override + def byteorder(self) -> Literal["|"]: ... + @property + @override + def char(self) -> Literal["\x00"]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @property + @override + def kind(self) -> Literal["\x00"]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @property + @override + def num(self) -> Literal[-1]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @property + @override + def shape(self) -> tuple[()]: ... + @property + @override + def ndim(self) -> Literal[0]: ... + @property + @override + def fields(self) -> None: ... + @property + @override + def base(self) -> Self: ... + @property + @override + def subdtype(self) -> None: ... + @property + @override + def hasobject(self) -> Literal[False]: ... + @property + @override + def isbuiltin(self) -> Literal[0]: ... + @property + @override + def isnative(self) -> Literal[True]: ... + @property + @override + def isalignedstruct(self) -> Literal[False]: ... + @override + def __getitem__(self, key: Never, /) -> Self: ... # type: ignore[override] + +@final +class QuadPrecision: # NOTE: It doesn't inherit from `np.generic` which is type-unsafe + def __new__(cls, /, value: _IntoQuad, backend: _Backend = "sleef") -> Self: ... + + # Rich comparison operators + # NOTE: Unlike other numpy scalars, these return `builtins.bool`, not `np.bool`. + @override + def __eq__(self, other: object, /) -> bool: ... + @override + def __ne__(self, other: object, /) -> bool: ... + def __lt__(self, other: _IntoQuad, /) -> bool: ... + def __le__(self, other: _IntoQuad, /) -> bool: ... + def __gt__(self, other: _IntoQuad, /) -> bool: ... + def __ge__(self, other: _IntoQuad, /) -> bool: ... + + # Binary operators + def __add__(self, other: _CastsQuad, /) -> Self: ... + def __radd__(self, other: _CastsQuad, /) -> Self: ... # type: ignore[misc] + def __sub__(self, other: _CastsQuad, /) -> Self: ... + def __rsub__(self, other: _CastsQuad, /) -> Self: ... + def __mul__(self, other: _CastsQuad, /) -> Self: ... + def __rmul__(self, other: _CastsQuad, /) -> Self: ... # type: ignore[misc] + def __pow__(self, other: _CastsQuad, mod: None = None, /) -> Self: ... + def __rpow__(self, other: _CastsQuad, mod: None = None, /) -> Self: ... + def __truediv__(self, other: _CastsQuad, /) -> Self: ... + def __rtruediv__(self, other: _CastsQuad, /) -> Self: ... + + # Unary operators + def __neg__(self, /) -> Self: ... + def __pos__(self, /) -> Self: ... + def __abs__(self, /) -> Self: ... + + # Conversion methods + def __bool__(self, /) -> bool: ... + def __int__(self, /) -> int: ... + def __float__(self, /) -> float: ... + + # String representation + @override + def __repr__(self, /) -> str: ... + @override + def __str__(self, /) -> str: ... + +# +def is_longdouble_128() -> bool: ... +def get_sleef_constant( + constant_name: Literal[ + "pi", + "e", + "log2e", + "log10e", + "ln2", + "ln10", + "max_value", + "epsilon", + "smallest_normal", + "smallest_subnormal", + "bits", + "precision", + "resolution", + ], + /, +) -> QuadPrecision: ... +def set_num_threads(num_threads: int, /) -> None: ... +def get_num_threads() -> int: ... +def get_quadblas_version() -> Literal[ + "QuadBLAS 1.0.0 - High Performance Quad Precision BLAS" +]: ... diff --git a/quaddtype/numpy_quaddtype/py.typed b/quaddtype/numpy_quaddtype/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/quaddtype/pyproject.toml b/quaddtype/pyproject.toml index 466b523..3934183 100644 --- a/quaddtype/pyproject.toml +++ b/quaddtype/pyproject.toml @@ -23,4 +23,18 @@ dependencies = [ test = [ "pytest", "pytest-run-parallel" -] \ No newline at end of file +] + +[tool.pyright] +include = ["numpy_quaddtype/*.pyi"] +typeCheckingMode = "strict" +enableTypeIgnoreComments = false +reportImplicitOverride = true +reportUnnecessaryTypeIgnoreComment = true + +[tool.mypy] +strict = true +strict_equality_for_none = true +exclude = ["build", "numpy_quaddtype/src", "subprojects", "tests"] +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] +warn_unreachable = false