tinyopt 700
Tinyopt, a lightweight, header only optimization library
Loading...
Searching...
No Matches
stop_reasons.h
1// Copyright 2026 Julien Michot.
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <ostream>
7#include <sstream>
8
9#include <tinyopt/traits.h>
10
11namespace tinyopt {
12
14enum StopReason : int {
19
20 kOutOfMemory = -4,
21 kSolverFailed = -3,
22 kSystemHasNaNOrInf = -2,
23 kSkipped = -1,
24
30
31 kNone = 0,
32 kMinError,
33 kMinRelError,
34 kMinDeltaNorm,
35 kMinGradNorm,
36 kMaxIters,
37 kMaxNoDecr,
38 kMaxConsecNoDecr,
39 kTimedOut,
40 kUserStopped
41
43};
44
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)";
52 break;
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 << "]";
61 break;
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 << "]";
66 break;
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) << "]";
73 else
74 os << " [|δX| < " << std::sqrt(options.stop.min_step_norm2) << "]";
75 }
76 break;
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) << "]";
81 break;
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 << "]";
91 break;
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 << "]";
96 break;
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 << "]";
101 break;
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]";
106 break;
107 case StopReason::kUserStopped:
108 os << "👍 User stopped the process (success)";
109 break;
111
116 case StopReason::kOutOfMemory:
117 os << "❌ Out of memory when allocating the Hessian(s), use SparseMatrix? (failure)";
118 break;
119 case StopReason::kSystemHasNaNOrInf:
120 os << "❌ Residuals or Jacobians have NaNs or Inf (failure)";
121 break;
122 case StopReason::kSolverFailed:
123 os << "❌ Failed to solve the normal equations (failure)";
124 break;
125 case StopReason::kSkipped:
126 os << "❌ The system has no residuals or nothing to optimize (failure)";
127 break;
129 default:
130 os << "⛈️ Unknown reason:" << (int)sum.stop_reason;
131 break;
132 }
133 return os.str();
134}
135
136} // namespace tinyopt
Definition options.h:18
Definition summary.h:27