Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
newton_corrector.hpp
Go to the documentation of this file.
1//
2// newton_corrector.hpp
3// Xcode_b2
4//
5// Created by Collins, James B. on 4/27/16.
6// Copyright (c) 2016 West Texas A&M University. All rights reserved.
7//
8
9#ifndef BERTINI_NEWTON_CORRECTOR_HPP
10#define BERTINI_NEWTON_CORRECTOR_HPP
11
16
17
18namespace bertini{
19 namespace tracking{
20 namespace correct{
21
22
44
46 {
47 public:
48
49
51 NewtonCorrector(const System& S) : current_precision_(DefaultPrecision())
52 {
53 ChangeSystem(S);
54 }
55
56
57
58
59
60
61
68
69 void Settings(const NewtonConfig& newton_settings)
70 {
71 newton_config_ = newton_settings;
72 }
73
74
75
76
77
84 void ChangePrecision(unsigned new_precision)
85 {
86 Precision(std::get< Vec<complex_mp> >(f_temp_), new_precision);
87 Precision(std::get< Vec<complex_mp> >(step_temp_), new_precision);
88 Precision(std::get< Mat<complex_mp> >(J_temp_), new_precision);
89 // the probe is re-derived from the stored copy, never rounded in place: a drop
90 // in precision would otherwise destroy digits that a later rise cannot restore
91 {
92 auto& probe = std::get< Vec<complex_mp> >(rand_temp_);
93 probe = probe_as_drawn_;
94 Precision(probe, new_precision);
95 }
96 Precision(std::get< Vec<complex_mp> >(solve_temp_), new_precision);
97 std::get< linalg::PartialPivLU<complex_mp> >(LU_).ChangePrecision(new_precision);
98
99 current_precision_ = new_precision;
100 }
101
102
104 unsigned precision() const
105 {
106 return current_precision_;
107 }
108
115 void ChangeSystem(const System& S)
116 {
117 numTotalFunctions_ = static_cast<unsigned>(S.NumTotalFunctions());
118 numVariables_ = static_cast<unsigned>(S.NumVariables());
119 std::get< Mat<complex_dbl> >(J_temp_).resize(numTotalFunctions_, numVariables_);
120 std::get< Mat<complex_mp> >(J_temp_).resize(numTotalFunctions_, numVariables_);
121 std::get< Vec<complex_dbl> >(f_temp_).resize(numTotalFunctions_);
122 std::get< Vec<complex_mp> >(f_temp_).resize(numTotalFunctions_);
123 std::get< Vec<complex_dbl> >(step_temp_).resize(numTotalFunctions_);
124 std::get< Vec<complex_mp> >(step_temp_).resize(numTotalFunctions_);
125 std::get< Vec<complex_dbl> >(solve_temp_).resize(numVariables_);
126 std::get< Vec<complex_mp> >(solve_temp_).resize(numVariables_);
127 std::get< linalg::PartialPivLU<complex_dbl> >(LU_).ChangeSize(numVariables_);
128 std::get< linalg::PartialPivLU<complex_mp> >(LU_).ChangeSize(numVariables_);
130 }
131
144 {
145 std::get< Vec<complex_dbl> >(rand_temp_) = RandomOfUnits<complex_dbl>(numVariables_);
146 probe_as_drawn_ = RandomOfUnits<complex_mp>(numVariables_);
147 std::get< Vec<complex_mp> >(rand_temp_) = probe_as_drawn_;
148 }
149
157 std::tuple< Vec<complex_dbl>, Vec<complex_mp> > ConditionProbe() const
158 {
159 return { std::get< Vec<complex_dbl> >(rand_temp_), probe_as_drawn_ };
160 }
161
162
163
164
165
166
186 template <typename ComplexT>
188 StepMetadata & meta,
189 System const& S,
190 Vec<ComplexT> const& current_space,
191 ComplexT const& current_time,
192 NumErrorT const& tracking_tolerance,
193 unsigned min_num_newton_iterations,
194 unsigned max_num_newton_iterations,
195 AdaptiveMultiplePrecisionConfig const* AMP_config = nullptr)
196 {
197 #ifndef BERTINI_DISABLE_ASSERTS
198 assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
199 #endif
200
201 Vec<ComplexT>& step_ref = std::get< Vec<ComplexT> >(step_temp_);
202
203 next_space = current_space;
204 for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
205 {
206 //Update the newton iterate by one iteration
207 auto success_code = EvalIterationStep(step_ref, S, next_space, current_time);
208 if(success_code != SuccessCode::Success)
209 return success_code;
210
211 next_space -= step_ref; // step_ref = +J^{-1}f = -(Newton step); see EvalIterationStep
212
213 // Fixed precision: cheap convergence-only loop, no norms / probe / criteria.
214 if (AMP_config == nullptr)
215 {
216 if ( (step_ref.template lpNorm<Eigen::Infinity>() < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
218 continue;
219 }
220
221 // Adaptive precision: fill metadata + enforce AMP criteria B and C.
222 Mat<ComplexT>& J_temp_ref = std::get< Mat<ComplexT> >(J_temp_);
223 linalg::PartialPivLU<ComplexT>& LU_ref = std::get< linalg::PartialPivLU<ComplexT> >(LU_);
224
225 meta.norm_delta_z = NumErrorT(step_ref.template lpNorm<Eigen::Infinity>());
226 meta.norm_J = NumErrorT(J_temp_ref.norm());
227 {
228 // Reuse the FIXED probe vector generated once at setup (do NOT regenerate
229 // per call): a fresh random probe direction every Newton step occasionally
230 // produced an inflated ||J^{-1}|| estimate -> spurious HigherPrecisionNecessary
231 // -> precision escalation/grind. A single fixed direction also makes the
232 // condition estimates comparable across steps and keeps tracking deterministic.
233 Vec<ComplexT>& rand_ref = std::get< Vec<ComplexT> >(rand_temp_);
234 Vec<ComplexT>& solve_ref = std::get< Vec<ComplexT> >(solve_temp_);
235 LU_ref.Solve(rand_ref, solve_ref); // reuse the factorization from EvalIterationStep
236 meta.norm_J_inverse = NumErrorT(solve_ref.norm());
237 }
239
240 if ( (meta.norm_delta_z < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
242
243 if (!amp::CriterionB<ComplexT>(meta.norm_J, meta.norm_J_inverse, max_num_newton_iterations - ii, tracking_tolerance, meta.norm_delta_z, *AMP_config))
245
246 if (!amp::CriterionC<ComplexT>(meta.norm_J_inverse, next_space, tracking_tolerance, *AMP_config))
248 }
249
251 }
252
253
254 private:
255
257 //
258 // Private Data Methods
259 //
261
262
272
273 template<typename ComplexT, typename Derived>
274 SuccessCode EvalIterationStep(Vec<ComplexT> & newton_step,
275 const System& S,
276 const Eigen::MatrixBase<Derived>& current_space, const ComplexT& current_time)
277 {
278 Vec<ComplexT>& f_temp_ref = std::get< Vec<ComplexT> >(f_temp_);
279 Mat<ComplexT>& J_temp_ref = std::get< Mat<ComplexT> >(J_temp_);
280
281 linalg::PartialPivLU<ComplexT>& LU_ref = std::get< linalg::PartialPivLU<ComplexT> >(LU_);
282
283 S.SetAndReset<ComplexT>(current_space, current_time);
284 S.EvalInPlace(f_temp_ref);
285 S.JacobianInPlace(J_temp_ref);
286 // Factor a copy of J (J_temp_ref is read again afterward for meta.norm_J). The health
287 // check is folded into Factor().
288 if (LU_ref.Factor(J_temp_ref)!=MatrixSuccessCode::Success)
290
291 // Solve J*newton_step = f (NOT -f): this lets us skip materializing the negated RHS
292 // temporary. newton_step therefore holds +J^{-1}f = -(true Newton step), so callers
293 // SUBTRACT it (next_space -= newton_step). The convergence test uses lpNorm, which is
294 // sign-insensitive, so it is unaffected.
295 LU_ref.Solve(f_temp_ref, newton_step);
296
298
299 }
300
301
302
304 //
305 // Private Data Members
306 //
308
309 unsigned numTotalFunctions_; // Number of total functions for the current system
310 unsigned numVariables_; // Number of variables for the current system
311
312 std::tuple< Vec<complex_dbl>, Vec<complex_mp> > f_temp_;
313 std::tuple< Vec<complex_dbl>, Vec<complex_mp> > step_temp_;
314 std::tuple< Mat<complex_dbl>, Mat<complex_mp> > J_temp_;
315 std::tuple< Vec<complex_dbl>, Vec<complex_mp> > rand_temp_; // reused scratch: random RHS for norm_J_inverse
316 Vec<complex_mp> probe_as_drawn_;
317 std::tuple< Vec<complex_dbl>, Vec<complex_mp> > solve_temp_; // reused scratch: LU solve result
318
319 std::tuple< linalg::PartialPivLU<complex_dbl>, linalg::PartialPivLU<complex_mp> > LU_;
320
321 unsigned current_precision_;
322
323 NewtonConfig newton_config_; // Hold the settings of the Newton iteration
324
325
326 }; //re: class NewtonCorrector
327
328 } //re: namespace correct
329 }// re: namespace tracking
330}// re: namespace bertini
331
332#endif
Provides the Adaptive Multiple Precision criteria functions.
The fundamental polynomial system class for Bertini2.
Definition system.hpp:106
void SetAndReset(Vec< T > const &new_space, T const &new_time) const
Stage the system's current point (variables and path value) for a subsequent Eval/Jacobian.
Definition system.hpp:964
void EvalInPlace(Vec< T > &function_values) const
Evaluate the system using the previously set variable (and time) values, in place.
Definition system.hpp:213
void JacobianInPlace(Mat< T > &J) const
Evaluate the Jacobian matrix of the system, using the previous space and time values,...
Definition system.hpp:413
size_t NumVariables() const
Get the total number of variables in this system, including homogenizing variables.
size_t NumTotalFunctions() const
Get the total number of functions, including patches.
Stateful partial-pivot LU factor/solve with preallocated, precision-adjustable banks.
Definition lu_solver.hpp:58
std::tuple< Vec< complex_dbl >, Vec< complex_mp > > ConditionProbe() const
The condition-number probe direction as drawn (both precisions), so the tracker can share the SAME pe...
Definition newton_corrector.hpp:157
void RefreshRandomDirection()
(Re)draw the random probe direction used to estimate ||J^{-1}|| (the condition number) from this thre...
Definition newton_corrector.hpp:143
void Settings(const NewtonConfig &newton_settings)
Sets the Newton configuration settings.
Definition newton_corrector.hpp:69
void ChangeSystem(const System &S)
Change the system(number of total functions) that the predictor uses.
Definition newton_corrector.hpp:115
NewtonCorrector(const System &S)
Construct a Newton corrector for a system, at the current default precision.
Definition newton_corrector.hpp:51
unsigned precision() const
Get the corrector's current working precision.
Definition newton_corrector.hpp:104
void ChangePrecision(unsigned new_precision)
Change the precision of the predictor variables and reassign the Butcher table variables.
Definition newton_corrector.hpp:84
SuccessCode Correct(Vec< ComplexT > &next_space, StepMetadata &meta, System const &S, Vec< ComplexT > const &current_space, ComplexT const &current_time, NumErrorT const &tracking_tolerance, unsigned min_num_newton_iterations, unsigned max_num_newton_iterations, AdaptiveMultiplePrecisionConfig const *AMP_config=nullptr)
Run Newton's method, optionally with adaptive multiple precision.
Definition newton_corrector.hpp:187
A stateful partial-pivot LU solver that owns precision-adjustable temporary banks.
bool CriterionB(double const &norm_J, double const &norm_J_inverse, unsigned num_newton_iterations_remaining, NumErrorT const &tracking_tolerance, double const &norm_of_latest_newton_residual, AdaptiveMultiplePrecisionConfig const &AMP_config)
Check AMP Criterion B.
Definition amp_criteria.hpp:128
bool CriterionC(double const &norm_J_inverse, const Eigen::MatrixBase< Derived > &z, NumErrorT tracking_tolerance, AdaptiveMultiplePrecisionConfig const &AMP_config)
Check AMP Criterion C.
Definition amp_criteria.hpp:202
Definition newton_corrector.hpp:20
Definition adaptive_precision_utilities.hpp:35
Definition algorithm_builder.hpp:36
@ Success
The decomposition looks healthy.
Definition eigen_extensions.hpp:465
Eigen::Matrix< NumT, Eigen::Dynamic, 1 > Vec
A dynamically-sized column vector of NumT.
Definition eigen_extensions.hpp:296
Mat< NumberType > RandomOfUnits(unsigned int rows, unsigned int cols)
Make a random matrix of units (numbers with norm 1).
Definition eigen_extensions.hpp:565
Eigen::Matrix< NumT, Eigen::Dynamic, Eigen::Dynamic > Mat
A dynamically-sized matrix of NumT.
Definition eigen_extensions.hpp:298
double NumErrorT
The numeric type used to hold error/tolerance magnitudes throughout Bertini2 – tracking tolerances,...
Definition num_traits.hpp:48
auto DefaultPrecision()
Get the global default precision (digits) for multiprecision numbers.
Definition mpfr_complex.hpp:135
SuccessCode
Definition config.hpp:42
@ FailedToConverge
Definition config.hpp:55
@ Success
Definition config.hpp:51
@ MatrixSolveFailure
Definition config.hpp:56
@ HigherPrecisionNecessary
Definition config.hpp:52
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object.
Definition eigen_extensions.hpp:339
Holds the program parameters with respect to Adaptive Multiple Precision.
Definition config.hpp:214
Settings governing the Newton corrector's iteration bounds.
Definition config.hpp:119
Metadata produced by a single predict or correct step.
Definition config.hpp:84
NumErrorT condition_number_estimate
norm_J * norm_J_inverse (refreshed per frequency_of_CN_estimation).
Definition config.hpp:87
NumErrorT norm_J_inverse
estimate of ||J^{-1}|| via the condition probe.
Definition config.hpp:86
NumErrorT norm_J
||J|| (Frobenius) at the step.
Definition config.hpp:85
NumErrorT norm_delta_z
||latest Newton step|| (corrector only).
Definition config.hpp:90
Provides the bertini::System class.
Configs and settings for tracking.