web-dev-qa-db-ja.com

MatlabとOctaveでinv()とpinv()の出力が等しくないのはなぜですか?

AがNxN行列であり、逆行列がある場合に気づきました。ただし、inv()関数とpinv()関数の出力は異なります。 -私の環境はWin7x64SP1、Matlab R2012a、Cygwin Octave 3.6.4、FreeMat4.2です。

Octaveの例をご覧ください。

_A = Rand(3,3)
A =
0.185987   0.192125   0.046346
0.140710   0.351007   0.236889
0.155899   0.107302   0.300623

pinv(A) == inv(A)
ans =
0 0 0
0 0 0
0 0 0
_
  • 上記のMatlabで同じコマンドを実行すると、すべて同じansの結果になります。

  • そして、inv(A)*AまたはA*inv(A)を計算すると、結果はOctaveとMatlabの両方で同一性の3x3行列になります。
  • A*pinv(A)pinv(A)*Aの結果は、MatlabとFreeMatの同一性3x3行列です。
  • A*pinv(A)の結果は、Octaveのアイデンティティ3x3行列です。
  • pinv(A)*Aの結果はnot Octaveのアイデンティティ3x3行列です。

inv(A) != pinv(A)の理由はわかりませんが、行列内の要素の詳細を検討しました。この問題の原因は、浮動精度の問題のようです。

ドットポイントの後の10桁以上は、次のように異なる場合があります。

  • inv(A)(1,1)の_6.65858991579923298331777914427220821380615200000000_要素に対して

  • pinv(A)(1,1)の_6.65858991579923209513935944414697587490081800000000_要素

14
myme5261314

この質問はかなり古いですが、いくつかのグーグル検索でほぼ一番上に表示されるので、とにかく答えます。

私の例では、N行N列の魔方陣を返すmagic(N)関数を使用します。

3x3の魔方陣M3を作成し、疑似逆行列PI_M3を取得して、それらを乗算します。

   Prompt_ $ M3 = magic(3)、PI_M3 = pinv(M3)、M3 * PI_M3
 M3 = 
 
 8 1 6 
 3 5 7 
 4 9 2 
 
 PI_M3 = 
 
 0.147222 -0.144444 0.063889 
-0.061111 0.022222 0.105556 
-0.019444 0.188889 -0.102778 
 
 ans = 
 
 1.0000e + 00 -1.2212e-14 6.3283e-15 
 5.5511e-17 1.0000e + 00 -2.2204e-16 
-5.9952e-15 1.2268e-14 1.0000e +00 

ご覧のとおり、答えは、丸め誤差を除いた単位行列です。 4x4の魔方陣で操作を繰り返します。

   Prompt_ $ M4 = magic(4)、PI_M4 = pinv(M4)、M4 * PI_M4
 
 M4 = 
 
 16 2 3 13 
 5 11 10 8 
 9 7 6 12 
 4 14 15 1 
 
 PI_M4 = 
 
 0.1011029 -0.0738971 -0.0613971 0.0636029 
-0.0363971 0.0386029 0.0261029 0.0011029 
 0.0136029 -0.0113971 -0.0238 。]-0.0488971 0.0761029 0.0886029 -0.0863971 
 
 ans = 
 
 0.950000 -0.150000 0.150000 0.050000 
-0.150000 0.550000 0.450000 0.150000 [.____。 0.150000 0.450000 0.550000 -0.150000 
 0.050000 0.150000 -0.150000 0.950000 

結果は単位行列ではなく、4x4魔方陣に逆行列がないことを意味します。これは、ムーアペンローズ疑似逆の規則の1つを試すことで確認できます。

   Prompt_ $ M4 * PI_M4 * M4
  
 ans = 
 
 16.00000 2.00000 3.00000 13.00000 
 5.00000 11.00000 10.00000 8.00000 
 9.00000 7.00000 6.00000 12.00000 
 4.00000 14.00000 15.00000 1.00000 

ルールA * B * A = Aが満たされます。これは、pinvが利用可能な場合は逆行列を返し、逆行列が利用できない場合は疑似逆行列を返すことを示しています。これが、状況によっては小さな差が発生し、丸め誤差が発生する場合もあれば、大きな差が発生する場合もある理由です。それを示すために、両方のマジッククアドラントの逆行列を取得し、それらを疑似逆行列から減算します。

   Prompt_ $ I_M3 = inv(M3)、I_M4 = inv(M4)、DIFF_M3 = PI_M3-I_M3、DIFF_M4 = PI_M4-I_M4
 I_M3 = 
 
 0.147222 -0.144444 0.063889 
-0.061111 0.022222 0.105556 
-0.019444 0.188889 -0.102778 
 
警告:逆行列:行列はマシンの精度に対して特異、rcond = 1.30614e-17 
 I_M4 = 
 
 9.3825e + 13 2.8147e + 14 -2.8147e + 14 -9.3825e + 13 
 2.8147e + 14 8.4442e + 14 -8.4442e + 14 -2.8147e + 14 
-2.8147e + 14 -8.4442e + 14 8.4442e + 14 2.8147e + 14 
-9.3825e + 13 -2.8147e + 14 2.8147e + 14 9.3825e + 13 
 
 DIFF_M3 = 
 
 4.7184e-16 -1.0270e- 15 5.5511e-16 
-9.9226e-16 2.0470e-15 -1.0825e-15 
 5.2042e-16 -1.0270e-15 4.9960e-16 
 
 DIFF_M4 = 
 
-9.3825e + 13 -2.8147e + 14 2.8147e + 14 9.3825e + 13 
-2.8147e + 14 -8.4442e + 14 8.4442e + 14 2.8147e + 14 
 2.8147e + 14 8.4442e + 14 -8.4442e + 14 -2.8147e + 14 
 9.3825e + 13 2.8147e + 14 -2.8147e + 14 -9.3825e + 13 
15
goth

あなたがここの一番下であなた自身の質問に答えたように私には思えます。その理由は浮動小数点演算です。 inv()pinv()のアルゴリズムは完全に同じではありません。これは、pinv()が非正方行列を処理できる必要があるためです。したがって、答えは完全に同じではありません。

pinv(A)*Aの値を見ると、単位行列に非常に近いことがわかります。

私は得る:

_ans =

   1.0000e+00   6.1062e-16  -3.0809e-15
  -5.8877e-15   1.0000e+00   6.3942e-15
   2.4425e-15  -3.0184e-16   1.0000e+00
_

行列を_==_と比較する代わりに、_< tolerance_limit_を使用します

_c = A*pinv(A);
d = pinv(A)*A;

(c-d) < 1e-10
_

補足:

_x = A^-1*b_は解決すべきではありませんx = inv(A)*b;ではなく、_x = A \ b;_説明については Shaiが投稿したリンク を参照してください。

9
Stewie Griffin

浮動小数点演算には一定の精度があり、平等に頼ることはできません。このようなエラーを回避するには、matlabのシンボリックツールボックスを使用してみてください。

問題を示すためのオクターブ単位の非常に単純なコード行:

>>> (1/48)*48==(1/49)*49
ans = 0
>>> (1/48)*48-(1/49)*49
ans =  1.1102e-16
>>>
2
Daniel