github.com/gonum/matrix@v0.0.0-20181209220409-c518dec07be9/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 matrix 6 7 import ( 8 "fmt" 9 "runtime" 10 11 "github.com/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 innacurate. 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^T 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 mat64.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("mat64: 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 mat64.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("mat64: 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 mat64.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("mat64: 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 ErrIndexOutOfRange = Error{"matrix: index out of range"} 118 ErrRowAccess = Error{"matrix: row index out of range"} 119 ErrColAccess = Error{"matrix: column index out of range"} 120 ErrVectorAccess = Error{"matrix: vector index out of range"} 121 ErrZeroLength = Error{"matrix: zero length in matrix definition"} 122 ErrRowLength = Error{"matrix: row length mismatch"} 123 ErrColLength = Error{"matrix: col length mismatch"} 124 ErrSquare = Error{"matrix: expect square matrix"} 125 ErrNormOrder = Error{"matrix: invalid norm order for matrix"} 126 ErrSingular = Error{"matrix: matrix is singular"} 127 ErrShape = Error{"matrix: dimension mismatch"} 128 ErrIllegalStride = Error{"matrix: illegal stride"} 129 ErrPivot = Error{"matrix: malformed pivot list"} 130 ErrTriangle = Error{"matrix: triangular storage mismatch"} 131 ErrTriangleSet = Error{"matrix: triangular set out of bounds"} 132 ErrSliceLengthMismatch = Error{"matrix: input slice length mismatch"} 133 ErrNotPSD = Error{"matrix: input not positive symmetric definite"} 134 ErrFailedEigen = Error{"matrix: eigendecomposition not successful"} 135 ) 136 137 // ErrorStack represents matrix handling errors that have been recovered by Maybe wrappers. 138 type ErrorStack struct { 139 Err error 140 141 // StackTrace is the stack trace 142 // recovered by Maybe, MaybeFloat 143 // or MaybeComplex. 144 StackTrace string 145 } 146 147 func (err ErrorStack) Error() string { return err.Err.Error() }