mirror of https://github.com/k3s-io/k3s
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
372 lines
11 KiB
372 lines
11 KiB
// 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 (
|
|
triBand TriBanded
|
|
_ Banded = triBand
|
|
_ Triangular = triBand
|
|
|
|
triBandDense *TriBandDense
|
|
_ Matrix = triBandDense
|
|
_ allMatrix = triBandDense
|
|
_ denseMatrix = triBandDense
|
|
_ Triangular = triBandDense
|
|
_ Banded = triBandDense
|
|
_ TriBanded = triBandDense
|
|
_ RawTriBander = triBandDense
|
|
_ MutableTriBanded = triBandDense
|
|
)
|
|
|
|
// TriBanded is a triangular band matrix interface type.
|
|
type TriBanded interface {
|
|
Banded
|
|
|
|
// Triangle returns the number of rows/columns in the matrix and its
|
|
// orientation.
|
|
Triangle() (n int, kind TriKind)
|
|
|
|
// TTri is the equivalent of the T() method in the Matrix interface but
|
|
// guarantees the transpose is of triangular type.
|
|
TTri() Triangular
|
|
|
|
// TriBand returns the number of rows/columns in the matrix, the
|
|
// size of the bandwidth, and the orientation.
|
|
TriBand() (n, k int, kind TriKind)
|
|
|
|
// TTriBand is the equivalent of the T() method in the Matrix interface but
|
|
// guarantees the transpose is of banded triangular type.
|
|
TTriBand() TriBanded
|
|
}
|
|
|
|
// A RawTriBander can return a blas64.TriangularBand representation of the receiver.
|
|
// Changes to the blas64.TriangularBand.Data slice will be reflected in the original
|
|
// matrix, changes to the N, K, Stride, Uplo and Diag fields will not.
|
|
type RawTriBander interface {
|
|
RawTriBand() blas64.TriangularBand
|
|
}
|
|
|
|
// MutableTriBanded is a triangular band matrix interface type that allows
|
|
// elements to be altered.
|
|
type MutableTriBanded interface {
|
|
TriBanded
|
|
SetTriBand(i, j int, v float64)
|
|
}
|
|
|
|
var (
|
|
tTriBand TransposeTriBand
|
|
_ Matrix = tTriBand
|
|
_ TriBanded = tTriBand
|
|
_ Untransposer = tTriBand
|
|
_ UntransposeTrier = tTriBand
|
|
_ UntransposeBander = tTriBand
|
|
_ UntransposeTriBander = tTriBand
|
|
)
|
|
|
|
// TransposeTriBand is a type for performing an implicit transpose of a TriBanded
|
|
// matrix. It implements the TriBanded interface, returning values from the
|
|
// transpose of the matrix within.
|
|
type TransposeTriBand struct {
|
|
TriBanded TriBanded
|
|
}
|
|
|
|
// At returns the value of the element at row i and column j of the transposed
|
|
// matrix, that is, row j and column i of the TriBanded field.
|
|
func (t TransposeTriBand) At(i, j int) float64 {
|
|
return t.TriBanded.At(j, i)
|
|
}
|
|
|
|
// Dims returns the dimensions of the transposed matrix. TriBanded matrices are
|
|
// square and thus this is the same size as the original TriBanded.
|
|
func (t TransposeTriBand) Dims() (r, c int) {
|
|
c, r = t.TriBanded.Dims()
|
|
return r, c
|
|
}
|
|
|
|
// T performs an implicit transpose by returning the TriBand field.
|
|
func (t TransposeTriBand) T() Matrix {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// Triangle returns the number of rows/columns in the matrix and its orientation.
|
|
func (t TransposeTriBand) Triangle() (int, TriKind) {
|
|
n, upper := t.TriBanded.Triangle()
|
|
return n, !upper
|
|
}
|
|
|
|
// TTri performs an implicit transpose by returning the TriBand field.
|
|
func (t TransposeTriBand) TTri() Triangular {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// Bandwidth returns the upper and lower bandwidths of the matrix.
|
|
func (t TransposeTriBand) Bandwidth() (kl, ku int) {
|
|
kl, ku = t.TriBanded.Bandwidth()
|
|
return ku, kl
|
|
}
|
|
|
|
// TBand performs an implicit transpose by returning the TriBand field.
|
|
func (t TransposeTriBand) TBand() Banded {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// TriBand returns the number of rows/columns in the matrix, the
|
|
// size of the bandwidth, and the orientation.
|
|
func (t TransposeTriBand) TriBand() (n, k int, kind TriKind) {
|
|
n, k, kind = t.TriBanded.TriBand()
|
|
return n, k, !kind
|
|
}
|
|
|
|
// TTriBand performs an implicit transpose by returning the TriBand field.
|
|
func (t TransposeTriBand) TTriBand() TriBanded {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// Untranspose returns the Triangular field.
|
|
func (t TransposeTriBand) Untranspose() Matrix {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// UntransposeTri returns the underlying Triangular matrix.
|
|
func (t TransposeTriBand) UntransposeTri() Triangular {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// UntransposeBand returns the underlying Banded matrix.
|
|
func (t TransposeTriBand) UntransposeBand() Banded {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// UntransposeTriBand returns the underlying TriBanded matrix.
|
|
func (t TransposeTriBand) UntransposeTriBand() TriBanded {
|
|
return t.TriBanded
|
|
}
|
|
|
|
// TriBandDense represents a triangular band matrix in dense storage format.
|
|
type TriBandDense struct {
|
|
mat blas64.TriangularBand
|
|
}
|
|
|
|
// NewTriBandDense creates a new triangular banded matrix with n rows and columns,
|
|
// k bands in the direction of the specified kind. 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
|
|
// TriBandDense will be reflected in data. If neither of these is true, NewTriBandDense
|
|
// will panic. k must be at least zero and less than n, otherwise NewTriBandDense 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. For example, if
|
|
// the upper-triangular banded matrix
|
|
// 1 2 3 0 0 0
|
|
// 0 4 5 6 0 0
|
|
// 0 0 7 8 9 0
|
|
// 0 0 0 10 11 12
|
|
// 0 0 0 0 13 14
|
|
// 0 0 0 0 0 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 NewTriBandDense as []float64{1, 2, ..., 15, *, *, *}
|
|
// with k=2 and kind = mat.Upper.
|
|
// The lower triangular banded matrix
|
|
// 1 0 0 0 0 0
|
|
// 2 3 0 0 0 0
|
|
// 4 5 6 0 0 0
|
|
// 0 7 8 9 0 0
|
|
// 0 0 10 11 12 0
|
|
// 0 0 0 13 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 NewTriBandDense as []float64{*, *, *, 1, 2, ..., 15}
|
|
// with k=2 and kind = mat.Lower.
|
|
// Only the values in the band portion of the matrix are used.
|
|
func NewTriBandDense(n, k int, kind TriKind, data []float64) *TriBandDense {
|
|
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)
|
|
}
|
|
uplo := blas.Lower
|
|
if kind {
|
|
uplo = blas.Upper
|
|
}
|
|
return &TriBandDense{
|
|
mat: blas64.TriangularBand{
|
|
Uplo: uplo,
|
|
Diag: blas.NonUnit,
|
|
N: n,
|
|
K: k,
|
|
Data: data,
|
|
Stride: bc,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Dims returns the number of rows and columns in the matrix.
|
|
func (t *TriBandDense) Dims() (r, c int) {
|
|
return t.mat.N, t.mat.N
|
|
}
|
|
|
|
// T performs an implicit transpose by returning the receiver inside a Transpose.
|
|
func (t *TriBandDense) T() Matrix {
|
|
return Transpose{t}
|
|
}
|
|
|
|
// 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 (t *TriBandDense) IsEmpty() bool {
|
|
// It must be the case that t.Dims() returns
|
|
// zeros in this case. See comment in Reset().
|
|
return t.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 (t *TriBandDense) Reset() {
|
|
t.mat.N = 0
|
|
t.mat.Stride = 0
|
|
t.mat.K = 0
|
|
t.mat.Data = t.mat.Data[:0]
|
|
}
|
|
|
|
// Zero sets all of the matrix elements to zero.
|
|
func (t *TriBandDense) Zero() {
|
|
if t.isUpper() {
|
|
for i := 0; i < t.mat.N; i++ {
|
|
u := min(1+t.mat.K, t.mat.N-i)
|
|
zero(t.mat.Data[i*t.mat.Stride : i*t.mat.Stride+u])
|
|
}
|
|
return
|
|
}
|
|
for i := 0; i < t.mat.N; i++ {
|
|
l := max(0, t.mat.K-i)
|
|
zero(t.mat.Data[i*t.mat.Stride+l : i*t.mat.Stride+t.mat.K+1])
|
|
}
|
|
}
|
|
|
|
func (t *TriBandDense) isUpper() bool {
|
|
return isUpperUplo(t.mat.Uplo)
|
|
}
|
|
|
|
func (t *TriBandDense) triKind() TriKind {
|
|
return TriKind(isUpperUplo(t.mat.Uplo))
|
|
}
|
|
|
|
// Triangle returns the dimension of t and its orientation. The returned
|
|
// orientation is only valid when n is not zero.
|
|
func (t *TriBandDense) Triangle() (n int, kind TriKind) {
|
|
return t.mat.N, t.triKind()
|
|
}
|
|
|
|
// TTri performs an implicit transpose by returning the receiver inside a TransposeTri.
|
|
func (t *TriBandDense) TTri() Triangular {
|
|
return TransposeTri{t}
|
|
}
|
|
|
|
// Bandwidth returns the upper and lower bandwidths of the matrix.
|
|
func (t *TriBandDense) Bandwidth() (kl, ku int) {
|
|
if t.isUpper() {
|
|
return 0, t.mat.K
|
|
}
|
|
return t.mat.K, 0
|
|
}
|
|
|
|
// TBand performs an implicit transpose by returning the receiver inside a TransposeBand.
|
|
func (t *TriBandDense) TBand() Banded {
|
|
return TransposeBand{t}
|
|
}
|
|
|
|
// TriBand returns the number of rows/columns in the matrix, the
|
|
// size of the bandwidth, and the orientation.
|
|
func (t *TriBandDense) TriBand() (n, k int, kind TriKind) {
|
|
return t.mat.N, t.mat.K, TriKind(!t.IsEmpty()) && t.triKind()
|
|
}
|
|
|
|
// TTriBand performs an implicit transpose by returning the receiver inside a TransposeTriBand.
|
|
func (t *TriBandDense) TTriBand() TriBanded {
|
|
return TransposeTriBand{t}
|
|
}
|
|
|
|
// RawTriBand returns the underlying blas64.TriangularBand used by the receiver.
|
|
// Changes to the blas64.TriangularBand.Data slice will be reflected in the original
|
|
// matrix, changes to the N, K, Stride, Uplo and Diag fields will not.
|
|
func (t *TriBandDense) RawTriBand() blas64.TriangularBand {
|
|
return t.mat
|
|
}
|
|
|
|
// SetRawTriBand sets the underlying blas64.TriangularBand used by the receiver.
|
|
// Changes to elements in the receiver following the call will be reflected
|
|
// in the input.
|
|
//
|
|
// The supplied TriangularBand must not use blas.Unit storage format.
|
|
func (t *TriBandDense) SetRawTriBand(mat blas64.TriangularBand) {
|
|
if mat.Diag == blas.Unit {
|
|
panic("mat: cannot set TriBand with Unit storage")
|
|
}
|
|
t.mat = mat
|
|
}
|
|
|
|
// DiagView returns the diagonal as a matrix backed by the original data.
|
|
func (t *TriBandDense) DiagView() Diagonal {
|
|
if t.mat.Diag == blas.Unit {
|
|
panic("mat: cannot take view of Unit diagonal")
|
|
}
|
|
n := t.mat.N
|
|
data := t.mat.Data
|
|
if !t.isUpper() {
|
|
data = data[t.mat.K:]
|
|
}
|
|
return &DiagDense{
|
|
mat: blas64.Vector{
|
|
N: n,
|
|
Inc: t.mat.Stride,
|
|
Data: data[:(n-1)*t.mat.Stride+1],
|
|
},
|
|
}
|
|
}
|
|
|
|
// Trace returns the trace.
|
|
func (t *TriBandDense) Trace() float64 {
|
|
rb := t.RawTriBand()
|
|
var tr float64
|
|
var offsetIndex int
|
|
if rb.Uplo == blas.Lower {
|
|
offsetIndex = rb.K
|
|
}
|
|
for i := 0; i < rb.N; i++ {
|
|
tr += rb.Data[offsetIndex+i*rb.Stride]
|
|
}
|
|
return tr
|
|
}
|