Numpy: 错误形状时的gufunc行为

创建于 2020-06-02  ·  5评论  ·  资料来源: numpy/numpy

从这里的讨论中: https :

下面的示例在out形状不正确或将输入广播到输出时似乎不会引发错误,但是会以无声的结果+垃圾值来填充out。

import numpy as np
from numpy.core import _umath_tests as umt
from numpy.testing import assert_raises
a = np.arange(6).reshape(3, 2)
b = np.ones(2)
out = np.empty((5, 3))
umt.inner1d(a, b, out)
print(out)

结果:

[[ 1.00000000e+000  5.00000000e+000  9.00000000e+000]
 [ 6.91217735e-310 -1.45681599e+144 -1.45681599e+144]
 [-1.45681599e+144 -1.45681599e+144 -1.45681599e+144]
 [-1.45681599e+144 -1.45681599e+144 -1.45681599e+144]
 [-1.45681599e+144 -1.45681599e+144  6.32404027e-322]]
00 - Bug numpy.core numpy.ufunc

最有用的评论

嗯,很简单:

diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 19876d641..85820e3a0 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -2614,7 +2614,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
      * dimensions.
      */
     broadcast_ndim = 0;
-    for (i = 0; i < nin; ++i) {
+    for (i = 0; i < nop; ++i) {
         int n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
         if (n > broadcast_ndim) {
             broadcast_ndim = n;

可能就是它的全部了。 然后,我们可以正确广播输入到输出的输出,并且如果过时了,任何不赞成使用此输出的想法都可以推迟到以后。

编辑:加上op的null检查...

所有5条评论

呵呵,想了一会儿...。还ping @mhvk以防万一。

奇怪的是, NPY_ITER_NO_BROADCAST标志几乎总是以一种方式使用,即您可以简单地完全取出该操作数以进行形状发现(例如,作为输出操作)。 但是,如果我们仅使用它来解决该问题,那将是一个不兼容的中断。

因此,我正在考虑添加一个新的NPY_ITER_OUTPUT_OPERAND 。 或者制作一个NPY_ITER_OUTPUT_OPERAND和另一个标志NPY_ITER_DOES_NOT_AFFECT_SHAPE以便输出操作数标志可以同时包含“分配”和“不广播”标志。

感觉就像分配和不广播的结合,可能已经暗示了这一点。 但是问题是我们是否要进行这样的更改,从理论上讲,它可以影响使用NpyIter的外部库。 (除非我们在启动时将其设置为VisibleDeprecationWarning,但不能确保实现起来非常简洁。)

认为这可以解决这个问题。 有一些有趣的附带情况,例如由一个(或多个)输出数组使用的轴。 一个人可以尝试支持这一点(在某个时候?),但是它可能会增加太多的复杂性,而没有真正的收益。
我只是没有真正看到(),()->(k) gufunc的用例太多。 当然不是(),()->(3,3)->(3,3) ,当然是有道理的,但这不是问题。

我必须承认,所有标志都有些混乱。 但是带有签名()->(k)的gufunc moments也许可以计算输出中的直到k力矩。 当然,它牵强附会,但我的感觉是不要明确排除它(也没有明确允许它的代码!)。

与此处的问题更直接相关的是输出的外部形状不一致,这是常规ufunc的先例:

np.add(1, 1, out=np.empty((3,)))
# array([2., 2., 2.])

这也建议对于gufuncs,应从所有输入和输出确定外形。 显然,这将导致不必要的计算,但事实如此……

哦,我不知道该怎么做才行。 我想在这种情况下,我们可以简单地允许输出在输入中引起广播(从而调整形状)。 基本上只是保留当前行为。

因此,除了确保多次调用(g)ufunc(在很多情况下,获取结果会有点慢,但这是调用者的问题)之外,在这里什么都不做。 虽然我认为支持这一点并不重要,但我也认为这样做没有任何问题。

但显然,我们仍然需要在gufuncs中解决此问题!

嗯,很简单:

diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 19876d641..85820e3a0 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -2614,7 +2614,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
      * dimensions.
      */
     broadcast_ndim = 0;
-    for (i = 0; i < nin; ++i) {
+    for (i = 0; i < nop; ++i) {
         int n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
         if (n > broadcast_ndim) {
             broadcast_ndim = n;

可能就是它的全部了。 然后,我们可以正确广播输入到输出的输出,并且如果过时了,任何不赞成使用此输出的想法都可以推迟到以后。

编辑:加上op的null检查...

此页面是否有帮助?
0 / 5 - 0 等级