Problemy przy podstawianiu macierzy do wielomianu

Jan 12 2021

Przykład: niech

M = Matrix([[1,2],[3,4]]) # and 
p = Poly(x**3 + x + 1)    # then
p.subs(x,M).expand()

podaje błąd:

TypeError: nie można dodać <class'sympy.matrices.immutable.ImmutableDenseMatrix '> i <class' sympy.core.numbers.One '>

co jest bardzo prawdopodobne, ponieważ dwa pierwsze wyrazy stają się macierzami, ale ostatni człon (człon stały) nie jest macierzą, ale skalarem. Aby zaradzić tej sytuacji, zmieniłem wielomian na

p = Poly(x**3 + x + x**0)    # then

ten sam błąd będzie się powtarzał. Czy muszę wpisywać wyrażenie ręcznie, zastępując x przez M? W tym przykładzie wielomian ma tylko trzy wyrazy, ale w rzeczywistości napotykam (wielomiany wieloczynnikowe z) dziesiątkami wyrazów.

Odpowiedzi

1 wsdookadr Jan 12 2021 at 12:40

Myślę więc, że pytanie dotyczy głównie pojęcia wielomianu macierzy :

(gdzie P jest wielomianem, a A jest macierzą)

Myślę, że to mówi, że termin wolny jest liczbą i nie można go dodać z resztą, która jest macierzą, w rzeczywistości operacja dodawania jest niezdefiniowana między tymi dwoma typami.

TypeError: nie można dodać <class'sympy.matrices.immutable.ImmutableDenseMatrix '> i <class' sympy.core.numbers.One '>

Można to jednak obejść, definiując funkcję, która ocenia wielomian macierzy dla określonej macierzy. Różnica polega na tym, że używamy potęgowania macierzy , więc poprawnie obliczamy człon swobodny wielomianu macierzy, a_0 * Igdzie I=A^0jest macierzą tożsamości o wymaganym kształcie:

from sympy import *
x = symbols('x')
M = Matrix([[1,2],[3,4]])
p = Poly(x**3 + x + 1)

def eval_poly_matrix(P,A):
    res = zeros(*A.shape)
    for t in enumerate(P.all_coeffs()[::-1]):
        i, a_i = t
        res += a_i * (A**i)
    return res

eval_poly_matrix(p,M)

Wynik:

W tym przykładzie wielomian ma tylko trzy wyrazy, ale w rzeczywistości napotykam (wielomiany wieloczynnikowe z) dziesiątkami wyrazów.

eval_poly_matrixPowyższą funkcję można rozszerzyć, aby działała dla wielomianów wielowymiarowych, używając .monoms()metody do wyodrębniania jednomianów o niezerowych współczynnikach , na przykład:

from sympy import *
x,y = symbols('x y')
M = Matrix([[1,2],[3,4]])
p = poly( x**3 * y + x * y**2 + y )

def eval_poly_matrix(P,*M):
    res = zeros(*M[0].shape)
    for m in P.monoms():
        term = eye(*M[0].shape)
        for j in enumerate(m):
            i,e = j
            term *= M[i]**e
        res += term
    return res

eval_poly_matrix(p,M,eye(M.rows))

Uwaga: możliwe są pewne testy poprawności, obsługa skrajnych przypadków i optymalizacje:

  1. Liczba zmiennych obecnych w wielomianu odnosi się do liczby macierzy przekazanych jako parametry (ta pierwsza nigdy nie powinna być większa od drugiej, a jeśli jest mniejsza niż jakaś logika musi być obecna, aby to obsłużyć, załatwiłem tylko przypadek kiedy te dwa są równe)
  2. Wszystkie macierze muszą być kwadratowe zgodnie z definicją wielomianu macierzy
  3. W komentarzach do tego pytania pojawia się dyskusja na temat wielowymiarowej wersji reguły Hornera . Może to być przydatne do zminimalizowania liczby mnożenia macierzy.
  4. Weź pod uwagę fakt, że wielomian macierzy x*yróżni się od tego, y*xże mnożenie macierzy jest nieprzemienne . Najwyraźniej funkcje poli w sympy nie obsługują zmiennych nieprzemiennych , ale możesz definiować symbole za pomocą commutative=Falsei wydaje się, że jest tam sposób na przyszłość

O czwartym punkcie powyżej, w SymPy jest obsługa wyrażeń Matrix , co może pomóc tutaj:

from sympy import *
from sympy.matrices import MatrixSymbol

A = Matrix([[1,2],[3,4]])
B = Matrix([[2,3],[3,4]])

X = MatrixSymbol('X',2,2)
Y = MatrixSymbol('Y',2,2)
I = eye(X.rows)

p = X**2 * Y + Y * X ** 2 + X ** 3 - I
display(p)

p = p.subs({X: A, Y: B}).doit()
display(p)

Wynik:

Więcej informacji na temat tej funkcji można znaleźć pod numerem 18555