python - получить перевернутую матрицу с плавающей точкой с sympy и numpy - PullRequest
0 голосов
/ 26 ноября 2018

Я пытаюсь реализовать какой-то алгоритм на python.Для документации и ясного понимания деталей потока я использую sympy.Как оказалось, это не помогает при вычислении инвертированной матрицы с плавающей точкой.

Итак, я получаю

TypeError                                 Traceback (most recent call last)
<ipython-input-20-c2193b2ae217> in <module>()
     10 np.linalg.inv(xx)
     11 symInv = lambdify(X0,X0Inv)
---> 12 symInv(xx)

/opt/anaconda3/lib/python3.6/site-packages/numpy/__init__.py in <lambda>(X0)

TypeError: ufunc 'bitwise_xor' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

Если матрица целочисленная, она отлично работает:

import numpy as np
from sympy import *
init_printing()


X0 = MatrixSymbol('X0',2,2)
xx = np.random.rand(4,4) 
#xx = np.random.randint(10,size=(4,4)) # this line makes it workable
X0Inv = X0**-1
np.linalg.inv(xx)
symInv = lambdify(X0,X0Inv)
symInv(xx)

Ссылка на живую версию кода

Если кто-нибудь знает обходной путь, было бы здорово, если бы вы могли поделиться.Заранее спасибо.

ОБНОВЛЕНИЕ .Как указывают @hpaulj и @tel, проблема в том, как lambdify переводит ** в простой код для матричных символов: по какой-то причине он пытается XOR-элементы.Я постараюсь найти простой способ изменить это поведение.Любая помощь / советы приветствуются.

1 Ответ

0 голосов
/ 27 ноября 2018

Как указывает hpaulj, ошибка, по-видимому, связана с преобразованием ** в ^, которое происходит по какой-то причине в lambdify.

Вы можете исправить ошибку,получение с использованием np.power вместо **:

import numpy as np
from sympy import MatrixSymbol, lambdify

X0 = MatrixSymbol('X0',2,2)
xx = np.random.rand(4,4)
X0Inv = np.power(X0, -1)
symInv = lambdify(X0,X0Inv)

print('matrix xx')
print(xx, end='\n\n')
print('result of symInv(xx)')
print(symInv(xx), end='\n\n')

Вывод:

matrix xx
[[0.4514882  0.84588859 0.02431252 0.25468078]
 [0.46767727 0.85748153 0.51207567 0.59636962]
 [0.84557537 0.38459205 0.76814414 0.96624407]
 [0.0933803  0.43467119 0.77823338 0.58770188]]

result of symInv(xx)
[[2.214897321138516, 1.1821887747951494], [2.1382266426713077, 1.1662058776397513]]

Однако при настройке symInv матрица не инвертируется, но вместо этого только поэлементное возведение в степень каждого значения в xx.Другими словами, symInv(xx)[i,j] == xx[i,j]**-1.Этот код показывает разницу между поэлементным возведением в степень и истинным обратным.

print('result of xx**-1')
print(xx**-1, end='\n\n')
print('result of np.linalg.inv(xx)')
print(np.linalg.inv(xx))

Вывод:

result of xx**-1
[[ 2.21489732  1.18218877 41.13107402  3.92648394]
 [ 2.13822664  1.16620588  1.95283638  1.67681243]
 [ 1.18262669  2.60015778  1.301839    1.0349352 ]
 [10.7088969   2.30058954  1.28496159  1.70154295]]

result of np.linalg.inv(xx)
[[-118.7558445   171.37619558  -20.37188041  -88.94733652]
 [  -0.56274492    2.49107626   -1.00812489   -0.62648633]
 [-160.35674704  230.3266324   -28.87548299 -116.75862026]
 [ 231.62940572 -334.07044947   42.21936405  170.90926978]]

Редактировать: обходной путь

Я уверен на 95%То, с чем вы столкнулись, является ошибкой в ​​коде Sympy.Кажется, что X0^-1 был допустимым синтаксисом для объектов Sympy Matrix в некоторый момент, но больше не.Тем не менее, кажется, что кто-то забыл сказать, что тот, кто поддерживает код lambdify, так как он по-прежнему переводит все возведения в матрицу в синтаксис морковного ^.

Так что вы должны сделать, это отправить вопрос на Sympy Github .Просто опубликуйте свой код и ошибку, которую он вызывает, и спросите, является ли это предполагаемым поведением.А пока вот грязный хак, чтобы обойти эту проблему:

import numpy as np
from sympy import MatrixSymbol, lambdify

class XormulArray(np.ndarray):
    def __new__(cls, input_array):
        return np.asarray(input_array).view(cls)

    def __xor__(self, other):
        return np.linalg.matrix_power(self, other)

X0 = MatrixSymbol('X0',2,2)
xx = np.random.rand(4,4)
X0Inv = X0.inv()
symInv = lambdify(X0,X0Inv,'numpy')

print('result of symInv(XormulArray(xx))')
print(symInv(XormulArray(xx)), end='\n\n')

print('result of np.linalg.inv(xx)')
print(np.linalg.inv(xx))

Вывод:

result of symInv(XormulArray(xx))
[[ 3.50382881 -3.84573344  3.29173896 -2.01224981]
 [-1.88719742  1.86688465  0.3277883   0.0319487 ]
 [-3.77627792  4.30823019 -5.53247103  5.53412775]
 [ 3.89620805 -3.30073088  4.27921307 -4.68944191]]

result of np.linalg.inv(xx)
[[ 3.50382881 -3.84573344  3.29173896 -2.01224981]
 [-1.88719742  1.86688465  0.3277883   0.0319487 ]
 [-3.77627792  4.30823019 -5.53247103  5.53412775]
 [ 3.89620805 -3.30073088  4.27921307 -4.68944191]]

По сути, вам придется привести все ваши массивы к тонкой оболочкевведите XormulArray прямо перед тем, как передать их в symInv.Этот хак не является лучшей практикой по ряду причин (включая тот факт, что он, очевидно, нарушает ограничение формы (2,2), которое вы наложили на X0), но, вероятно, будет лучшим, что вы можете сделать, пока не исправлена ​​база кода Sympy..

...