Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions quaddtype/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))
Expand Down Expand Up @@ -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
Expand All @@ -134,4 +137,4 @@ py.extension_module('_quaddtype_main',
install: true,
subdir: 'numpy_quaddtype',
include_directories: [includes, build_includes],
)
)
56 changes: 56 additions & 0 deletions quaddtype/numpy_quaddtype/__init__.pyi
Original file line number Diff line number Diff line change
@@ -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
134 changes: 134 additions & 0 deletions quaddtype/numpy_quaddtype/_quaddtype_main.pyi
Original file line number Diff line number Diff line change
@@ -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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong - we need an override for the function since it returns normal integers for the integer constants bits and precision

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yea of course; "bits" and "precision" return an int. I'll fix this in a follow-up.

And out of curiosity, why is this a function instead of "bare" constants?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wanted to keep all definitions in the C(++) code so that Python only re-exports them

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constants can be re-exported 🤷🏻

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean declaring the value a Python constant in the C++ code? That could be nice, though not something I'd know how to do

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea pretty much, but I'm not much of a C expert, so maybe I'm talking nonsense here. Although for the int ones it shouldn't be too difficult I'm guessing?

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"
]: ...
Empty file.
16 changes: 15 additions & 1 deletion quaddtype/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,18 @@ dependencies = [
test = [
"pytest",
"pytest-run-parallel"
]
]

[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
Loading