github.com/gopherd/gonum@v0.0.4/mat/errors.go (about)

     1  // Copyright ©2013 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package mat
     6  
     7  import (
     8  	"fmt"
     9  	"runtime"
    10  
    11  	"github.com/gopherd/gonum/lapack"
    12  )
    13  
    14  // Condition is the condition number of a matrix. The condition
    15  // number is defined as |A| * |A^-1|.
    16  //
    17  // One important use of Condition is during linear solve routines (finding x such
    18  // that A * x = b). The condition number of A indicates the accuracy of
    19  // the computed solution. A Condition error will be returned if the condition
    20  // number of A is sufficiently large. If A is exactly singular to working precision,
    21  // Condition == ∞, and the solve algorithm may have completed early. If Condition
    22  // is large and finite the solve algorithm will be performed, but the computed
    23  // solution may be inaccurate. Due to the nature of finite precision arithmetic,
    24  // the value of Condition is only an approximate test of singularity.
    25  type Condition float64
    26  
    27  func (c Condition) Error() string {
    28  	return fmt.Sprintf("matrix singular or near-singular with condition number %.4e", c)
    29  }
    30  
    31  // ConditionTolerance is the tolerance limit of the condition number. If the
    32  // condition number is above this value, the matrix is considered singular.
    33  const ConditionTolerance = 1e16
    34  
    35  const (
    36  	// CondNorm is the matrix norm used for computing the condition number by routines
    37  	// in the matrix packages.
    38  	CondNorm = lapack.MaxRowSum
    39  
    40  	// CondNormTrans is the norm used to compute on Aᵀ to get the same result as
    41  	// computing CondNorm on A.
    42  	CondNormTrans = lapack.MaxColumnSum
    43  )
    44  
    45  const stackTraceBufferSize = 1 << 20
    46  
    47  // Maybe will recover a panic with a type mat.Error from fn, and return this error
    48  // as the Err field of an ErrorStack. The stack trace for the panicking function will be
    49  // recovered and placed in the StackTrace field. Any other error is re-panicked.
    50  func Maybe(fn func()) (err error) {
    51  	defer func() {
    52  		if r := recover(); r != nil {
    53  			if e, ok := r.(Error); ok {
    54  				if e.string == "" {
    55  					panic("mat: invalid error")
    56  				}
    57  				buf := make([]byte, stackTraceBufferSize)
    58  				n := runtime.Stack(buf, false)
    59  				err = ErrorStack{Err: e, StackTrace: string(buf[:n])}
    60  				return
    61  			}
    62  			panic(r)
    63  		}
    64  	}()
    65  	fn()
    66  	return
    67  }
    68  
    69  // MaybeFloat will recover a panic with a type mat.Error from fn, and return this error
    70  // as the Err field of an ErrorStack. The stack trace for the panicking function will be
    71  // recovered and placed in the StackTrace field. Any other error is re-panicked.
    72  func MaybeFloat(fn func() float64) (f float64, err error) {
    73  	defer func() {
    74  		if r := recover(); r != nil {
    75  			if e, ok := r.(Error); ok {
    76  				if e.string == "" {
    77  					panic("mat: invalid error")
    78  				}
    79  				buf := make([]byte, stackTraceBufferSize)
    80  				n := runtime.Stack(buf, false)
    81  				err = ErrorStack{Err: e, StackTrace: string(buf[:n])}
    82  				return
    83  			}
    84  			panic(r)
    85  		}
    86  	}()
    87  	return fn(), nil
    88  }
    89  
    90  // MaybeComplex will recover a panic with a type mat.Error from fn, and return this error
    91  // as the Err field of an ErrorStack. The stack trace for the panicking function will be
    92  // recovered and placed in the StackTrace field. Any other error is re-panicked.
    93  func MaybeComplex(fn func() complex128) (f complex128, err error) {
    94  	defer func() {
    95  		if r := recover(); r != nil {
    96  			if e, ok := r.(Error); ok {
    97  				if e.string == "" {
    98  					panic("mat: invalid error")
    99  				}
   100  				buf := make([]byte, stackTraceBufferSize)
   101  				n := runtime.Stack(buf, false)
   102  				err = ErrorStack{Err: e, StackTrace: string(buf[:n])}
   103  				return
   104  			}
   105  			panic(r)
   106  		}
   107  	}()
   108  	return fn(), nil
   109  }
   110  
   111  // Error represents matrix handling errors. These errors can be recovered by Maybe wrappers.
   112  type Error struct{ string }
   113  
   114  func (err Error) Error() string { return err.string }
   115  
   116  var (
   117  	ErrNegativeDimension   = Error{"mat: negative dimension"}
   118  	ErrIndexOutOfRange     = Error{"mat: index out of range"}
   119  	ErrReuseNonEmpty       = Error{"mat: reuse of non-empty matrix"}
   120  	ErrRowAccess           = Error{"mat: row index out of range"}
   121  	ErrColAccess           = Error{"mat: column index out of range"}
   122  	ErrVectorAccess        = Error{"mat: vector index out of range"}
   123  	ErrZeroLength          = Error{"mat: zero length in matrix dimension"}
   124  	ErrRowLength           = Error{"mat: row length mismatch"}
   125  	ErrColLength           = Error{"mat: col length mismatch"}
   126  	ErrSquare              = Error{"mat: expect square matrix"}
   127  	ErrNormOrder           = Error{"mat: invalid norm order for matrix"}
   128  	ErrSingular            = Error{"mat: matrix is singular"}
   129  	ErrShape               = Error{"mat: dimension mismatch"}
   130  	ErrIllegalStride       = Error{"mat: illegal stride"}
   131  	ErrPivot               = Error{"mat: malformed pivot list"}
   132  	ErrTriangle            = Error{"mat: triangular storage mismatch"}
   133  	ErrTriangleSet         = Error{"mat: triangular set out of bounds"}
   134  	ErrBandwidth           = Error{"mat: bandwidth out of range"}
   135  	ErrBandSet             = Error{"mat: band set out of bounds"}
   136  	ErrDiagSet             = Error{"mat: diagonal set out of bounds"}
   137  	ErrSliceLengthMismatch = Error{"mat: input slice length mismatch"}
   138  	ErrNotPSD              = Error{"mat: input not positive symmetric definite"}
   139  	ErrFailedEigen         = Error{"mat: eigendecomposition not successful"}
   140  )
   141  
   142  // ErrorStack represents matrix handling errors that have been recovered by Maybe wrappers.
   143  type ErrorStack struct {
   144  	Err error
   145  
   146  	// StackTrace is the stack trace
   147  	// recovered by Maybe, MaybeFloat
   148  	// or MaybeComplex.
   149  	StackTrace string
   150  }
   151  
   152  func (err ErrorStack) Error() string { return err.Err.Error() }
   153  
   154  const badCap = "mat: bad capacity"