_L*U
_が直接A
になり、実際のL
行列も取得できるように、MATLABで関数lu(A)
を実装するにはどうすればよいですか?
[L,U] = lu(A)
を使用すると、MATLABは正しいL
行列を提供しません。 _[L,U,P]
_ = lu(A)を使用する場合、_P*A = L*U
_を実装する必要がありますが、Aを受け取るには_L*U
_を乗算するだけです。
MATLABのlu
は、デフォルトで常にピボットを実行します。たとえば、従来のLU分解アルゴリズムを実行しようとしたときに、対角係数が0に等しい場合、ガウスの消去法を実行して作成するときに対角係数が必要になるため、機能しません。上三角行列U
なので、ゼロ除算エラーが発生します。分解が安定していることを確認するには、ピボットが必要です。
ただし、行列の対角係数がゼロ以外であることを保証できる場合、それは非常に簡単ですが、これは自分で作成する必要があります。あなたがしなければならないのは、行列に対してガウスの消去法を実行し、行列を縮小された階段形に縮小することです。結果の縮小された階段形行列はU
ですが、ガウスの消去法でL
の下三角部分を削除するために必要な係数は、U
を作成するために下三角半分に配置されます。
行列がA
に格納されていると仮定すると、このようなことが機能する可能性があります。ここでは正方行列を想定していることを思い出してください。非ピボットLU分解アルゴリズムの実装は、lu_nopivot
と呼ばれるMATLAB関数ファイルに配置されます。
function [L, U] = lu_nopivot(A)
n = size(A, 1); % Obtain number of rows (should equal number of columns)
L = eye(n); % Start L off as identity and populate the lower triangular half slowly
for k = 1 : n
% For each row k, access columns from k+1 to the end and divide by
% the diagonal coefficient at A(k ,k)
L(k + 1 : n, k) = A(k + 1 : n, k) / A(k, k);
% For each row k+1 to the end, perform Gaussian elimination
% In the end, A will contain U
for l = k + 1 : n
A(l, :) = A(l, :) - L(l, k) * A(k, :);
end
end
U = A;
end
実行例として、次の3 x3行列があるとします。
>> rng(123)
>> A = randi(10, 3, 3)
A =
7 6 10
3 8 7
3 5 5
アルゴリズムを実行すると、次のことがわかります。
>> [L,U] = lu_nopivot(A)
L =
1.0000 0 0
0.4286 1.0000 0
0.4286 0.4474 1.0000
U =
7.0000 6.0000 10.0000
0 5.4286 2.7143
0 0 -0.5000
L
とU
を掛け合わせると、次のようになります。
>> L*U
ans =
7 6 10
3 8 7
3 5 5
...これは元の行列A
です。
ピボットされていないLUの代わりにLDU分解を行うことを検討することをお勧めします。を参照してください。LUピボットなしでは、フルランクで可逆な行列であっても、数値的に不安定です。上記の単純なアルゴリズムは、その理由を示しています。関連する行列の各対角要素による除算があります。したがって、対角のどこかにゼロがある場合、行列が非特異であっても、分解は失敗します。
ウィキペディアはここでLDU分解について少し話します:
https://en.wikipedia.org/wiki/LU_decomposition#LDU_decomposition
アルゴリズムを引用せずに。それは存在の証明のために次の教科書を引用しています:
ホーン、ロジャーA。; Johnson、Charles R.(1985)、Matrix Analysis、Cambridge University Press、ISBN978-0-521-38632-6。セクション3.5を参照してください。
LDUは(少なくとも可逆行列の場合)存在することが保証されており、数値的に安定しており、一意でもあります(LとUの両方が対角線上に単位要素を持つように制約されている場合)。
次に、何らかの理由で「D」が邪魔になった場合、対角行列DをL(L:= LD)またはU(U:= DU)、またはLとUの間で対称的に分割する(L:= L * sqrt(D)やU:= sqrt(D)* Uなど)、またはどのように実行したいか。 LDUをLUに分割する方法は無数にあり、これがLU分解が一意ではない理由です。
このハックを使用できます(すでに述べたように、数値安定性が失われる可能性があります)。
[L, U] = lu(sparse(A), 0)