| // Copyright ©2018 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 ( |
| diagDense *DiagDense |
| _ Matrix = diagDense |
| _ allMatrix = diagDense |
| _ denseMatrix = diagDense |
| _ Diagonal = diagDense |
| _ MutableDiagonal = diagDense |
| _ Triangular = diagDense |
| _ TriBanded = diagDense |
| _ Symmetric = diagDense |
| _ SymBanded = diagDense |
| _ Banded = diagDense |
| _ RawBander = diagDense |
| _ RawSymBander = diagDense |
| |
| diag Diagonal |
| _ Matrix = diag |
| _ Diagonal = diag |
| _ Triangular = diag |
| _ TriBanded = diag |
| _ Symmetric = diag |
| _ SymBanded = diag |
| _ Banded = diag |
| ) |
| |
| // Diagonal represents a diagonal matrix, that is a square matrix that only |
| // has non-zero terms on the diagonal. |
| type Diagonal interface { |
| Matrix |
| // Diag returns the number of rows/columns in the matrix. |
| Diag() int |
| |
| // Bandwidth and TBand are included in the Diagonal interface |
| // to allow the use of Diagonal types in banded functions. |
| // Bandwidth will always return (0, 0). |
| Bandwidth() (kl, ku int) |
| TBand() Banded |
| |
| // Triangle and TTri are included in the Diagonal interface |
| // to allow the use of Diagonal types in triangular functions. |
| Triangle() (int, TriKind) |
| TTri() Triangular |
| |
| // Symmetric and SymBand are included in the Diagonal interface |
| // to allow the use of Diagonal types in symmetric and banded symmetric |
| // functions respectively. |
| Symmetric() int |
| SymBand() (n, k int) |
| |
| // TriBand and TTriBand are included in the Diagonal interface |
| // to allow the use of Diagonal types in triangular banded functions. |
| TriBand() (n, k int, kind TriKind) |
| TTriBand() TriBanded |
| } |
| |
| // MutableDiagonal is a Diagonal matrix whose elements can be set. |
| type MutableDiagonal interface { |
| Diagonal |
| SetDiag(i int, v float64) |
| } |
| |
| // DiagDense represents a diagonal matrix in dense storage format. |
| type DiagDense struct { |
| mat blas64.Vector |
| } |
| |
| // NewDiagDense creates a new Diagonal matrix with n rows and n columns. |
| // The length of data must be n or data must be nil, otherwise NewDiagDense |
| // will panic. NewDiagDense will panic if n is zero. |
| func NewDiagDense(n int, data []float64) *DiagDense { |
| if n <= 0 { |
| if n == 0 { |
| panic(ErrZeroLength) |
| } |
| panic("mat: negative dimension") |
| } |
| if data == nil { |
| data = make([]float64, n) |
| } |
| if len(data) != n { |
| panic(ErrShape) |
| } |
| return &DiagDense{ |
| mat: blas64.Vector{N: n, Data: data, Inc: 1}, |
| } |
| } |
| |
| // Diag returns the dimension of the receiver. |
| func (d *DiagDense) Diag() int { |
| return d.mat.N |
| } |
| |
| // Dims returns the dimensions of the matrix. |
| func (d *DiagDense) Dims() (r, c int) { |
| return d.mat.N, d.mat.N |
| } |
| |
| // T returns the transpose of the matrix. |
| func (d *DiagDense) T() Matrix { |
| return d |
| } |
| |
| // TTri returns the transpose of the matrix. Note that Diagonal matrices are |
| // Upper by default. |
| func (d *DiagDense) TTri() Triangular { |
| return TransposeTri{d} |
| } |
| |
| // TBand performs an implicit transpose by returning the receiver inside a |
| // TransposeBand. |
| func (d *DiagDense) TBand() Banded { |
| return TransposeBand{d} |
| } |
| |
| // TTriBand performs an implicit transpose by returning the receiver inside a |
| // TransposeTriBand. Note that Diagonal matrices are Upper by default. |
| func (d *DiagDense) TTriBand() TriBanded { |
| return TransposeTriBand{d} |
| } |
| |
| // Bandwidth returns the upper and lower bandwidths of the matrix. |
| // These values are always zero for diagonal matrices. |
| func (d *DiagDense) Bandwidth() (kl, ku int) { |
| return 0, 0 |
| } |
| |
| // Symmetric implements the Symmetric interface. |
| func (d *DiagDense) Symmetric() int { |
| return d.mat.N |
| } |
| |
| // SymBand returns the number of rows/columns in the matrix, and the size of |
| // the bandwidth. |
| func (d *DiagDense) SymBand() (n, k int) { |
| return d.mat.N, 0 |
| } |
| |
| // Triangle implements the Triangular interface. |
| func (d *DiagDense) Triangle() (int, TriKind) { |
| return d.mat.N, Upper |
| } |
| |
| // TriBand returns the number of rows/columns in the matrix, the |
| // size of the bandwidth, and the orientation. Note that Diagonal matrices are |
| // Upper by default. |
| func (d *DiagDense) TriBand() (n, k int, kind TriKind) { |
| return d.mat.N, 0, Upper |
| } |
| |
| // 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 (d *DiagDense) Reset() { |
| // No change of Inc or n to 0 may be |
| // made unless both are set to 0. |
| d.mat.Inc = 0 |
| d.mat.N = 0 |
| d.mat.Data = d.mat.Data[:0] |
| } |
| |
| // Zero sets all of the matrix elements to zero. |
| func (d *DiagDense) Zero() { |
| for i := 0; i < d.mat.N; i++ { |
| d.mat.Data[d.mat.Inc*i] = 0 |
| } |
| } |
| |
| // DiagView returns the diagonal as a matrix backed by the original data. |
| func (d *DiagDense) DiagView() Diagonal { |
| return d |
| } |
| |
| // DiagFrom copies the diagonal of m into the receiver. The receiver must |
| // be min(r, c) long or empty, otherwise DiagFrom will panic. |
| func (d *DiagDense) DiagFrom(m Matrix) { |
| n := min(m.Dims()) |
| d.reuseAsNonZeroed(n) |
| |
| var vec blas64.Vector |
| switch r := m.(type) { |
| case *DiagDense: |
| vec = r.mat |
| case RawBander: |
| mat := r.RawBand() |
| vec = blas64.Vector{ |
| N: n, |
| Inc: mat.Stride, |
| Data: mat.Data[mat.KL : (n-1)*mat.Stride+mat.KL+1], |
| } |
| case RawMatrixer: |
| mat := r.RawMatrix() |
| vec = blas64.Vector{ |
| N: n, |
| Inc: mat.Stride + 1, |
| Data: mat.Data[:(n-1)*mat.Stride+n], |
| } |
| case RawSymBander: |
| mat := r.RawSymBand() |
| vec = blas64.Vector{ |
| N: n, |
| Inc: mat.Stride, |
| Data: mat.Data[:(n-1)*mat.Stride+1], |
| } |
| case RawSymmetricer: |
| mat := r.RawSymmetric() |
| vec = blas64.Vector{ |
| N: n, |
| Inc: mat.Stride + 1, |
| Data: mat.Data[:(n-1)*mat.Stride+n], |
| } |
| case RawTriBander: |
| mat := r.RawTriBand() |
| data := mat.Data |
| if mat.Uplo == blas.Lower { |
| data = data[mat.K:] |
| } |
| vec = blas64.Vector{ |
| N: n, |
| Inc: mat.Stride, |
| Data: data[:(n-1)*mat.Stride+1], |
| } |
| case RawTriangular: |
| mat := r.RawTriangular() |
| if mat.Diag == blas.Unit { |
| for i := 0; i < n; i += d.mat.Inc { |
| d.mat.Data[i] = 1 |
| } |
| return |
| } |
| vec = blas64.Vector{ |
| N: n, |
| Inc: mat.Stride + 1, |
| Data: mat.Data[:(n-1)*mat.Stride+n], |
| } |
| case RawVectorer: |
| d.mat.Data[0] = r.RawVector().Data[0] |
| return |
| default: |
| for i := 0; i < n; i++ { |
| d.setDiag(i, m.At(i, i)) |
| } |
| return |
| } |
| blas64.Copy(vec, d.mat) |
| } |
| |
| // RawBand returns the underlying data used by the receiver represented |
| // as a blas64.Band. |
| // Changes to elements in the receiver following the call will be reflected |
| // in returned blas64.Band. |
| func (d *DiagDense) RawBand() blas64.Band { |
| return blas64.Band{ |
| Rows: d.mat.N, |
| Cols: d.mat.N, |
| KL: 0, |
| KU: 0, |
| Stride: d.mat.Inc, |
| Data: d.mat.Data, |
| } |
| } |
| |
| // RawSymBand returns the underlying data used by the receiver represented |
| // as a blas64.SymmetricBand. |
| // Changes to elements in the receiver following the call will be reflected |
| // in returned blas64.Band. |
| func (d *DiagDense) RawSymBand() blas64.SymmetricBand { |
| return blas64.SymmetricBand{ |
| N: d.mat.N, |
| K: 0, |
| Stride: d.mat.Inc, |
| Uplo: blas.Upper, |
| Data: d.mat.Data, |
| } |
| } |
| |
| // reuseAsNonZeroed resizes an empty diagonal to a r×r diagonal, |
| // or checks that a non-empty matrix is r×r. |
| func (d *DiagDense) reuseAsNonZeroed(r int) { |
| if r == 0 { |
| panic(ErrZeroLength) |
| } |
| if d.IsEmpty() { |
| d.mat = blas64.Vector{ |
| Inc: 1, |
| Data: use(d.mat.Data, r), |
| } |
| d.mat.N = r |
| return |
| } |
| if r != d.mat.N { |
| panic(ErrShape) |
| } |
| } |
| |
| // 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 (d *DiagDense) IsEmpty() bool { |
| // It must be the case that d.Dims() returns |
| // zeros in this case. See comment in Reset(). |
| return d.mat.Inc == 0 |
| } |
| |
| // Trace returns the trace. |
| func (d *DiagDense) Trace() float64 { |
| rb := d.RawBand() |
| var tr float64 |
| for i := 0; i < rb.Rows; i++ { |
| tr += rb.Data[rb.KL+i*rb.Stride] |
| } |
| return tr |
| |
| } |