9#include <tinyopt/traits.h>
14enum StopReason :
int {
22 kSystemHasNaNOrInf = -2,
46template <
typename Summary,
typename Options = std::
nullptr_t>
47std::string StopReasonDescription(
const Summary &sum,
const Options &options = {}) {
48 std::ostringstream os;
49 switch (sum.stop_reason) {
50 case StopReason::kNone:
51 os <<
"🌱 Optimization not ran or used with Step() (success)";
57 case StopReason::kMinError:
58 os <<
"🌞 Reached minimum error (success)";
59 if constexpr (!traits::is_nullptr_v<Options>)
60 os <<
" ε:[" << (
double)sum.final_cost <<
" < " << options.stop.min_error <<
"]";
62 case StopReason::kMinRelError:
63 os <<
"🌞 Reached minimum relative error (success)";
64 if constexpr (!traits::is_nullptr_v<Options>)
65 os <<
" ε:[" << sum.final_rerr_dec <<
" < " << options.stop.min_rerr_dec <<
"]";
67 case StopReason::kMinDeltaNorm:
68 os <<
"🌞 Reached minimal delta norm (success)";
69 if constexpr (!traits::is_nullptr_v<Options>) {
70 if (!sum.hist.empty())
71 os <<
" |δX|:[" << sum.hist.last_delta2() <<
" < "
72 << std::sqrt(options.stop.min_step_norm2) <<
"]";
74 os <<
" [|δX| < " << std::sqrt(options.stop.min_step_norm2) <<
"]";
77 case StopReason::kMinGradNorm:
78 os <<
"🌞 Reached minimal gradient (success)";
79 if constexpr (!traits::is_nullptr_v<Options>)
80 os <<
" [|∇| < " << std::sqrt(options.stop.min_grad_norm2) <<
"]";
87 case StopReason::kMaxIters:
88 os <<
"⛅ Reached maximum number of iterations (success)";
89 if constexpr (!traits::is_nullptr_v<Options>)
90 os <<
" [#it == " << (
int)options.stop.max_iters <<
"]";
92 case StopReason::kMaxNoDecr:
93 os <<
"⛅ Failed to decrease error too many times (success)";
94 if constexpr (!traits::is_nullptr_v<Options>)
95 os <<
" [=" << (
int)options.stop.max_total_failures <<
"]";
97 case StopReason::kMaxConsecNoDecr:
98 os <<
"⛅ Failed to decrease error consecutively too many times (success)";
99 if constexpr (!traits::is_nullptr_v<Options>)
100 os <<
" [=" << (
int)options.stop.max_consec_failures <<
"]";
102 case StopReason::kTimedOut:
103 os <<
"⌛ Reached maximum allocated time (success)";
104 if constexpr (!traits::is_nullptr_v<Options>)
105 os <<
" τ:[" << sum.duration_ms <<
" > " << options.stop.max_duration_ms <<
"ms]";
107 case StopReason::kUserStopped:
108 os <<
"👍 User stopped the process (success)";
116 case StopReason::kOutOfMemory:
117 os <<
"❌ Out of memory when allocating the Hessian(s), use SparseMatrix? (failure)";
119 case StopReason::kSystemHasNaNOrInf:
120 os <<
"❌ Residuals or Jacobians have NaNs or Inf (failure)";
122 case StopReason::kSolverFailed:
123 os <<
"❌ Failed to solve the normal equations (failure)";
125 case StopReason::kSkipped:
126 os <<
"❌ The system has no residuals or nothing to optimize (failure)";
130 os <<
"⛈️ Unknown reason:" << (int)sum.stop_reason;