2019-08-30 18:33:25 +00:00
|
|
|
// 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
|
2020-03-26 21:07:15 +00:00
|
|
|
_ allMatrix = symBandDense
|
|
|
|
_ denseMatrix = symBandDense
|
2019-08-30 18:33:25 +00:00
|
|
|
_ 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
|
|
|
|
}
|
|
|
|
|
2020-03-26 21:07:15 +00:00
|
|
|
// 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]
|
|
|
|
}
|
|
|
|
|
2019-08-30 18:33:25 +00:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-26 21:07:15 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|