Точечный продукт B^tDB не возвращает симметричный массив
Я пытаюсь сделать точечное произведение выражения, и оно должно было быть симметричным.
Оказывается, это просто не так.
B - это четырехмерный массив, который я должен перенести в два последних измерения, чтобы он стал B^ t.
D - это двумерный массив. (Это выражение матрицы жесткости, известное программистам метода конечных элементов)
numpy.dot
продукт, связанный с numpy.transpose
и как вторая альтернатива numpy.einsum
(идея пришла из этой темы: умножение матриц Numpy U*B*UT Результаты в несимметричной матрице) уже были использованы, и проблема остается.
К концу вычислений получается произведение B^ tDB, и когда проверяется, действительно ли оно симметрично, вычитая его транспонированную B^ tDB, остается остаток.
Продукт Точки или Суммирование Эйнштейна используются только по интересующим измерениям (последние).
Вопрос в том, как эти остатки можно устранить?
1 ответ
Вам нужно использовать математику с плавающей точкой произвольной точности. Вот как вы можете комбинировать numpy
и mpmath
пакет для определения версии матрицы умножения произвольной точности (т.е. np.dot
метод):
from mpmath import mp, mpf
import numpy as np
# stands for "decimal places". Larger values
# mean higher precision, but slower computation
mp.dps = 75
def tompf(arr):
"""Convert any numpy array to one of arbitrary precision mpmath.mpf floats
"""
if arr.size and not isinstance(arr.flat[0], mpf):
return np.array([mpf(x) for x in arr.flat]).reshape(*arr.shape)
else:
return arr
def dotmpf(arr0, arr1):
"""An arbitrary precision version of np.dot
"""
return tompf(arr0).dot(tompf(arr1))
Например, если вы затем установите матрицы B, B^ t и D следующим образом:
bshape = (8,8,8,8)
dshape = (8,8)
B = np.random.rand(*bshape)
BT = np.swapaxes(B, -2, -1)
d = np.random.rand(*dshape)
D = d.dot(d.T)
тогда B^ tDB - (B^ tDB) ^ t всегда будет иметь ненулевое значение, если вы вычисляете его, используя стандартный метод умножения матриц из numpy
:
M = np.dot(np.dot(B, D), BT)
np.sum(M - M.T)
но если вы используете версию произвольной точности, приведенную выше, у нее не будет остатка:
M = dotmpf(dotmpf(B, D), BT)
np.sum(M - M.T)
Берегись, хотя. Расчеты с использованием математических вычислений произвольной точности выполняются намного медленнее, чем при использовании стандартных чисел с плавающей запятой.