123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- // Copyright ©2017 The Gonum Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package mat
- import (
- "gonum.org/v1/gonum/blas"
- "gonum.org/v1/gonum/blas/blas64"
- )
- var (
- symBandDense *SymBandDense
- _ Matrix = symBandDense
- _ allMatrix = symBandDense
- _ denseMatrix = symBandDense
- _ Symmetric = symBandDense
- _ Banded = symBandDense
- _ SymBanded = symBandDense
- _ RawSymBander = symBandDense
- _ MutableSymBanded = symBandDense
- _ NonZeroDoer = symBandDense
- _ RowNonZeroDoer = symBandDense
- _ ColNonZeroDoer = symBandDense
- )
- // SymBandDense represents a symmetric band matrix in dense storage format.
- type SymBandDense struct {
- mat blas64.SymmetricBand
- }
- // SymBanded is a symmetric band matrix interface type.
- type SymBanded interface {
- Banded
- // Symmetric returns the number of rows/columns in the matrix.
- Symmetric() int
- // SymBand returns the number of rows/columns in the matrix, and the size of
- // the bandwidth.
- SymBand() (n, k int)
- }
- // MutableSymBanded is a symmetric band matrix interface type that allows elements
- // to be altered.
- type MutableSymBanded interface {
- SymBanded
- SetSymBand(i, j int, v float64)
- }
- // A RawSymBander can return a blas64.SymmetricBand representation of the receiver.
- // Changes to the blas64.SymmetricBand.Data slice will be reflected in the original
- // matrix, changes to the N, K, Stride and Uplo fields will not.
- type RawSymBander interface {
- RawSymBand() blas64.SymmetricBand
- }
- // NewSymBandDense creates a new SymBand matrix with n rows and columns. If data == nil,
- // a new slice is allocated for the backing slice. If len(data) == n*(k+1),
- // data is used as the backing slice, and changes to the elements of the returned
- // SymBandDense will be reflected in data. If neither of these is true, NewSymBandDense
- // will panic. k must be at least zero and less than n, otherwise NewSymBandDense will panic.
- //
- // The data must be arranged in row-major order constructed by removing the zeros
- // from the rows outside the band and aligning the diagonals. SymBandDense matrices
- // are stored in the upper triangle. For example, the matrix
- // 1 2 3 0 0 0
- // 2 4 5 6 0 0
- // 3 5 7 8 9 0
- // 0 6 8 10 11 12
- // 0 0 9 11 13 14
- // 0 0 0 12 14 15
- // becomes (* entries are never accessed)
- // 1 2 3
- // 4 5 6
- // 7 8 9
- // 10 11 12
- // 13 14 *
- // 15 * *
- // which is passed to NewSymBandDense as []float64{1, 2, ..., 15, *, *, *} with k=2.
- // Only the values in the band portion of the matrix are used.
- func NewSymBandDense(n, k int, data []float64) *SymBandDense {
- if n <= 0 || k < 0 {
- if n == 0 {
- panic(ErrZeroLength)
- }
- panic("mat: negative dimension")
- }
- if k+1 > n {
- panic("mat: band out of range")
- }
- bc := k + 1
- if data != nil && len(data) != n*bc {
- panic(ErrShape)
- }
- if data == nil {
- data = make([]float64, n*bc)
- }
- return &SymBandDense{
- mat: blas64.SymmetricBand{
- N: n,
- K: k,
- Stride: bc,
- Uplo: blas.Upper,
- Data: data,
- },
- }
- }
- // Dims returns the number of rows and columns in the matrix.
- func (s *SymBandDense) Dims() (r, c int) {
- return s.mat.N, s.mat.N
- }
- // Symmetric returns the size of the receiver.
- func (s *SymBandDense) Symmetric() int {
- return s.mat.N
- }
- // Bandwidth returns the bandwidths of the matrix.
- func (s *SymBandDense) Bandwidth() (kl, ku int) {
- return s.mat.K, s.mat.K
- }
- // SymBand returns the number of rows/columns in the matrix, and the size of
- // the bandwidth.
- func (s *SymBandDense) SymBand() (n, k int) {
- return s.mat.N, s.mat.K
- }
- // T implements the Matrix interface. Symmetric matrices, by definition, are
- // equal to their transpose, and this is a no-op.
- func (s *SymBandDense) T() Matrix {
- return s
- }
- // TBand implements the Banded interface.
- func (s *SymBandDense) TBand() Banded {
- return s
- }
- // RawSymBand returns the underlying blas64.SymBand used by the receiver.
- // Changes to elements in the receiver following the call will be reflected
- // in returned blas64.SymBand.
- func (s *SymBandDense) RawSymBand() blas64.SymmetricBand {
- return s.mat
- }
- // SetRawSymBand sets the underlying blas64.SymmetricBand used by the receiver.
- // Changes to elements in the receiver following the call will be reflected
- // in the input.
- //
- // The supplied SymmetricBand must use blas.Upper storage format.
- func (s *SymBandDense) SetRawSymBand(mat blas64.SymmetricBand) {
- if mat.Uplo != blas.Upper {
- panic("mat: blas64.SymmetricBand does not have blas.Upper storage")
- }
- s.mat = mat
- }
- // IsEmpty returns whether the receiver is empty. Empty matrices can be the
- // receiver for size-restricted operations. The receiver can be emptied using
- // Reset.
- func (s *SymBandDense) IsEmpty() bool {
- return s.mat.Stride == 0
- }
- // Reset empties the matrix so that it can be reused as the
- // receiver of a dimensionally restricted operation.
- //
- // Reset should not be used when the matrix shares backing data.
- // See the Reseter interface for more information.
- func (s *SymBandDense) Reset() {
- s.mat.N = 0
- s.mat.K = 0
- s.mat.Stride = 0
- s.mat.Uplo = 0
- s.mat.Data = s.mat.Data[:0:0]
- }
- // Zero sets all of the matrix elements to zero.
- func (s *SymBandDense) Zero() {
- for i := 0; i < s.mat.N; i++ {
- u := min(1+s.mat.K, s.mat.N-i)
- zero(s.mat.Data[i*s.mat.Stride : i*s.mat.Stride+u])
- }
- }
- // DiagView returns the diagonal as a matrix backed by the original data.
- func (s *SymBandDense) DiagView() Diagonal {
- n := s.mat.N
- return &DiagDense{
- mat: blas64.Vector{
- N: n,
- Inc: s.mat.Stride,
- Data: s.mat.Data[:(n-1)*s.mat.Stride+1],
- },
- }
- }
- // DoNonZero calls the function fn for each of the non-zero elements of s. The function fn
- // takes a row/column index and the element value of s at (i, j).
- func (s *SymBandDense) DoNonZero(fn func(i, j int, v float64)) {
- for i := 0; i < s.mat.N; i++ {
- for j := max(0, i-s.mat.K); j < min(s.mat.N, i+s.mat.K+1); j++ {
- v := s.at(i, j)
- if v != 0 {
- fn(i, j, v)
- }
- }
- }
- }
- // DoRowNonZero calls the function fn for each of the non-zero elements of row i of s. The function fn
- // takes a row/column index and the element value of s at (i, j).
- func (s *SymBandDense) DoRowNonZero(i int, fn func(i, j int, v float64)) {
- if i < 0 || s.mat.N <= i {
- panic(ErrRowAccess)
- }
- for j := max(0, i-s.mat.K); j < min(s.mat.N, i+s.mat.K+1); j++ {
- v := s.at(i, j)
- if v != 0 {
- fn(i, j, v)
- }
- }
- }
- // DoColNonZero calls the function fn for each of the non-zero elements of column j of s. The function fn
- // takes a row/column index and the element value of s at (i, j).
- func (s *SymBandDense) DoColNonZero(j int, fn func(i, j int, v float64)) {
- if j < 0 || s.mat.N <= j {
- panic(ErrColAccess)
- }
- for i := 0; i < s.mat.N; i++ {
- if i-s.mat.K <= j && j < i+s.mat.K+1 {
- v := s.at(i, j)
- if v != 0 {
- fn(i, j, v)
- }
- }
- }
- }
- // Trace returns the trace.
- func (s *SymBandDense) Trace() float64 {
- rb := s.RawSymBand()
- var tr float64
- for i := 0; i < rb.N; i++ {
- tr += rb.Data[i*rb.Stride]
- }
- return tr
- }
- // MulVecTo computes S⋅x storing the result into dst.
- func (s *SymBandDense) MulVecTo(dst *VecDense, _ bool, x Vector) {
- n := s.mat.N
- if x.Len() != n {
- panic(ErrShape)
- }
- dst.reuseAsNonZeroed(n)
- xMat, _ := untransposeExtract(x)
- if xVec, ok := xMat.(*VecDense); ok {
- if dst != xVec {
- dst.checkOverlap(xVec.mat)
- blas64.Sbmv(1, s.mat, xVec.mat, 0, dst.mat)
- } else {
- xCopy := getWorkspaceVec(n, false)
- xCopy.CloneFromVec(xVec)
- blas64.Sbmv(1, s.mat, xCopy.mat, 0, dst.mat)
- putWorkspaceVec(xCopy)
- }
- } else {
- xCopy := getWorkspaceVec(n, false)
- xCopy.CloneFromVec(x)
- blas64.Sbmv(1, s.mat, xCopy.mat, 0, dst.mat)
- putWorkspaceVec(xCopy)
- }
- }
|