github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/u_inv.go (about) 1 package eeslism 2 3 import ( 4 "fmt" 5 "io" 6 "math" 7 "os" 8 ) 9 10 ///* ------------------------------------------------ 11 // 12 // 逆行列の計算 13 // 14 //*/ 15 16 /* ========= ガウスジョルダン法の関数====================== */ 17 18 func Matinv(a []float64, n, m int, s string) { 19 row := make([]int, m) 20 mattemp := make([]float64, m*m) 21 22 matcpy(a, mattemp, m*m) 23 24 for ipv := 0; ipv < m; ipv++ { 25 /* ---- 最大値探索 ---------------------------- */ 26 big := 0.0 27 pivot_row := ipv 28 for i := ipv; i < m; i++ { 29 if math.Abs(a[i*n+ipv]) > big { 30 big = math.Abs(a[i*n+ipv]) 31 pivot_row = i 32 } 33 } 34 if big == 0.0 { 35 var E string 36 if s != "" { 37 E = fmt.Sprintf("対角要素に0があります matrix=%dx%d i=%d [%s]", m, m, ipv, s) 38 } else { 39 E = fmt.Sprintf("対角要素に0があります matrix=%dx%d i=%d", m, m, ipv) 40 } 41 Matprint("%.2g ", m, mattemp) 42 Eprint("<matinv>", E) 43 Preexit() 44 os.Exit(EXIT_MATINV) 45 } 46 row[ipv] = pivot_row 47 48 /* ---- 行の入れ替え -------------------------- */ 49 if ipv != pivot_row { 50 for i := 0; i < m; i++ { 51 temp := a[ipv*n+i] 52 a[ipv*n+i] = a[pivot_row*n+i] 53 a[pivot_row*n+i] = temp 54 } 55 } 56 57 /* ---- 対角成分=1(ピボット行の処理) ---------- */ 58 inv_pivot := 1.0 / a[ipv*n+ipv] 59 a[ipv*n+ipv] = 1.0 60 for j := 0; j < m; j++ { 61 a[ipv*n+j] *= inv_pivot 62 } 63 64 /* ---- ピボット列=0(ピボット行以外の処理) ---- */ 65 for i := 0; i < m; i++ { 66 if i != ipv { 67 temp := a[i*n+ipv] 68 a[i*n+ipv] = 0.0 69 for j := 0; j < m; j++ { 70 a[i*n+j] -= temp * a[ipv*n+j] 71 } 72 } 73 } 74 } 75 76 /* ---- 列の入れ替え(逆行列) -------------------------- */ 77 for j := m - 1; j >= 0; j-- { 78 if j != row[j] { 79 for i := 0; i < m; i++ { 80 temp := a[i*n+j] 81 a[i*n+j] = a[i*n+row[j]] 82 a[i*n+row[j]] = temp 83 } 84 } 85 } 86 } 87 88 ///* -----------------------------------------------------*/ 89 // 連立1次方程式の解法 90 // ガウス・ザイデル法 91 92 // [A]{B}={C} 93 // [A]:係数行列 94 // {B}:解 95 // {C}:定数行列 96 97 // m :未知数の数 98 // n :配列の定義数 99 100 // 参考文献:C言語による科学技術計算サブルーチンライブラリ 101 // pp.104-106 102 // ----------------------------------------------------- */ 103 func Gausei(A, C []float64, m, n int, B []float64) { 104 eps := 1.0e-6 105 l := m + 1 106 a := make([]float64, m*l) 107 108 for i := 0; i < m*l; i++ { 109 a[i] = 0.0 110 } 111 112 for i := 0; i < m; i++ { 113 for j := 0; j < m+1; j++ { 114 if j < m { 115 a[i*l+j] = A[i*n+j] / A[i*n+i] 116 } else { 117 a[i*l+j] = C[i] / A[i*n+i] 118 } 119 } 120 } 121 122 for i := 0; i < m; i++ { 123 B[i] = 0.2 124 } 125 126 def := -999.0 127 k := 0 128 129 for def > eps { 130 def = 0.0 131 132 for i := 0; i < m; i++ { 133 sum := 0.0 134 s := i * l 135 w := a[s+i] 136 137 for j := 0; j < m; j++ { 138 if i != j { 139 sum += a[s+j] * B[j] 140 } 141 } 142 143 y := (a[s+m] - sum) / w 144 ay := math.Abs(y - B[i]) 145 146 def = math.Max(def, ay) 147 B[i] = y 148 } 149 150 if def <= eps { 151 break 152 } 153 154 if k > 100 { 155 for i := 0; i < m; i++ { 156 fmt.Printf("i=%d %f\n", i, B[i]) 157 } 158 159 fmt.Println("収束せず") 160 Preexit() 161 os.Exit(EXIT_MATINV) 162 } 163 164 k++ 165 } 166 } 167 168 // /* ----------------------------------------------------- 169 // 連立1次方程式の解法 170 // ガウスの消去法 171 // 172 // [A]{B}={C} 173 // [A]:係数行列 174 // {B}:解 175 // {C}:定数行列 176 // 177 // m :未知数の数 178 // n :配列の定義数 179 // 180 // 参考文献:C言語による科学技術計算サブルーチンライブラリ 181 // pp.104-106 182 // ----------------------------------------------------- */ 183 func Gauss(A, C, B []float64, m, n int) { 184 num := make([]int, m) 185 pivot := make([]int, m) 186 wfs := make([]float64, m*m) 187 188 for i := 0; i < m; i++ { 189 B[i] = C[i] 190 for j := 0; j < m; j++ { 191 wfs[i*m+j] = A[i*n+j] 192 } 193 } 194 195 for i := 0; i < m; i++ { 196 num[i] = i + 1 197 } 198 199 for k := 0; k < m; k++ { 200 pv := 0.0 201 202 for i := 0; i < m; i++ { 203 if num[i] != 0 { 204 if math.Abs(wfs[i*m+k]) > math.Abs(pv) { 205 pv = wfs[i*m+k] 206 pivot[k] = i 207 } 208 } 209 } 210 211 if pv == 0.0 { 212 Eprint("<gauss>", "対角要素に 0 があります") 213 Preexit() 214 os.Exit(EXIT_MATINV) 215 } 216 217 for j := k; j < m; j++ { 218 wfs[pivot[k]*m+j] /= pv 219 } 220 221 B[pivot[k]] /= pv 222 num[pivot[k]] = 0 223 224 for i := 0; i < m; i++ { 225 if num[i] != 0 { 226 tmp := wfs[i*m+k] 227 228 for j := k + 1; j < m; j++ { 229 wfs[i*m+j] -= wfs[pivot[k]*m+j] * tmp 230 } 231 232 B[i] -= B[pivot[k]] * tmp 233 } 234 } 235 } 236 237 for i := m - 2; i >= 0; i-- { 238 for j := i + 1; j < m; j++ { 239 B[pivot[i]] -= B[pivot[i]*m+j] 240 } 241 } 242 } 243 244 ///* ----------------------------------------------------- 245 // 246 // 正方行列の出力 247 //*/ 248 func Matprint(format string, N int, a []float64) { 249 fmt.Println() 250 for i := 0; i < N; i++ { 251 for j := 0; j < N; j++ { 252 fmt.Printf(format, a[i*N+j]) 253 } 254 fmt.Println() 255 } 256 } 257 258 ///* ----------------------------------------------------- 259 // 260 // 正方行列のファイル出力 261 //*/ 262 func Matfiprint(f io.Writer, fmtStr string, N int, a []float64) { 263 for i := 0; i < N; i++ { 264 for j := 0; j < N; j++ { 265 fmt.Fprintf(f, fmtStr, a[i*N+j]) 266 } 267 fmt.Fprintln(f) 268 } 269 } 270 271 ///* ----------------------------------------------------- 272 // 273 // 正方行列の出力 (単精度) 274 //*/ 275 func Matfprint(fmtStr string, N int, a []float64) { 276 fmt.Printf("\n") 277 for i := 0; i < N; i++ { 278 for j := 0; j < N; j++ { 279 fmt.Printf(fmtStr, a[i*N+j]) 280 } 281 fmt.Printf("\n") 282 } 283 } 284 285 ///* ----------------------------------------------------- 286 // 287 // 連立一次方程式の係数行列及び右辺の出力 288 // 289 //*/ 290 func Seqprint(fmt1 string, N int, a []float64, fmt2 string, c []float64) { 291 fmt.Println("--- seqprint") 292 for i := 0; i < N; i++ { 293 for j := 0; j < N; j++ { 294 fmt.Printf(fmt1, a[i*N+j]) 295 } 296 fmt.Print(" c=") 297 fmt.Printf(fmt2, c[i]) 298 fmt.Println() 299 } 300 } 301 302 ///* ---------------------------------------------- */ 303 // 304 ///* 305 //行列の掛け算 306 // 307 // (T)=[A](V) 308 // N:宣言寸法 n:使用寸法 309 //*/ 310 func Matmalv(A []float64, V []float64, N int, n int, T []float64) { 311 for i := 0; i < n; i++ { 312 var sum float64 = 0.0 313 a := A[i*N : (i+1)*N] 314 for j := 0; j < n; j++ { 315 sum += a[j] * V[j] 316 } 317 T[i] = sum 318 } 319 } 320 321 /****************************************************************/ 322 // 行列の0初期化 323 /****************************************************************/ 324 func matinit(A []float64, N int) { 325 for i := 0; i < N; i++ { 326 A[i] = 0.0 327 } 328 } 329 330 func imatinit(A []int, N int) { 331 for i := 0; i < N; i++ { 332 A[i] = 0 333 } 334 } 335 336 /****************************************************************/ 337 // 行列の数値初期化 338 /****************************************************************/ 339 func matinitx(A []float64, N int, x float64) { 340 for i := 0; i < N; i++ { 341 A[i] = x 342 } 343 } 344 345 /****************************************************************/ 346 // 行列のコピー 347 /****************************************************************/ 348 func matcpy(A []float64, B []float64, N int) { 349 for i := 0; i < N; i++ { 350 B[i] = A[i] 351 } 352 }