Из обсуждения здесь: https://github.com/numpy/numpy/pull/15162#discussion_r434122175
В следующем примере, похоже, не возникает ошибка, когда выходная форма неверна или транслирует входные данные на выход, но молча заполняет выход значениями результат + мусор.
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]]
Хе-хе, какое-то время думал об этом… .Также пинг
Флаг 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)
конечно, имеет смысл, но это не проблема.
Я должен признать, что немного запутался в отношении всех флагов. Но gufunc moments
с сигнатурой ()->(k)
возможно, мог бы вычислить моменты до k
на выходе. Конечно, это невероятно надумано, но я не считаю, что это явно исключать (или код, явно позволяющий это!)
Немного более прямое отношение к проблеме здесь, где выход имеет непоследовательную внешнюю форму, заключается в том, что есть прецедент из обычных ufuncs:
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 ...
Самый полезный комментарий
Ах, это очень просто:
это, наверное, все, что нужно. Тогда мы получаем правильную трансляцию входов в выходы, и любые мысли об отказе от этого можно просто отложить на будущее, если они когда-нибудь возникнут.
РЕДАКТИРОВАТЬ: Плюс нулевая проверка op ...