mirror of https://github.com/k3s-io/k3s
152 lines
5.4 KiB
Go
152 lines
5.4 KiB
Go
// Copyright ©2013 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 (
|
|
"fmt"
|
|
"runtime"
|
|
|
|
"gonum.org/v1/gonum/lapack"
|
|
)
|
|
|
|
// Condition is the condition number of a matrix. The condition
|
|
// number is defined as |A| * |A^-1|.
|
|
//
|
|
// One important use of Condition is during linear solve routines (finding x such
|
|
// that A * x = b). The condition number of A indicates the accuracy of
|
|
// the computed solution. A Condition error will be returned if the condition
|
|
// number of A is sufficiently large. If A is exactly singular to working precision,
|
|
// Condition == ∞, and the solve algorithm may have completed early. If Condition
|
|
// is large and finite the solve algorithm will be performed, but the computed
|
|
// solution may be innacurate. Due to the nature of finite precision arithmetic,
|
|
// the value of Condition is only an approximate test of singularity.
|
|
type Condition float64
|
|
|
|
func (c Condition) Error() string {
|
|
return fmt.Sprintf("matrix singular or near-singular with condition number %.4e", c)
|
|
}
|
|
|
|
// ConditionTolerance is the tolerance limit of the condition number. If the
|
|
// condition number is above this value, the matrix is considered singular.
|
|
const ConditionTolerance = 1e16
|
|
|
|
const (
|
|
// CondNorm is the matrix norm used for computing the condition number by routines
|
|
// in the matrix packages.
|
|
CondNorm = lapack.MaxRowSum
|
|
|
|
// CondNormTrans is the norm used to compute on Aᵀ to get the same result as
|
|
// computing CondNorm on A.
|
|
CondNormTrans = lapack.MaxColumnSum
|
|
)
|
|
|
|
const stackTraceBufferSize = 1 << 20
|
|
|
|
// Maybe will recover a panic with a type mat.Error from fn, and return this error
|
|
// as the Err field of an ErrorStack. The stack trace for the panicking function will be
|
|
// recovered and placed in the StackTrace field. Any other error is re-panicked.
|
|
func Maybe(fn func()) (err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if e, ok := r.(Error); ok {
|
|
if e.string == "" {
|
|
panic("mat: invalid error")
|
|
}
|
|
buf := make([]byte, stackTraceBufferSize)
|
|
n := runtime.Stack(buf, false)
|
|
err = ErrorStack{Err: e, StackTrace: string(buf[:n])}
|
|
return
|
|
}
|
|
panic(r)
|
|
}
|
|
}()
|
|
fn()
|
|
return
|
|
}
|
|
|
|
// MaybeFloat will recover a panic with a type mat.Error from fn, and return this error
|
|
// as the Err field of an ErrorStack. The stack trace for the panicking function will be
|
|
// recovered and placed in the StackTrace field. Any other error is re-panicked.
|
|
func MaybeFloat(fn func() float64) (f float64, err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if e, ok := r.(Error); ok {
|
|
if e.string == "" {
|
|
panic("mat: invalid error")
|
|
}
|
|
buf := make([]byte, stackTraceBufferSize)
|
|
n := runtime.Stack(buf, false)
|
|
err = ErrorStack{Err: e, StackTrace: string(buf[:n])}
|
|
return
|
|
}
|
|
panic(r)
|
|
}
|
|
}()
|
|
return fn(), nil
|
|
}
|
|
|
|
// MaybeComplex will recover a panic with a type mat.Error from fn, and return this error
|
|
// as the Err field of an ErrorStack. The stack trace for the panicking function will be
|
|
// recovered and placed in the StackTrace field. Any other error is re-panicked.
|
|
func MaybeComplex(fn func() complex128) (f complex128, err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if e, ok := r.(Error); ok {
|
|
if e.string == "" {
|
|
panic("mat: invalid error")
|
|
}
|
|
buf := make([]byte, stackTraceBufferSize)
|
|
n := runtime.Stack(buf, false)
|
|
err = ErrorStack{Err: e, StackTrace: string(buf[:n])}
|
|
return
|
|
}
|
|
panic(r)
|
|
}
|
|
}()
|
|
return fn(), nil
|
|
}
|
|
|
|
// Error represents matrix handling errors. These errors can be recovered by Maybe wrappers.
|
|
type Error struct{ string }
|
|
|
|
func (err Error) Error() string { return err.string }
|
|
|
|
var (
|
|
ErrNegativeDimension = Error{"mat: negative dimension"}
|
|
ErrIndexOutOfRange = Error{"mat: index out of range"}
|
|
ErrReuseNonEmpty = Error{"mat: reuse of non-empty matrix"}
|
|
ErrRowAccess = Error{"mat: row index out of range"}
|
|
ErrColAccess = Error{"mat: column index out of range"}
|
|
ErrVectorAccess = Error{"mat: vector index out of range"}
|
|
ErrZeroLength = Error{"mat: zero length in matrix dimension"}
|
|
ErrRowLength = Error{"mat: row length mismatch"}
|
|
ErrColLength = Error{"mat: col length mismatch"}
|
|
ErrSquare = Error{"mat: expect square matrix"}
|
|
ErrNormOrder = Error{"mat: invalid norm order for matrix"}
|
|
ErrSingular = Error{"mat: matrix is singular"}
|
|
ErrShape = Error{"mat: dimension mismatch"}
|
|
ErrIllegalStride = Error{"mat: illegal stride"}
|
|
ErrPivot = Error{"mat: malformed pivot list"}
|
|
ErrTriangle = Error{"mat: triangular storage mismatch"}
|
|
ErrTriangleSet = Error{"mat: triangular set out of bounds"}
|
|
ErrBandSet = Error{"mat: band set out of bounds"}
|
|
ErrDiagSet = Error{"mat: diagonal set out of bounds"}
|
|
ErrSliceLengthMismatch = Error{"mat: input slice length mismatch"}
|
|
ErrNotPSD = Error{"mat: input not positive symmetric definite"}
|
|
ErrFailedEigen = Error{"mat: eigendecomposition not successful"}
|
|
)
|
|
|
|
// ErrorStack represents matrix handling errors that have been recovered by Maybe wrappers.
|
|
type ErrorStack struct {
|
|
Err error
|
|
|
|
// StackTrace is the stack trace
|
|
// recovered by Maybe, MaybeFloat
|
|
// or MaybeComplex.
|
|
StackTrace string
|
|
}
|
|
|
|
func (err ErrorStack) Error() string { return err.Err.Error() }
|