github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/mat/dense.go (about) 1 // Copyright ©2013 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mat 6 7 import ( 8 "github.com/jingcheng-WU/gonum/blas" 9 "github.com/jingcheng-WU/gonum/blas/blas64" 10 ) 11 12 var ( 13 dense *Dense 14 15 _ Matrix = dense 16 _ allMatrix = dense 17 _ denseMatrix = dense 18 _ Mutable = dense 19 20 _ ClonerFrom = dense 21 _ RowViewer = dense 22 _ ColViewer = dense 23 _ RawRowViewer = dense 24 _ Grower = dense 25 26 _ RawMatrixSetter = dense 27 _ RawMatrixer = dense 28 29 _ Reseter = dense 30 ) 31 32 // Dense is a dense matrix representation. 33 type Dense struct { 34 mat blas64.General 35 36 capRows, capCols int 37 } 38 39 // NewDense creates a new Dense matrix with r rows and c columns. If data == nil, 40 // a new slice is allocated for the backing slice. If len(data) == r*c, data is 41 // used as the backing slice, and changes to the elements of the returned Dense 42 // will be reflected in data. If neither of these is true, NewDense will panic. 43 // NewDense will panic if either r or c is zero. 44 // 45 // The data must be arranged in row-major order, i.e. the (i*c + j)-th 46 // element in the data slice is the {i, j}-th element in the matrix. 47 func NewDense(r, c int, data []float64) *Dense { 48 if r <= 0 || c <= 0 { 49 if r == 0 || c == 0 { 50 panic(ErrZeroLength) 51 } 52 panic(ErrNegativeDimension) 53 } 54 if data != nil && r*c != len(data) { 55 panic(ErrShape) 56 } 57 if data == nil { 58 data = make([]float64, r*c) 59 } 60 return &Dense{ 61 mat: blas64.General{ 62 Rows: r, 63 Cols: c, 64 Stride: c, 65 Data: data, 66 }, 67 capRows: r, 68 capCols: c, 69 } 70 } 71 72 // ReuseAs changes the receiver if it IsEmpty() to be of size r×c. 73 // 74 // ReuseAs re-uses the backing data slice if it has sufficient capacity, 75 // otherwise a new slice is allocated. The backing data is zero on return. 76 // 77 // ReuseAs panics if the receiver is not empty, and panics if 78 // the input sizes are less than one. To empty the receiver for re-use, 79 // Reset should be used. 80 func (m *Dense) ReuseAs(r, c int) { 81 if r <= 0 || c <= 0 { 82 if r == 0 || c == 0 { 83 panic(ErrZeroLength) 84 } 85 panic(ErrNegativeDimension) 86 } 87 if !m.IsEmpty() { 88 panic(ErrReuseNonEmpty) 89 } 90 m.reuseAsZeroed(r, c) 91 } 92 93 // reuseAsNonZeroed resizes an empty matrix to a r×c matrix, 94 // or checks that a non-empty matrix is r×c. It does not zero 95 // the data in the receiver. 96 func (m *Dense) reuseAsNonZeroed(r, c int) { 97 // reuseAs must be kept in sync with reuseAsZeroed. 98 if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols { 99 // Panic as a string, not a mat.Error. 100 panic(badCap) 101 } 102 if r == 0 || c == 0 { 103 panic(ErrZeroLength) 104 } 105 if m.IsEmpty() { 106 m.mat = blas64.General{ 107 Rows: r, 108 Cols: c, 109 Stride: c, 110 Data: use(m.mat.Data, r*c), 111 } 112 m.capRows = r 113 m.capCols = c 114 return 115 } 116 if r != m.mat.Rows || c != m.mat.Cols { 117 panic(ErrShape) 118 } 119 } 120 121 // reuseAsZeroed resizes an empty matrix to a r×c matrix, 122 // or checks that a non-empty matrix is r×c. It zeroes 123 // all the elements of the matrix. 124 func (m *Dense) reuseAsZeroed(r, c int) { 125 // reuseAsZeroed must be kept in sync with reuseAsNonZeroed. 126 if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols { 127 // Panic as a string, not a mat.Error. 128 panic(badCap) 129 } 130 if r == 0 || c == 0 { 131 panic(ErrZeroLength) 132 } 133 if m.IsEmpty() { 134 m.mat = blas64.General{ 135 Rows: r, 136 Cols: c, 137 Stride: c, 138 Data: useZeroed(m.mat.Data, r*c), 139 } 140 m.capRows = r 141 m.capCols = c 142 return 143 } 144 if r != m.mat.Rows || c != m.mat.Cols { 145 panic(ErrShape) 146 } 147 m.Zero() 148 } 149 150 // Zero sets all of the matrix elements to zero. 151 func (m *Dense) Zero() { 152 r := m.mat.Rows 153 c := m.mat.Cols 154 for i := 0; i < r; i++ { 155 zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]) 156 } 157 } 158 159 // isolatedWorkspace returns a new dense matrix w with the size of a and 160 // returns a callback to defer which performs cleanup at the return of the call. 161 // This should be used when a method receiver is the same pointer as an input argument. 162 func (m *Dense) isolatedWorkspace(a Matrix) (w *Dense, restore func()) { 163 r, c := a.Dims() 164 if r == 0 || c == 0 { 165 panic(ErrZeroLength) 166 } 167 w = getWorkspace(r, c, false) 168 return w, func() { 169 m.Copy(w) 170 putWorkspace(w) 171 } 172 } 173 174 // Reset empties the matrix so that it can be reused as the 175 // receiver of a dimensionally restricted operation. 176 // 177 // Reset should not be used when the matrix shares backing data. 178 // See the Reseter interface for more information. 179 func (m *Dense) Reset() { 180 // Row, Cols and Stride must be zeroed in unison. 181 m.mat.Rows, m.mat.Cols, m.mat.Stride = 0, 0, 0 182 m.capRows, m.capCols = 0, 0 183 m.mat.Data = m.mat.Data[:0] 184 } 185 186 // IsEmpty returns whether the receiver is empty. Empty matrices can be the 187 // receiver for size-restricted operations. The receiver can be emptied using 188 // Reset. 189 func (m *Dense) IsEmpty() bool { 190 // It must be the case that m.Dims() returns 191 // zeros in this case. See comment in Reset(). 192 return m.mat.Stride == 0 193 } 194 195 // asTriDense returns a TriDense with the given size and side. The backing data 196 // of the TriDense is the same as the receiver. 197 func (m *Dense) asTriDense(n int, diag blas.Diag, uplo blas.Uplo) *TriDense { 198 return &TriDense{ 199 mat: blas64.Triangular{ 200 N: n, 201 Stride: m.mat.Stride, 202 Data: m.mat.Data, 203 Uplo: uplo, 204 Diag: diag, 205 }, 206 cap: n, 207 } 208 } 209 210 // DenseCopyOf returns a newly allocated copy of the elements of a. 211 func DenseCopyOf(a Matrix) *Dense { 212 d := &Dense{} 213 d.CloneFrom(a) 214 return d 215 } 216 217 // SetRawMatrix sets the underlying blas64.General used by the receiver. 218 // Changes to elements in the receiver following the call will be reflected 219 // in b. 220 func (m *Dense) SetRawMatrix(b blas64.General) { 221 m.capRows, m.capCols = b.Rows, b.Cols 222 m.mat = b 223 } 224 225 // RawMatrix returns the underlying blas64.General used by the receiver. 226 // Changes to elements in the receiver following the call will be reflected 227 // in returned blas64.General. 228 func (m *Dense) RawMatrix() blas64.General { return m.mat } 229 230 // Dims returns the number of rows and columns in the matrix. 231 func (m *Dense) Dims() (r, c int) { return m.mat.Rows, m.mat.Cols } 232 233 // Caps returns the number of rows and columns in the backing matrix. 234 func (m *Dense) Caps() (r, c int) { return m.capRows, m.capCols } 235 236 // T performs an implicit transpose by returning the receiver inside a Transpose. 237 func (m *Dense) T() Matrix { 238 return Transpose{m} 239 } 240 241 // ColView returns a Vector reflecting the column j, backed by the matrix data. 242 // 243 // See ColViewer for more information. 244 func (m *Dense) ColView(j int) Vector { 245 var v VecDense 246 v.ColViewOf(m, j) 247 return &v 248 } 249 250 // SetCol sets the values in the specified column of the matrix to the values 251 // in src. len(src) must equal the number of rows in the receiver. 252 func (m *Dense) SetCol(j int, src []float64) { 253 if j >= m.mat.Cols || j < 0 { 254 panic(ErrColAccess) 255 } 256 if len(src) != m.mat.Rows { 257 panic(ErrColLength) 258 } 259 260 blas64.Copy( 261 blas64.Vector{N: m.mat.Rows, Inc: 1, Data: src}, 262 blas64.Vector{N: m.mat.Rows, Inc: m.mat.Stride, Data: m.mat.Data[j:]}, 263 ) 264 } 265 266 // SetRow sets the values in the specified rows of the matrix to the values 267 // in src. len(src) must equal the number of columns in the receiver. 268 func (m *Dense) SetRow(i int, src []float64) { 269 if i >= m.mat.Rows || i < 0 { 270 panic(ErrRowAccess) 271 } 272 if len(src) != m.mat.Cols { 273 panic(ErrRowLength) 274 } 275 276 copy(m.rawRowView(i), src) 277 } 278 279 // RowView returns row i of the matrix data represented as a column vector, 280 // backed by the matrix data. 281 // 282 // See RowViewer for more information. 283 func (m *Dense) RowView(i int) Vector { 284 var v VecDense 285 v.RowViewOf(m, i) 286 return &v 287 } 288 289 // RawRowView returns a slice backed by the same array as backing the 290 // receiver. 291 func (m *Dense) RawRowView(i int) []float64 { 292 if i >= m.mat.Rows || i < 0 { 293 panic(ErrRowAccess) 294 } 295 return m.rawRowView(i) 296 } 297 298 func (m *Dense) rawRowView(i int) []float64 { 299 return m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+m.mat.Cols] 300 } 301 302 // DiagView returns the diagonal as a matrix backed by the original data. 303 func (m *Dense) DiagView() Diagonal { 304 n := min(m.mat.Rows, m.mat.Cols) 305 return &DiagDense{ 306 mat: blas64.Vector{ 307 N: n, 308 Inc: m.mat.Stride + 1, 309 Data: m.mat.Data[:(n-1)*m.mat.Stride+n], 310 }, 311 } 312 } 313 314 // Slice returns a new Matrix that shares backing data with the receiver. 315 // The returned matrix starts at {i,j} of the receiver and extends k-i rows 316 // and l-j columns. The final row in the resulting matrix is k-1 and the 317 // final column is l-1. 318 // Slice panics with ErrIndexOutOfRange if the slice is outside the capacity 319 // of the receiver. 320 func (m *Dense) Slice(i, k, j, l int) Matrix { 321 return m.slice(i, k, j, l) 322 } 323 324 func (m *Dense) slice(i, k, j, l int) *Dense { 325 mr, mc := m.Caps() 326 if i < 0 || mr <= i || j < 0 || mc <= j || k < i || mr < k || l < j || mc < l { 327 if i == k || j == l { 328 panic(ErrZeroLength) 329 } 330 panic(ErrIndexOutOfRange) 331 } 332 t := *m 333 t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (k-1)*t.mat.Stride+l] 334 t.mat.Rows = k - i 335 t.mat.Cols = l - j 336 t.capRows -= i 337 t.capCols -= j 338 return &t 339 } 340 341 // Grow returns the receiver expanded by r rows and c columns. If the dimensions 342 // of the expanded matrix are outside the capacities of the receiver a new 343 // allocation is made, otherwise not. Note the receiver itself is not modified 344 // during the call to Grow. 345 func (m *Dense) Grow(r, c int) Matrix { 346 if r < 0 || c < 0 { 347 panic(ErrIndexOutOfRange) 348 } 349 if r == 0 && c == 0 { 350 return m 351 } 352 353 r += m.mat.Rows 354 c += m.mat.Cols 355 356 var t Dense 357 switch { 358 case m.mat.Rows == 0 || m.mat.Cols == 0: 359 t.mat = blas64.General{ 360 Rows: r, 361 Cols: c, 362 Stride: c, 363 // We zero because we don't know how the matrix will be used. 364 // In other places, the mat is immediately filled with a result; 365 // this is not the case here. 366 Data: useZeroed(m.mat.Data, r*c), 367 } 368 case r > m.capRows || c > m.capCols: 369 cr := max(r, m.capRows) 370 cc := max(c, m.capCols) 371 t.mat = blas64.General{ 372 Rows: r, 373 Cols: c, 374 Stride: cc, 375 Data: make([]float64, cr*cc), 376 } 377 t.capRows = cr 378 t.capCols = cc 379 // Copy the complete matrix over to the new matrix. 380 // Including elements not currently visible. Use a temporary structure 381 // to avoid modifying the receiver. 382 var tmp Dense 383 tmp.mat = blas64.General{ 384 Rows: m.mat.Rows, 385 Cols: m.mat.Cols, 386 Stride: m.mat.Stride, 387 Data: m.mat.Data, 388 } 389 tmp.capRows = m.capRows 390 tmp.capCols = m.capCols 391 t.Copy(&tmp) 392 return &t 393 default: 394 t.mat = blas64.General{ 395 Data: m.mat.Data[:(r-1)*m.mat.Stride+c], 396 Rows: r, 397 Cols: c, 398 Stride: m.mat.Stride, 399 } 400 } 401 t.capRows = r 402 t.capCols = c 403 return &t 404 } 405 406 // CloneFrom makes a copy of a into the receiver, overwriting the previous value of 407 // the receiver. The clone from operation does not make any restriction on shape and 408 // will not cause shadowing. 409 // 410 // See the ClonerFrom interface for more information. 411 func (m *Dense) CloneFrom(a Matrix) { 412 r, c := a.Dims() 413 mat := blas64.General{ 414 Rows: r, 415 Cols: c, 416 Stride: c, 417 } 418 m.capRows, m.capCols = r, c 419 420 aU, trans := untransposeExtract(a) 421 switch aU := aU.(type) { 422 case *Dense: 423 amat := aU.mat 424 mat.Data = make([]float64, r*c) 425 if trans { 426 for i := 0; i < r; i++ { 427 blas64.Copy(blas64.Vector{N: c, Inc: amat.Stride, Data: amat.Data[i : i+(c-1)*amat.Stride+1]}, 428 blas64.Vector{N: c, Inc: 1, Data: mat.Data[i*c : (i+1)*c]}) 429 } 430 } else { 431 for i := 0; i < r; i++ { 432 copy(mat.Data[i*c:(i+1)*c], amat.Data[i*amat.Stride:i*amat.Stride+c]) 433 } 434 } 435 case *VecDense: 436 amat := aU.mat 437 mat.Data = make([]float64, aU.mat.N) 438 blas64.Copy(blas64.Vector{N: aU.mat.N, Inc: amat.Inc, Data: amat.Data}, 439 blas64.Vector{N: aU.mat.N, Inc: 1, Data: mat.Data}) 440 default: 441 mat.Data = make([]float64, r*c) 442 w := *m 443 w.mat = mat 444 for i := 0; i < r; i++ { 445 for j := 0; j < c; j++ { 446 w.set(i, j, a.At(i, j)) 447 } 448 } 449 *m = w 450 return 451 } 452 m.mat = mat 453 } 454 455 // Copy makes a copy of elements of a into the receiver. It is similar to the 456 // built-in copy; it copies as much as the overlap between the two matrices and 457 // returns the number of rows and columns it copied. If a aliases the receiver 458 // and is a transposed Dense or VecDense, with a non-unitary increment, Copy will 459 // panic. 460 // 461 // See the Copier interface for more information. 462 func (m *Dense) Copy(a Matrix) (r, c int) { 463 r, c = a.Dims() 464 if a == m { 465 return r, c 466 } 467 r = min(r, m.mat.Rows) 468 c = min(c, m.mat.Cols) 469 if r == 0 || c == 0 { 470 return 0, 0 471 } 472 473 aU, trans := untransposeExtract(a) 474 switch aU := aU.(type) { 475 case *Dense: 476 amat := aU.mat 477 if trans { 478 if amat.Stride != 1 { 479 m.checkOverlap(amat) 480 } 481 for i := 0; i < r; i++ { 482 blas64.Copy(blas64.Vector{N: c, Inc: amat.Stride, Data: amat.Data[i : i+(c-1)*amat.Stride+1]}, 483 blas64.Vector{N: c, Inc: 1, Data: m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]}) 484 } 485 } else { 486 switch o := offset(m.mat.Data, amat.Data); { 487 case o < 0: 488 for i := r - 1; i >= 0; i-- { 489 copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c]) 490 } 491 case o > 0: 492 for i := 0; i < r; i++ { 493 copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c]) 494 } 495 default: 496 // Nothing to do. 497 } 498 } 499 case *VecDense: 500 var n, stride int 501 amat := aU.mat 502 if trans { 503 if amat.Inc != 1 { 504 m.checkOverlap(aU.asGeneral()) 505 } 506 n = c 507 stride = 1 508 } else { 509 n = r 510 stride = m.mat.Stride 511 } 512 if amat.Inc == 1 && stride == 1 { 513 copy(m.mat.Data, amat.Data[:n]) 514 break 515 } 516 switch o := offset(m.mat.Data, amat.Data); { 517 case o < 0: 518 blas64.Copy(blas64.Vector{N: n, Inc: -amat.Inc, Data: amat.Data}, 519 blas64.Vector{N: n, Inc: -stride, Data: m.mat.Data}) 520 case o > 0: 521 blas64.Copy(blas64.Vector{N: n, Inc: amat.Inc, Data: amat.Data}, 522 blas64.Vector{N: n, Inc: stride, Data: m.mat.Data}) 523 default: 524 // Nothing to do. 525 } 526 default: 527 m.checkOverlapMatrix(aU) 528 for i := 0; i < r; i++ { 529 for j := 0; j < c; j++ { 530 m.set(i, j, a.At(i, j)) 531 } 532 } 533 } 534 535 return r, c 536 } 537 538 // Stack appends the rows of b onto the rows of a, placing the result into the 539 // receiver with b placed in the greater indexed rows. Stack will panic if the 540 // two input matrices do not have the same number of columns or the constructed 541 // stacked matrix is not the same shape as the receiver. 542 func (m *Dense) Stack(a, b Matrix) { 543 ar, ac := a.Dims() 544 br, bc := b.Dims() 545 if ac != bc || m == a || m == b { 546 panic(ErrShape) 547 } 548 549 m.reuseAsNonZeroed(ar+br, ac) 550 551 m.Copy(a) 552 w := m.slice(ar, ar+br, 0, bc) 553 w.Copy(b) 554 } 555 556 // Augment creates the augmented matrix of a and b, where b is placed in the 557 // greater indexed columns. Augment will panic if the two input matrices do 558 // not have the same number of rows or the constructed augmented matrix is 559 // not the same shape as the receiver. 560 func (m *Dense) Augment(a, b Matrix) { 561 ar, ac := a.Dims() 562 br, bc := b.Dims() 563 if ar != br || m == a || m == b { 564 panic(ErrShape) 565 } 566 567 m.reuseAsNonZeroed(ar, ac+bc) 568 569 m.Copy(a) 570 w := m.slice(0, br, ac, ac+bc) 571 w.Copy(b) 572 } 573 574 // Trace returns the trace of the matrix. The matrix must be square or Trace 575 // will panic. 576 func (m *Dense) Trace() float64 { 577 if m.mat.Rows != m.mat.Cols { 578 panic(ErrSquare) 579 } 580 // TODO(btracey): could use internal asm sum routine. 581 var v float64 582 for i := 0; i < m.mat.Rows; i++ { 583 v += m.mat.Data[i*m.mat.Stride+i] 584 } 585 return v 586 }