Numpy: 不正確な形状でのgufuncの動作

作成日 2020年06月02日  ·  5コメント  ·  ソース: numpy/numpy

ここでの議論から: https

次の例では、出力の形状が正しくない場合や入力を出力にブロードキャストする場合にエラーが発生することはないようですが、出力に結果+ガベージ値をサイレントに入力します。

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のヌルチェック...

全てのコメント5件

Hehe、しばらくの間これについて考えていました…。念のために@mhvkにもpingを

NPY_ITER_NO_BROADCASTフラグは、奇妙なことに、ほとんどの場合、形状検出のためにそのオペランドを完全に取り出すことができる方法で使用されているようです(出力演算など)。 しかし、それを使用してその問題に対処するだけでは、互換性のないブレークになります。

だから私は新しいNPY_ITER_OUTPUT_OPERAND追加することを考えています。 または、 NPY_ITER_OUTPUT_OPERANDと別のフラグNPY_ITER_DOES_NOT_AFFECT_SHAPEして、出力オペランドフラグに「allocate」フラグと「nobroadcast」フラグの両方を含めることができるようにします。

割り当てと非ブロードキャストの組み合わせのように感じますが、おそらくすでにある程度これを暗示しています。 しかし、問題は、そのような変更を加えたいかどうかです。理論的には、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のヌルチェック...

このページは役に立ちましたか?
0 / 5 - 0 評価

関連する問題

navytux picture navytux  ·  4コメント

qualiaa picture qualiaa  ·  3コメント

inducer picture inducer  ·  3コメント

Kreol64 picture Kreol64  ·  3コメント

toddrjen picture toddrjen  ·  4コメント