errors.go 5.4 KB

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