gijyutsu-keisan.com

10.行列の分解(LU分解、QR分解)

10.2.QR分解

QR分解に関する使い方を説明します。
QR分解
FuncMatQRGS(mat1, Optional aryFlag) QR分解:グラムシュミット法
FuncMatQRHH(mat1, Optional pivFlag, Optional plim, Optional rlim, Optional aryFlag) QR分解:ハウスホルダー法

QR分解:グラムシュミット法

FuncMatQRGS(mat1, Optional aryFlag)
グラムシュミット法を用いたQR分解を行います。
一般に、数値計算プログラムでQR分解を利用する場合は、次のハウスホルダー法を用います。 グラム・シュミット法はあまり使用されません。
戻り値 ジャグ配列または二次配列で結果を出力。
二次配列の場合、上からユニタリ行列Q、上三角行列R。
ジャグ配列の場合、(0)(行,列)=ユニタリ行列Q、(1)(行,列)=上三角行列R。
mat1 QR分解対象行列(二次配列)。
aryFlag 前処理行列の出力方法。
0=ジャグ配列。
2=1つの配列にまとめて出力。

VBAサンプルは次の通りです。
Sub test2()

Dim cnt1 As Integer
Dim cntC1 As Integer, cntC2 As Integer
Dim cntR1 As Integer, cntR2 As Integer

Dim tmp As Variant
Dim matA As Variant

’行列の取得
cntR1 = 3
cntC1 = 2
cntR2 = Cells(cntR1, cntC1).End(xlDown).Row
cntC2 = Cells(cntR1, cntC1).End(xlToRight).Column
matA = Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value

’グラムシュミット法によるQR分解
tmp = FuncMatQRGS(matA, 0)

’結果出力(ジャグ配列)
cntR1 = 3
cntC1 = 7
For cnt1 = 0 To UBound(tmp)
cntR2 = cntR1 + UBound(tmp(cnt1), 1)
cntC2 = cntC1 + UBound(tmp(cnt1), 2)
Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value = tmp(cnt1)
cntR1 = cntR2 + 2
Next cnt1

End Sub
二次配列として返す場合は次のように書きます。
Sub test3()

Dim cnt1 As Integer
Dim cntC1 As Integer, cntC2 As Integer
Dim cntR1 As Integer, cntR2 As Integer

Dim tmp As Variant
Dim matA As Variant

’行列の取得
cntR1 = 3
cntC1 = 2
cntR2 = Cells(cntR1, cntC1).End(xlDown).Row
cntC2 = Cells(cntR1, cntC1).End(xlToRight).Column
matA = Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value

’グラムシュミット法によるQR分解
tmp = FuncMatQRGS(matA, 2)

’結果出力(二次配列)
cntR1 = 3
cntC1 = 7
cntR2 = cntR1 + UBound(tmp, 1)
cntC2 = cntC1 + UBound(tmp, 2)
Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value = tmp

End Sub

QR分解:ハウスホルダー法

FuncMatQRHH(mat1, Optional pivFlag, Optional plim, Optional rlim, Optional aryFlag)
ハウスホルダー法を用いたQR分解を行います。
数値計算でのQR分解と言えば、一般にこのハウスホルダー法のことを指します。
戻り値 ジャグ配列または二次配列で結果を出力。
二次配列の場合、上からユニタリ行列Q、上三角行列R、列前処理行列Pc。
ジャグ配列の場合、(0)(行,列)=ユニタリ行列Q、(1)(行,列)=上三角行列R、(2)(行,列)=列前処理行列Pc。
mat1 QR分解対象行列(二次配列)。
行数≧列数を満たせば、正方行列でなくても構いません。
pivFlag 前処理フラグ(省略可)。
0=部分列ピボット、1=列スケーリング+ピボット
plim ピボット処理閾値(省略可)。デフォルト値=2e-12。
rlim 数値丸め閾値(省略可)。デフォルト値=2e-12。
aryFlag 前処理行列の出力方法。
0=ジャグ配列 + 変換行列連立方程式用(デフォルト)。
1=ジャグ配列 + 変換行列分解確認用。
2=1つの配列にまとめて出力 + 変換行列連立方程式用。
3=1つの配列にまとめて出力 + 変換行列分解確認用。
引数の指定方法例を紹介しておきます。
  1. 部分列ピボットでQR分解する場合(通常はこの方法で使用します)
    FuncMatQRHH(mat1)
  2. スケーリング+列ピボットでQR分解する場合
    FuncMatQRHH(mat1,3)
  3. ピボット処理判定値を1e-6として、完全ピボットでLU分解する場合
    FuncMatQRHH(mat1,3,1e-6)
  4. 出力(aryFlag)を二次配列、ユニタリ行列Qと変換行列の逆行列を出力する場合
    FuncMatQRHH(mat1,,,,3)
  5. VBAサンプルは次の通りです。
    Sub test2()
    
    Dim cnt1 As Integer
    Dim cntC1 As Integer, cntC2 As Integer
    Dim cntR1 As Integer, cntR2 As Integer
    
    Dim tmp As Variant
    Dim matA As Variant
    
    ’行列の取得
    cntR1 = 3
    cntC1 = 2
    cntR2 = Cells(cntR1, cntC1).End(xlDown).Row
    cntC2 = Cells(cntR1, cntC1).End(xlToRight).Column
    matA = Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value
    
    ’ハウスホルダー法によるQR分解
    tmp = FuncMatQRHH(matA, , , , 1)
    
    ’結果出力(ジャグ配列)
    cntR1 = 3
    cntC1 = 7
    For cnt1 = 0 To UBound(tmp)
    cntR2 = cntR1 + UBound(tmp(cnt1), 1)
    cntC2 = cntC1 + UBound(tmp(cnt1), 2)
    Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value = tmp(cnt1)
    cntR1 = cntR2 + 2
    Next cnt1
    
    End Sub
    
    二次配列として返す場合は次のように書きます。
    Sub test3()
    
    Dim cnt1 As Integer
    Dim cntC1 As Integer, cntC2 As Integer
    Dim cntR1 As Integer, cntR2 As Integer
    
    Dim tmp As Variant
    Dim matA As Variant
    
    ’行列の取得
    cntR1 = 3
    cntC1 = 2
    cntR2 = Cells(cntR1, cntC1).End(xlDown).Row
    cntC2 = Cells(cntR1, cntC1).End(xlToRight).Column
    matA = Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value
    
    ’ハウスホルダー法によるQR分解
    tmp = FuncMatQRHH(matA, , , , 3)
    
    ’結果出力(二次配列)
    cntR1 = 3
    cntC1 = 7
    cntR2 = cntR1 + UBound(tmp, 1)
    cntC2 = cntC1 + UBound(tmp, 2)
    Range(Cells(cntR1, cntC1), Cells(cntR2, cntC2)).Value = tmp
    
    End Sub
    
    FuncMatQRHHは、二次配列で返す場合、Excel関数としても使えます(この場合、aryFlag=2または3とします)。
    なお、Functionプロシージャを用いると、出力操作等計算には不必要な処理が入るため、効率的に計算を進めたい場合は、Functionプロシージャ内で指示されているSubプロシージャ
    CalcMatQRHH(matQ, matR, matPc, ByVal matA, Optional pivFlag, Optional plim, Optional rlim, Optional outFlag)
    の使用をお勧めします。

参考文献