-
-
Notifications
You must be signed in to change notification settings - Fork 12
implement same_value casting for numpy <-> quadtype #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0d234bd
5cd17c8
36b7a64
445d544
b35756a
e7143dd
40c1ba9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
#define PY_ARRAY_UNIQUE_SYMBOL QuadPrecType_ARRAY_API | ||
#define PY_UFUNC_UNIQUE_SYMBOL QuadPrecType_UFUNC_API | ||
#define NPY_NO_DEPRECATED_API NPY_2_0_API_VERSION | ||
#define NPY_TARGET_VERSION NPY_2_0_API_VERSION | ||
#ifndef NPY_TARGET_VERSION | ||
#define NPY_TARGET_VERSION NPY_2_0_API_VERSION | ||
#endif | ||
#define NO_IMPORT_ARRAY | ||
#define NO_IMPORT_UFUNC | ||
|
||
|
@@ -21,6 +23,11 @@ extern "C" { | |
#include "casts.h" | ||
#include "dtype.h" | ||
|
||
#if NPY_FEATURE_VERSION < NPY_2_0_API_VERSION | ||
#warning "Is NPY_TARGET_VERSION set too high for this numpy installation?" | ||
#error "NPY_FEATURE_VERSION too low, must be > NPY_2_0_API_VERSION" | ||
#endif | ||
|
||
#define NUM_CASTS 34 // 16 to_casts + 16 from_casts + 1 quad_to_quad + 1 void_to_quad | ||
|
||
static NPY_CASTING | ||
|
@@ -157,7 +164,7 @@ void_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta * | |
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], | ||
npy_intp *view_offset) | ||
{ | ||
PyErr_SetString(PyExc_TypeError, | ||
PyErr_SetString(PyExc_TypeError, | ||
"Void to QuadPrecision cast is not implemented"); | ||
return (NPY_CASTING)-1; | ||
} | ||
|
@@ -401,7 +408,7 @@ to_quad<long double>(long double x, QuadBackendType backend) | |
} | ||
|
||
template <typename T> | ||
static NPY_CASTING | ||
static int | ||
numpy_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta *dtypes[2], | ||
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], | ||
npy_intp *view_offset) | ||
|
@@ -419,7 +426,11 @@ numpy_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta | |
} | ||
|
||
loop_descrs[0] = PyArray_GetDefaultDescr(dtypes[0]); | ||
#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) | ||
return NPY_SAFE_CASTING | NPY_SAME_VALUE_CASTING_FLAG; | ||
#else | ||
return NPY_SAFE_CASTING; | ||
#endif | ||
} | ||
|
||
template <typename T> | ||
|
@@ -667,6 +678,27 @@ from_quad<long double>(quad_value x, QuadBackendType backend) | |
} | ||
|
||
template <typename T> | ||
static inline int | ||
from_quad_checked(quad_value x, QuadBackendType backend, typename NpyType<T>::TYPE *ret) { | ||
*ret = from_quad<typename NpyType<T>::TYPE>(x, backend); | ||
quad_value check = to_quad<typename NpyType<T>::TYPE>(*ret, backend); | ||
if (backend == BACKEND_SLEEF) { | ||
if (check.sleef_value == x.sleef_value) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just compare sleef values here? Should this use equality with NaN = NaN? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I was following the pattern from elsewhere. Is it guaranteed that the sleef backend is used?
Good point! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the SLEEF branch, I was thinking of |
||
return 0; | ||
} | ||
} | ||
else { | ||
if (check.longdouble_value == x.longdouble_value) { | ||
return 0; | ||
} | ||
} | ||
NPY_ALLOW_C_API_DEF; | ||
NPY_ALLOW_C_API; | ||
PyErr_SetString(PyExc_ValueError, "could not cast 'same_value' to QuadType"); | ||
NPY_DISABLE_C_API; | ||
return -1; | ||
} | ||
|
||
static NPY_CASTING | ||
quad_to_numpy_resolve_descriptors(PyObject *NPY_UNUSED(self), PyArray_DTypeMeta *dtypes[2], | ||
PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], | ||
|
@@ -694,6 +726,28 @@ quad_to_numpy_strided_loop_unaligned(PyArrayMethod_Context *context, char *const | |
|
||
size_t elem_size = (backend == BACKEND_SLEEF) ? sizeof(Sleef_quad) : sizeof(long double); | ||
|
||
#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) | ||
int same_value_casting = 0; | ||
if (PyArray_GetNDArrayCFeatureVersion() > NPY_2_3_API_VERSION) { | ||
same_value_casting = ((context->flags & NPY_SAME_VALUE_CONTEXT_FLAG) == NPY_SAME_VALUE_CONTEXT_FLAG); | ||
} | ||
if (same_value_casting) { | ||
while (N--) { | ||
quad_value in_val; | ||
memcpy(&in_val, in_ptr, elem_size); | ||
typename NpyType<T>::TYPE out_val; | ||
if (from_quad_checked<T>(in_val, backend, &out_val) < 0) { | ||
return -1; | ||
} | ||
memcpy(out_ptr, &out_val, sizeof(typename NpyType<T>::TYPE)); | ||
|
||
in_ptr += strides[0]; | ||
out_ptr += strides[1]; | ||
} | ||
} else { | ||
#else | ||
{ | ||
#endif | ||
while (N--) { | ||
quad_value in_val; | ||
memcpy(&in_val, in_ptr, elem_size); | ||
|
@@ -703,7 +757,7 @@ quad_to_numpy_strided_loop_unaligned(PyArrayMethod_Context *context, char *const | |
|
||
in_ptr += strides[0]; | ||
out_ptr += strides[1]; | ||
} | ||
}} | ||
return 0; | ||
} | ||
|
||
|
@@ -720,6 +774,33 @@ quad_to_numpy_strided_loop_aligned(PyArrayMethod_Context *context, char *const d | |
QuadPrecDTypeObject *quad_descr = (QuadPrecDTypeObject *)context->descriptors[0]; | ||
QuadBackendType backend = quad_descr->backend; | ||
|
||
#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) | ||
int same_value_casting = 0; | ||
if (PyArray_GetNDArrayCFeatureVersion() > NPY_2_3_API_VERSION) { | ||
same_value_casting = ((context->flags & NPY_SAME_VALUE_CONTEXT_FLAG) == NPY_SAME_VALUE_CONTEXT_FLAG); | ||
} | ||
if (same_value_casting) { | ||
while (N--) { | ||
quad_value in_val; | ||
if (backend == BACKEND_SLEEF) { | ||
in_val.sleef_value = *(Sleef_quad *)in_ptr; | ||
} | ||
else { | ||
in_val.longdouble_value = *(long double *)in_ptr; | ||
} | ||
|
||
typename NpyType<T>::TYPE out_val; | ||
if (from_quad_checked<T>(in_val, backend, &out_val) < 0) { | ||
return -1; | ||
} | ||
*(typename NpyType<T>::TYPE *)(out_ptr) = out_val; | ||
|
||
in_ptr += strides[0]; | ||
out_ptr += strides[1]; | ||
}} else { | ||
#else | ||
{ | ||
#endif | ||
while (N--) { | ||
quad_value in_val; | ||
if (backend == BACKEND_SLEEF) { | ||
|
@@ -734,7 +815,7 @@ quad_to_numpy_strided_loop_aligned(PyArrayMethod_Context *context, char *const d | |
|
||
in_ptr += strides[0]; | ||
out_ptr += strides[1]; | ||
} | ||
}} | ||
return 0; | ||
} | ||
|
||
|
@@ -762,7 +843,7 @@ add_cast_from(PyArray_DTypeMeta *to) | |
PyArray_DTypeMeta **dtypes = new PyArray_DTypeMeta *[2]{&QuadPrecDType, to}; | ||
|
||
PyType_Slot *slots = new PyType_Slot[]{ | ||
{NPY_METH_resolve_descriptors, (void *)&quad_to_numpy_resolve_descriptors<T>}, | ||
{NPY_METH_resolve_descriptors, (void *)&quad_to_numpy_resolve_descriptors}, | ||
{NPY_METH_strided_loop, (void *)&quad_to_numpy_strided_loop_aligned<T>}, | ||
{NPY_METH_unaligned_strided_loop, (void *)&quad_to_numpy_strided_loop_unaligned<T>}, | ||
{0, nullptr}}; | ||
|
@@ -771,7 +852,11 @@ add_cast_from(PyArray_DTypeMeta *to) | |
.name = "cast_QuadPrec_to_NumPy", | ||
.nin = 1, | ||
.nout = 1, | ||
#if defined(NPY_2_3_API_VERSION) && (NPY_TARGET_VERSION > NPY_2_3_API_VERSION) | ||
.casting = NPY_SAME_VALUE_CASTING, | ||
#else | ||
.casting = NPY_UNSAFE_CASTING, | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not clear how this is used, doesn't the resolver actually state which casting is supported? |
||
.flags = NPY_METH_SUPPORTS_UNALIGNED, | ||
.dtypes = dtypes, | ||
.slots = slots, | ||
|
@@ -904,4 +989,4 @@ free_casts(void) | |
} | ||
} | ||
spec_count = 0; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
#include <algorithm> | ||
|
||
#ifndef DISABLE_QUADBLAS | ||
#include "../subprojects/qblas/include/quadblas/quadblas.hpp" | ||
#include "quadblas/quadblas.hpp" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I needed this to build with |
||
#endif // DISABLE_QUADBLAS | ||
|
||
extern "C" { | ||
|
@@ -230,4 +230,4 @@ _quadblas_get_num_threads(void) | |
|
||
#endif // DISABLE_QUADBLAS | ||
|
||
} // extern "C" | ||
} // extern "C" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I think this is OK? I didn't see any new warnings, but there are thousands of build warnings when using sleef and I might have missed it.