| Server IP : 217.160.0.135 / Your IP : 216.73.216.73 Web Server : Apache System : Linux www 6.18.52-i1-ampere #1203 SMP Mon Sep 14 18:29:59 CEST 2026 aarch64 User : sws1074145052 ( 1074145052) PHP Version : 8.3.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /lib/python3/dist-packages/pythran/pythonic/numpy/ |
Upload File : |
//
// From NumpySrc/numpy/core/src/multiarray/compiled_base.c
/** @brief find index of a sorted array such that arr[i] <= key < arr[i + 1].
*
* If an starting index guess is in-range, the array values around this
* index are first checked. This allows for repeated calls for well-ordered
* keys (a very common case) to use the previous index as a very good guess.
*
* If the guess value is not useful, bisection of the array is used to
* find the index. If there is no such index, the return values are:
* key < arr[0] -- -1
* key == arr[len - 1] -- len - 1
* key > arr[len - 1] -- len
* The array is assumed contiguous and sorted in ascending order.
*
* @param key key value.
* @param arr contiguous sorted array to be searched.
* @param len length of the array.
* @param guess initial guess of index
* @return index
*/
#include "pythonic/numpy/isnan.hpp"
#include "pythonic/utils/functor.hpp"
#define LIKELY_IN_CACHE_SIZE 8
PYTHONIC_NS_BEGIN
template <typename npy_intp, typename npy_double, class T>
static npy_intp binary_search_with_guess(const npy_double key, const T &arr,
npy_intp len, npy_intp guess)
{
npy_intp imin = 0;
npy_intp imax = len;
/* Handle keys outside of the arr range first */
if (key > arr[len - 1]) {
return len;
} else if (key < arr[0]) {
return -1;
}
/*
* If len <= 4 use linear search.
* From above we know key >= arr[0] when we start.
*/
if (len <= 4) {
npy_intp i;
for (i = 1; i < len && key >= arr[i]; ++i)
;
return i - 1;
}
if (guess > len - 3) {
guess = len - 3;
}
if (guess < 1) {
guess = 1;
}
/* check most likely values: guess - 1, guess, guess + 1 */
if (key < arr[guess]) {
if (key < arr[guess - 1]) {
imax = guess - 1;
/* last attempt to restrict search to items in cache */
if (guess > LIKELY_IN_CACHE_SIZE &&
key >= arr[guess - LIKELY_IN_CACHE_SIZE]) {
imin = guess - LIKELY_IN_CACHE_SIZE;
}
} else {
/* key >= arr[guess - 1] */
return guess - 1;
}
} else {
/* key >= arr[guess] */
if (key < arr[guess + 1]) {
return guess;
} else {
/* key >= arr[guess + 1] */
if (key < arr[guess + 2]) {
return guess + 1;
} else {
/* key >= arr[guess + 2] */
imin = guess + 2;
/* last attempt to restrict search to items in cache */
if (guess < len - LIKELY_IN_CACHE_SIZE - 1 &&
key < arr[guess + LIKELY_IN_CACHE_SIZE]) {
imax = guess + LIKELY_IN_CACHE_SIZE;
}
}
}
}
/* finally, find index by bisection */
while (imin < imax) {
const npy_intp imid = imin + ((imax - imin) >> 1);
if (key >= arr[imid]) {
imin = imid + 1;
} else {
imax = imid;
}
}
return imin - 1;
}
//
//#undef LIKELY_IN_CACHE_SIZE
//
// NPY_NO_EXPORT PyObject *
// arr_interp(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
//{
//
// PyObject *fp, *xp, *x;
// PyObject *left = NULL, *right = NULL;
// PyArrayObject *afp = NULL, *axp = NULL, *ax = NULL, *af = NULL;
// npy_intp i, lenx, lenxp;
// double lval, rval;
// const double *dy, *dx, *dz;
// double *dres, *slopes = NULL;
//
// static char *kwlist[] = {"x", "xp", "fp", "left", "right", NULL};
//
// NPY_BEGIN_THREADS_DEF;
//
// if (!PyArg_ParseTupleAndKeywords(args, kwdict, "OOO|OO:interp", kwlist,
// &x, &xp, &fp, &left, &right)) {
// return NULL;
// }
//
// afp = (PyArrayObject *)PyArray_ContiguousFromAny(fp, double, 1, 1);
// if (afp == NULL) {
// return NULL;
// }
// axp = (PyArrayObject *)PyArray_ContiguousFromAny(xp, double, 1, 1);
// if (axp == NULL) {
// goto fail;
// }
// ax = (PyArrayObject *)PyArray_ContiguousFromAny(x, double, 0, 0);
// if (ax == NULL) {
// goto fail;
// }
// lenxp = PyArray_SIZE(axp);
// if (lenxp == 0) {
// PyErr_SetString(PyExc_ValueError,
// "array of sample points is empty");
// goto fail;
// }
// if (PyArray_SIZE(afp) != lenxp) {
// PyErr_SetString(PyExc_ValueError,
// "fp and xp are not of the same length.");
// goto fail;
// }
//
// af = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(ax),
// PyArray_DIMS(ax), double);
// if (af == NULL) {
// goto fail;
// }
// lenx = PyArray_SIZE(ax);
//
// dy = (const double *)PyArray_DATA(afp);
// dx = (const double *)PyArray_DATA(axp);
// dz = (const double *)PyArray_DATA(ax);
// dres = (double *)PyArray_DATA(af);
// /* Get left and right fill values. */
// if ((left == NULL) || (left == Py_None)) {
// lval = dy[0];
// }
// else {
// lval = PyFloat_AsDouble(left);
// if (error_converting(lval)) {
// goto fail;
// }
// }
// if ((right == NULL) || (right == Py_None)) {
// rval = dy[lenxp - 1];
// }
// else {
// rval = PyFloat_AsDouble(right);
// if (error_converting(rval)) {
// goto fail;
// }
// }
// xp->dx fp->dy x -> dz
// This is the output type, based on the type of T, which can be complex.
template <class T>
using out_type =
typename std::conditional<types::is_complex<typename T::dtype>::value,
std::complex<double>, double>::type;
template <typename npy_intp, typename T5, class T1, class T2, class T3,
class T4>
void do_interp(const T1 &dz, const T2 &dx, const T3 &dy, T4 &dres,
npy_intp lenxp, npy_intp lenx, T5 lval, T5 rval)
{
npy_intp i;
out_type<T3> *slopes = NULL;
std::vector<out_type<T3>> slope_vect;
/* binary_search_with_guess needs at least a 3 item long array */
if (lenxp == 1) {
const double xp_val = dx[0];
const out_type<T3> fp_val = dy[0];
// NPY_BEGIN_THREADS_THRESHOLDED(lenx);
for (i = 0; i < lenx; ++i) {
const double x_val = dz[i];
dres[i] = (x_val < xp_val) ? lval : ((x_val > xp_val) ? rval : fp_val);
}
// NPY_END_THREADS;
} else {
npy_intp j = 0;
/* only pre-calculate slopes if there are relatively few of them. */
if (lenxp <= lenx) {
slope_vect.resize(lenxp - 1);
slopes = slope_vect.data();
}
// NPY_BEGIN_THREADS;
if (slopes != NULL) {
for (i = 0; i < lenxp - 1; ++i) {
slopes[i] = (dy[i + 1] - dy[i]) / (dx[i + 1] - dx[i]);
}
}
for (i = 0; i < lenx; ++i) {
const double x_val = dz[i];
if (pythonic::numpy::functor::isnan()(x_val)) {
dres[i] = x_val;
continue;
}
j = binary_search_with_guess(x_val, dx, lenxp, j);
if (j == -1) {
dres[i] = lval;
} else if (j == lenxp) {
dres[i] = rval;
} else if (j == lenxp - 1) {
dres[i] = dy[j];
} else if (dx[j] == x_val) {
/* Avoid potential non-finite interpolation */
dres[i] = dy[j];
} else {
const out_type<T3> slope =
(slopes != NULL) ? slopes[j]
: (dy[j + 1] - dy[j]) / (dx[j + 1] - dx[j]);
dres[i] = slope * (x_val - dx[j]) + dy[j];
}
}
// NPY_END_THREADS;
}
}
PYTHONIC_NS_END