// Matrix /* ------------------------------------------------------ 作者 : Black Ghost 日期 : 2018-11-20 版本 : 0.0.0 0.0.1 2018-12-11 增加切片与矩阵转换 0.0.2 2018-12-26 增加错误报告 0.0.3 2018-12-27 增加追加行/列 ------------------------------------------------------ 矩阵的创建及其操作创建及其简单操作/运算 理论: 参考 OneThin // http://outofmemery.cn/code-snippet /16991/go-language-matrix-operation 进行了主要运算和结构的补充与修改 ------------------------------------------------------ 注意事项: 1. r, c 是从零开始算的 ------------------------------------------------------ */ package goNum import ( "fmt" "strconv" ) //数据结构定义----------------------------------------+ // Matrix 定义Matrix数据类型 type Matrix struct { Rows, Columns int //行数和列数 Data []float64 //将矩阵中所有元素作为一维切片 } //矩阵操作-------------------------------------------+ //通过行列号寻找指定矩阵位置在一维切片中的编号 func findIndex(r, c int, A *Matrix) int { //r E [0, n), c E [0, n) return r*A.Columns + c } // SetMatrix 设置指定行列的值 func (A *Matrix) SetMatrix(r, c int, val float64) { if (r >= A.Rows) || (c >= A.Columns) { panic("Error in goNum.(*Matrix).SetMatrix: Out of range") } A.Data[findIndex(r, c, A)] = val } // GetFromMatrix 获取指定行列的值 func (A *Matrix) GetFromMatrix(r, c int) float64 { if (r >= A.Rows) || (c >= A.Columns) { panic("Error in goNum.(*Matrix).GetFromMatrix: Out of range") } return A.Data[findIndex(r, c, A)] } // RowOfMatrix 获取指定行的值的切片 func (A *Matrix) RowOfMatrix(i int) []float64 { if i >= A.Rows { panic("Error in goNum.(*Matrix).RowOfMatrix: Out of range") } return A.Data[findIndex(i, 0, A):findIndex(i, A.Columns, A)] } // ColumnOfMatrix 获取指定列的值的切片 func (A *Matrix) ColumnOfMatrix(j int) []float64 { if j >= A.Columns { panic("Error in goNum.(*Matrix).ColumnOfMatrix: Out of range") } col := make([]float64, A.Rows) for i := 0; i < A.Rows; i++ { col[i] = A.RowOfMatrix(i)[j] } return col } // Transpose 矩阵转置 func (A *Matrix) Transpose() Matrix { B := ZeroMatrix(A.Columns, A.Rows) for i := 0; i < A.Rows; i++ { for j := 0; j < A.Columns; j++ { B.SetMatrix(j, i, A.GetFromMatrix(i, j)) } } return B } // AppendRow 追加一行,另外一种方法是追加数据到A.Data,测试显示其速度表现更差 func (A *Matrix) AppendRow(row []float64) Matrix { //判断row长度是否等于A列数 if len(row) != A.Columns { panic("Error in goNum.(*Matrix).AppendRow: Slice length error") } B := ZeroMatrix(A.Rows+1, A.Columns) n := A.Rows * A.Columns for i := 0; i < n; i++ { B.Data[i] = A.Data[i] } for i := 0; i < len(row); i++ { B.Data[n+i] = row[i] } return B } // AppendColumn 追加一列,对于多次调用,建议组合使用转置和追加行 func (A *Matrix) AppendColumn(col []float64) Matrix { //判断row长度是否等于A列数 if len(col) != A.Rows { panic("Error in goNum.(*Matrix).AppendColumn: Slice length error") } B := ZeroMatrix(A.Rows, A.Columns+1) for i := 0; i < A.Rows; i++ { for j := 0; j < A.Columns; j++ { B.SetMatrix(i, j, A.GetFromMatrix(i, j)) } B.SetMatrix(i, A.Columns, col[i]) } return B } // PrintMatrix 格式输出 func (A *Matrix) PrintMatrix() { //求出最长字符 colwidstr := make([]string, A.Columns) for i := range colwidstr { var maxLen int thisColumn := A.ColumnOfMatrix(i) for j := range thisColumn { thisLen := len(strconv.FormatFloat(thisColumn[j], 'f', -1, 64)) if thisLen > maxLen { maxLen = thisLen } } } for i := 0; i < A.Rows; i++ { thisRow := A.RowOfMatrix(i) fmt.Printf("[") for j := range thisRow { var format string if j == 0 { format = "%" + colwidstr[j] + "s" } else { format = " %" + colwidstr[j] + "s" } fmt.Printf(format, strconv.FormatFloat(thisRow[j], 'f', -1, 64)) } fmt.Printf("]\n") } } //矩阵初始化-----------------------------------------+ // ZeroMatrix r行c列零矩阵 func ZeroMatrix(r, c int) Matrix { return Matrix{r, c, make([]float64, r*c)} } // IdentityE n阶单位矩阵 func IdentityE(n int) Matrix { A := ZeroMatrix(n, n) for i := 0; i < len(A.Data); i += (n + 1) { A.Data[i] = 1.0 } return A } // NewMatrix 以已有数据创建r行c列矩阵 func NewMatrix(r, c int, data []float64) Matrix { if len(data) != r*c { panic("goNum.Matrix.New: Length of data does not matched r rows and c columns") } A := ZeroMatrix(r, c) A.Data = data return A } // Slices1ToMatrix 一维切片转为矩阵(列向量) func Slices1ToMatrix(s []float64) Matrix { A := ZeroMatrix(len(s), 1) for i := 0; i < A.Rows; i++ { A.Data[i] = s[i] } return A } // Slices2ToMatrix 二维切片转为矩阵 func Slices2ToMatrix(s [][]float64) Matrix { row := len(s) col := len(s[0]) A := ZeroMatrix(row, col) for i := 0; i < row; i++ { for j := 0; j < col; j++ { A.SetMatrix(i, j, s[i][j]) } } return A } // Matrix1ToSlices 列向量转为一维切片 func Matrix1ToSlices(A Matrix) []float64 { s := make([]float64, A.Rows) for i := 0; i < A.Rows; i++ { s[i] = A.Data[i] } return s } // Matrix2ToSlices 二维矩阵转为二维切片 func Matrix2ToSlices(A Matrix) [][]float64 { s := make([][]float64, A.Rows) for i := 0; i < A.Rows; i++ { s[i] = make([]float64, A.Columns) for j := 0; j < A.Columns; j++ { s[i][j] = A.GetFromMatrix(i, j) } } return s } //矩阵运算------------------------------------------+ // AddMatrix 矩阵相加 func AddMatrix(A, B Matrix) Matrix { if (A.Rows != B.Rows) || (A.Columns != B.Columns) { panic("goNum.Matrix.Add: A and B does not matched") } AaddB := ZeroMatrix(A.Rows, A.Columns) for i := 0; i < A.Rows; i++ { for j := 0; j < A.Columns; j++ { AaddB.SetMatrix(i, j, A.GetFromMatrix(i, j)+B.GetFromMatrix(i, j)) } } return AaddB } // SubMatrix 矩阵相减 func SubMatrix(A, B Matrix) Matrix { if (A.Rows != B.Rows) || (A.Columns != B.Columns) { panic("goNum.Matrix.Sub: A and B does not matched") } AsubB := ZeroMatrix(A.Rows, A.Columns) for i := 0; i < A.Rows; i++ { for j := 0; j < A.Columns; j++ { AsubB.SetMatrix(i, j, A.GetFromMatrix(i, j)-B.GetFromMatrix(i, j)) } } return AsubB } // NumProductMatrix 矩阵数乘 func NumProductMatrix(A Matrix, c float64) Matrix { cA := ZeroMatrix(A.Rows, A.Columns) for i := 0; i < len(cA.Data); i++ { cA.Data[i] = c * A.Data[i] } return cA } // DotPruduct 矩阵点乘 func DotPruduct(A, B Matrix) Matrix { if A.Columns != B.Rows { panic("goNum.Matrix.DotPruduct: A and B does not matched") } AdotB := ZeroMatrix(A.Rows, B.Columns) for i := 0; i < A.Rows; i++ { for j := 0; j < B.Columns; j++ { for k := 0; k < A.Columns; k++ { AdotB.Data[B.Columns*i+j] += A.GetFromMatrix(i, k) * B.GetFromMatrix(k, j) } } } return AdotB } // CrossVector 向量叉乘,得到垂直于两个向量所在平面的向量 func CrossVector(a, b []float64) []float64 { if (len(a) != 3) || (len(b) != 3) { panic("goNum.Matrix.CrossVector: vector a or b length is not 3") } acrossb := make([]float64, 3) acrossb[0] = a[1]*b[2] - a[2]*b[1] acrossb[1] = a[2]*b[0] - a[0]*b[2] acrossb[2] = a[0]*b[1] - a[1]*b[0] return acrossb }