Juliaの逆行列計算:getri!関数を徹底解説

2025-05-27

LinearAlgebra.LAPACK.getri!() とは

LinearAlgebra.LAPACK.getri!() は、Juliaの線形代数モジュール LinearAlgebra の一部であり、低レベルのLAPACK (Linear Algebra PACKage) 関数である GETRI を呼び出すものです。この関数は、LU分解された行列の逆行列を計算するために使用されます。

LAPACKとは?

LAPACKは、線形代数における数値計算のための標準的なソフトウェアライブラリです。行列のLU分解、QR分解、固有値計算、線形方程式の求解など、多岐にわたる機能を提供します。Juliaの LinearAlgebra モジュールは、これらのLAPACK関数を効率的に呼び出すためのインターフェースを提供しています。

! の意味

Juliaの関数名に付いている ! は、その関数が引数として渡されたオブジェクトを「インプレースで(その場で)変更する」ことを示す慣習です。したがって、getri!() は、入力として渡された行列を直接変更して、その逆行列を格納します。

使用方法

getri!() は通常、単独で使われることは少なく、まず行列のLU分解を行う LinearAlgebra.LAPACK.getrf!() と組み合わせて使われます。

基本的な流れは以下のようになります。

  1. LU分解
    LinearAlgebra.LAPACK.getrf!(A) を呼び出して、行列 A をLU分解します。この関数は、A をインプレースでLU分解された行列に変換し、ピボット情報(行の入れ替えに関する情報)も返します。
  2. 逆行列の計算
    LinearAlgebra.LAPACK.getri!(A_lu, ipiv) を呼び出します。ここで A_lugetrf! によってLU分解された行列、ipiv はピボット情報です。getri!A_lu をインプレースで逆行列に変換します。


using LinearAlgebra

# 例として正方行列を作成
A = [1.0 2.0; 3.0 4.0]

# 行列のコピーを作成(getrf!がAをインプレースで変更するため)
A_copy = copy(A)

# 1. LU分解を実行
# getrf! は (LU分解された行列, ピボット情報, 成功コード) を返します
A_lu, ipiv, info_getrf = LinearAlgebra.LAPACK.getrf!(A_copy)

# info_getrf が 0 でない場合、エラーが発生したことを示します(例:行列が特異)
if info_getrf != 0
    error("LU分解に失敗しました。行列は特異かもしれません。")
end

# 2. 逆行列を計算
# getri! は LU分解された行列とピボット情報から逆行列を計算し、A_luをインプレースで変更します
inv_A_lu, info_getri = LinearAlgebra.LAPACK.getri!(A_lu, ipiv)

# info_getri が 0 でない場合もエラーを示します
if info_getri != 0
    error("逆行列の計算に失敗しました。")
end

println("元の行列 A:")
println(A)

println("\n計算された逆行列 inv(A):")
println(inv_A_lu)

# Juliaの標準のinv関数と比較
println("\nJuliaの標準inv(A)関数による逆行列:")
println(inv(A))

なぜ getri!() を使うのか?

通常、Juliaで逆行列を計算するには inv(A) を使うのが最も簡単です。しかし、LinearAlgebra.LAPACK.getri!() のような低レベルのLAPACK関数を直接使うことには、いくつかのメリットがあります。

  • 低レベルな制御
    特定のアルゴリズムを実装する際に、LAPACKの提供する低レベルなルーチンを直接利用したい場合があります。例えば、LU分解の結果を再利用して複数の線形システムを効率的に解く場合などに役立ちます。
  • メモリ効率
    ! が付く関数はインプレース操作を行うため、新しいメモリを割り当てることなく既存の配列を変更します。これは大規模な行列を扱う場合にメモリ使用量を削減するのに役立ちます。
  • パフォーマンス
    特定のシナリオ(例:大量の行列の逆行列を繰り返し計算する場合)では、LAPACK関数を直接呼び出すことで、より細かい制御が可能になり、パフォーマンスの最適化に役立つことがあります。
  • 行列が特異(非可逆)の場合、エラーが発生します。LAPACK関数の info コードを確認して、計算が成功したかどうかを判断することが重要です。Juliaの inv() 関数は、内部的にこれらのエラー処理を行いますが、getri!() を直接使用する場合は、ユーザー自身でエラーハンドリングを行う必要があります。
  • getri!() はLU分解された行列(getrf!() の結果)を期待します。元の行列を直接渡すことはできません。


LinearAlgebra.LAPACK.getri!() におけるよくあるエラーとトラブルシューティング

getri!() を使用する際に遭遇する可能性のある一般的なエラーと、それらの対処法について説明します。

info コードによるエラー (最も一般的)

getri!() は、LU分解関数である getrf!() と同様に、最後の戻り値として info コードを返します。この info コードが 0 でない場合、何らかの問題が発生したことを意味します。

  • コード例(info コードのチェック)

    using LinearAlgebra
    
    A = [1.0 2.0; 3.0 4.0]
    A_lu = copy(A)
    
    # LU分解
    A_lu, ipiv, info_getrf = LinearAlgebra.LAPACK.getrf!(A_lu)
    
    if info_getrf > 0
        println("getrf!エラー: 行列は特異です (info = $info_getrf)")
    elseif info_getrf < 0
        println("getrf!エラー: 不正な引数です (info = $info_getrf)")
    else
        # LU分解が成功した場合のみgetri!を呼び出す
        inv_A_lu, info_getri = LinearAlgebra.LAPACK.getri!(A_lu, ipiv)
    
        if info_getri > 0
            println("getri!エラー: 行列は特異です (info = $info_getri)")
        elseif info_getri < 0
            println("getri!エラー: 不正な引数です (info = $info_getri)")
        else
            println("逆行列:\n", inv_A_lu)
        end
    end
    
    # 特異行列の例
    B = [1.0 1.0; 1.0 1.0]
    B_lu = copy(B)
    B_lu, ipiv_b, info_getrf_b = LinearAlgebra.LAPACK.getrf!(B_lu)
    println("\n特異行列 B の getrf! info: ", info_getrf_b) # info > 0 が返るはず
    
    # getri! を呼び出すとエラーになる、または info > 0 が返る
    if info_getrf_b == 0
        inv_B_lu, info_getri_b = LinearAlgebra.LAPACK.getri!(B_lu, ipiv_b)
        println("特異行列 B の getri! info: ", info_getri_b)
    end
    
  • トラブルシューティング

    • info < 0 の場合
      • getri!() に渡す引数(LU分解された行列 A_lu とピボット情報 ipiv)の型、次元、値が正しいことを確認してください。
      • 特に、ipivgetrf!() の結果として得られたものをそのまま渡す必要があります。
      • これらの引数がLU分解の要件を満たしているか(例えば、正方行列であるかなど)も確認してください。
    • info > 0 の場合
      • 行列の特異性
        渡された行列が数学的に特異である可能性が高いです。これは、その行列の逆行列が存在しないことを意味します。
        • 原因の特定
          行列がなぜ特異になったのかを検討してください。例えば、線形従属な行や列が存在する、あるいは非常に小さな値の組み合わせで特特異になっている場合などです。
        • 代替手段の検討
          行列が特異である場合、逆行列を計算しようとしても意味がありません。線形方程式 Ax=b を解きたいのであれば、inv(A) * b の代わりに A \ b (バックスラッシュ演算子) を使うことを検討してください。バックスラッシュ演算子は、特異な、または近似的に特異なシステムに対しても、最小二乗解などの頑健な解法を自動的に選択することがあります。
        • 条件数の確認
          cond(A) を使って行列の条件数を確認すると良いでしょう。条件数が非常に大きい場合、行列は「悪条件」であり、数値的に特異に近い状態であることを示します。このような行列では、わずかな丸め誤差でも結果に大きな影響が出やすく、逆行列の計算が不安定になることがあります。
    • info = 0: 正常終了。
    • info < 0: -info 番目の引数が不正であることを示します。これは通常、プログラミングエラー(間違った型の引数を渡した、次元が合わないなど)を示します。
    • info > 0: 入力行列が特異(非可逆)であることを示します。info の値は、LU分解の過程で特異性が検出された対角要素の位置を示します。これは数値的な問題であり、行列の性質に起因します。

MethodError: no method matching getri!(...)

  • トラブルシューティング
    • 引数の型
      getri!() は、LinearAlgebra.LAPACK.getrf!() から返された特定の型の行列 (A_lu、通常は Matrix{Float64}Matrix{ComplexF64} など) と、ピボット情報 (ipiv、通常は Vector{Int64}) を期待します。
    • 例えば、LU分解されていない通常の行列を getri!() に直接渡そうとすると、このエラーが発生します。必ず getrf!() を先に実行し、その結果を使用してください。
    • また、行列の要素型が Float64ComplexF64 など、LAPACKがサポートする数値型であるかを確認してください。Int 型の行列では直接使用できない場合があります(要素型を変換する必要がある)。
  • 原因
    getri!() 関数に、定義されているメソッドと一致しない型の引数を渡した場合に発生します。

StackOverflowError

  • トラブルシューティング
    • Juliaのバージョン
      最新の安定版Juliaを使用していることを確認してください。古いバージョンに存在するバグが修正されている可能性があります。
    • BLASスレッド数
      環境変数 JULIA_NUM_THREADS または Juliaセッション内で BLAS.set_num_threads(1) のようにBLASのスレッド数を制限することで、スタックオーバーフローが回避される場合があります。ただし、これによりパフォーマンスが低下する可能性があります。
    • メモリ設定
      システムのスタックサイズ設定が十分であるかを確認します(OSに依存)。ただし、通常はJuliaやBLASが適切に管理します。
    • 問題の規模
      非常に巨大な行列の場合、システムのリソースを超えている可能性があります。計算の規模を縮小するか、分散計算などの代替手段を検討する必要があります。
  • 原因
    非常に大きな行列を扱う場合や、Juliaが使用するBLAS/LAPACKライブラリの設定によっては、スタックオーバーフローが発生することがあります。これは、特に古いJuliaバージョンや特定のOpenBLASのバージョンで報告されたことがあります。

LAPACKException (直接的なエラー)

  • トラブルシューティング
    • info コードによるエラーと同じく、引数の妥当性を確認します。
    • エラーメッセージに付随する info コードの値を確認し、それが示す問題に対処します。
  • LinearAlgebra.LAPACK.getri!() は、内部でLAPACK関数の info コードをチェックし、それがゼロでない場合には LAPACKException をスローすることがあります。特に負の info コード(不正な引数)の場合に発生しやすいです。
  • 数値安定性
    非常に悪条件の行列(小さな摂動で結果が大きく変わる行列)の場合、どのような線形代数ルーチンを使っても正確な逆行列を得ることは困難です。このような場合は、そもそも逆行列を明示的に計算する必要があるのか、あるいは線形システムを解く別の数値的に安定した方法があるのかを再検討することが重要です。
  • ドキュメントの参照
    Juliaの公式ドキュメントやLAPACKのドキュメント(GETRI ルーチンに関するもの)を参照すると、詳細な情報や引数の要件について確認できます。
  • inv() 関数との比較
    最終的な結果が正しいことを確認するために、Juliaの標準的な inv() 関数と比較してみると良いでしょう。
    A_original = [1.0 2.0; 3.0 4.0]
    inv_A_julia = inv(A_original)
    println("inv(A_original)による逆行列:\n", inv_A_julia)
    
  • 小さい行列でテスト
    複雑な行列で問題が発生した場合、まず小さいシンプルな行列(例:2x2 や 3x3 の既知の逆行列を持つ行列)でコードをテストし、期待通りの結果が得られるかを確認してください。
  • ステップバイステップでデバッグ
    LU分解 (getrf!()) と逆行列計算 (getri!()) は密接に関連しているため、まず getrf!() が正常に動作しているかを確認し、その info コードが 0 であることを確認してから getri!() に進んでください。


例1: 基本的な逆行列の計算

最も基本的な使用例です。正方行列のLU分解を行い、その結果を使って逆行列を計算します。

using LinearAlgebra

println("--- 例1: 基本的な逆行列の計算 ---")

# 元の行列 A を定義
A = [1.0 2.0; 3.0 4.0]
println("元の行列 A:\n", A)

# getrf! は行列をインプレースで変更するため、コピーを作成
A_lu = copy(A)

# 1. LU分解を実行
# getrf! は LU分解された行列 (A_lu)、ピボット情報 (ipiv)、成功コード (info_getrf) を返す
# A_lu は変更され、LU分解後の情報が格納される
A_lu, ipiv, info_getrf = LinearAlgebra.LAPACK.getrf!(A_lu)

# LU分解の成功をチェック
if info_getrf != 0
    error("LU分解に失敗しました (info = $info_getrf)。行列が特異かもしれません。")
end
println("\nLU分解後の A_lu (元の A_lu は変更されています):\n", A_lu)
println("ピボット情報 ipiv:\n", ipiv)

# 2. 逆行列を計算
# getri! は A_lu (LU分解された行列) と ipiv (ピボット情報) を使用し、
# A_lu をインプレースで逆行列に変換する
inv_A, info_getri = LinearAlgebra.LAPACK.getri!(A_lu, ipiv)

# 逆行列計算の成功をチェック
if info_getri != 0
    error("逆行列の計算に失敗しました (info = $info_getri)。")
end

println("\n計算された逆行列 inv(A):\n", inv_A)

# Julia標準の inv() 関数と比較 (結果が一致することを確認)
println("\nJulia標準の inv(A) 関数による逆行列:\n", inv(A))

解説

  • info コードは、各関数の実行が成功したかどうかを示します。0 以外の場合はエラーや問題が発生しています。
  • getrf!() の結果である A_luipivgetri!() の入力として使われます。
  • copy(A) で元の行列 A の変更を防ぎます。getrf!()getri!() も引数をインプレースで変更するため、元の A を残したい場合はコピーが必要です。

例2: 特異行列の処理

特異行列(逆行列を持たない行列)を getri!() に渡した場合の挙動と、info コードによるエラーハンドリングの例です。

using LinearAlgebra

println("\n--- 例2: 特異行列の処理 ---")

# 特異行列 (行が線形従属)
B = [1.0 2.0; 2.0 4.0]
println("元の特異行列 B:\n", B)

B_lu = copy(B)

# 1. LU分解を実行
B_lu, ipiv_b, info_getrf_b = LinearAlgebra.LAPACK.getrf!(B_lu)

println("\nLU分解後の B_lu (info = $info_getrf_b):\n", B_lu)
println("ピボット情報 ipiv_b:\n", ipiv_b)

# getrf! の info_getrf_b が 0 より大きい場合、行列は特異
if info_getrf_b > 0
    println("\ngetrf! が info = $info_getrf_b を返しました。行列 B は特異です(逆行列は存在しません)。")
    println("したがって、getri! を呼び出しても逆行列は計算できません。")
    # ここで処理を終了するか、代替手段を講じる
else # info_getrf_b が 0 以下の場合
    println("\ngetrf! は info = $info_getrf_b を返しました。引き続き getri! を試みます。")
    # 2. 逆行列を計算(この場合、失敗するはず)
    inv_B, info_getri_b = LinearAlgebra.LAPACK.getri!(B_lu, ipiv_b)

    println("getri! の info_getri_b: $info_getri_b")
    if info_getri_b != 0
        println("getri! も info = $info_getri_b を返しました。特異行列であるため、逆行列は計算できませんでした。")
    else
        println("計算された逆行列 inv(B):\n", inv_B)
    end
end

# 標準の inv() 関数で試すと SingularException がスローされる
try
    inv(B)
catch e
    if isa(e, SingularException)
        println("\nJulia標準の inv(B) 関数は SingularException をスローしました。")
    else
        rethrow(e)
    end
end

解説

  • 低レベル関数を使う場合、このような info コードをチェックして適切にエラーハンドリングを行う責任はプログラマにあります。
  • この場合、getri!() を呼び出しても意味がなく、やはり info_getri_b0 より大きい値を返します。
  • 特異行列の場合、getrf!() の時点で info_getrf_b0 より大きい値(通常は特異性が見つかったピボット位置)を返します。

例3: 複数の線形システムを効率的に解く (逆行列は使わないが関連する応用)

using LinearAlgebra

println("\n--- 例3: 複数の線形システムを効率的に解く ---")

# 元の行列 A と異なる右辺ベクトル b1, b2
A = [1.0 2.0; 3.0 4.0]
b1 = [5.0, 6.0]
b2 = [7.0, 8.0]
println("元の行列 A:\n", A)
println("右辺ベクトル b1:\n", b1)
println("右辺ベクトル b2:\n", b2)

# getrf! は行列をインプレースで変更するため、コピーを作成
A_lu_for_solve = copy(A)

# 1. LU分解を実行 (一度だけ行えばよい)
A_lu_for_solve, ipiv_for_solve, info_getrf_solve = LinearAlgebra.LAPACK.getrf!(A_lu_for_solve)

if info_getrf_solve != 0
    error("LU分解に失敗しました (info = $info_getrf_solve)。")
end
println("\nLU分解後の A_lu_for_solve:\n", A_lu_for_solve)
println("ピボット情報 ipiv_for_solve:\n", ipiv_for_solve)

# 2. 最初の線形システム Ax = b1 を解く
# getrs! は LU分解された行列とピボット情報を使って線形システムを解く
# 2番目の引数 'N' は行列 A の転置を使わないことを意味する
# 3番目の引数は右辺ベクトル b を意味し、これもインプレースで変更される
x1 = copy(b1) # b1 を変更したくないのでコピー
x1, info_getrs1 = LinearAlgebra.LAPACK.getrs!('N', A_lu_for_solve, ipiv_for_solve, x1)

if info_getrs1 != 0
    error("最初の線形システムの求解に失敗しました (info = $info_getrs1)。")
end
println("\nAx = b1 の解 x1:\n", x1)
println("検証 A * x1:\n", A * x1)

# 3. 2番目の線形システム Ax = b2 を解く (LU分解の結果を再利用)
x2 = copy(b2) # b2 を変更したくないのでコピー
x2, info_getrs2 = LinearAlgebra.LAPACK.getrs!('N', A_lu_for_solve, ipiv_for_solve, x2)

if info_getrs2 != 0
    error("2番目の線形システムの求解に失敗しました (info = $info_getrs2)。")
end
println("\nAx = b2 の解 x2:\n", x2)
println("検証 A * x2:\n", A * x2)

# Julia標準のバックスラッシュ演算子と比較
println("\nJulia標準の A \\ b1 による解:\n", A \ b1)
println("Julia標準の A \\ b2 による解:\n", A \ b2)

解説

  • getrs!() は、LU分解された行列とピボット情報から線形方程式の解を計算するLAPACKルーチンです。
  • getrf!() で一度LU分解を行えば、その結果 (A_lu_for_solve, ipiv_for_solve) を使って、複数の異なる右辺ベクトル b に対して線形システムを効率的に解くことができます。
  • この例は直接 getri!() を使用していませんが、LAPACKの哲学とパフォーマンス上の利点を示しています。

getri!() は複素数行列にも対応しています。

using LinearAlgebra

println("\n--- 例4: 複素数行列の逆行列 ---")

# 複素数行列 C を定義
C = [1.0+1.0im 2.0-1.0im; 3.0im 4.0+2.0im]
println("元の複素数行列 C:\n", C)

C_lu = copy(C)

# 1. LU分解を実行
C_lu, ipiv_c, info_getrf_c = LinearAlgebra.LAPACK.getrf!(C_lu)

if info_getrf_c != 0
    error("複素数行列のLU分解に失敗しました (info = $info_getrf_c)。")
end
println("\nLU分解後の C_lu:\n", C_lu)
println("ピボット情報 ipiv_c:\n", ipiv_c)

# 2. 逆行列を計算
inv_C, info_getri_c = LinearAlgebra.LAPACK.getri!(C_lu, ipiv_c)

if info_getri_c != 0
    error("複素数行列の逆行列計算に失敗しました (info = $info_getri_c)。")
end

println("\n計算された逆行列 inv(C):\n", inv_C)

# Julia標準の inv() 関数と比較
println("\nJulia標準の inv(C) 関数による逆行列:\n", inv(C))
  • LAPACKは実数と複素数の両方に対応するルーチンを提供しており、Juliaの LinearAlgebra.LAPACK モジュールはそれを適切に呼び出します。
  • 複素数型 (ComplexF64) の行列に対しても、全く同じ方法で getrf!()getri!() を使用できます。


getri!() の代替となるプログラミング方法を、目的別に説明します。

最も一般的で推奨される方法: inv() 関数

単に行列 A の逆行列 A−1 を計算したいだけであれば、Julia の inv() 関数を使用するのが最も簡単で推奨される方法です。

  • getri!() との違い

    • inv()getrf!()getri!() の両方のステップをカプセル化しており、ユーザーはLU分解の詳細を意識する必要がない。
    • inv() は新しいメモリを割り当てて逆行列を返すため、インプレース操作ではない。
  • 使用例

    using LinearAlgebra
    
    A = [1.0 2.0; 3.0 4.0]
    println("元の行列 A:\n", A)
    
    # inv() 関数で逆行列を計算
    inv_A = inv(A)
    println("\ninv(A) による逆行列:\n", inv_A)
    
    # 検証: A * inv_A は単位行列になるはず
    println("\nA * inv_A:\n", A * inv_A)
    
    • 高レベルなインターフェースで使いやすい。
    • 内部で最適なLAPACKルーチン(多くの場合、getrfgetri を組み合わせたもの)を呼び出し、エラー処理も適切に行われる。
    • 新しい行列として逆行列を返すため、元の行列は変更されない。

線形方程式の求解 (逆行列の計算が不要な場合): \ (バックスラッシュ) 演算子

多くの場合、逆行列 A−1 を明示的に計算する必要はなく、線形方程式 Ax=b の解 x を求めることが目的です。この場合、Julia の \ (バックスラッシュ) 演算子を使用するのが最も効率的で数値的に安定した方法です。

  • getri!() との違い

    • getri!() は逆行列を計算するが、\ 演算子は逆行列を介さずに直接解を求める。
    • 線形方程式を解くのが目的であれば、inv(A) * b よりも A \ b の方が強く推奨される。
  • 使用例

    using LinearAlgebra
    
    A = [1.0 2.0; 3.0 4.0]
    b = [5.0, 6.0]
    println("元の行列 A:\n", A)
    println("右辺ベクトル b:\n", b)
    
    # A \ b で Ax = b の解 x を計算
    x = A \ b
    println("\nA \\ b による解 x:\n", x)
    
    # 検証: A * x は b になるはず
    println("\nA * x:\n", A * x)
    
    # 複数の右辺ベクトルを持つ線形システム (A * X = B) の場合も同様
    B_matrix = [5.0 7.0; 6.0 8.0]
    X_matrix = A \ B_matrix
    println("\nA \\ B_matrix による解行列 X:\n", X_matrix)
    println("\nA * X_matrix:\n", A * X_matrix)
    
  • 特徴

    • 逆行列を明示的に計算するよりも、メモリ効率が良く、数値的に安定していることが多い。
    • 行列の性質(正方、長方形、対称、正定値など)に応じて、自動的に最適な分解(LU、QR、Choleskyなど)を選択して使用する。
    • 特異な、または悪条件のシステムに対しても、最小二乗解などの頑健な解法を提供することがある。

特定の高度なシナリオでは、行列分解の結果を明示的に保存し、それを再利用したい場合があります。これは、例えば、同じ行列 A に対して何度も線形方程式を解く場合や、行列の特定のプロパティ(条件数など)を分析する場合に有用です。

  • getri!() との違い

    • lu() はLU分解の結果を構造体として返すため、その後の操作(逆行列計算、線形システム求解など)をより柔軟に行える。
    • getri!() はLU分解された行列をインプレースで逆行列に変換するが、lu() は元の行列を保持し、分解結果を新しいオブジェクトとして返す。
    • lu() は通常、LinearAlgebra.LAPACK.getrf!() を内部的に呼び出すが、ユーザーは低レベルな info コードなどを直接扱う必要がない。
  • 使用例

    using LinearAlgebra
    
    A = [1.0 2.0; 3.0 4.0]
    b = [5.0, 6.0]
    println("元の行列 A:\n", A)
    
    # 1. lu() 関数でLU分解を実行
    F = lu(A) # F は LU分解オブジェクト
    println("\nLU分解オブジェクト F:\n", F)
    println("LU分解された行列 F.L * F.U:\n", F.L * F.U) # L と U 行列にアクセス可能
    
    # 2. LU分解オブジェクトを使って逆行列を計算
    inv_A_from_lu = inv(F) # LU分解オブジェクトから逆行列を計算できる
    println("\nLU分解オブジェクトからの逆行列:\n", inv_A_from_lu)
    
    # 3. LU分解オブジェクトを使って線形方程式を解く
    x_from_lu = F \ b # F \ b も A \ b と同じ結果を返す
    println("\nLU分解オブジェクトからの解 x:\n", x_from_lu)
    
  • lu() 関数 (LU分解)

    • LU分解の結果を LU オブジェクトとして返します。このオブジェクトは、LU分解された行列、ピボット情報などを内部に持ちます。
    • この LU オブジェクトを使って、線形方程式の解を効率的に求めたり、行列式を計算したりできます。
方法目的特徴getri!() との主な違い
inv(A)行列 A の逆行列 A−1 を明示的に計算最も簡単で高レベル。エラー処理も含む。インプレースではなく、新しい行列を返す。低レベルな詳細を隠蔽。
A \ b線形方程式 Ax=b の解 x を求める最も効率的で数値的に安定。逆行列の計算は不要。逆行列を計算しない。直接解を求める。
lu(A)LU分解の結果を再利用したい場合LU分解オブジェクトを返す。そのオブジェクトから逆行列や解を計算できる。低レベルなLAPACK関数を直接呼び出す必要がない。分解結果を構造体として保持。
LinearAlgebra.LAPACK.getri!()LU分解された行列をインプレースで逆行列に変換低レベルでメモリ効率が良い。プログラマによる詳細な制御が必要。LU分解が別途必要。インプレース操作。エラーハンドリングは手動。