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  }