Ответ 1
Операция x = x + x.T
работает, потому что вы создаете новый массив, а затем назначаете x
, конечно.
Я создаю симметричные матрицы/массивы в Python с NumPy, используя стандартный метод:
x = rand(500,500)
x = (x+x.T)
all(x==x.T)
> True
Теперь позвольте быть умным:
x = rand(500,500)
x += x.T
all(x==x.T)
> False
Подождите, что?
x==x.T
> array([[ True, True, True, ..., False, False, False],
[ True, True, True, ..., False, False, False],
[ True, True, True, ..., False, False, False],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]], dtype=bool)
Верхний левый и нижний правый сегменты симметричны. Что делать, если я выбрал меньший массив?
x = rand(50,50)
x += x.T
all(x==x.T)
> True
OK....
x = rand(90,90)
x += x.T
all(x==x.T)
> True
x = rand(91,91)
x += x.T
all(x==x.T)
> False
И просто чтобы быть уверенным...
x = rand(91,91)
x = (x+x.T)
all(x==x.T)
> True
Является ли это ошибкой, или я собираюсь узнать что-то сумасшедшее о +=
и массивах NumPy?
Операция x = x + x.T
работает, потому что вы создаете новый массив, а затем назначаете x
, конечно.
Детали реализации, упомянутые другими, называются буферизацией. Вы можете больше узнать об этом в документах по итерации массива.
Если вы посмотрите на свой неудачный пример чуть подробнее:
>>> a = np.random.rand(91, 91)
>>> a += a.T
>>> a[:5, -1]
array([ 0.83818399, 1.06489316, 1.23675312, 0.00379798, 1.08967428])
>>> a[-1, :5]
array([ 0.83818399, 1.06489316, 1.75091827, 0.00416305, 1.76315071])
Итак, первое неправильное значение - 90*91 + 2 = 8192
, что неудивительно, что мы получаем от:
>>> np.getbufsize()
8192
И мы также можем установить его выше, а затем:
>>> np.setbufsize(16384) # Must be a multiple of 16
8192 # returns the previous buffer size
>>> a = np.random.rand(91, 91)
>>> a += a.T
>>> np.all(a == a.T)
True
Хотя теперь:
>>> a = np.random.rand(129, 129)
>>> a += a.T
>>> np.all(a == a.T)
False
Это, конечно, опасная вещь, чтобы полагаться на правильность, поскольку это действительно деталь реализации, подлежащая изменению.
Проблема заключается в том, что добавление не выполняется "сразу"; x.T
- это вид x
, так как вы начинаете добавлять к каждому элементу x
, x.T
мутируется. Это испортит более поздние дополнения.
Тот факт, что он работает для размеров ниже (91, 91)
, почти определенно является детальностью реализации. Использование
x = numpy.random.rand(1000, 1000)
x += x.T.copy()
numpy.all(x==x.T)
#>>> True
исправляет это, но тогда у вас действительно нет свободного места.