-
Notifications
You must be signed in to change notification settings - Fork 44
/
Matrix.go
285 lines (261 loc) · 7.54 KB
/
Matrix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// 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
}