この本のmatlabコードを使用しています: http://books.google.com/books/about/Probability_Markov_chains_queues_and_sim.html?id=HdAQdzAjl60C コードは次のとおりです。
function [pi] = GE(Q)
A = Q';
n = size(A);
for i=1:n-1
for j=i+1:n
A(j,i) = -A(j,i)/A(i,i);
end
for j =i+1:n
for k=i+1:n
A(j,k) = A(j,k)+ A(j,i) * A(i,k);
end
end
end
x(n) = 1;
for i = n-1:-1:1
for j= i+1:n
x(i) = x(i) + A(i,j)*x(j);
end
x(i) = -x(i)/A(i,i);
end
pi = x/norm(x,1);
私が気付いていないより速いコードはありますか?私はこの関数を何百万回も呼んでいますが、時間がかかりすぎます。
MATLABには、組み込みの線形代数ルーチンのセット全体があります-type help slash
、help lu
またはhelp chol
MATLABで線形方程式を効率的に解くためのいくつかの一般的な方法を開始します。
内部的には、これらの関数は通常、最適化されたLAPACK
/BLAS
ライブラリルーチンを呼び出します。これは、一般に、プログラミング言語で線形代数を実行するための最速の方法です。 MATLABのような「遅い」言語と比較して、mファイルの実装よりも桁違いに高速である場合は予想外ではありません。
お役に立てれば。
特に独自の実装を検討している場合を除き、Matlabのバックスラッシュ演算子( mldivide
)を使用するか、係数が必要な場合は lu
。 mldivideは、ガウスの消去法以上のことを実行できることに注意してください(たとえば、適切な場合、線形最小二乗法を実行します)。
mldivide
とlu
で使用されるアルゴリズムは、CおよびFortranライブラリからのものであり、Matlabでの独自の実装は決して高速ではありません。ただし、独自の実装を使用することを決定し、それをより高速にしたい場合、1つのオプションは、実装をベクトル化する方法を探すことです(おそらく、 ここ から開始します)。
注意すべきもう1つのこと:質問からの実装は ピボット を実行しないため、数値的安定性は一般にピボットを実行する実装よりも悪くなり、いくつかの非特異行列。
ガウスの消去法にはさまざまなバリエーションがありますが、それらはすべてO(nです。3)アルゴリズム。あるアプローチが別のアプローチよりも優れているかどうかは、特定の状況によって異なり、さらに調査する必要があります。
function x = naiv_gauss(A,b);
n = length(b); x = zeros(n,1);
for k=1:n-1 % forward elimination
for i=k+1:n
xmult = A(i,k)/A(k,k);
for j=k+1:n
A(i,j) = A(i,j)-xmult*A(k,j);
end
b(i) = b(i)-xmult*b(k);
end
end
% back substitution
x(n) = b(n)/A(n,n);
for i=n-1:-1:1
sum = b(i);
for j=i+1:n
sum = sum-A(i,j)*x(j);
end
x(i) = sum/A(i,i);
end
end
Ax = dと仮定しましょう。ここで、Aとdは既知の行列です。 matlabに埋め込まれた「LU分解」関数を使用して「A」を「LU」として表現したいので、次のようになります。Lux= dこれはmatlabで次のように実行できます:[L、U] = lu (A)これは、A = LUとなるように、Uで上三角行列を返し、Lで並べ替えられた下三角行列を返します。戻り値Lは、下三角行列と置換行列の積です。 ( https://www.mathworks.com/help/matlab/ref/lu.html )
次に、Ly = dと仮定すると、y = Uxとなります。 xは不明であるため、yも不明です。yを知ることにより、xは次のようになります。y= L\d; x = U\y
解はxに格納されます。
これは、行列が特異でない(つまり、行列Aとdの行列式がゼロでない)ことを条件として、連立一次方程式を解く最も簡単な方法です。そうしないと、解の品質が期待したほど良くなく、間違った結果になる可能性があります。結果。
行列が特異であるために反転できない場合は、別の方法を使用して線形方程式のシステムを解く必要があります。
function Sol = GaussianElimination(A,b)
[i,j] = size(A);
for j = 1:i-1
for i = j+1:i
Sol(i,j) = Sol(i,:) -( Sol(i,j)/(Sol(j,j)*Sol(j,:)));
end
end
disp(Sol);
end
私はあなたがmatlab関数rrefを使うことができると思います:
[R、jb] = rref(A、tol)
これは、行階段形を縮小した行列を生成します。私の場合、それは最速の解決策ではありませんでした。以下の解決策は、私の場合、約30パーセント高速でした。
function C = gauss_elimination(A,B)
i = 1; % loop variable
X = [ A B ];
[ nX mX ] = size( X); % determining the size of matrix
while i <= nX % start of loop
if X(i,i) == 0 % checking if the diagonal elements are zero or not
disp('Diagonal element zero') % displaying the result if there exists zero
return
end
X = elimination(X,i,i); % proceeding forward if diagonal elements are non-zero
i = i +1;
end
C = X(:,mX);
function X = elimination(X,i,j)
% Pivoting (i,j) element of matrix X and eliminating other column
% elements to zero
[ nX mX ] = size( X);
a = X(i,j);
X(i,:) = X(i,:)/a;
for k = 1:nX % loop to find triangular form
if k == i
continue
end
X(k,:) = X(k,:) - X(i,:)*X(k,j);
end
N行n列の行列の単純なアプローチ(行スワッピングなし)の場合:
function A = naiveGauss(A)
% find's the size
n = size(A);
n = n(1);
B = zeros(n,1);
% We have 3 steps for a 4x4 matrix so we have
% n-1 steps for an nxn matrix
for k = 1 : n-1
for i = k+1 : n
% step 1: Create multiples that would make the top left 1
% printf("multi = %d / %d\n", A(i,k), A(k,k), A(i,k)/A(k,k) )
for j = k : n
A(i,j) = A(i,j) - (A(i,k)/A(k,k)) * A(k,j);
end
B(i) = B(i) - (A(i,k)/A(k,k)) * B(k);
end
end