123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- // 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
- }
|