Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
solver_recording.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//solver_recording.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8//solver_recording.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with solver_recording.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// Copyright(C) Bertini2 Development Team
17//
18// See <http://www.gnu.org/licenses/> for a copy of the license,
19// as well as COPYING. Bertini2 is provided with permitted
20// additional terms in the b2/licenses/ directory.
21
37
38#pragma once
39
40#include <cstdio>
41#include <cstdlib>
42#include <string>
43
44#include <boost/json.hpp>
45
48
49namespace bertini {
50namespace records {
51
53inline std::string ExactDoubleText(double v)
54{
55 char buffer[32];
56 std::snprintf(buffer, sizeof(buffer), "%.17g", v);
57 return buffer;
58}
59
61inline double DoubleFromText(std::string const& s)
62{
63 return std::strtod(s.c_str(), nullptr);
64}
65
67inline std::string EncodeRealScalar(double v) { return ExactDoubleText(v); }
69inline std::string EncodeRealScalar(real_mp const& v) { return v.str(0, std::ios::scientific); }
70
72inline boost::json::array EncodeComplexScalar(complex_dbl const& z)
73{
74 return {ExactDoubleText(z.real()), ExactDoubleText(z.imag()),
75 static_cast<std::int64_t>(DoublePrecision())};
76}
77
78inline boost::json::array EncodeComplexScalar(complex_mp const& z)
79{
80 return {z.real().str(0, std::ios::scientific), z.imag().str(0, std::ios::scientific),
81 static_cast<std::int64_t>(z.precision())};
82}
83
85template <typename ComplexT>
86ComplexT DecodeComplexScalar(boost::json::array const& triple);
87
89template <>
90inline complex_dbl DecodeComplexScalar<complex_dbl>(boost::json::array const& triple)
91{
92 return complex_dbl(DoubleFromText(std::string(triple.at(0).as_string())),
93 DoubleFromText(std::string(triple.at(1).as_string())));
94}
95
97template <>
98inline complex_mp DecodeComplexScalar<complex_mp>(boost::json::array const& triple)
99{
100 auto const digits = static_cast<unsigned>(triple.at(2).as_int64());
101 complex_mp z(real_mp(std::string(triple.at(0).as_string()), digits),
102 real_mp(std::string(triple.at(1).as_string()), digits));
103 z.precision(digits);
104 return z;
105}
106
108template <typename ComplexT>
109boost::json::array EncodePoint(Vec<ComplexT> const& point)
110{
111 boost::json::array out;
112 for (Eigen::Index ii = 0; ii < point.size(); ++ii)
113 out.push_back(EncodeComplexScalar(point(ii)));
114 return out;
115}
116
118template <typename ComplexT>
119Vec<ComplexT> DecodePoint(boost::json::array const& coords)
120{
121 Vec<ComplexT> out(static_cast<Eigen::Index>(coords.size()));
122 for (std::size_t ii = 0; ii < coords.size(); ++ii)
123 out(static_cast<Eigen::Index>(ii)) = DecodeComplexScalar<ComplexT>(coords[ii].as_array());
124 return out;
125}
126
136inline std::string CanonicalName(SuccessCode code)
137{
138 switch (code)
139 {
140 case SuccessCode::NeverStarted: return "NeverStarted";
141 case SuccessCode::Success: return "Success";
142 case SuccessCode::HigherPrecisionNecessary: return "HigherPrecisionNecessary";
143 case SuccessCode::ReduceStepSize: return "ReduceStepSize";
144 case SuccessCode::GoingToInfinity: return "GoingToInfinity";
145 case SuccessCode::FailedToConverge: return "FailedToConverge";
146 case SuccessCode::MatrixSolveFailure: return "MatrixSolveFailure";
147 case SuccessCode::MatrixSolveFailureFirstPartOfPrediction: return "MatrixSolveFailureFirstPartOfPrediction";
148 case SuccessCode::MaxNumStepsTaken: return "MaxNumStepsTaken";
149 case SuccessCode::MaxPrecisionReached: return "MaxPrecisionReached";
150 case SuccessCode::MinStepSizeReached: return "MinStepSizeReached";
151 case SuccessCode::Failure: return "Failure";
152 case SuccessCode::SingularStartPoint: return "SingularStartPoint";
153 case SuccessCode::ExternallyTerminated: return "ExternallyTerminated";
154 case SuccessCode::MinTrackTimeReached: return "MinTrackTimeReached";
155 case SuccessCode::SecurityMaxNormReached: return "SecurityMaxNormReached";
156 case SuccessCode::CycleNumTooHigh: return "CycleNumTooHigh";
157 case SuccessCode::FailedToSelectPrecisionAndStepsize: return "FailedToSelectPrecisionAndStepsize";
158 case SuccessCode::WallClockLimitReached: return "WallClockLimitReached";
159 }
160 return "UnknownSuccessCode";
161}
162
175inline std::string CoarsePathStatus(SuccessCode code)
176{
177 if (code == SuccessCode::Success)
178 return "success";
180 return "diverged";
181 return "failed";
182}
183
191template <typename ComplexT>
193{
194 boost::json::object out;
195 out["pre_endgame_success_code"] = static_cast<std::int64_t>(r.pre_endgame_success_code);
196 out["pre_endgame_success_code_name"] = CanonicalName(r.pre_endgame_success_code);
197 out["boundary_point"] = EncodePoint(r.boundary_point);
198 out["boundary_stepsize"] = EncodeRealScalar(r.boundary_stepsize);
199 out["boundary_precision"] = static_cast<std::int64_t>(r.boundary_precision);
200 out["endgame_success_code"] = static_cast<std::int64_t>(r.endgame_success_code);
201 out["endgame_success_code_name"] = CanonicalName(r.endgame_success_code);
202 out["endpoint"] = EncodePoint(r.solution);
203 out["function_residual"] = ExactDoubleText(r.function_residual);
204 out["condition_number"] = ExactDoubleText(r.condition_number);
205 {
206 boost::json::array sv;
207 for (Eigen::Index i = 0; i < r.singular_values.size(); ++i)
208 sv.push_back(boost::json::value(ExactDoubleText(r.singular_values(i))));
209 out["singular_values"] = std::move(sv);
210 }
211 out["newton_residual"] = ExactDoubleText(r.newton_residual);
212 out["final_time_used"] = EncodeComplexScalar(r.final_time_used);
213 out["accuracy_estimate_internal_coords"] = ExactDoubleText(r.accuracy_estimate_internal_coords);
214 out["accuracy_estimate_user_coords"] = ExactDoubleText(r.accuracy_estimate_user_coords);
215 out["cycle_num"] = static_cast<std::int64_t>(r.cycle_num);
216 out["precision_digits"] = static_cast<std::int64_t>(r.precision_digits);
217 out["accuracy_digits"] = static_cast<std::int64_t>(r.accuracy_digits);
218 out["precision_changed"] = r.precision_changed;
219 out["time_of_first_prec_increase"] = EncodeComplexScalar(r.time_of_first_prec_increase);
220 out["max_precision_used"] = static_cast<std::int64_t>(r.max_precision_used);
221 out["path_time_seconds"] = ExactDoubleText(r.path_time_seconds);
222 // where the path got to: the step tally always, the point only when the path did not
223 // succeed (a successful path's point is `endpoint`)
224 out["num_successful_steps"] = static_cast<std::int64_t>(r.num_successful_steps);
225 out["num_failed_steps"] = static_cast<std::int64_t>(r.num_failed_steps);
226 if (r.latest_path_point.size() > 0)
227 out["latest_path_point"] = EncodePoint(r.latest_path_point);
228 // the wall-clock budget the path ran under, when there was one: what a later run compares
229 // its own patience against before reusing an abandonment
230 if (r.wall_clock_limit_seconds > 0)
231 out["wall_clock_limit_seconds"] = ExactDoubleText(r.wall_clock_limit_seconds);
232 // the crossing verdict, written only when the library could NOT vouch for the endpoint.
233 // Absent means clean -- which is also what every record written before this field existed
234 // meant, since a store from then has no way to say otherwise.
236 out["crossing_unresolved"] = true;
237 return out;
238}
239
241template <typename ComplexT>
243 std::size_t path_index)
244{
245 using RealT = typename parallel::FullPathResult<ComplexT>::RealT;
247 r.path_index = path_index;
249 static_cast<SuccessCode>(rec.at("pre_endgame_success_code").as_int64());
250 r.boundary_point = DecodePoint<ComplexT>(rec.at("boundary_point").as_array());
251 if constexpr (std::is_same<RealT, double>::value)
252 r.boundary_stepsize = DoubleFromText(std::string(rec.at("boundary_stepsize").as_string()));
253 else
254 r.boundary_stepsize = RealT(std::string(rec.at("boundary_stepsize").as_string()));
255 r.boundary_precision = static_cast<unsigned>(rec.at("boundary_precision").as_int64());
256 r.endgame_success_code = static_cast<SuccessCode>(rec.at("endgame_success_code").as_int64());
257 r.solution = DecodePoint<ComplexT>(rec.at("endpoint").as_array());
258 r.function_residual = DoubleFromText(std::string(rec.at("function_residual").as_string()));
259 r.condition_number = DoubleFromText(std::string(rec.at("condition_number").as_string()));
260 // records written before the spectrum was archived simply lack it
261 if (auto const* sv = rec.if_contains("singular_values"))
262 {
263 auto const& arr = sv->as_array();
264 r.singular_values.resize(static_cast<Eigen::Index>(arr.size()));
265 for (std::size_t i = 0; i < arr.size(); ++i)
266 r.singular_values(static_cast<Eigen::Index>(i)) = DoubleFromText(std::string(arr[i].as_string()));
267 }
268 r.newton_residual = DoubleFromText(std::string(rec.at("newton_residual").as_string()));
269 r.final_time_used = DecodeComplexScalar<ComplexT>(rec.at("final_time_used").as_array());
270 // the internal estimate was recorded under the bare key `accuracy_estimate` until the
271 // field was named for its coordinates (ADR-0069); a record written before that reads the
272 // same, under the key it was written with
274 (rec.if_contains("accuracy_estimate_internal_coords")
275 ? rec.at("accuracy_estimate_internal_coords")
276 : rec.at("accuracy_estimate")).as_string()));
278 DoubleFromText(std::string(rec.at("accuracy_estimate_user_coords").as_string()));
279 r.cycle_num = static_cast<unsigned>(rec.at("cycle_num").as_int64());
280 r.precision_digits = static_cast<unsigned>(rec.at("precision_digits").as_int64());
281 r.accuracy_digits = static_cast<unsigned>(rec.at("accuracy_digits").as_int64());
282 r.precision_changed = rec.at("precision_changed").as_bool();
284 DecodeComplexScalar<ComplexT>(rec.at("time_of_first_prec_increase").as_array());
285 r.max_precision_used = static_cast<unsigned>(rec.at("max_precision_used").as_int64());
286 r.path_time_seconds = DoubleFromText(std::string(rec.at("path_time_seconds").as_string()));
287 // records written before paths were stamped with where they got to simply lack these
288 if (auto const* v = rec.if_contains("num_successful_steps"))
289 r.num_successful_steps = static_cast<unsigned>(v->as_int64());
290 if (auto const* v = rec.if_contains("num_failed_steps"))
291 r.num_failed_steps = static_cast<unsigned>(v->as_int64());
292 if (auto const* v = rec.if_contains("latest_path_point"))
293 r.latest_path_point = DecodePoint<ComplexT>(v->as_array());
294 if (auto const* v = rec.if_contains("wall_clock_limit_seconds"))
295 r.wall_clock_limit_seconds = DoubleFromText(std::string(v->as_string()));
296 if (auto const* v = rec.if_contains("crossing_unresolved"))
297 r.crossing_unresolved = v->as_bool();
298 return r;
299}
300
301} // namespace records
302} // namespace bertini
Definition config_encoding.hpp:66
complex_mp DecodeComplexScalar< complex_mp >(boost::json::array const &triple)
Decode a multiprecision complex value at its recorded precision.
Definition solver_recording.hpp:98
boost::json::object EncodeFullPathResult(parallel::FullPathResult< ComplexT > const &r)
Serialize one whole-path result as a b2rec/1 track record body.
Definition solver_recording.hpp:192
complex_dbl DecodeComplexScalar< complex_dbl >(boost::json::array const &triple)
Decode a double-precision complex value.
Definition solver_recording.hpp:90
double DoubleFromText(std::string const &s)
Parse a double written by ExactDoubleText (bit-exact round trip).
Definition solver_recording.hpp:61
Vec< ComplexT > DecodePoint(boost::json::array const &coords)
Decode a point written by EncodePoint.
Definition solver_recording.hpp:119
std::string ExactDoubleText(double v)
A double as full-round-trip decimal text (%.17g: bit-exact per IEEE-754).
Definition solver_recording.hpp:53
std::string CoarsePathStatus(SuccessCode code)
The coarse outcome of a path, from its endgame verdict: "success", "diverged" (the path went to infin...
Definition solver_recording.hpp:175
parallel::FullPathResult< ComplexT > DecodeFullPathResult(boost::json::object const &rec, std::size_t path_index)
Reconstruct a whole-path result from a track record (the recall half).
Definition solver_recording.hpp:242
std::string CanonicalName(tracking::Predictor p)
The fixed canonical name of a predictor choice (never its numeric value).
boost::json::array EncodePoint(Vec< ComplexT > const &point)
Encode a point (vector of complex coordinates) as an array of scalar triples.
Definition solver_recording.hpp:109
boost::json::array EncodeComplexScalar(complex_dbl const &z)
Encode one complex value as ["re", "im", precision] (precision in digits).
Definition solver_recording.hpp:72
std::string EncodeRealScalar(double v)
Encode one real scalar as text: doubles via %.17g; real_mp at full stored precision.
Definition solver_recording.hpp:67
ComplexT DecodeComplexScalar(boost::json::array const &triple)
Decode a complex value written by EncodeComplexScalar, at its recorded precision.
Definition algorithm_builder.hpp:36
constexpr unsigned DoublePrecision()
The number of digits considered "double precision" (16).
Definition num_traits.hpp:152
std::complex< double > complex_dbl
The double-precision complex number type.
Definition double_extensions.hpp:47
Eigen::Matrix< NumT, Eigen::Dynamic, 1 > Vec
A dynamically-sized column vector of NumT.
Definition eigen_extensions.hpp:296
bmp::number< mpc_complex_backend< 0 >, bmp::et_on > complex_mp
The arbitrary-precision complex number type.
Definition mpfr_complex.hpp:58
SuccessCode
Definition config.hpp:42
@ MinStepSizeReached
Definition config.hpp:60
@ FailedToConverge
Definition config.hpp:55
@ MatrixSolveFailureFirstPartOfPrediction
Definition config.hpp:57
@ FailedToSelectPrecisionAndStepsize
Definition config.hpp:67
@ NeverStarted
No tracking was attempted.
Definition config.hpp:50
@ ExternallyTerminated
Definition config.hpp:63
@ Success
Definition config.hpp:51
@ MaxNumStepsTaken
Definition config.hpp:58
@ GoingToInfinity
Definition config.hpp:54
@ MinTrackTimeReached
Definition config.hpp:64
@ WallClockLimitReached
The tracker's wall-clock deadline passed between steps; the path was abandoned where it was....
Definition config.hpp:68
@ MatrixSolveFailure
Definition config.hpp:56
@ MaxPrecisionReached
Definition config.hpp:59
@ ReduceStepSize
Definition config.hpp:53
@ HigherPrecisionNecessary
Definition config.hpp:52
@ CycleNumTooHigh
Definition config.hpp:66
@ Failure
Definition config.hpp:61
@ SecurityMaxNormReached
Definition config.hpp:65
@ SingularStartPoint
Definition config.hpp:62
boost::multiprecision::number< boost::multiprecision::mpfr_float_backend< 0 >, boost::multiprecision::et_on > real_mp
The arbitrary-precision real number type.
Definition mpfr_extensions.hpp:53
Provides an Eigen-like NumTraits struct for querying traits of a number type.
Result struct used in the manager-worker MPI protocol for ZeroDim.
Result of executing one WHOLE path: start -> endgame boundary -> target.
Definition path_result.hpp:101
unsigned max_precision_used
The highest precision used over the whole path.
Definition path_result.hpp:130
unsigned num_successful_steps
Successful predictor-corrector steps over the whole path.
Definition path_result.hpp:136
bool precision_changed
Whether precision changed during the path.
Definition path_result.hpp:128
unsigned cycle_num
The estimated cycle number at the endpoint.
Definition path_result.hpp:123
SuccessCode pre_endgame_success_code
Outcome of pre-endgame tracking to the boundary.
Definition path_result.hpp:108
double accuracy_estimate_user_coords
Estimated accuracy in the user's coordinates.
Definition path_result.hpp:122
bool crossing_unresolved
Whether a crossing involving this path was detected at the endgame boundary and never resolved,...
Definition path_result.hpp:144
unsigned num_failed_steps
Failed predictor-corrector steps over the whole path.
Definition path_result.hpp:137
ComplexT final_time_used
The time value the endgame finished at.
Definition path_result.hpp:120
typename NumTraits< ComplexT >::Real RealT
The real companion of the complex type.
Definition path_result.hpp:103
Vec< ComplexT > solution
The solution point (final endpoint of the path).
Definition path_result.hpp:115
SolnIndT path_index
The index of the path this result is for.
Definition path_result.hpp:105
double function_residual
Residual of the system at the final solution.
Definition path_result.hpp:116
double wall_clock_limit_seconds
The per-path wall-clock budget in force when the path ran, seconds; 0 = none.
Definition path_result.hpp:139
double newton_residual
Final Newton residual.
Definition path_result.hpp:119
unsigned precision_digits
Digits the endgame finished in (= solution point's precision).
Definition path_result.hpp:124
SuccessCode endgame_success_code
Outcome of the endgame.
Definition path_result.hpp:114
double condition_number
Condition-number estimate at the final solution.
Definition path_result.hpp:117
unsigned boundary_precision
The precision at the endgame boundary.
Definition path_result.hpp:111
ComplexT time_of_first_prec_increase
The time of the first precision increase (if any).
Definition path_result.hpp:129
Vec< ComplexT > latest_path_point
The last point the tracker reached on a path that did not succeed; empty otherwise.
Definition path_result.hpp:138
double path_time_seconds
Wall-clock seconds to execute the whole path.
Definition path_result.hpp:133
unsigned accuracy_digits
Trustworthy digit count, from the convergence agreement.
Definition path_result.hpp:125
RealT boundary_stepsize
The step size at the endgame boundary.
Definition path_result.hpp:110
double accuracy_estimate_internal_coords
Estimated accuracy in the solver's internal coordinates (homogenized, on the patch).
Definition path_result.hpp:121
Vec< ComplexT > boundary_point
The space point at the endgame boundary.
Definition path_result.hpp:109
Vec< double > singular_values
Singular values of the target Jacobian at the final solution, largest first (the spectrum behind cond...
Definition path_result.hpp:118