Ответ 1
Это поведение является результатом изменения, внесенного для NumPy 1.11.0, в запрос на переноС# 6932. Из примечания к выпуску для 1.11.0:
Ранее операции GAMM BLAS использовались для всех матричных продуктов. Теперь, если матричный продукт находится между матрицей и ее транспонированием, будет использовать операции SYRK BLAS для повышения производительности. Эта оптимизация была расширена до @, numpy.dot, numpy.inner и numpy.matmul.
В изменениях для этого PR вы найдете этот комментарий:
/*
* Use syrk if we have a case of a matrix times its transpose.
* Otherwise, use gemm for all other cases.
*/
Итак, NumPy делает явную проверку для случая, когда матрица переставляет ее транспонирование, и вызывает в этом случае другую базовую функцию BLAS. Как отмечает @hpaulj в комментарии, такая проверка дешева для NumPy, поскольку транспонированный 2d-массив - это просто представление исходного массива с инвертированной формой и шагами, поэтому достаточно проверить несколько фрагментов метаданных на массивах ( вместо того, чтобы сравнивать фактические данные массива).
Вот немного более простой случай, показывающий несоответствие. Обратите внимание, что использование .copy
для одного из аргументов dot
достаточно, чтобы победить специальную оболочку NumPy.
import numpy as np
random = np.random.RandomState(12345)
A = random.uniform(size=(10, 5))
Sym1 = A.dot(A.T)
Sym2 = A.dot(A.T.copy())
print(abs(Sym1 - Sym2).max())
Я думаю, что одно преимущество этого специального корпуса, помимо очевидного потенциала ускорения, заключается в том, что вы гарантированы (я надеюсь, но на практике это будет зависеть от реализации BLAS), чтобы получить совершенно симметричный результат, когда используется syrk
, а не матрица, которая просто симметрична с числовой погрешностью. В качестве (по общему признанию, не очень хорошего) теста для этого я попытался:
import numpy as np
random = np.random.RandomState(12345)
A = random.uniform(size=(100, 50))
Sym1 = A.dot(A.T)
Sym2 = A.dot(A.T.copy())
print("Sym1 symmetric: ", (Sym1 == Sym1.T).all())
print("Sym2 symmetric: ", (Sym2 == Sym2.T).all())
Результаты на моей машине:
Sym1 symmetric: True
Sym2 symmetric: False