2.4 連立方程式の解法 大きく分類して,以下の方法がある。 ①直接法 ②間接法(別名:反復法) [直接法] ①ガウス(Gauss)の消去法 ②ガウス・ジョルダン(Gauss-Jordan)法 (別名:掃出し法) ③LU分解法 Johann Carl Friedrich Gaus(1777-1855) [間接法](別名反復法) ①ヤコビの反復法(連立変位法) (ヤコブ法ともいう) ②ガウス・ザイデル(Gauss-Seidel)法 ②SOR法 (Successive Over-Relaxation method:逐次過緩和法) Carl Gustav Jacob Jacobi(1804年-1851) ちょっと横道にそれて… 同一人物と間違えそうな二人のジョルダン ①ドイツの測地学者 Wilhelm Jordan(1819-1904) ガウス・ジョルダン法の発案者 ②フランスの数学者 Camille Jordan (1771-1821) ジョルダン標準形の発案者 ちょっと横道にそれて… ルートヴィヒ・ザイデル(Philipp Ludwig von Seidel)ってどんな人? (1821年8月24日 - 1896年8月13日) ツバイブリュッケン生まれ。ドイツの数学者、光学者、天文学者。 光学の研究を行いザイデル収差で知られる。 1846年: ミュンヘン大学で望遠鏡の光学系の研究で博士号。 1847年: ミュンヘン大学教授。 1856年: 収差理論に関する著書を出版。 1874年: 連立一次方程式の解法である ガウス=ザイデル法を発表。 1879年~1882年までボーゲンハウゼン天文台の所長。 (1)ガウス(Gauss)の消去法 前進消去(forward elimination )と 後退代入(backward substitution)に分かれる。 [前進消去] 6 5 4 8 12 13 10 16 18 21 17 27 2行目-1行目×2→2行目 3行目-1行目×3→3行目 6 5 4 8 0 3 2 0 0 6 5 3 3行目-2行目×2→3行目 [後退代入] x3 3 b2 2 x3 0 2 3 x2 2 3 3 b1 5 x2 4 x3 8 5 (2) 4 3 x1 1 6 6 6 5 4 8 0 3 2 0 0 0 1 3 ガウスの消去法の考え方 一般化 [前進消去] 処理効率をあげるため共通の係数を先に計算(対角項を1にしてもよい) aik akk (i k 1, , n) aij aij akj bi bi bk [後退代入] ( j k 1, , n) (i j 1, , n) 対角項を1にすれば,除算は必要ない。 bn xn ann bk xk n a x j k 1 akk kj j (k n 1, ,1) a12 a11 0 a 22 0 0 a1n x1 b1 a2 n x2 b2 ann xn bn VBでプログラムを作る ①シートの定義(なおA*xを計算する部分を用意しておく) 配列は,N×(N+1)とし,最後にBの値を入れる。 ②データの設定部分 Public A() As Double Public B() As Double Public C() As Double Public ESP As Double Private Function データ設定() N = 3 N1 = N + 1 ReDim A(N, N1) EPS = 0.000001 N1 = N + 1 With Worksheets("Sheet1") For i = 1 To N For J = 1 To N1 A(i, J) = Val(.Cells(i, J)) Next J Next i End With データ設定 = N End Function ③結果設定部分とボタンイベントハンドラ Private Sub 結果表示(N) N1 = N + 1 With Worksheets("Sheet1") For i = 1 To N ‘ 以下3行は1行に書くこと .Cells(i, 6) = Right(Space(12) & Format(A(i, N1), "0.00000E+00"), 12) Next i End With End Sub Sub ボタン1_Click() N = データ設定() If N >= 2 Then R = 消去法(A, N, ESP) 結果表示 N End If End Sub ④処理本体(1) Public Function 消去法(A, N, ESP) As Boolean On Error GoTo エラー 消去法 = False N1 = N + 1 For K = 1 To N ' 前進消去 If Abs(A(K, K)) < ESP Then 消去法 = True MsgBox “解を求めることができません" Exit Function End If For I = K + 1 To N ALFA = A(I, K) / A(K, K) For j = K + 1 To N1 A(I, j) = A(I, j) - ALFA * A(K, j) Next Next Next K (続きあり) ④処理本体(2:後退代入) For I = N To 1 Step -1 ' 後退代入 T = A(I, N + 1) For j = I + 1 To N T = T - A(I, j) * A(j, N + 1) Next A(I, N + 1) = T / A(I, I) Next 復帰: Exit Function エラー: 消去法 = True MsgBox Error(Err) Resume 復帰 End Function (2)ガウス-ジョルダン(Gauss-Jordan)法 (掃出し法) 消去方法 1 2 1 3 1 1 1 10 1 3 2 21 3 2 1 17 2 1 1 14 1行目/1 2行目-1行目×2 3行目-1行目 4行目-1行目×3 1 0 0 0 11 1 9 0 3 2 17 0 2 1 1 0 3 1 0 0 1行目-3行目×(2/3) 2行目-3行目×(-1/3) 3行目/3 4行目-1行目×(-3/3) 1 1 10 1 1 0 1 1 0 1 0 2 1 0 7 0 1 2 2 16 1行目-2行目×(-1) 2行目/(-1) 3行目-2行目×2×(- 1) 4行目-1行目×(-1) 1 0 0 0 0 0 2 8 0 0 1 0 0 1 1 0 0 5 2 3 1行目-4行目×(-1/2) 2行目-4行目×0 3行目-4行目×0 4行目/(-2) 1 0 0 0 11 1 9 0 3 2 17 0 2 1 1 0 3 1 0 0 0 1 0 0 0 0 0 1 1 0 0 2 0 1 0 3 0 0 1 4 ④処理本体(1) Public Function 掃出法(A, N, ESP) As Boolean On Error GoTo エラー 掃出法 = False N1 = N + 1 For K = 1 To N If Abs(A(K, K)) < ESP Then 掃出法 = True MsgBox "行列式の解を求めることができません" Exit Function End If K1 = K + 1 For J = K1 To N1 A(K, J) = A(K, J) / A(K, K) Next (続きあり) ④処理本体(2) For i = 1 To N If i <> K Then For J = K1 To N1 A(i, J) = A(i, J) - A(i, K) * A(K, J) Next End If Next Next K 復帰: Exit Function エラー: 掃出法 = True MsgBox Error(Err) Resume 復帰 End Function (3)ピボット選択付きのガウスの消去法 最大値を対角項にもってくるよう行を入替える。 (行を入替えても解は変わらないことに注意) 0 5 4 x1 8 12 0 10 x 16 2 18 21 0 x3 27 5 x2 4 x3 8 12 x1 18 x1 21x2 両者とも 同じ連立方程式で あることに注意 18 21 0 x1 27 0 5 4 x 8 2 12 0 10 x3 16 18 x1 21x2 10 x3 16 27 27 5 x2 4 x3 8 12 x1 10 x3 16 ④処理本体(1) Private Function 消去法(A, N, ESP) As Boolean On Error GoTo エラー 消去法 = False N1 = N + 1 For K = 1 To N K1 = K + 1 Max = Abs(A(K, K)): IR = K ' ピボット入替え If K <> N Then For i = K1 To N If Abs(A(i, K)) >= Max Then Max = Abs(A(i, K)) IR = i End If Next i End If (続きあり) ピボット入替え部分 ④処理本体(2) If Max < ESP Then 消去法 = True MsgBox "行列式の解を求めることができません" Exit Function End If If IR <> K Then For j = K To N1 AA = A(K, j): A(K, j) = A(IR, j): A(IR, j) = AA Next j End If W = A(K, K) ' 前進消去 For j = K To N1 A(K, j) = A(K, j) / W Next j (続きあり) ④処理本体(3) If K = N Then Exit For For i = K1 To N For j = K1 To N1 A(i, j) = A(i, j) - A(i, K) * A(K, j) Next j Next i Next K For K = N - 1 To 1 Step -1 ' 後退代入 For j = K + 1 To N A(K, N1) = A(K, N1) - A(K, j) * A(j, N1) Next j Next K 復帰: Exit Function エラー: 消去法 = True MsgBox Error(Err) Resume 復帰 End Function (4)逆行列 定義から 18 21 0 b11 b12 b13 1 0 0 0 5 4 b b 0 1 0 b 21 22 23 12 0 10 b31 b32 b33 0 0 1 次のような方程式を解き,bij を求めることに帰着する。 18 21 0 b11 1 0 5 4 b 0 21 12 0 10 b31 0 18 21 0 b12 0 0 5 4 b 1 22 12 0 10 b32 0 18 21 0 b13 0 0 5 4 b 0 23 12 0 10 b33 1 すなわち,N×(2N)の行列を用意し,連立方程式を解けばよい。 VBでプログラムを作る ①シートの定義(なおA*A-1を計算する部分を用意しておく) 配列サイズは,N×2Nとし,N+1から2Nの範囲に 対角項のみ1,それ以外に0を入れてから掃出し法を 適用する。 ②データの設定部分 Public A() As Double Public B() As Double Public C() As Double Function データ設定() N=3 ReDim A(N, N * 2) With Worksheets("Sheet1") For i = 1 To N For j = 1 To N A(i, j) = Val(.Cells(i, j)) Next j Next i End With データ設定 = N End Function ③結果設定部分とボタンイベントハンドラ Sub 結果表示(N) With Worksheets("Sheet1") For k = 1 To N For i = 1 To N ‘ 以下2行は1行に記述する .Cells(i, k + 4) = Right(Space(12) & Format(A(i, k + N), "0.00000E+00"), 12) Next i Next .Select End With End Sub Sub ボタン1_Click() N = データ設定() ESP = 0.00001 R = 掃出法(A, N, ESP) 結果表示 N End Sub ④処理本体(1) Public Function 掃出法(A, N, ESP) As Boolean 'On Error GoTo エラー For i = 1 To N For j = 1 To N A(i, j + N) = 0 If i = j Then A(i, j + N) = 1 Next Next 掃出法 = False N2 = N * 2 For k = 1 To N If Abs(A(k, k)) < ESP Then 掃出法 = True MsgBox "行列式の解を求めることができません" Exit Function End If (続きあり) ④処理本体(2) S = 1 / A(k, k) For j = k + 1 To N2 A(k, j) = A(k, j) * S Next For i = 1 To N If i <> k Then S = A(i, k) For j = k + 1 To N2 A(i, j) = A(i, j) - S * A(k, j) Next End If Next Next 復帰: Exit Function エラー: 掃出法 = True MsgBox Error(Err) Resume 復帰 End Function (5)LU分解による方法 [例] 6 5 4 x1 1 0 0 6 5 4 x1 8 12 13 10 x 2 1 0 0 3 2 x 16 2 2 18 21 17 x3 3 2 1 0 0 1 x3 27 6 5 4 x1 y1 1 0 0 y1 8 0 3 2 x y と置くと y 16 2 1 0 2 2 2 0 0 1 x3 y3 3 2 1 y3 27 y1 8, 2 y1 y2 16, 3 y1 2 y2 y3 27 y2 16 2 y1 16 16 0, y3 27 3 y1 2 y2 27 24 0 3 6 5 4 x1 8 0 3 2 x 0 2 0 0 1 x3 3 この演算の意味 元の行列に施した処理を 列ベクトルにも施す。 下三角行列は, 元の行列を 上三角行列に変換する行列の 逆行列である。 x3 3, 3 x2 2 x3 0, 6 x1 5 x2 4 x3 8 0 2 x3 2 3 2 3 3 8 5 x2 4 x3 8 5 (2) 4 3 6 x1 1 6 6 6 x2 確認 (例)下三角行列の逆行列を元の行列に乗じると上三角行列になる 0 0 1 0 0 1 0 0 1 0 0 1 2 1 0 2 1 0 2 2 0 1 0 0 1 0 0 1 2 1 3 2 1 1 4 3 0 2 2 0 0 1 0 0 1 すなわち 1 0 0 2 1 0 3 2 1 の逆行列 0 0 1 2 1 0 1 2 1 を元の行列に 乗じると 0 0 6 5 4 6 5 4 1 6 5 4 2 1 0 12 13 10 12 12 0 3 2 10 13 8 10 1 2 1 18 21 17 6 24 18 5 26 21 4 20 17 0 0 1 VBでプログラムを作る ①シートの定義(行列のLU分解で作ったシートに追加する) (なおA*A-1を計算する部分を用意しておく) この部分を追加 ②データの設定部分 Private A(3, 3) As Double Private L(3, 3) As Double Private U(3, 3) As Double Private Y(3) As Double Private X(3) As Double Private B(3) As Double Private Sub データ設定() With Worksheets("Sheet1") For i = 1 To 3 For j = 1 To 3 A(i, j) = .Cells(i + 1, j + 1) Next Next For i = 1 To 3 B(i) = .Cells(i + 1, 16) Next End With End Sub ③結果設定部分とボタンイベントハンドラ Private Sub 結果設定(L, U, Y, X) With Worksheets("Sheet1") For i = 1 To 3 For j = 1 To 3 .Cells(i + 1, j + 6) = L(i, j) .Cells(i + 1, j + 11) = U(i, j) Next Next For i = 1 To 3 .Cells(i + 1, 17) = Y(i) .Cells(i + 1, 18) = X(i) Next End With End Sub Sub ボタン3_Click() データ設定 LU分解による連立方程式 A, L, U, B, Y, X, 3 結果設定 L, U, Y, X End Sub ④LU分解処理(2.3に同じ。再掲) Private Sub LU分解(A, L, U, N) For i = 1 To N For j = 1 To N L(i, j) = 0 U(i, j) = 0 Next Next L(1, 1) = 1 For j = 1 To N U(1, j) = A(1, j) Next For i = 2 To N U(i, 1) = 0 L(1, i) = 0 L(i, 1) = A(i, 1) / U(1, 1) Next For i = 2 To N L(i, i) = 1 T = A(i, i) For k = 1 To i T = T - L(i, k) * U(k, i) Next U(i, i) = T For j = i + 1 To N U(j, i) = 0: L(i, j) = 0 T = A(j, i) For k = 1 To i T = T - L(j, k) * U(k, i) Next L(j, i) = T / U(i, i) T = A(i, j) For k = 1 To i T = T - L(i, k) * U(k, j) Next U(i, j) = T Next Next End Sub ⑤LU分解した結果を使って連立方程式を解く処理 Sub LU分解による連立方程式(A, L, U, B, Y, X, N) LU分解 A, L, U, N For i = 1 To N T = B(i) For k = 1 To i - 1 T = T - L(i, k) * Y(k) Next Y(i) = T Next For i = N To 1 Step -1 T = Y(i) For k = i + 1 To N T = T - U(i, k) * X(k) Next X(i) = T / U(i, i) Next End Sub (6)ピボット選択によるLU分解 ①クラウト法によるLU分解は分かりやすいが,ピボット選択(対角 項の絶対値を最大値にとる)が適用できない。 ②ガウスの消去法における前進消去は,上三角行列を作成する 過程と同じ。したがって,ガウスの消去法における前進消去を用 いてLU分解することが可能。 考え方の基本 ①ガウスの消去法の前進消去は,注目する i 列に対して a g ki ki (k i ) それ以外は,対角項=1, 非対角項=0 aii という変換行列で表すことができる。 [例] 0 0 18 21 17 18 21 17 1 12 18 1 0 12 13 10 0 1 4 3 6 18 0 1 6 5 4 0 2 5 3 ②ピボット選択は置換行列で表現できる 0 0 1 a11 a12 0 1 0 a 21 a22 1 0 0 a31 a32 a13 a31 a32 a23 a21 a22 a33 a11 a12 a33 a23 a13 ガウスの消去法によるLU分解の考え方(1) (以下,式の展開を覚える必要はない。どのような手順で計算されるのかを理解するこ と) ピボット選択を行うガウスの消去法の前進消去は,置換行列 Pi (i 1,, n 1) および変換行列 Gi (i 1,, n 1) を用いると Gn 1 Pn 1 G1 P1 Ax Gn 1 Pn1 G1 P1 x 右辺の Gn 1 Pn 1 G1 P1 を計算すると Gn 1 Pn 1Gn 2 Pn 2 G1 P1 P1 1 P 1 Gn 1 Pn 1Gn 2 Pn 2 P2G1 I P1 P P P 1 Gn 1 Pn 1Gn 2 P2G1 IP2 P2 P1 Gn 1 Gn 1 Gn 1 同様にして n 1G n 2 P2G1 IP2 1 P P 2 P P P P P P G IP P P P P n 1G n 2 Pn 2 P2G1 IP2 n 1G n 2 Pn 2 1 Gn1 Pn1 P3 P2G1 IP2 1 1 3 3 1 3 1 2 1 2 P P 1 3 3 1 2 1 1 3 3 2 1 Pn11 Pn1 P3 P2 P1 ガウスの消去法によるLU分解の考え方(1) (以下,式の展開を覚える必要はない。どのような手順で計算されるのかを理解すること) Gn1 Pn1 P3 P2G1 IP2 1 P P 1 3 3 1 Pn11 Pn1 P3 P2 P1 この式を計算するために漸化式の形で表現する。 H0 I, H i 1 PiGi 1 H i 2 Pi 1 (i 2, , n 2), n 1 P Pk k 1 ガウスの消去法によるLU分解の考え方(2) さらに A0 A, Ai Gi Pi Ai 1 (i 1,, n 1) とすると An 1 は,前進消去の最後であるため,上三角行列となる。したがって, Gn 1 Pn 1 G1 P1 Ax Gn 1 Pn1 G1 P1 x は,次のように表現できる。 Ux Gn 1 H n 2 Px すなわち, 下三角行列は Gn1 H n2 1Ux Px L Gn1 H n2 1 となる。 ガウスの消去法によるLU分解のアルゴリズム ピボット選択を行う前進消去を,置換行列 Pi (i 1,, n 1) および変換行列Gi (i 1,, n 1) を用いて表すと, ① P1 , G1 を求め, A1 P1 G1 A , H 0 I とする。 (ピボット選択を行う前進消去を1桁だけ実行したことと同じ) P1 の替わりに置換した元のピボット位置を記憶してもよい。 ガウスの消去法によるLU分解のアルゴリズム ② 2 i について Pi , Gi を求め Ai Pi Gi Ai 1 , Hi 1 Pi Gi 1 Hi 2 Pi (置換行列の性質から Pi Pi 1 1 であることに注意) ③ステップ②を i n 1 まで繰返し, i n 1 のときの An1 Pn1 Gn1 An2 が上三角行列, L (Gn 1 H n 2 ) 1 が下三角行列となる。 VBでプログラムを作る ①シートの定義 置換行列があることに注意 ②行列演算等,共通的な処理が多いので,できる限り共通ルーチン化する。 ③連立方程式の解法は,クラウト法による解法を参考にして作成してみよう。 なお,列ベクトルに置換行列を乗じてから前進代入,後退代入を行うこと。 ③データの設定部分 Private A(3, 3) As Double Private U(3, 3) As Double Private L(3, 3) As Double Private multP(3, 3) As Double Private Sub データ設定() With Worksheets("Sheet1") For i = 1 To 3 For J = 1 To 3 A(i, J) = .Cells(i Next Next End With End Sub ' 対象とする配列 ' 上三角行列 ' 下三角行列 '置換行列の積 + 1, J + 1) ④結果設定とボタンイベントハンドラ Sub 結果設定() With Worksheets("Sheet1") For i = 1 To 3 For J = 1 To 3 .Cells(i + 1, J + 6) = L(i, J) .Cells(i + 1, J + 11) = U(i, J) .Cells(i + 1, J + 16) = multP(i, J) Next Next End With End Sub Sub ボタン2_Click() TraceMode = True データ設定 ピボット選択LU分解 A, L, U, multP, 3 結果設定 End Sub ⑤共通ルーチン(1) Private Function 最大対角項(A, K, N) As Integer ID = K For J = K + 1 To N If Abs(A(ID, K)) < Abs(A(J, K)) Then ID = J Next 最大対角項 = ID End Function Private Sub 行入替え(K1, K2, P, N) '行入替え For i = 1 To N T = P(K1, i): P(K1, i) = P(K2, i): P(K2, i) = T Next End Sub ⑤共通ルーチン(2) Private Sub 単位行列設定(H, N) ' 単位行列の設定 For i = 1 To N For J = 1 To N H(i, J) = 0 If i = J Then H(i, J) = 1 Next Next End Sub Private Sub 置換行列(K1, K2, P, N) '置換行列Pの設定 単位行列設定 P, N If K1 = K2 Then Exit Sub 行入替え K1, K2, P, N End Sub ⑤共通ルーチン(3) Private Sub 行列乗算(A, B, C, N1, N2) '行列乗算 For i = 1 To N1 ' C = A * B For J = 1 To N2 C(i, J) = 0 For K = 1 To N1 C(i, J) = C(i, J) + A(i, K) * B(K, J) Next Next Next End Sub ⑤共通ルーチン(4) Private Sub 変換行列(A, K, G, N) '変換行列Gの設定 単位行列設定 G, N AKK = A(K, K) For i = K + 1 To N G(i, K) = -A(i, K) / AKK Next End Sub ⑤共通ルーチン(5) Public Function 掃出法(A, N, ESP) As Boolean 'On Error GoTo 掃出エラー For i = 1 To N For J = 1 To N For i = 1 To N A(i, J + N) = 0 If i <> K Then If i = J Then A(i, J + N) = 1 S = A(i, K) Next For J = K + 1 To N2 Next A(i, J) = A(i, J) - S * A(K, J) 掃出法 = False Next N2 = N * 2 End If For K = 1 To N Next If Abs(A(K, K)) < ESP Then Next 掃出法 = True 掃出復帰: Exit Function MsgBox "解を求めることができません" 掃出エラー: Exit Function 掃出法 = True End If MsgBox Error(Err) S = 1 / A(K, K) Resume 掃出復帰 For J = K + 1 To N2 End Function A(K, J) = A(K, J) * S Next ⑤共通ルーチン(6) Private Sub 掃出結果設定(A, R, N) For i = 1 To N For J = 1 To N R(i, J) = A(i, J + N) Next Next End Sub Private Sub 配列複写(A, R, N) For i = 1 To N For J = 1 To N R(i, J) = A(i, J) Next Next End Sub ⑥処理本体(初期設定) Private Sub ピボット選択LU分解(A, L, U, multP, N) Dim G() As Double ' 置換行列 Dim GB() As Double ' Gn-1を保存するための作業領域 Dim P() As Double ' 置換行列 Dim H() As Double ' 下三角行列用行列 Hi Dim C() As Double ' 乗算用作業領域1 Dim CC() As Double ' 乗算および逆行列計算用作業領域 ReDim G(N, N), P(N, N), H(N, N), C(N, N), CC(N, 2 * N), GB(N, N) 単位行列設定 H, N ' H0を単位行列とする 単位行列設定 multP, N ' multPを単位行列とする (実行部分の続きあり) ⑥処理本体(実行部分) For i = 1 To N - 1 ID = 最大対角項(A, i, N) ' 最大対角項の選択 置換行列 i, ID, P, N ' 置換行列Piの設定 行列乗算 P, A, C, N, N ' C=Pi*Ai-1 変換行列 C, i, G, N ' 前進代入の変換行列Giを求める 行列乗算 G, C, A, N, N ' Ai = Gi*C = Gi*Pi*Ai-1 If i > 1 Then ' (i=1のときGi-1がない) 行列乗算 GB, H, C, N, N ' Hi = Pi*Gi-1*Hi-2*Pi^(-1) 行列乗算 P, C, CC, N, N ' (Pi^(-1) =Piに注意) 行列乗算 CC, P, H, N, N End If 行列乗算 P, multP, C, N, N ' Pmult=Pi*Pmult 配列複写 C, multP, N 配列複写 G, GB, N ' Gi-1を保存 Next 行列乗算 G, H, CC, N, N ' CC=Gn-1*Hn-2 ESP = 0.0001 R = 掃出法(CC, N, ESP) ' CCの逆行列を計算して 掃出結果設定 CC, L, N ' 下三角行列とする。 配列複写 A, U, N ' An-1を上三角行列とする End Sub (7)ピボット選択によるLU分解の改善 ①置換行列は結局のところ,行の入替えである。ピボットの位置だ けを持っていれば可能。 ②下三角行列の対角項は1に決まっている。 ③上三角行列の左下非対角項は0,下三角行列の右上非対角項 は0である。 ⑤したがって,左下非対角項には下三角行列,対角項と右上非対 角項には上三角行列の各項を入れることにすれば,配列サイズ を削減できる。 VBでプログラムを作る ①シートの定義 ②データの設定部分 Public A() As Double Public B() As Double Public C() As Double Public X() As Double Public LU() As Double Public IPivot() As Integer Function データ設定() N = 4 ReDim A(N, N), LU(N, N), IPivot(N) With Worksheets("Sheet1") For I = 1 To N For J = 1 To N A(I, J) = Val(.Cells(I + 1, J + 1)) Next Next End With データ設定 = N End Function ③結果の設定とイベントハンドラ Sub 結果表示(LU, IPivot, N) With Worksheets("Sheet1") For I = 1 To N For J = 1 To N .Cells(I + 1, J + 7) = LU(I, J) Next Next For I = 1 To N .Cells(I + 1, 13) = IPivot(I) Next End With End Sub Sub ボタン1_Click() N = データ設定() EPS = 0.001 LU分解 A, LU, IPivot, N, EPS 結果表示 LU, IPivot, N End Sub ④共通ルーチン Sub 配列移動(A, B, N) For I = 1 To N For J = 1 To N B(I, J) = A(I, J) Next Next End Sub ⑤処理本体 Sub LU分解(A, LU, IPivot, N, EPS) 配列移動 A, LU, N For k = 1 To N IPivot(k) = k Next For k = 1 To N I = k For J = k + 1 To N If Abs(LU(IPivot(J), k)) > Abs(LU(IPivot(I), k)) Then I = J Next J = IPivot(k): IPivot(k) = IPivot(I): IPivot(I) = J pivot = LU(IPivot(k), k) If Abs(pivot) < EPS Then MsgBox (k & "番目の対角項が" & pivot & "です") For I = k + 1 To N T = LU(IPivot(I), k) / pivot: LU(IPivot(I), k) = T For J = k + 1 To N LU(IPivot(I), J) = LU(IPivot(I), J) - T * LU(IPivot(k), J) Next Next Next End Sub ⑥確認用乗算と設定(1) Sub 確認用乗算と表示() N = 4 ReDim A(N, N), B(N, N), C(N, N), IPivot(N) With Worksheets("Sheet1") For I = 1 To N IPivot(I) = .Cells(I + 1, 13) For J = 1 To N If J = I Then A(I, J) = Val(.Cells(I + 1, J + 7)) B(I, J) = 1 ElseIf J > I Then A(I, J) = Val(.Cells(I + 1, J + 7)) B(I, J) = 0 Else A(I, J) = 0 B(I, J) = Val(.Cells(I + 1, J + 7)) End If Next Next (続きあり) ⑥確認用乗算と設定(2) For I = 1 To N For J = 1 To N C(I, J) = 0 For k = 1 To N C(I, J) = C(I, J) + B(I, k) * A(k, J) Next .Cells(I + 1, J + 18) = C(I, J) Next Next End With End Sub Sub ボタン2_Click() 確認用乗算と表示 End Sub LU分解による連立方程式の解法,逆行列の計算 参考プログラム1(連立方程式の解法)を開く 参考プログラム2(逆行列の計算)を開く (8)ヤコビ(Jacobi)の反復法(連立変位法) 連立方程式 a11x1 a12 x2 a1n xn b1 a21x1 a22 x2 a2 n xn b2 an1 x1 an 2 x2 ann xn bn を,次のように並び替えて考える。 b x1 b1 a12 x2 a13 x3 a1n xn a11 x2 2 a21x1 a23 x3 a2 n xn a22 xn bn an1 x1 an 2 x2 an ,n 1 xn ann ヤコビ反復法の手順 ①適当な初期値 x1( 0 ) , x2( 0 ) , , xn( 0 ) を与え,以下のように計算する。 b a x1(i ) b1 a12 x2(i 1) a13 x3(i 1) a1n xn(i 1) a11 x2(i ) ( i 1) ( i 1) ( i 1) a x a x a x 2 21 1 23 3 2n n 22 xn(i ) bn an1 x1(i 1) an 2 x2(i 1) an ,n 1 xn(i11) ann ② xk( i ) xk( i 1) (k 1, , n) のとき収束したものとする。 この判定には色々考えられるが,たとえば以下のようにする。 xn(i ) xn(i 1) x1(i ) x1(i 1) x2(i ) x2(i 1) (i ) (i ) (i ) x1 x2 xn VBでプログラムを作る ①シートの定義 ②データの設定部分 Private A(3, 3) As Double Private B(3) As Double Private X(3) As Double Private Sub データ設定() With Worksheets("Sheet1") For i = 1 To 3 B(i) = Val(.Cells(i + 1, 6)) For j = 1 To 3 A(i, j) = Val(.Cells(i + 1, j + 1)) Next Next End With End Sub ③結果の設定とイベントハンドラ Private Sub 結果設定() With Worksheets("Sheet1") For i = 1 To 3 .Cells(i + 1, 8) = X(i) Next End With End Sub Sub ボタン1_Click() データ設定 EPS = 0.001 numLoop = Jacobi反復(A, B, X, EPS, 1000, 3) MsgBox "収束回数=" & numLoop 結果設定 End Sub ④処理本体(1) Private Function Jacobi反復(A, B, X, EPS, iterMax, N) As Integer Dim Y() As Double: ReDim Y(N) For i = 1 To N X(i) = B(i) / A(i, i) Next E = EPS * 100: R = 0 Do While E > EPS And R < iterMax R = R + 1 S = "" For i = 1 To N Y(i) = B(i) For j = 1 To N If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Next Y(i) = Y(i) / A(i, i) Next (続きあり) ④処理本体(2) dev = 0 For i = 1 To N EI = (Y(i) - X(i)) / Y(i): dev = dev + Sqr(EI * EI) X(i) = Y(i) Next E = dev Loop Jacobi反復 = R End Function ヤコビの反復法の発散について 非対角項の絶対値に比べ,対角項の絶対値がかなり大きいとき は収束するが,同じくらいか小さい場合はなかなか収束しない。 逆に発散することもある。 ただし,工学的には,非対角項に比べ対角項の絶対値が大きい 問題が圧倒的に多い。 [演習] 以下の連立方程式がヤコブの反復法で発散することを確認せよ。 6 5 4 x1 8 12 13 10 x 16 2 18 21 17 x3 27 (9)ガウス・ザイデル(Gauss-Seidel)法 ヤコビの反復法における j 行目の計算で xk( i 1) ( k j ) の替わりに, 既に計算されている xk( i ) (k j ) を用いて収束を早める。 すなわち, j 1 x (i ) j bi a jk xk(i ) k 1 n ( i 1) a x jk k k j 1 aii 収束条件は, x (i ) x (i 1) VBでプログラムを作る ①シートの定義(ヤコビの反復法で収束しなかった例を使う) ②データの設定部分(ヤコビの反復法と同じ) Private A(3, 3) As Double Private B(3) As Double Private X(3) As Double Private Sub データ設定() With Worksheets("Sheet1") For i = 1 To 3 B(i) = Val(.Cells(i + 1, 6)) For j = 1 To 3 A(i, j) = Val(.Cells(i + 1, j + 1)) Next Next End With End Sub ③結果の設定とイベントハンドラ(関数呼出し以外はヤコビの反復法と同じ) Private Sub 結果設定() With Worksheets("Sheet1") For i = 1 To 3 .Cells(i + 1, 8) = X(i) Next End With End Sub Sub ボタン1_Click() データ設定 EPS = 0.00001 numLoop = GaussSeidel(A, B, X, EPS, 500, 3) MsgBox "収束回数=" & numLoop 結果設定 End Sub ③処理本体 Private Function GaussSeidel(A, B, X, EPS, iterMax, N) As Integer Dim Y() As Double: ReDim Y(N) For i = 1 To N X(i) = B(i) / A(i, i) Next E = EPS * 100: R = 0 Do While E > EPS And R < iterMax R = R + 1: dev = 0 For i = 1 To N Y(i) = B(i) For j = 1 To N If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Next Y(i) = Y(i) / A(i, i): EI = (X(i) - Y(i)) dev = dev + EI * EI: X(i) = Y(i) Next E = Sqr(dev) Loop GaussSeidel = R End Function ヤコビの反復法とガウス・ザイデル法のプログラム上の違い [演習1]両ソースプログラムを比較し,関数宣言以外で異なっている部分を指摘せよ。 Private Function Jacobi反復(A, B, X, EPS, iterMax, N) As Integer Dim Y() As Double: ReDim Y(N) For i = 1 To N Private Function GaussSeidel(A, B, X, EPS, iterMax, N) As Integer X(i) = B(i) / A(i, i) Dim Y() As Double: ReDim Y(N) Next For i = 1 To N E = EPS * 100: R = 0 X(i) = B(i) / A(i, i) Do While E > EPS And R < iterMax Next R=R+1 E = EPS * 100: R = 0 For i = 1 To N Do While E > EPS And R < iterMax Y(i) = B(i) R = R + 1: dev = 0 For j = 1 To N For i = 1 To N If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Y(i) = B(i) Next For j = 1 To N Y(i) = Y(i) / A(i, i) If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Next Next dev = 0 Y(i) = Y(i) / A(i, i) For i = 1 To N EI = (Y(i) - Y(i)) EI = (Y(i) - X(i)) / Y(i) dev = dev + EI * EI: X(i) = Y(i) dev = dev + Sqr(EI * EI) Next X(i) = Y(i) E = Sqr(dev) Next Loop E = dev GaussSeidel = R Loop End Function Jacobi反復 = R End Function ヤコビの反復法とガウス・ザイデル法の収束回数の違い [演習2] 以下の連立方程式を両手法で解き,収束回数を確認し,比較せよ。 3 1 1 x1 10 1 5 2 x 21 2 1 2 5 x3 30 ヤコビの反復法の収束回数 =( ) ガウスザイデル法の収束回数 = ( ) したがって( 短い回数で収束する。 )のほうが (10)SOR法(Successive Over-Relaxation method) 逐次過緩和法ともいい,以下の反復式を用いる。 他は,ガウス・ザイデル法と同じ。 j 1 (i ) j x (i ) j bi a jk xk(i ) x k 1 ( i 1) j n ( i 1) a x jk k k j 1 aii (i ) j x ( i 1) j where 0 2 [演習] 1 のとき,ガウス・ザイデル法と同じであることを示せ。 VBでプログラムを作る ①シートの定義(ヤコビの反復法で収束しなかった例を使う) ②データの設定部分(加速度パラメータの部分が異なる) Private A(3, 3) As Double Private B(3) As Double Private X(3) As Double Private Omega As Double ’ 加速度パラメータ Private Sub データ設定() With Worksheets("Sheet1") For i = 1 To 3 B(i) = Val(.Cells(i + 1, 6)) For j = 1 To 3 A(i, j) = Val(.Cells(i + 1, j + 1)) Next Next Omega = Val(.Cells(6, 5)) ’ 加速度パラメータ設定 End With End Sub ③結果の設定とイベントハンドラ Private Sub 結果設定() With Worksheets("Sheet1") For i = 1 To 3 .Cells(i + 1, 8) = X(i) Next End With End Sub Sub ボタン1_Click() データ設定 EPS = 0.00001 numLoop = SOR(A, B, X, EPS, 500, Omega, 3) MsgBox "収束回数=" & numLoop 結果設定 End Sub ③処理本体 Private Function SOR(A, B, X, EPS, iterMax, Omega, N) As Integer Dim Y() As Double: ReDim Y(N) For i = 1 To N X(i) = B(i) / A(i, i) Next E = EPS * 100: R = 0 Do While E > EPS And R < iterMax R = R + 1: dev = 0 For i = 1 To N Y(i) = B(i) For j = 1 To N If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Next Y(i) = Y(i) / A(i, i): EI = (Y(i) - X(i)) dev = dev + EI * EI: X(i) = X(i) + Omega * EI Next E = Sqr(dev) Loop SOR = R End Function ガウス・ザイデル法とSOR法のプログラム上の違い [演習1]両ソースプログラムを比較し,関数宣言以外で異なっている部分を指摘せよ。 Private Function GaussSeidel(A, B, X, EPS, iterMax, N) As Integer Dim Y() As Double: ReDim Y(N) For i = 1 To N X(i) = B(i) / A(i, i) Next E = EPS * 100: R = 0 Do While E > EPS And R < iterMax R = R + 1: dev = 0 For i = 1 To N Y(i) = B(i) For j = 1 To N If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Next Y(i) = Y(i) / A(i, i): EI = (Y(i) - Y(i)) dev = dev + EI * EI: X(i) = Y(i) Next E = Sqr(dev) Loop GaussSeidel = R End Function Private Function SOR(A, B, X, EPS, iterMax, Omega, N) As Integer Dim Y() As Double: ReDim Y(N) For i = 1 To N X(i) = B(i) / A(i, i) Next E = EPS * 100: R = 0 Do While E > EPS And R < iterMax R = R + 1: dev = 0 For i = 1 To N Y(i) = B(i) For j = 1 To N If i <> j Then Y(i) = Y(i) - A(i, j) * X(j) Next Y(i) = Y(i) / A(i, i): EI = (Y(i) - X(i)) dev = dev + EI * EI: X(i) = X(i) + Omega * EI Next E = Sqr(dev) Loop SOR = R End Function 加速度パラメータによる収束回数の違い [演習2] 以下の連立方程式で,加速度パラメータを変化させSOR手法で解いた場合の収束回 数を確認せよ。なお,加速度パラメータ=0または2のとき収束しないことを確認せよ。 3 1 1 x1 10 1 5 2 x 21 2 1 2 5 x3 30 加速度パラメータ=1.0 のときの収束回数=( ) (ガウス・ザイデル法と同じ) 加速度パラメータ=1.2 のときの収束回数=( ) 加速度パラメータ=1.5 のときの収束回数=( ) 加速度パラメータ=1.7 のときの収束回数=( ) (11)3重対角な連立方程式の場合 問題によっては,はじめから3重対角な行列式になることが分かっている場合が ある。このような場合,N×Nの行列を用意する必要はない。 b1 a 2 0 0 0 c1 0 0 b2 c2 0 a 3 b3 c3 0 a n 1 b n 1 0 0 an 0 0 0 c n 1 b n b1 c1 0 a b c 2 2 2 a3 b3 c3 a n 1 b n 1 c n 1 bn 0 a n ガウスの消去法と同じ方法で,次のような行列に変換。ただし,隣あう行・列要素 だけに処理すればよい。 0 0 1 c1 0 0 1 c 0 0 2 0 0 1 c 3 0 0 0 0 1 cn 1 1 0 0 0 0 VBでプログラムを作る ①シートの定義 ②データの設定部分 Private A(6, 3) As Double Private D(6) As Double Private X(6) As Double Function データ設定() As Integer With Worksheets("Sheet1") N = 6: AA = "" For i = 1 To N A(i, 1) = .Cells(i + 1, i) A(i, 2) = .Cells(i + 1, i + 1) A(i, 3) = .Cells(i + 1, i + 2) D(i) = .Cells(i + 1, 8) If i = 1 Then A(i, 1) = 0 If i = N Then A(i, 3) = 0 Next End With データ設定 = N End Function ③結果設定部分 Sub 結果設定(N) With Worksheets("Sheet1") For i = 1 To N .Cells(i + 1, 9) = X(i) Next End With End Sub Sub ボタン1_Click() N = データ設定() TriDiag A, D, X, N 結果設定 N End Sub ④計算部分 Sub TriDiag(A, D, X, N) Dim CC() As Double ReDim CC(N) btemp = A(1, 2): X(1) = D(1) / btemp For j = 2 To N CC(j) = A(j - 1, 3) / btemp btemp = A(j, 2) - A(j, 1) * CC(j) X(j) = (D(j) - A(j, 1) * X(j - 1)) / btemp Next For j = N - 1 To 1 Step -1 X(j) = X(j) - CC(j + 1) * X(j + 1) Next End Sub (X)演習 (問題1) 次の連立方程式を,サンプルプログラムを利用して解け (場合によっては,配列サイズ等を変更する必要があるので注意すること) ① 2 x1 2 x2 4 x3 2 x4 10 x1 3 x2 2 x3 x4 17 3 x1 x2 3 x3 x4 18 x1 3 x2 4 x3 2 x4 27 x1 3 x2 x3 ① x5 2 x6 4 x7 1 x4 2 x2 2 x6 3x3 x4 x5 2 x4 2 x2 2 x1 6 x2 2 x3 3 x7 5 4 x6 3 x7 1 6 x5 5 x6 9 x7 3 x1 5 x2 x3 x4 x5 5 x6 6 x7 7 x1 4 x3 x4 2 x5 2 x6 8 x7 8 (X)演習 (問題2)回路内に流れる電流を求めよ。なお,R1 = R2 = R3 = R4 = 1Ωとする。 A C B I4 I2 E I5 I3 I1 I1 D F I 4+I 5 G I5 キルヒホッフの法則およびB,C点に流れる電流の関係から, R1 I1 R2 I 2 R2 I 2 R3 I 3 R4 I 4 E1 (A-B-F-E-A) 0 (B-C-G-F-B) R4 I 4 R5 I 5 E2 I1 I2 I3 I3 I4 (C-D-H-G-C) 0 (B点) I5 0 (C点) H (X)演習 R1 = R2 = R3 = R4 = 1Ωだから,次の連立方程式を解くことに帰着する。 1 1 0 0 0 I1 2 0 1 1 1 0 I 0 2 0 0 0 1 1 I 3 1 1 1 1 0 0 I 4 0 0 0 1 1 1 I 5 0 あるいは,対角項に非ゼロ項がくるように整理した連立方程式を解く。 1 1 0 0 0 I1 2 1 1 1 0 0 I 0 2 0 1 1 1 0 I 3 0 0 0 1 1 1 I 4 0 0 0 0 1 1 I 5 1 1行目 4行目 2行目 5行目 3行目 (X)演習 Pspiceによる結果は次のとおりである。結果と比較せよ。 (X)演習 (問題3)下図のように,構造物に分布荷重,集中荷重がかかったときの,節点の偏角と 水平変位は次のような連立方程式で表現される。 x 3 wL3 41 2 x L 24 EI 3 wL3 1 4 2 x L 24 EI 4 PL3 1 2 x L 6 EI 1 w P L L L 2m, I 0.02m4 , w 2kg / m, P 20kg, E 2 106 kg / m2 のときの 1 , 2 , x 2 を求めよ。 (なお,できる限り,Excelにおける式定義等を使い,手計算を行わないこと)
© Copyright 2025 ExpyDoc