行列方程式のクロネッカー積による解法
運動制御モデルの論文を読んでいた際に,行列方程式\(AXB + CXD = E\)の解法を忘却していたので,メモとして記事を書いた.結論から言えばクロネッカー積を用いて解くことができる.以下ではクロネッカー積の定義について触れ,簡単な行列方程式\(AXB=C\)に対してクロネッカー積を用いた解法を用いた後,\(AXB + CXD = E\)の解き方について説明する.
なお,これに基づいて筆者が執筆した記事が無限時間最適制御モデル (infinite-horizon optimal feedback control model)[外部リンク] である.
クロネッカー積
定義と例
以下,Wikipediaの説明から引用する.
\(A = (a_{ij})\) を \(m \times n\) 行列,\(B = (b_{kl})\) を \(p \times q\) 行列とすると、それらのクロネッカー積 \(A \otimes B\) は
で与えられる \(mp \times nq\) 区分行列である.例えば,
のような計算が成り立つ.
実装
Pythonではnumpy.kron(),JuliaではKronecker.jlを用いる.以下ではPythonを使用する.
import numpy as np
np.set_printoptions(precision=3, suppress=True) # print時の設定
A = np.array([[1, 2], [3, 4]])
B = np.array([[0, 5], [6, 7]])
print(np.kron(A, B))
行列方程式の解法
1. AXB = C
\(A, B, C\)が与えられていて,\(X\)を未知とするときの方程式 \(AXB = C\)を考える.この場合,\(A, B\)は正則であると仮定すると,\(X=A^{-1}CB^{-1}\)と求まる.ただし,以下では後の問題のためにRoth's column lemma (vec-trick)を用いた方法について考えよう.Roth's column lemmaは,先程と同様の方程式 \(AXB = C\)を考えると,この方程式は
の形に書き下すことができる,というものである.\(\text{vec}(\cdot)\)はvec作用素(行列を列ベクトル化する作用素)である.numpyだとflatten()で実現できる.Roth's column lemmaを用いれば,\(AXB = C\)の解は
として得られる.ただし,\(\text{vec}(\cdot)^{-1}\)は列ベクトルを行列に戻す作用素(inverse of the vectorization operator)である.numpyだとreshape()で実現できる (numpyのベクトルはデフォルトで行ベクトルであることに注意).2つの作用素をまとめると,
であり,\(\text{vec}^{−1}\left(\text{vec}(X)\right)=X\ (\text{for all}\ X\in R^{m\times n}),\text{vec}\left(\text{vec}^{−1}(x)\right)=x\ (\text{for all}\ x \in R^{mn})\)となる.
以下では\(P, Q, R\)が与えられている際に,方程式\(PYQ=R\)の解\(Y\)を求める.
m = 4
P = np.random.randn(m, m)
Q = np.random.randn(m, m)
R = np.arange(m**2).reshape(m, m)
print(R)
上記に基づいて方程式を解く.
Y = (np.linalg.inv(np.kron(P, Q.T)) @ R.flatten()).reshape(m, m)
print(P @ Y @ Q)
少々元の式と実装が異なるが,計算はできているので良しとしておく.また,\(Y=P^{-1}RQ^{-1}\)としても解けることも示す.
Y2 = np.linalg.inv(P) @ R @ np.linalg.inv(Q)
print(P @ Y2 @ Q)
2. AXB + CXD = E
この記事の本題.\(A, B, C, D, E\)が与えられていて,\(X\)を未知とするときの方程式 \(AXB + CXD = E\)を考えると,この方程式は
として解ける.例えば連続的リアプノフ方程式 (continuous Lyapunov equation) \(AX+XA^{H}+Q=0\)は\(AXB + CXD = E\)の特別な場合であるので,
と解ける.ただし,\(A^H\)は\(A\)の随伴行列,\(\bar{A}\)は\(A\)の各成分を複素共役で置き換えた行列,\(I\)は単位行列である.他にはシルベスター方程式 (Sylvester equation) \(AX+XB=C\)も同様に解ける.
以下では\(PZQ + SZT = R\)の解\(Z\)を求める.
S = np.random.randn(m, m)
T = np.random.randn(m, m)
Z = (np.linalg.inv(np.kron(P, Q.T) + np.kron(S, T.T)) @ R.flatten()).reshape(m, m)
print(P @ Z @ Q + S @ Z @ T)
3. XAX = B
クロネッカー積は使わないが,\(XAX=B\)の解法を記載しておく.\(A\)が正則であると仮定すると,行列平方根(の一つ)\(A^{1/2}\)が求まり,両辺の両側から\(A^{1/2}\)をかけることで,\(\left(A^{1/2}X A^{1/2}\right)^2 = A^{1/2}B A^{1/2}\)が得られる.よって,
と求まる.\(A^{1/2}\)の計算にはscipy.linalg.sqrtm()を用いる.なお,一般に\(n\)次正則行列の場合に行列平方根は(よって\(XAX = B\)の解も)\(2^n\)個存在する.以下では\(XPX=R\)を解く.
from scipy.linalg import sqrtm
Psqrt = sqrtm(P)
Pinvsqrt = np.linalg.inv(Psqrt)
X = Pinvsqrt @ sqrtm(Psqrt @ R @ Psqrt) @ Pinvsqrt
print(X @ P @ X)
- 前の記事 : PtitPrinceによるPythonでのRaincloud plotの描画
- 次の記事 : attention勉強会2
- 関連記事 :
