summaryrefslogtreecommitdiff
path: root/numpy/core/src
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2023-02-09 17:01:15 +0200
committerGitHub <noreply@github.com>2023-02-09 16:01:15 +0100
commit11a7e2d4aa85e902384bcb9459a83045fab602b4 (patch)
tree8abc35474c6512eeeef58b16d60b421649eaddb0 /numpy/core/src
parenta91a31e2ff22c3c6cbbc4bacca2d6d7a8fe6bdff (diff)
downloadnumpy-11a7e2d4aa85e902384bcb9459a83045fab602b4.tar.gz
ENH: add indexed loops for maximum, minimum, fmax, fmin (#23177)
Continuation of the ufunc.at optimizations: add indexed loops for maximum, minimum, fmax, fmin ufuncs and a benchmark for maximum.at (performance increased by ~13x) * BENCH: add np.maximum.at benchmark * remove 'explain_chain' * add a seed to `default_rng() (from review) * MAINT: formatting and change comments, from review
Diffstat (limited to 'numpy/core/src')
-rw-r--r--numpy/core/src/umath/loops.c.src55
-rw-r--r--numpy/core/src/umath/loops.h.src17
-rw-r--r--numpy/core/src/umath/loops_minmax.dispatch.c.src18
3 files changed, 83 insertions, 7 deletions
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index 09268f681..d445fd700 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -455,7 +455,9 @@ BOOL_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void
#define @TYPE@_floor_divide @TYPE@_divide
#define @TYPE@_floor_divide_indexed @TYPE@_divide_indexed
#define @TYPE@_fmax @TYPE@_maximum
+#define @TYPE@_fmax_indexed @TYPE@_maximum_indexed
#define @TYPE@_fmin @TYPE@_minimum
+#define @TYPE@_fmin_indexed @TYPE@_minimum_indexed
NPY_NO_EXPORT void
@TYPE@__ones_like(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
@@ -538,8 +540,8 @@ NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ void
NPY_NO_EXPORT NPY_GCC_OPT_3 @ATTR@ int
@TYPE@_@kind@@isa@_indexed(PyArrayMethod_Context *NPY_UNUSED(context),
- char * const*args, npy_intp const *dimensions,
- npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
+ char **args, npy_intp const *dimensions, npy_intp const *steps,
+ void *NPY_UNUSED(func))
{
char *ip1 = args[0];
char *indx = args[1];
@@ -902,6 +904,7 @@ NPY_NO_EXPORT void
}
}
}
+
/**end repeat1**/
/**begin repeat1
@@ -1695,7 +1698,9 @@ HALF_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void
}
NPY_NO_EXPORT int
-HALF_@kind@_indexed(void *NPY_UNUSED(context), char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func))
+HALF_@kind@_indexed(void *NPY_UNUSED(context),
+ char **args, npy_intp const *dimensions, npy_intp const *steps,
+ void *NPY_UNUSED(func))
{
char *ip1 = args[0];
char *indx = args[1];
@@ -1812,6 +1817,27 @@ HALF_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void
}
/* npy_half_isnan will never set floatstatus_invalid, so do not clear */
}
+
+NPY_NO_EXPORT int
+HALF_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context),
+ char **args, npy_intp const *dimensions, npy_intp const *steps,
+ void *NPY_UNUSED(func))
+{
+ char *ip1 = args[0];
+ char *indx = args[1];
+ char *value = args[2];
+ npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
+ npy_intp n = dimensions[0];
+ npy_intp i;
+ npy_half *indexed;
+ for(i = 0; i < n; i++, indx += isindex, value += isb) {
+ indexed = (npy_half *)(ip1 + is1 * *(npy_intp *)indx);
+ npy_half v = *(npy_half *)value;
+ *indexed = (@OP@(*indexed, v) || npy_half_isnan(*indexed)) ? *indexed : v;
+ }
+ return 0;
+}
+
/**end repeat**/
/**begin repeat
@@ -1827,8 +1853,29 @@ HALF_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void
const npy_half in2 = *(npy_half *)ip2;
*((npy_half *)op1) = (@OP@(in1, in2) || npy_half_isnan(in2)) ? in1 : in2;
}
- /* npy_half_isnan will never set floatstatus_invalid, so do not clear */
+ /* no need to clear floatstatus_invalid */
+}
+
+NPY_NO_EXPORT int
+HALF_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context),
+ char **args, npy_intp const *dimensions, npy_intp const *steps,
+ void *NPY_UNUSED(func))
+{
+ char *ip1 = args[0];
+ char *indx = args[1];
+ char *value = args[2];
+ npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
+ npy_intp n = dimensions[0];
+ npy_intp i;
+ npy_half *indexed;
+ for (i = 0; i < n; i++, indx += isindex, value += isb) {
+ indexed = (npy_half *)(ip1 + is1 * *(npy_intp *)indx);
+ npy_half v = *(npy_half *)value;
+ *indexed = (@OP@(*indexed, v) || npy_half_isnan(v)) ? *indexed: v;
+ }
+ return 0;
}
+
/**end repeat**/
NPY_NO_EXPORT void
diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src
index f1d91d1fe..f773d94bc 100644
--- a/numpy/core/src/umath/loops.h.src
+++ b/numpy/core/src/umath/loops.h.src
@@ -137,6 +137,8 @@ NPY_CPU_DISPATCH_DECLARE(NPY_NO_EXPORT void @TYPE@_@kind@,
#define @S@@TYPE@_floor_divide_indexed @S@@TYPE@_divide_indexed
#define @S@@TYPE@_fmax @S@@TYPE@_maximum
#define @S@@TYPE@_fmin @S@@TYPE@_minimum
+#define @S@@TYPE@_fmax_indexed @S@@TYPE@_maximum_indexed
+#define @S@@TYPE@_fmin_indexed @S@@TYPE@_minimum_indexed
NPY_NO_EXPORT void
@S@@TYPE@__ones_like(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data));
@@ -192,10 +194,13 @@ NPY_NO_EXPORT void
/**begin repeat2
* #kind = maximum, minimum#
- * #OP = >, <#
**/
NPY_NO_EXPORT void
@S@@TYPE@_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
+NPY_NO_EXPORT int
+@S@@TYPE@_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context), char *const *args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func));
+
/**end repeat2**/
NPY_NO_EXPORT void
@@ -475,18 +480,24 @@ NPY_NO_EXPORT void
/**begin repeat1
* #kind = maximum, minimum#
- * #OP = >=, <=#
**/
NPY_NO_EXPORT void
@TYPE@_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
+NPY_NO_EXPORT int
+@TYPE@_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context), char *const *args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func));
+
/**end repeat1**/
/**begin repeat1
* #kind = fmax, fmin#
- * #OP = >=, <=#
**/
NPY_NO_EXPORT void
@TYPE@_@kind@(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func));
+
+NPY_NO_EXPORT int
+@TYPE@_@kind@_indexed(PyArrayMethod_Context *NPY_UNUSED(context), char *const *args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func));
+
/**end repeat1**/
NPY_NO_EXPORT void
diff --git a/numpy/core/src/umath/loops_minmax.dispatch.c.src b/numpy/core/src/umath/loops_minmax.dispatch.c.src
index 237c8e933..9d8667d38 100644
--- a/numpy/core/src/umath/loops_minmax.dispatch.c.src
+++ b/numpy/core/src/umath/loops_minmax.dispatch.c.src
@@ -451,6 +451,24 @@ clear_fp:
#endif
}
+
+NPY_NO_EXPORT int NPY_CPU_DISPATCH_CURFX(@TYPE@_@kind@_indexed)
+(PyArrayMethod_Context *NPY_UNUSED(context), char *const *args, npy_intp const *dimensions, npy_intp const *steps, NpyAuxData *NPY_UNUSED(func))
+{
+ char *ip1 = args[0];
+ char *indx = args[1];
+ char *value = args[2];
+ npy_intp is1 = steps[0], isindex = steps[1], isb = steps[2];
+ npy_intp n = dimensions[0];
+ npy_intp i;
+ @type@ *indexed;
+ for(i = 0; i < n; i++, indx += isindex, value += isb) {
+ indexed = (@type@ *)(ip1 + is1 * *(npy_intp *)indx);
+ *indexed = SCALAR_OP(*indexed, *(@type@ *)value);
+ }
+ return 0;
+}
+
#undef SCALAR_OP
#endif // !fp_only || (is_fp && fp_only)