github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/mat/symband.go (about) 1 // Copyright ©2017 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 symBandDense *SymBandDense 14 _ Matrix = symBandDense 15 _ allMatrix = symBandDense 16 _ denseMatrix = symBandDense 17 _ Symmetric = symBandDense 18 _ Banded = symBandDense 19 _ SymBanded = symBandDense 20 _ RawSymBander = symBandDense 21 _ MutableSymBanded = symBandDense 22 23 _ NonZeroDoer = symBandDense 24 _ RowNonZeroDoer = symBandDense 25 _ ColNonZeroDoer = symBandDense 26 ) 27 28 // SymBandDense represents a symmetric band matrix in dense storage format. 29 type SymBandDense struct { 30 mat blas64.SymmetricBand 31 } 32 33 // SymBanded is a symmetric band matrix interface type. 34 type SymBanded interface { 35 Banded 36 37 // Symmetric returns the number of rows/columns in the matrix. 38 Symmetric() int 39 40 // SymBand returns the number of rows/columns in the matrix, and the size of 41 // the bandwidth. 42 SymBand() (n, k int) 43 } 44 45 // MutableSymBanded is a symmetric band matrix interface type that allows elements 46 // to be altered. 47 type MutableSymBanded interface { 48 SymBanded 49 SetSymBand(i, j int, v float64) 50 } 51 52 // A RawSymBander can return a blas64.SymmetricBand representation of the receiver. 53 // Changes to the blas64.SymmetricBand.Data slice will be reflected in the original 54 // matrix, changes to the N, K, Stride and Uplo fields will not. 55 type RawSymBander interface { 56 RawSymBand() blas64.SymmetricBand 57 } 58 59 // NewSymBandDense creates a new SymBand matrix with n rows and columns. If data == nil, 60 // a new slice is allocated for the backing slice. If len(data) == n*(k+1), 61 // data is used as the backing slice, and changes to the elements of the returned 62 // SymBandDense will be reflected in data. If neither of these is true, NewSymBandDense 63 // will panic. k must be at least zero and less than n, otherwise NewSymBandDense will panic. 64 // 65 // The data must be arranged in row-major order constructed by removing the zeros 66 // from the rows outside the band and aligning the diagonals. SymBandDense matrices 67 // are stored in the upper triangle. For example, the matrix 68 // 1 2 3 0 0 0 69 // 2 4 5 6 0 0 70 // 3 5 7 8 9 0 71 // 0 6 8 10 11 12 72 // 0 0 9 11 13 14 73 // 0 0 0 12 14 15 74 // becomes (* entries are never accessed) 75 // 1 2 3 76 // 4 5 6 77 // 7 8 9 78 // 10 11 12 79 // 13 14 * 80 // 15 * * 81 // which is passed to NewSymBandDense as []float64{1, 2, ..., 15, *, *, *} with k=2. 82 // Only the values in the band portion of the matrix are used. 83 func NewSymBandDense(n, k int, data []float64) *SymBandDense { 84 if n <= 0 || k < 0 { 85 if n == 0 { 86 panic(ErrZeroLength) 87 } 88 panic("mat: negative dimension") 89 } 90 if k+1 > n { 91 panic("mat: band out of range") 92 } 93 bc := k + 1 94 if data != nil && len(data) != n*bc { 95 panic(ErrShape) 96 } 97 if data == nil { 98 data = make([]float64, n*bc) 99 } 100 return &SymBandDense{ 101 mat: blas64.SymmetricBand{ 102 N: n, 103 K: k, 104 Stride: bc, 105 Uplo: blas.Upper, 106 Data: data, 107 }, 108 } 109 } 110 111 // Dims returns the number of rows and columns in the matrix. 112 func (s *SymBandDense) Dims() (r, c int) { 113 return s.mat.N, s.mat.N 114 } 115 116 // Symmetric returns the size of the receiver. 117 func (s *SymBandDense) Symmetric() int { 118 return s.mat.N 119 } 120 121 // Bandwidth returns the bandwidths of the matrix. 122 func (s *SymBandDense) Bandwidth() (kl, ku int) { 123 return s.mat.K, s.mat.K 124 } 125 126 // SymBand returns the number of rows/columns in the matrix, and the size of 127 // the bandwidth. 128 func (s *SymBandDense) SymBand() (n, k int) { 129 return s.mat.N, s.mat.K 130 } 131 132 // T implements the Matrix interface. Symmetric matrices, by definition, are 133 // equal to their transpose, and this is a no-op. 134 func (s *SymBandDense) T() Matrix { 135 return s 136 } 137 138 // TBand implements the Banded interface. 139 func (s *SymBandDense) TBand() Banded { 140 return s 141 } 142 143 // RawSymBand returns the underlying blas64.SymBand used by the receiver. 144 // Changes to elements in the receiver following the call will be reflected 145 // in returned blas64.SymBand. 146 func (s *SymBandDense) RawSymBand() blas64.SymmetricBand { 147 return s.mat 148 } 149 150 // SetRawSymBand sets the underlying blas64.SymmetricBand used by the receiver. 151 // Changes to elements in the receiver following the call will be reflected 152 // in the input. 153 // 154 // The supplied SymmetricBand must use blas.Upper storage format. 155 func (s *SymBandDense) SetRawSymBand(mat blas64.SymmetricBand) { 156 if mat.Uplo != blas.Upper { 157 panic("mat: blas64.SymmetricBand does not have blas.Upper storage") 158 } 159 s.mat = mat 160 } 161 162 // IsEmpty returns whether the receiver is empty. Empty matrices can be the 163 // receiver for size-restricted operations. The receiver can be emptied using 164 // Reset. 165 func (s *SymBandDense) IsEmpty() bool { 166 return s.mat.Stride == 0 167 } 168 169 // Reset empties the matrix so that it can be reused as the 170 // receiver of a dimensionally restricted operation. 171 // 172 // Reset should not be used when the matrix shares backing data. 173 // See the Reseter interface for more information. 174 func (s *SymBandDense) Reset() { 175 s.mat.N = 0 176 s.mat.K = 0 177 s.mat.Stride = 0 178 s.mat.Uplo = 0 179 s.mat.Data = s.mat.Data[:0:0] 180 } 181 182 // Zero sets all of the matrix elements to zero. 183 func (s *SymBandDense) Zero() { 184 for i := 0; i < s.mat.N; i++ { 185 u := min(1+s.mat.K, s.mat.N-i) 186 zero(s.mat.Data[i*s.mat.Stride : i*s.mat.Stride+u]) 187 } 188 } 189 190 // DiagView returns the diagonal as a matrix backed by the original data. 191 func (s *SymBandDense) DiagView() Diagonal { 192 n := s.mat.N 193 return &DiagDense{ 194 mat: blas64.Vector{ 195 N: n, 196 Inc: s.mat.Stride, 197 Data: s.mat.Data[:(n-1)*s.mat.Stride+1], 198 }, 199 } 200 } 201 202 // DoNonZero calls the function fn for each of the non-zero elements of s. The function fn 203 // takes a row/column index and the element value of s at (i, j). 204 func (s *SymBandDense) DoNonZero(fn func(i, j int, v float64)) { 205 for i := 0; i < s.mat.N; i++ { 206 for j := max(0, i-s.mat.K); j < min(s.mat.N, i+s.mat.K+1); j++ { 207 v := s.at(i, j) 208 if v != 0 { 209 fn(i, j, v) 210 } 211 } 212 } 213 } 214 215 // DoRowNonZero calls the function fn for each of the non-zero elements of row i of s. The function fn 216 // takes a row/column index and the element value of s at (i, j). 217 func (s *SymBandDense) DoRowNonZero(i int, fn func(i, j int, v float64)) { 218 if i < 0 || s.mat.N <= i { 219 panic(ErrRowAccess) 220 } 221 for j := max(0, i-s.mat.K); j < min(s.mat.N, i+s.mat.K+1); j++ { 222 v := s.at(i, j) 223 if v != 0 { 224 fn(i, j, v) 225 } 226 } 227 } 228 229 // DoColNonZero calls the function fn for each of the non-zero elements of column j of s. The function fn 230 // takes a row/column index and the element value of s at (i, j). 231 func (s *SymBandDense) DoColNonZero(j int, fn func(i, j int, v float64)) { 232 if j < 0 || s.mat.N <= j { 233 panic(ErrColAccess) 234 } 235 for i := 0; i < s.mat.N; i++ { 236 if i-s.mat.K <= j && j < i+s.mat.K+1 { 237 v := s.at(i, j) 238 if v != 0 { 239 fn(i, j, v) 240 } 241 } 242 } 243 } 244 245 // Trace returns the trace. 246 func (s *SymBandDense) Trace() float64 { 247 rb := s.RawSymBand() 248 var tr float64 249 for i := 0; i < rb.N; i++ { 250 tr += rb.Data[i*rb.Stride] 251 } 252 return tr 253 } 254 255 // MulVecTo computes S⋅x storing the result into dst. 256 func (s *SymBandDense) MulVecTo(dst *VecDense, _ bool, x Vector) { 257 n := s.mat.N 258 if x.Len() != n { 259 panic(ErrShape) 260 } 261 dst.reuseAsNonZeroed(n) 262 263 xMat, _ := untransposeExtract(x) 264 if xVec, ok := xMat.(*VecDense); ok { 265 if dst != xVec { 266 dst.checkOverlap(xVec.mat) 267 blas64.Sbmv(1, s.mat, xVec.mat, 0, dst.mat) 268 } else { 269 xCopy := getWorkspaceVec(n, false) 270 xCopy.CloneFromVec(xVec) 271 blas64.Sbmv(1, s.mat, xCopy.mat, 0, dst.mat) 272 putWorkspaceVec(xCopy) 273 } 274 } else { 275 xCopy := getWorkspaceVec(n, false) 276 xCopy.CloneFromVec(x) 277 blas64.Sbmv(1, s.mat, xCopy.mat, 0, dst.mat) 278 putWorkspaceVec(xCopy) 279 } 280 }