github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/mat/diagonal.go (about) 1 // Copyright ©2018 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 diagDense *DiagDense 14 _ Matrix = diagDense 15 _ allMatrix = diagDense 16 _ denseMatrix = diagDense 17 _ Diagonal = diagDense 18 _ MutableDiagonal = diagDense 19 _ Triangular = diagDense 20 _ TriBanded = diagDense 21 _ Symmetric = diagDense 22 _ SymBanded = diagDense 23 _ Banded = diagDense 24 _ RawBander = diagDense 25 _ RawSymBander = diagDense 26 27 diag Diagonal 28 _ Matrix = diag 29 _ Diagonal = diag 30 _ Triangular = diag 31 _ TriBanded = diag 32 _ Symmetric = diag 33 _ SymBanded = diag 34 _ Banded = diag 35 ) 36 37 // Diagonal represents a diagonal matrix, that is a square matrix that only 38 // has non-zero terms on the diagonal. 39 type Diagonal interface { 40 Matrix 41 // Diag returns the number of rows/columns in the matrix. 42 Diag() int 43 44 // Bandwidth and TBand are included in the Diagonal interface 45 // to allow the use of Diagonal types in banded functions. 46 // Bandwidth will always return (0, 0). 47 Bandwidth() (kl, ku int) 48 TBand() Banded 49 50 // Triangle and TTri are included in the Diagonal interface 51 // to allow the use of Diagonal types in triangular functions. 52 Triangle() (int, TriKind) 53 TTri() Triangular 54 55 // Symmetric and SymBand are included in the Diagonal interface 56 // to allow the use of Diagonal types in symmetric and banded symmetric 57 // functions respectively. 58 Symmetric() int 59 SymBand() (n, k int) 60 61 // TriBand and TTriBand are included in the Diagonal interface 62 // to allow the use of Diagonal types in triangular banded functions. 63 TriBand() (n, k int, kind TriKind) 64 TTriBand() TriBanded 65 } 66 67 // MutableDiagonal is a Diagonal matrix whose elements can be set. 68 type MutableDiagonal interface { 69 Diagonal 70 SetDiag(i int, v float64) 71 } 72 73 // DiagDense represents a diagonal matrix in dense storage format. 74 type DiagDense struct { 75 mat blas64.Vector 76 } 77 78 // NewDiagDense creates a new Diagonal matrix with n rows and n columns. 79 // The length of data must be n or data must be nil, otherwise NewDiagDense 80 // will panic. NewDiagDense will panic if n is zero. 81 func NewDiagDense(n int, data []float64) *DiagDense { 82 if n <= 0 { 83 if n == 0 { 84 panic(ErrZeroLength) 85 } 86 panic("mat: negative dimension") 87 } 88 if data == nil { 89 data = make([]float64, n) 90 } 91 if len(data) != n { 92 panic(ErrShape) 93 } 94 return &DiagDense{ 95 mat: blas64.Vector{N: n, Data: data, Inc: 1}, 96 } 97 } 98 99 // Diag returns the dimension of the receiver. 100 func (d *DiagDense) Diag() int { 101 return d.mat.N 102 } 103 104 // Dims returns the dimensions of the matrix. 105 func (d *DiagDense) Dims() (r, c int) { 106 return d.mat.N, d.mat.N 107 } 108 109 // T returns the transpose of the matrix. 110 func (d *DiagDense) T() Matrix { 111 return d 112 } 113 114 // TTri returns the transpose of the matrix. Note that Diagonal matrices are 115 // Upper by default. 116 func (d *DiagDense) TTri() Triangular { 117 return TransposeTri{d} 118 } 119 120 // TBand performs an implicit transpose by returning the receiver inside a 121 // TransposeBand. 122 func (d *DiagDense) TBand() Banded { 123 return TransposeBand{d} 124 } 125 126 // TTriBand performs an implicit transpose by returning the receiver inside a 127 // TransposeTriBand. Note that Diagonal matrices are Upper by default. 128 func (d *DiagDense) TTriBand() TriBanded { 129 return TransposeTriBand{d} 130 } 131 132 // Bandwidth returns the upper and lower bandwidths of the matrix. 133 // These values are always zero for diagonal matrices. 134 func (d *DiagDense) Bandwidth() (kl, ku int) { 135 return 0, 0 136 } 137 138 // Symmetric implements the Symmetric interface. 139 func (d *DiagDense) Symmetric() int { 140 return d.mat.N 141 } 142 143 // SymBand returns the number of rows/columns in the matrix, and the size of 144 // the bandwidth. 145 func (d *DiagDense) SymBand() (n, k int) { 146 return d.mat.N, 0 147 } 148 149 // Triangle implements the Triangular interface. 150 func (d *DiagDense) Triangle() (int, TriKind) { 151 return d.mat.N, Upper 152 } 153 154 // TriBand returns the number of rows/columns in the matrix, the 155 // size of the bandwidth, and the orientation. Note that Diagonal matrices are 156 // Upper by default. 157 func (d *DiagDense) TriBand() (n, k int, kind TriKind) { 158 return d.mat.N, 0, Upper 159 } 160 161 // Reset empties the matrix so that it can be reused as the 162 // receiver of a dimensionally restricted operation. 163 // 164 // Reset should not be used when the matrix shares backing data. 165 // See the Reseter interface for more information. 166 func (d *DiagDense) Reset() { 167 // No change of Inc or n to 0 may be 168 // made unless both are set to 0. 169 d.mat.Inc = 0 170 d.mat.N = 0 171 d.mat.Data = d.mat.Data[:0] 172 } 173 174 // Zero sets all of the matrix elements to zero. 175 func (d *DiagDense) Zero() { 176 for i := 0; i < d.mat.N; i++ { 177 d.mat.Data[d.mat.Inc*i] = 0 178 } 179 } 180 181 // DiagView returns the diagonal as a matrix backed by the original data. 182 func (d *DiagDense) DiagView() Diagonal { 183 return d 184 } 185 186 // DiagFrom copies the diagonal of m into the receiver. The receiver must 187 // be min(r, c) long or empty, otherwise DiagFrom will panic. 188 func (d *DiagDense) DiagFrom(m Matrix) { 189 n := min(m.Dims()) 190 d.reuseAsNonZeroed(n) 191 192 var vec blas64.Vector 193 switch r := m.(type) { 194 case *DiagDense: 195 vec = r.mat 196 case RawBander: 197 mat := r.RawBand() 198 vec = blas64.Vector{ 199 N: n, 200 Inc: mat.Stride, 201 Data: mat.Data[mat.KL : (n-1)*mat.Stride+mat.KL+1], 202 } 203 case RawMatrixer: 204 mat := r.RawMatrix() 205 vec = blas64.Vector{ 206 N: n, 207 Inc: mat.Stride + 1, 208 Data: mat.Data[:(n-1)*mat.Stride+n], 209 } 210 case RawSymBander: 211 mat := r.RawSymBand() 212 vec = blas64.Vector{ 213 N: n, 214 Inc: mat.Stride, 215 Data: mat.Data[:(n-1)*mat.Stride+1], 216 } 217 case RawSymmetricer: 218 mat := r.RawSymmetric() 219 vec = blas64.Vector{ 220 N: n, 221 Inc: mat.Stride + 1, 222 Data: mat.Data[:(n-1)*mat.Stride+n], 223 } 224 case RawTriBander: 225 mat := r.RawTriBand() 226 data := mat.Data 227 if mat.Uplo == blas.Lower { 228 data = data[mat.K:] 229 } 230 vec = blas64.Vector{ 231 N: n, 232 Inc: mat.Stride, 233 Data: data[:(n-1)*mat.Stride+1], 234 } 235 case RawTriangular: 236 mat := r.RawTriangular() 237 if mat.Diag == blas.Unit { 238 for i := 0; i < n; i += d.mat.Inc { 239 d.mat.Data[i] = 1 240 } 241 return 242 } 243 vec = blas64.Vector{ 244 N: n, 245 Inc: mat.Stride + 1, 246 Data: mat.Data[:(n-1)*mat.Stride+n], 247 } 248 case RawVectorer: 249 d.mat.Data[0] = r.RawVector().Data[0] 250 return 251 default: 252 for i := 0; i < n; i++ { 253 d.setDiag(i, m.At(i, i)) 254 } 255 return 256 } 257 blas64.Copy(vec, d.mat) 258 } 259 260 // RawBand returns the underlying data used by the receiver represented 261 // as a blas64.Band. 262 // Changes to elements in the receiver following the call will be reflected 263 // in returned blas64.Band. 264 func (d *DiagDense) RawBand() blas64.Band { 265 return blas64.Band{ 266 Rows: d.mat.N, 267 Cols: d.mat.N, 268 KL: 0, 269 KU: 0, 270 Stride: d.mat.Inc, 271 Data: d.mat.Data, 272 } 273 } 274 275 // RawSymBand returns the underlying data used by the receiver represented 276 // as a blas64.SymmetricBand. 277 // Changes to elements in the receiver following the call will be reflected 278 // in returned blas64.Band. 279 func (d *DiagDense) RawSymBand() blas64.SymmetricBand { 280 return blas64.SymmetricBand{ 281 N: d.mat.N, 282 K: 0, 283 Stride: d.mat.Inc, 284 Uplo: blas.Upper, 285 Data: d.mat.Data, 286 } 287 } 288 289 // reuseAsNonZeroed resizes an empty diagonal to a r×r diagonal, 290 // or checks that a non-empty matrix is r×r. 291 func (d *DiagDense) reuseAsNonZeroed(r int) { 292 if r == 0 { 293 panic(ErrZeroLength) 294 } 295 if d.IsEmpty() { 296 d.mat = blas64.Vector{ 297 Inc: 1, 298 Data: use(d.mat.Data, r), 299 } 300 d.mat.N = r 301 return 302 } 303 if r != d.mat.N { 304 panic(ErrShape) 305 } 306 } 307 308 // IsEmpty returns whether the receiver is empty. Empty matrices can be the 309 // receiver for size-restricted operations. The receiver can be emptied using 310 // Reset. 311 func (d *DiagDense) IsEmpty() bool { 312 // It must be the case that d.Dims() returns 313 // zeros in this case. See comment in Reset(). 314 return d.mat.Inc == 0 315 } 316 317 // Trace returns the trace. 318 func (d *DiagDense) Trace() float64 { 319 rb := d.RawBand() 320 var tr float64 321 for i := 0; i < rb.Rows; i++ { 322 tr += rb.Data[rb.KL+i*rb.Stride] 323 } 324 return tr 325 326 }