mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			300 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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/blas64"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	bandDense *BandDense
 | 
						|
	_         Matrix      = bandDense
 | 
						|
	_         allMatrix   = bandDense
 | 
						|
	_         denseMatrix = bandDense
 | 
						|
	_         Banded      = bandDense
 | 
						|
	_         RawBander   = bandDense
 | 
						|
 | 
						|
	_ NonZeroDoer    = bandDense
 | 
						|
	_ RowNonZeroDoer = bandDense
 | 
						|
	_ ColNonZeroDoer = bandDense
 | 
						|
)
 | 
						|
 | 
						|
// BandDense represents a band matrix in dense storage format.
 | 
						|
type BandDense struct {
 | 
						|
	mat blas64.Band
 | 
						|
}
 | 
						|
 | 
						|
// Banded is a band matrix representation.
 | 
						|
type Banded interface {
 | 
						|
	Matrix
 | 
						|
	// Bandwidth returns the lower and upper bandwidth values for
 | 
						|
	// the matrix. The total bandwidth of the matrix is kl+ku+1.
 | 
						|
	Bandwidth() (kl, ku int)
 | 
						|
 | 
						|
	// TBand is the equivalent of the T() method in the Matrix
 | 
						|
	// interface but guarantees the transpose is of banded type.
 | 
						|
	TBand() Banded
 | 
						|
}
 | 
						|
 | 
						|
// A RawBander can return a blas64.Band representation of the receiver.
 | 
						|
// Changes to the blas64.Band.Data slice will be reflected in the original
 | 
						|
// matrix, changes to the Rows, Cols, KL, KU and Stride fields will not.
 | 
						|
type RawBander interface {
 | 
						|
	RawBand() blas64.Band
 | 
						|
}
 | 
						|
 | 
						|
// A MutableBanded can set elements of a band matrix.
 | 
						|
type MutableBanded interface {
 | 
						|
	Banded
 | 
						|
	SetBand(i, j int, v float64)
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	_ Matrix            = TransposeBand{}
 | 
						|
	_ Banded            = TransposeBand{}
 | 
						|
	_ UntransposeBander = TransposeBand{}
 | 
						|
)
 | 
						|
 | 
						|
// TransposeBand is a type for performing an implicit transpose of a band
 | 
						|
// matrix. It implements the Banded interface, returning values from the
 | 
						|
// transpose of the matrix within.
 | 
						|
type TransposeBand struct {
 | 
						|
	Banded Banded
 | 
						|
}
 | 
						|
 | 
						|
// 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 Banded field.
 | 
						|
func (t TransposeBand) At(i, j int) float64 {
 | 
						|
	return t.Banded.At(j, i)
 | 
						|
}
 | 
						|
 | 
						|
// Dims returns the dimensions of the transposed matrix.
 | 
						|
func (t TransposeBand) Dims() (r, c int) {
 | 
						|
	c, r = t.Banded.Dims()
 | 
						|
	return r, c
 | 
						|
}
 | 
						|
 | 
						|
// T performs an implicit transpose by returning the Banded field.
 | 
						|
func (t TransposeBand) T() Matrix {
 | 
						|
	return t.Banded
 | 
						|
}
 | 
						|
 | 
						|
// Bandwidth returns the lower and upper bandwidth values for
 | 
						|
// the transposed matrix.
 | 
						|
func (t TransposeBand) Bandwidth() (kl, ku int) {
 | 
						|
	kl, ku = t.Banded.Bandwidth()
 | 
						|
	return ku, kl
 | 
						|
}
 | 
						|
 | 
						|
// TBand performs an implicit transpose by returning the Banded field.
 | 
						|
func (t TransposeBand) TBand() Banded {
 | 
						|
	return t.Banded
 | 
						|
}
 | 
						|
 | 
						|
// Untranspose returns the Banded field.
 | 
						|
func (t TransposeBand) Untranspose() Matrix {
 | 
						|
	return t.Banded
 | 
						|
}
 | 
						|
 | 
						|
// UntransposeBand returns the Banded field.
 | 
						|
func (t TransposeBand) UntransposeBand() Banded {
 | 
						|
	return t.Banded
 | 
						|
}
 | 
						|
 | 
						|
// NewBandDense creates a new Band matrix with r rows and c columns. If data == nil,
 | 
						|
// a new slice is allocated for the backing slice. If len(data) == min(r, c+kl)*(kl+ku+1),
 | 
						|
// data is used as the backing slice, and changes to the elements of the returned
 | 
						|
// BandDense will be reflected in data. If neither of these is true, NewBandDense
 | 
						|
// will panic. kl must be at least zero and less r, and ku must be at least zero and
 | 
						|
// less than c, otherwise NewBandDense will panic.
 | 
						|
// NewBandDense will panic if either r or c is zero.
 | 
						|
//
 | 
						|
// 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, the matrix
 | 
						|
//    1  2  3  0  0  0
 | 
						|
//    4  5  6  7  0  0
 | 
						|
//    0  8  9 10 11  0
 | 
						|
//    0  0 12 13 14 15
 | 
						|
//    0  0  0 16 17 18
 | 
						|
//    0  0  0  0 19 20
 | 
						|
// becomes (* entries are never accessed)
 | 
						|
//     *  1  2  3
 | 
						|
//     4  5  6  7
 | 
						|
//     8  9 10 11
 | 
						|
//    12 13 14 15
 | 
						|
//    16 17 18  *
 | 
						|
//    19 20  *  *
 | 
						|
// which is passed to NewBandDense as []float64{*, 1, 2, 3, 4, ...} with kl=1 and ku=2.
 | 
						|
// Only the values in the band portion of the matrix are used.
 | 
						|
func NewBandDense(r, c, kl, ku int, data []float64) *BandDense {
 | 
						|
	if r <= 0 || c <= 0 || kl < 0 || ku < 0 {
 | 
						|
		if r == 0 || c == 0 {
 | 
						|
			panic(ErrZeroLength)
 | 
						|
		}
 | 
						|
		panic("mat: negative dimension")
 | 
						|
	}
 | 
						|
	if kl+1 > r || ku+1 > c {
 | 
						|
		panic("mat: band out of range")
 | 
						|
	}
 | 
						|
	bc := kl + ku + 1
 | 
						|
	if data != nil && len(data) != min(r, c+kl)*bc {
 | 
						|
		panic(ErrShape)
 | 
						|
	}
 | 
						|
	if data == nil {
 | 
						|
		data = make([]float64, min(r, c+kl)*bc)
 | 
						|
	}
 | 
						|
	return &BandDense{
 | 
						|
		mat: blas64.Band{
 | 
						|
			Rows:   r,
 | 
						|
			Cols:   c,
 | 
						|
			KL:     kl,
 | 
						|
			KU:     ku,
 | 
						|
			Stride: bc,
 | 
						|
			Data:   data,
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewDiagonalRect is a convenience function that returns a diagonal matrix represented by a
 | 
						|
// BandDense. The length of data must be min(r, c) otherwise NewDiagonalRect will panic.
 | 
						|
func NewDiagonalRect(r, c int, data []float64) *BandDense {
 | 
						|
	return NewBandDense(r, c, 0, 0, data)
 | 
						|
}
 | 
						|
 | 
						|
// Dims returns the number of rows and columns in the matrix.
 | 
						|
func (b *BandDense) Dims() (r, c int) {
 | 
						|
	return b.mat.Rows, b.mat.Cols
 | 
						|
}
 | 
						|
 | 
						|
// Bandwidth returns the upper and lower bandwidths of the matrix.
 | 
						|
func (b *BandDense) Bandwidth() (kl, ku int) {
 | 
						|
	return b.mat.KL, b.mat.KU
 | 
						|
}
 | 
						|
 | 
						|
// T performs an implicit transpose by returning the receiver inside a Transpose.
 | 
						|
func (b *BandDense) T() Matrix {
 | 
						|
	return Transpose{b}
 | 
						|
}
 | 
						|
 | 
						|
// TBand performs an implicit transpose by returning the receiver inside a TransposeBand.
 | 
						|
func (b *BandDense) TBand() Banded {
 | 
						|
	return TransposeBand{b}
 | 
						|
}
 | 
						|
 | 
						|
// RawBand returns the underlying blas64.Band used by the receiver.
 | 
						|
// Changes to elements in the receiver following the call will be reflected
 | 
						|
// in returned blas64.Band.
 | 
						|
func (b *BandDense) RawBand() blas64.Band {
 | 
						|
	return b.mat
 | 
						|
}
 | 
						|
 | 
						|
// SetRawBand sets the underlying blas64.Band used by the receiver.
 | 
						|
// Changes to elements in the receiver following the call will be reflected
 | 
						|
// in the input.
 | 
						|
func (b *BandDense) SetRawBand(mat blas64.Band) {
 | 
						|
	b.mat = mat
 | 
						|
}
 | 
						|
 | 
						|
// IsEmpty returns whether the receiver is empty. Empty matrices can be the
 | 
						|
// receiver for size-restricted operations. The receiver can be zeroed using Reset.
 | 
						|
func (b *BandDense) IsEmpty() bool {
 | 
						|
	return b.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 (b *BandDense) Reset() {
 | 
						|
	b.mat.Rows = 0
 | 
						|
	b.mat.Cols = 0
 | 
						|
	b.mat.KL = 0
 | 
						|
	b.mat.KU = 0
 | 
						|
	b.mat.Stride = 0
 | 
						|
	b.mat.Data = b.mat.Data[:0:0]
 | 
						|
}
 | 
						|
 | 
						|
// DiagView returns the diagonal as a matrix backed by the original data.
 | 
						|
func (b *BandDense) DiagView() Diagonal {
 | 
						|
	n := min(b.mat.Rows, b.mat.Cols)
 | 
						|
	return &DiagDense{
 | 
						|
		mat: blas64.Vector{
 | 
						|
			N:    n,
 | 
						|
			Inc:  b.mat.Stride,
 | 
						|
			Data: b.mat.Data[b.mat.KL : (n-1)*b.mat.Stride+b.mat.KL+1],
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// DoNonZero calls the function fn for each of the non-zero elements of b. The function fn
 | 
						|
// takes a row/column index and the element value of b at (i, j).
 | 
						|
func (b *BandDense) DoNonZero(fn func(i, j int, v float64)) {
 | 
						|
	for i := 0; i < min(b.mat.Rows, b.mat.Cols+b.mat.KL); i++ {
 | 
						|
		for j := max(0, i-b.mat.KL); j < min(b.mat.Cols, i+b.mat.KU+1); j++ {
 | 
						|
			v := b.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 b. The function fn
 | 
						|
// takes a row/column index and the element value of b at (i, j).
 | 
						|
func (b *BandDense) DoRowNonZero(i int, fn func(i, j int, v float64)) {
 | 
						|
	if i < 0 || b.mat.Rows <= i {
 | 
						|
		panic(ErrRowAccess)
 | 
						|
	}
 | 
						|
	for j := max(0, i-b.mat.KL); j < min(b.mat.Cols, i+b.mat.KU+1); j++ {
 | 
						|
		v := b.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 b. The function fn
 | 
						|
// takes a row/column index and the element value of b at (i, j).
 | 
						|
func (b *BandDense) DoColNonZero(j int, fn func(i, j int, v float64)) {
 | 
						|
	if j < 0 || b.mat.Cols <= j {
 | 
						|
		panic(ErrColAccess)
 | 
						|
	}
 | 
						|
	for i := 0; i < min(b.mat.Rows, b.mat.Cols+b.mat.KL); i++ {
 | 
						|
		if i-b.mat.KL <= j && j < i+b.mat.KU+1 {
 | 
						|
			v := b.at(i, j)
 | 
						|
			if v != 0 {
 | 
						|
				fn(i, j, v)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Zero sets all of the matrix elements to zero.
 | 
						|
func (b *BandDense) Zero() {
 | 
						|
	m := b.mat.Rows
 | 
						|
	kL := b.mat.KL
 | 
						|
	nCol := b.mat.KU + 1 + kL
 | 
						|
	for i := 0; i < m; i++ {
 | 
						|
		l := max(0, kL-i)
 | 
						|
		u := min(nCol, m+kL-i)
 | 
						|
		zero(b.mat.Data[i*b.mat.Stride+l : i*b.mat.Stride+u])
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Trace computes the trace of the matrix.
 | 
						|
func (b *BandDense) Trace() float64 {
 | 
						|
	r, c := b.Dims()
 | 
						|
	if r != c {
 | 
						|
		panic(ErrShape)
 | 
						|
	}
 | 
						|
	rb := b.RawBand()
 | 
						|
	var tr float64
 | 
						|
	for i := 0; i < r; i++ {
 | 
						|
		tr += rb.Data[rb.KL+i*rb.Stride]
 | 
						|
	}
 | 
						|
	return tr
 | 
						|
}
 |