Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
amp_tracker.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//amp_tracker.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//amp_tracker.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 amp_tracker.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
29
30#ifndef BERTINI_AMP_TRACKER_HPP
31#define BERTINI_AMP_TRACKER_HPP
32
33#include <assert.h>
34#include <optional>
35
36#pragma once
37
39
40
41namespace bertini{
42
43 namespace tracking{
44
45
46 using std::max;
47 using std::min;
48 using std::pow;
49
50 using bertini::max;
51
63 inline
64 real_mp MinTimeForCurrentPrecision(unsigned precision, real_mp const& time_to_go, int safety_digits = 3)
65 {
66 real_mp t = pow( real_mp(10), safety_digits-long(precision)) * time_to_go;
67 if (precision==DoublePrecision() && t<1e-150)
68 return real_mp("1e-150");
69 else
70 return t;
71 }
72
82 inline
83 real_mp MinStepSizeForPrecision(unsigned precision, real_mp const& time_to_go, int safety_digits = 3)
84 {
85 return MinTimeForCurrentPrecision(precision, time_to_go, safety_digits);
86 }
87
88
111 inline
112 double ArithmeticCost(unsigned precision)
113 {
114 if (precision==DoublePrecision())
115 return 1;
116 else
117 return 101.47 + 1.59 * precision;
118 }
119
120
121
122
135 template<typename RealT>
136 inline RealT StepsizeSatisfyingCriterionB(unsigned precision,
137 unsigned digits_B,
138 unsigned num_newton_iterations,
139 unsigned predictor_order = 0)
140 {
141 return pow(RealT(10), -(static_cast<int>(digits_B) - static_cast<int>(precision))
142 * static_cast<int>(num_newton_iterations) / (predictor_order+1.0));
143 }
144
145
155 inline
156 unsigned MinDigitsForLogOfStepsize(real_mp const& log_of_stepsize, real_mp const& time_to_go, unsigned safety_digits = 3)
157 {
158 return (ceil(log_of_stepsize) + ceil(log10(abs(time_to_go))) + safety_digits).convert_to<unsigned>();
159 }
160
171 inline
172 unsigned MinDigitsForStepsizeInterval(real_mp const& min_stepsize, real_mp const& max_stepsize, real_mp const& time_to_go)
173 {
174 return max(MinDigitsForLogOfStepsize(-log10(min_stepsize),time_to_go),
175 MinDigitsForLogOfStepsize(-log10(max_stepsize),time_to_go));
176 }
177
189 inline
190 unsigned ExtraDigitsBeforePrecisionDecrease(unsigned current_precision)
191 {
192 if (current_precision <= DoublePrecision())
193 return 0;
194 return (current_precision / PrecisionIncrement()) * 2;
195 }
196
204 inline
205 void ApplyPrecisionDecreaseMargin(int & digits_required, unsigned current_digits, unsigned extra)
206 {
207 if (digits_required < static_cast<int>(current_digits))
208 {
209 digits_required += static_cast<int>(extra);
210 if (digits_required > static_cast<int>(current_digits))
211 digits_required = static_cast<int>(current_digits);
212 }
213 }
214
215
236 template<typename RealT>
237 void MinimizeTrackingCost(unsigned & new_precision, RealT & new_stepsize,
238 unsigned min_precision, RealT const& min_stepsize,
239 unsigned max_precision, RealT const& max_stepsize,
240 unsigned digits_B,
241 unsigned num_newton_iterations,
242 unsigned predictor_order = 0)
243 {
244 double min_cost = Eigen::NumTraits<double>::highest();
245
246 unsigned minimizing_precision = 0; // initialize to an impossible value.
247
248 // a few casts so that we can work in double precision, because doing this in multiprec sucks
249 double min_stepsize_lowprec = static_cast<double>(min_stepsize);
250 double max_stepsize_lowprec = static_cast<double>(max_stepsize);
251
252 auto minimizer_routine =
253 [&min_cost, &minimizing_precision, digits_B, num_newton_iterations, predictor_order, min_stepsize_lowprec, max_stepsize_lowprec](unsigned p)
254 {
255 double criterion_b_stepsize = StepsizeSatisfyingCriterionB<double>(p, digits_B, num_newton_iterations, predictor_order);
256 if (criterion_b_stepsize < min_stepsize_lowprec)
257 return; // precision too low to satisfy min_stepsize constraint
258 double candidate_stepsize = min(criterion_b_stepsize, max_stepsize_lowprec);
259 using std::abs;
260 double current_cost = ArithmeticCost(p) / abs(candidate_stepsize);
261
262 if (current_cost < min_cost)
263 {
264 min_cost = current_cost;
265 minimizing_precision = p;
266 }
267 };
268
269 unsigned lowest_mp_precision_to_test = min_precision;
270
271 if (min_precision<=DoublePrecision())
272 minimizer_routine(DoublePrecision());
273
274
275 if (lowest_mp_precision_to_test < LowestMultiplePrecision())
276 lowest_mp_precision_to_test = LowestMultiplePrecision();
277 else
278 lowest_mp_precision_to_test = (lowest_mp_precision_to_test/PrecisionIncrement()) * PrecisionIncrement(); // use integer arithmetic to round.
279
280
281 if (max_precision < LowestMultiplePrecision())
282 max_precision = LowestMultiplePrecision();
283 else
284 max_precision = (max_precision/PrecisionIncrement()) * PrecisionIncrement(); // use integer arithmetic to round.
285
286 for (unsigned p = lowest_mp_precision_to_test; p <= max_precision; p+=PrecisionIncrement())
287 minimizer_routine(p);
288
289 if (minimizing_precision==0){
290 throw std::runtime_error("MinimizeTrackingCost failed to find a suitable stepsize and precision");
291 }
292
293 new_precision = minimizing_precision; // copy the computed value
294 // next, because the above computed the new stepsize in double precision, which may be lowprec, we compute in full precision
295 new_stepsize = max(
296 min(
297 StepsizeSatisfyingCriterionB<RealT>(new_precision, digits_B, num_newton_iterations, predictor_order),
298 max_stepsize
299 ),
300 min_stepsize
301 );
302 }
303
304
305
306
307
308
309
310
408 class AMPTracker : public Tracker<AMPTracker>
409 {
410 friend class Tracker<AMPTracker>;
411 public:
412
415
422
423
427 AMPTracker(class System const& sys) : Tracker(sys), current_precision_(DefaultPrecision())
428 {
429 // Deriving the criteria from the system needs a degree bound, and a system that is
430 // not polynomial has none. Rather than refuse to exist, keep the default config
431 // -- which is internally consistent, if meaningless for such a system -- so the
432 // caller can still reach PrecisionSetup and install bounds they can defend. That
433 // is the escape hatch the refusal in SetAMPConfigFrom names; without this guard it
434 // would be unreachable, because the refusal would fire here first.
435 if (sys.IsPolynomial())
437 }
438
439
444 {
445 Set<PrecConf>(AMP_config);
446 }
447
448
450 unsigned GetCurrentPrecision() const
451 {
452 return current_precision_;
453 }
454
455
461 void PrecisionPreservation(bool should_preseve_precision)
462 {
463 preserve_precision_ = should_preseve_precision;
464 }
465
472 void SetStartPrecision(std::optional<unsigned> p = std::nullopt)
473 {
474 override_start_precision_ = p;
475 }
476
477
478 virtual ~AMPTracker() = default;
479
480
483 {
484 if (this->CurrentPrecision()==DoublePrecision())
485 {
486 const auto& curr_vector = std::get<Vec<complex_dbl>>(this->current_space_);
487 Vec<complex_mp> returnme(NumVariables());
488 for (unsigned ii = 0; ii < NumVariables(); ++ii)
489 {
490 returnme(ii) = complex_mp(curr_vector(ii));
491 }
492 return returnme;
493 }
494 else
495 return std::get<Vec<complex_mp>>(this->current_space_);
496 }
497
498
499
500 private:
501
511 SuccessCode TrackerLoopInitialization(complex_mp const& start_time,
512 complex_mp const& end_time,
513 Vec<complex_mp> const& start_point) const override
514 {
515 initial_precision_ = override_start_precision_.value_or(Precision(start_point(0)));
516
517 #ifndef BERTINI_DISABLE_ASSERTS
518 assert(
519 (!preserve_precision_
520 ||
521 -log10(this->TrackingTolerance()) <= initial_precision_)
522 && "when tracking a path, either preservation of precision must be turned off (so precision can be higher at the end of tracking), or the initial precision must be high enough to support the resulting points to the desired tolerance"
523 );
524 #endif
525
526 NotifyObservers(Initializing<AMPTracker,complex_mp>(*this,start_time, end_time, start_point));
527 SetThreadPrecision(initial_precision_);
528 // set up the master current time and the current step size
529
530 current_time_ = start_time;
531 current_time_.precision(initial_precision_);
532
533
534 endtime_highest_precision_ = end_time;
535 endtime_highest_precision_.precision(initial_precision_);
536
537 endtime_ = end_time;
538 endtime_.precision(initial_precision_);
539
540 // The first step is built at THIS track's start precision, and the precision is set
541 // after the assignment, never before it. current_precision_ still holds wherever the
542 // previous track ended, and an assignment takes its source's precision
543 // (preserve_related_precision), so building it at current_precision_ rounded the
544 // exact initial_step_size at the previous track's precision. A track that starts in
545 // double then rounded that a second time, to a double, and the last bit of its first
546 // step -- and so its whole step sequence -- depended on which path the tracker had
547 // tracked before: thread scheduling made the threaded solve irreproducible, and path
548 // order made a serial solve depend on it (#378).
550 {
551 real_mp segment_length = abs(start_time-end_time)/Get<Stepping>().min_num_steps;
552 SetStepSize(min(real_mp(Get<Stepping>().initial_step_size, initial_precision_),segment_length));
553 }
554 current_stepsize_.precision(initial_precision_);
555
556 // populate the current space value with the start point, in appropriate precision
557 if (initial_precision_==DoublePrecision())
558 MultipleToDouble(start_point);
559 else
560 MultipleToMultiple(initial_precision_, start_point);
561
562 ChangePrecision<upsample_refine_off>(initial_precision_);
563
565
566 auto initial_refinement_code = InitialRefinement();
567
568 #ifndef BERTINI_DISABLE_ASSERTS
569 if (initial_precision_==DoublePrecision()){
570 PrecisionSanityCheck<complex_dbl>();
571 }
572 else{
573 PrecisionSanityCheck<complex_mp>();
574 }
575 #endif
576
577 return initial_refinement_code;
578 }
579
580
581
582
583
584 void ResetCounters() const override
585 {
587 num_precision_decreases_ = 0;
589 num_successful_steps_since_precision_decrease_ = 0;
590 // initialize to the frequency so guaranteed to compute it the first try
591 num_steps_since_last_condition_number_computation_ = this->Get<Stepping>().frequency_of_CN_estimation;
592 }
593
599 SuccessCode InitialRefinement() const
600 {
601 SuccessCode initial_refinement_code = RefineStoredPoint();
602 if (initial_refinement_code!=SuccessCode::Success)
603 {
604 do {
605 if (current_precision_ > Get<PrecConf>().maximum_precision)
606 {
609 }
610
611 if (current_precision_==DoublePrecision())
613 else
614 initial_refinement_code = ChangePrecision<upsample_refine_on>(current_precision_+PrecisionIncrement());
615 }
616 while (initial_refinement_code!=SuccessCode::Success);
617 }
619 }
620
621
622
623
629 SuccessCode PreIterationCheck() const override
630 {
631 // The budget counts EVERY step, not only the successful ones -- see the
632 // same check in FixedPrecisionTracker and issue #410. This is the guard
633 // that bounds a path whose steps fail without ever advancing.
634 if (NumTotalStepsTaken() >= Get<Stepping>().max_num_steps)
636 if (current_stepsize_ < Get<Stepping>().min_step_size)
638 if (current_precision_ > Get<PrecConf>().maximum_precision)
640
642 }
643
644
645
646
647
648
649
650 void PostTrackCleanup() const override
651 {
652 if (preserve_precision_)
653 ChangePrecision(initial_precision_);
654 NotifyObservers(TrackingEnded<EmitterType>(*this));
655 }
656
664 void CopySolution(Vec<complex_mp> & solution_at_endtime) const override
665 {
666
667 // the current precision is the precision of the output solution point.
668 if (current_precision_==DoublePrecision())
669 {
670 unsigned num_vars = static_cast<unsigned>(GetSystem().NumVariables());
671 solution_at_endtime.resize(num_vars);
672 for (unsigned ii=0; ii<num_vars; ii++)
673 solution_at_endtime(ii) = complex_mp(std::get<Vec<complex_dbl> >(current_space_)(ii));
674 }
675 else
676 {
677 unsigned num_vars = static_cast<unsigned>(GetSystem().NumVariables());
678 solution_at_endtime.resize(num_vars);
679 for (unsigned ii=0; ii<num_vars; ii++)
680 {
681 solution_at_endtime(ii) = std::get<Vec<complex_mp> >(current_space_)(ii);
682 solution_at_endtime(ii).precision(current_precision_);
683 }
684 }
685 }
686
687
688
689
697 SuccessCode TrackerIteration() const override
698 {
699 if (current_precision_==DoublePrecision())
700 return TrackerIteration<complex_dbl>();
701 else
702 return TrackerIteration<complex_mp>();
703 }
704
705
713 template <typename ComplexT>
714 SuccessCode TrackerIteration() const // not an override, because it is templated
715 {
716
717 using RealT = typename Eigen::NumTraits<ComplexT>::Real;
718
719 #ifndef BERTINI_DISABLE_ASSERTS
720 assert(PrecisionSanityCheck<ComplexT>() && "precision sanity check failed. some internal variable is not in correct precision");
721 #endif
722
723 NotifyObservers(NewStep<EmitterType>(*this));
724
725 Vec<ComplexT>& predicted_space = std::get<Vec<ComplexT> >(temporary_space_); // this will be populated in the Predict step
726 Vec<ComplexT>& current_space = std::get<Vec<ComplexT> >(current_space_); // the thing we ultimately wish to update
727 ComplexT current_time = ComplexT(current_time_);
728 ComplexT delta_t = ComplexT(delta_t_);
729
730 #ifndef BERTINI_DISABLE_ASSERTS
731 PrecisionSanityCheck<ComplexT>();
732 #endif
733
734 SuccessCode predictor_code = Predict<ComplexT, RealT>(predicted_space, current_space, current_time, delta_t);
736 {
737 NotifyObservers(FirstStepPredictorMatrixSolveFailure<EmitterType>(*this));
738 InitialMatrixSolveError();
739 return predictor_code;
740 }
741 else if (predictor_code==SuccessCode::MatrixSolveFailure)
742 {
743 NotifyObservers(PredictorMatrixSolveFailure<EmitterType>(*this));
744 NewtonConvergenceError();// decrease stepsize, and adjust precision as necessary
745 return predictor_code;
746 }
747 else if (predictor_code==SuccessCode::HigherPrecisionNecessary)
748 {
749 NotifyObservers(PredictorHigherPrecisionNecessary<EmitterType>(*this));
750 auto adj_code = AMPCriterionError<ComplexT>();
751 if (adj_code != SuccessCode::Success)
752 return adj_code;
753 return predictor_code;
754 }
755
756
757 NotifyObservers(SuccessfulPredict<AMPTracker, ComplexT>(*this, predicted_space));
758
759 Vec<ComplexT>& tentative_next_space = std::get<Vec<ComplexT> >(tentative_space_); // this will be populated in the Correct step
760
761 ComplexT tentative_next_time = current_time + delta_t;
762
763 SuccessCode corrector_code = Correct<ComplexT, RealT>(tentative_next_space,
764 predicted_space,
765 tentative_next_time);
766
767 #ifndef BERTINI_DISABLE_ASSERTS
768 assert(PrecisionSanityCheck<ComplexT>() && "precision sanity check failed. some internal variable is not in correct precision");
769 #endif
770
771 if (corrector_code==SuccessCode::MatrixSolveFailure || corrector_code==SuccessCode::FailedToConverge)
772 {
773 NotifyObservers(CorrectorMatrixSolveFailure<EmitterType>(*this));
774 NewtonConvergenceError();
775 return corrector_code;
776 }
777 else if (corrector_code == SuccessCode::HigherPrecisionNecessary)
778 {
779 NotifyObservers(CorrectorHigherPrecisionNecessary<EmitterType>(*this));
780 auto adj_code = AMPCriterionError<ComplexT>();
781 if (adj_code != SuccessCode::Success)
782 return adj_code;
783 return corrector_code;
784 }
785 else if (corrector_code == SuccessCode::GoingToInfinity)
786 {
787 // there is no corrective action possible...
788 return corrector_code;
789 }
790
791 NotifyObservers(SuccessfulCorrect<AMPTracker, ComplexT>(*this, tentative_next_space));
792
793 // copy the tentative vector into the current space vector;
794 current_space = tentative_next_space;
795 return AdjustAMPStepSuccess<ComplexT>();
796 }
797
798
802 SuccessCode CheckGoingToInfinity() const override
803 {
804 if (current_precision_ == DoublePrecision())
806 else
808 }
809
817 template <UpsampleRefinementOption refine_if_necessary = upsample_refine_off>
818 SuccessCode UpdatePrecisionAndStepsize() const
819 {
821 return ChangePrecision<refine_if_necessary>(next_precision_);
822 }
823
824
825
826
827
828
829
864 template <typename ComplexT>
865 SuccessCode AdjustAMPStepSuccess() const
866 {
867 // This mirrors Bertini 1's AMP2_update: pick the cost-minimizing (precision, stepsize)
868 // after a successful step. Faithful-to-B1 points, two of which were previously wrong:
869 // (1) The rule-B precision requirement CREDITS THE STEP. digits_B is the right-hand side
870 // of P + (p+1)*xi/N > digits_B (xi = -log10(stepsize)); the floor is therefore
871 // digits_B - (p+1)*(-log10(min_stepsize))/N, crediting the smallest allowed step, NOT
872 // the raw digits_B. Without this credit a tiny step (large size_proportion in the
873 // roundoff regime) spuriously forced precision up. B1: digits_B2 = ceil(P0 - eta_minSS/N).
874 // (2) Precision decrease (and stepsize increase) is gated by BOTH B1's StepsForIncrease
875 // consecutive-successful-steps counter AND the digits-margin hysteresis
876 // (ExtraDigitsBeforePrecisionDecrease). The single StepsForIncrease setting
877 // (SteppingConfig::consecutive_successful_steps_before_stepsize_increase) governs both
878 // gates -- the old, duplicate AMP-config precision-decrease setting was removed.
879 real_mp min_stepsize = current_stepsize_ * real_mp(Get<Stepping>().step_size_fail_factor, current_precision_);
880 real_mp max_stepsize = min( current_stepsize_ * real_mp(Get<Stepping>().step_size_success_factor, current_precision_), real_mp(Get<Stepping>().max_step_size, current_precision_));
881
882 const unsigned steps_for_increase = Get<Stepping>().consecutive_successful_steps_before_stepsize_increase; // B1 StepsForIncrease
883
884 if (num_successful_steps_since_stepsize_increase_ < steps_for_increase)
885 max_stepsize = current_stepsize_; // not enough successes in a row: disallow stepsize increase
886
887 const unsigned N = Get<NewtonConfig>().max_num_newton_iterations;
888 const unsigned curr_digits = current_precision_;
889 const unsigned extra = ExtraDigitsBeforePrecisionDecrease(curr_digits);
890
891 // rule B, step-credited (credit the smallest allowed step = the most credit)
892 int digits_B = static_cast<int>(ceil( double(B_RHS<ComplexT>())
893 - (predictor_order_ + 1.0) * double(-log10(min_stepsize)) / N ));
894 int digits_C = static_cast<int>(DigitsC<ComplexT>());
895 int digits_stepsize = static_cast<int>(MinDigitsForStepsizeInterval(min_stepsize, max_stepsize, abs(current_time_ - endtime_)));
896
897 // each requirement may only lower precision if it clears the hysteresis margin
898 ApplyPrecisionDecreaseMargin(digits_B, curr_digits, extra);
899 ApplyPrecisionDecreaseMargin(digits_C, curr_digits, extra);
900 ApplyPrecisionDecreaseMargin(digits_stepsize, curr_digits, extra);
901
902 int min_digits = std::max({ static_cast<int>(this->DigitsTrackingTolerance()),
903 static_cast<int>(digits_final_),
904 digits_B, digits_C, digits_stepsize,
905 static_cast<int>(DoublePrecision()) });
906 unsigned min_precision = static_cast<unsigned>(min_digits); // >= DoublePrecision(), so non-negative
907
908 // StepsForIncrease gate + safety cap: precision may only be lowered after enough successful
909 // steps in a row and while under the decrease budget; otherwise hold the current precision.
910 const bool decrease_allowed =
911 (num_successful_steps_since_precision_decrease_ >= steps_for_increase)
912 &&
913 (num_precision_decreases_ < Get<PrecConf>().max_num_precision_decreases);
914 if (!decrease_allowed)
915 min_precision = max(min_precision, current_precision_);
916
917 unsigned max_precision = Get<PrecConf>().maximum_precision;
918
919 try {
920 MinimizeTrackingCost(next_precision_, next_stepsize_,
921 min_precision, min_stepsize,
922 max_precision, max_stepsize,
923 DigitsB<ComplexT>(), // RAW digits_B (=P0) for the stepsize relation, per B1 minimize_cost
924 N,
926 } catch (std::runtime_error const&) {
928 }
929
930 if ( (next_stepsize_ > current_stepsize_) || (next_precision_ < current_precision_) )
932 else
934
935 if (next_precision_ < current_precision_)
936 {
937 ++num_precision_decreases_;
938 num_successful_steps_since_precision_decrease_ = 0;
939 }
940 else
941 ++num_successful_steps_since_precision_decrease_;
942
943 return UpdatePrecisionAndStepsize();
944 }
945
946
947
948 void InitialMatrixSolveError() const
949 {
951
952 if (current_precision_==DoublePrecision())
953 next_precision_ = LowestMultiplePrecision();
954 else
955 next_precision_ = current_precision_+(1+num_consecutive_failed_steps_) * PrecisionIncrement();
956
957 UpdatePrecisionAndStepsize();
958 }
959
971 void NewtonConvergenceError() const
972 {
973 next_precision_ = current_precision_;
974
976 while (next_stepsize_ < MinStepSizeForPrecision(next_precision_, abs(current_time_ - endtime_)))
977 {
978 if (next_precision_==DoublePrecision())
979 next_precision_=LowestMultiplePrecision();
980 else
981 next_precision_+=PrecisionIncrement();
982 }
983
984 UpdatePrecisionAndStepsize();
985 }
986
987
988
989
990
991
992
1002 template<typename ComplexT>
1003 SuccessCode AMPCriterionError() const
1004 {
1005
1006 unsigned min_next_precision; // sure, i could use a trigraph here, but it'd be terrible
1007 if (current_precision_==DoublePrecision())
1008 min_next_precision = LowestMultiplePrecision(); // precision increases
1009 else
1010 min_next_precision = current_precision_ + (1+num_consecutive_failed_steps_)*PrecisionIncrement(); // precision increases
1011
1012
1013 real_mp min_stepsize = MinStepSizeForPrecision(current_precision_, abs(current_time_ - endtime_));
1014 real_mp max_stepsize = current_stepsize_ * real_mp(Get<Stepping>().step_size_fail_factor, current_precision_); // Stepsize decreases.
1015
1016 if (min_stepsize > max_stepsize)
1017 {
1018 // stepsizes are incompatible, must increase precision
1019 next_precision_ = min_next_precision;
1020 // decrease stepsize somewhat less than the fail factor
1021 next_stepsize_ = max(current_stepsize_ * (1+real_mp(Get<Stepping>().step_size_fail_factor, current_precision_))/2, min_stepsize);
1022 }
1023 else
1024 {
1025 unsigned digits_B = DigitsB<ComplexT>(); // RAW digits_B (=P0); the stepsize relation in MinimizeTrackingCost needs it raw
1026
1027 // rule-B precision floor CREDITS THE STEP (B1 AMP2_update: digits_B2 = ceil(P0 - eta_minSS/N)):
1028 // floor = digits_B - (p+1)*(-log10(min_stepsize))/N, crediting the smallest allowed step.
1029 // This keeps a small step (large size_proportion in the roundoff regime) from forcing
1030 // precision up by itself; genuine ill-conditioning still escalates via D / rules A,C.
1031 const unsigned N = Get<NewtonConfig>().max_num_newton_iterations;
1032 int digits_B_credited = static_cast<int>(ceil( double(digits_B)
1033 - (predictor_order_ + 1.0) * double(-log10(min_stepsize)) / N ));
1034 if (digits_B_credited < 0)
1035 digits_B_credited = 0;
1036
1037 unsigned min_precision = max(min_next_precision,
1038 static_cast<unsigned>(digits_B_credited),
1039 DigitsC<ComplexT>(),
1040 MinDigitsForStepsizeInterval(min_stepsize, max_stepsize, abs(current_time_ - endtime_)),
1042 );
1043
1044 try {
1045 MinimizeTrackingCost(next_precision_, next_stepsize_,
1046 min_precision, min_stepsize,
1047 Get<PrecConf>().maximum_precision, max_stepsize,
1048 digits_B,
1049 N,
1051 } catch (std::runtime_error const&) {
1053 }
1054
1055 }
1056
1057 UpdatePrecisionAndStepsize();
1058 return SuccessCode::Success;
1059 }
1060
1061
1062
1063
1064
1068 template<typename ComplexT>
1069 NumErrorT B_RHS() const
1070 {
1071 return max(amp::CriterionBRHS(this->last_step_.norm_J,
1072 this->last_step_.norm_J_inverse,
1073 Get<NewtonConfig>().max_num_newton_iterations,
1074 this->TrackingTolerance(),
1075 this->last_step_.norm_delta_z,
1076 Get<PrecConf>()), NumErrorT(0));
1077 }
1078
1079
1080
1081
1097 template<typename ComplexT>
1098 unsigned DigitsB() const
1099 {
1100 unsigned d = unsigned(B_RHS<ComplexT>());
1101 return d;
1102 }
1103
1104
1105
1106
1107
1111 template<typename ComplexT>
1112 NumErrorT C_RHS() const
1113 {
1114 return max(amp::CriterionCRHS(this->last_step_.norm_J_inverse,
1115 NumErrorT(std::get<Vec<ComplexT> > (current_space_).norm()),
1116 this->TrackingTolerance(),
1117 Get<PrecConf>()), NumErrorT(0));
1118 }
1119
1120
1121
1135 template<typename ComplexT>
1136 unsigned DigitsC() const
1137 {
1138 return unsigned(C_RHS<ComplexT>());
1139 }
1140
1141
1142
1143
1144
1145 // (MinRequiredPrecision_BCTol was removed: it returned the UNCREDITED rule-B floor
1146 // max(DigitsB, DigitsC, tol, double), which is what spuriously escalated precision on
1147 // small steps. AdjustAMPStepSuccess now computes the step-credited, margin-gated floor
1148 // directly, faithful to Bertini 1's AMP2_update.)
1149
1150
1151
1152
1153
1155 //
1156 // overrides for counter adjustment after a TrackerIteration()
1157 //
1159
1163 void OnStepSuccess() const override
1164 {
1166 NotifyObservers(SuccessfulStep<EmitterType>(*this));
1167 }
1168
1172 void OnStepFail() const override
1173 {
1176 num_successful_steps_since_precision_decrease_ = 0;
1177 NotifyObservers(FailedStep<EmitterType>(*this));
1178 }
1179
1180
1181
1182 void OnInfiniteTruncation() const override
1183 {
1184 NotifyObservers(InfinitePathTruncation<EmitterType>(*this));
1185 }
1186
1187
1189 //
1190 // Predict and Correct functions
1191 //
1193
1194
1195
1196
1197
1213 template<typename ComplexT, typename RealT>
1214 SuccessCode Predict(Vec<ComplexT> & predicted_space,
1215 const Vec<ComplexT>& current_space,
1216 ComplexT const& current_time, ComplexT const& delta_t) const
1217 {
1218
1219
1220
1221
1222 static_assert(std::is_same< typename Eigen::NumTraits<RealT>::Real,
1223 typename Eigen::NumTraits<ComplexT>::Real>::value,
1224 "underlying complex type and the type for comparisons must match");
1225
1226
1227 return predictor_.Predict(predicted_space,
1228 this->last_step_,
1230 current_space, current_time,
1231 delta_t,
1233 Get<Stepping>().frequency_of_CN_estimation,
1234 this->TrackingTolerance(),
1235 &Get<PrecConf>());
1236 }
1237
1238
1239
1254 template<typename ComplexT, typename RealT>
1255 SuccessCode Correct(Vec<ComplexT> & corrected_space,
1256 Vec<ComplexT> const& current_space,
1257 ComplexT const& current_time) const
1258 {
1259 static_assert(std::is_same< typename Eigen::NumTraits<RealT>::Real,
1260 typename Eigen::NumTraits<ComplexT>::Real>::value,
1261 "underlying complex type and the type for comparisons must match");
1262
1263
1264
1265
1266 return corrector_.Correct(corrected_space,
1267 this->last_step_,
1269 current_space,
1270 current_time,
1271 this->TrackingTolerance(),
1272 Get<NewtonConfig>().min_num_newton_iterations,
1273 Get<NewtonConfig>().max_num_newton_iterations,
1274 &Get<PrecConf>());
1275 }
1276
1277
1278
1286 SuccessCode RefineStoredPoint() const
1287 {
1288 SuccessCode code;
1289 if (current_precision_==DoublePrecision())
1290 {
1291 code = RefineImpl<complex_dbl>(std::get<Vec<complex_dbl> >(temporary_space_),std::get<Vec<complex_dbl> >(current_space_), complex_dbl(current_time_));
1292 if (code == SuccessCode::Success)
1293 std::get<Vec<complex_dbl> >(current_space_) = std::get<Vec<complex_dbl> >(temporary_space_);
1294 }
1295 else
1296 {
1297 code = RefineImpl<complex_mp>(std::get<Vec<complex_mp> >(temporary_space_),std::get<Vec<complex_mp> >(current_space_), current_time_);
1298 if (code == SuccessCode::Success)
1299 std::get<Vec<complex_mp> >(current_space_) = std::get<Vec<complex_mp> >(temporary_space_);
1300 }
1301 return code;
1302 }
1303
1304
1305
1320 template <typename ComplexT>
1321 SuccessCode RefineImpl(Vec<ComplexT> & new_space,
1322 Vec<ComplexT> const& start_point, ComplexT const& current_time) const
1323 {
1324 using RealT = typename Eigen::NumTraits<ComplexT>::Real;
1325
1326 static_assert(std::is_same< typename Eigen::NumTraits<RealT>::Real,
1327 typename Eigen::NumTraits<ComplexT>::Real>::value,
1328 "underlying complex type and the type for comparisons must match");
1329
1330 auto target_precision = Precision(current_time);
1331 assert(Precision(start_point)==target_precision);
1332 ChangePrecision(target_precision);
1333 Precision(new_space,target_precision);
1334
1335
1336
1337
1338 return corrector_.Correct(new_space,
1339 this->last_step_,
1341 start_point,
1342 current_time,
1343 this->TrackingTolerance(),
1344 Get<NewtonConfig>().min_num_newton_iterations,
1345 Get<NewtonConfig>().max_num_newton_iterations,
1346 &Get<PrecConf>());
1347 }
1348
1349
1350
1351
1352
1353
1369 template <typename ComplexT>
1370 SuccessCode RefineImpl(Vec<ComplexT> & new_space,
1371 Vec<ComplexT> const& start_point, ComplexT const& current_time,
1372 NumErrorT const& tolerance, unsigned max_iterations) const
1373 {
1374 auto target_precision = Precision(current_time);
1375 assert(Precision(start_point)==target_precision);
1376 ChangePrecision(target_precision);
1377 Precision(new_space,target_precision);
1378
1379 return corrector_.Correct(new_space,
1380 this->last_step_,
1382 start_point,
1383 current_time,
1384 tolerance,
1385 1,
1386 max_iterations,
1387 &Get<PrecConf>());
1388 }
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1404 //
1405 // Functions for converting between precision types
1406 //
1408
1409 public:
1418 template <UpsampleRefinementOption refine_if_necessary = upsample_refine_off>
1419 SuccessCode ChangePrecision(unsigned new_precision) const
1420 {
1421 if (new_precision==current_precision_) // no op
1422 return SuccessCode::Success;
1423
1424
1425 NotifyObservers(PrecisionChanged<EmitterType>(*this,current_precision_,new_precision));
1426
1427
1428 bool upsampling_needed = new_precision > current_precision_;
1429 // reset the counter for estimating the condition number.
1430 num_steps_since_last_condition_number_computation_ = this->Get<Stepping>().frequency_of_CN_estimation;
1431
1432 if (new_precision==DoublePrecision() && current_precision_>DoublePrecision())
1433 {
1434 // convert from multiple precision to double precision
1435 MultipleToDouble();
1436 }
1437 else if(new_precision > DoublePrecision() && current_precision_ == DoublePrecision())
1438 {
1439 // convert from double to multiple precision
1440 DoubleToMultiple(new_precision);
1441 #ifndef BERTINI_DISABLE_ASSERTS
1442 assert(PrecisionSanityCheck<complex_mp>() && "precision sanity check failed. some internal variable is not in correct precision");
1443 #endif
1444 }
1445 else
1446 {
1447 MultipleToMultiple(new_precision);
1448 #ifndef BERTINI_DISABLE_ASSERTS
1449 assert(PrecisionSanityCheck<complex_mp>() && "precision sanity check failed. some internal variable is not in correct precision");
1450 #endif
1451 }
1452
1453 if (refine_if_necessary && upsampling_needed)
1454 return RefineStoredPoint();
1455 else
1456 return SuccessCode::Success;
1457 }
1458
1459
1460
1461
1462
1463 private:
1464
1472 void DoubleToDouble(Vec<complex_dbl> const& source_point) const
1473 {
1474 #ifndef BERTINI_DISABLE_ASSERTS
1475 assert(source_point.size() == GetSystem().NumVariables() && "source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1476 #endif
1477
1478 current_precision_ = DoublePrecision();
1480
1481
1482 std::get<Vec<complex_dbl> >(current_space_) = source_point;
1483 }
1484
1490 void DoubleToDouble() const
1491 {
1492 DoubleToDouble(std::get<Vec<complex_dbl> >(current_space_));
1493 }
1494
1495
1496
1504 void MultipleToDouble(Vec<complex_mp> const& source_point) const
1505 {
1506 #ifndef BERTINI_DISABLE_ASSERTS
1507 assert(source_point.size() == GetSystem().NumVariables() && "source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1508 #endif
1509
1510 AdjustCurrentPrecision(DoublePrecision());
1511
1512
1513 // copy the current space in.
1514 if (std::get<Vec<complex_dbl> >(current_space_).size()!=source_point.size())
1515 std::get<Vec<complex_dbl> >(current_space_).resize(source_point.size());
1516
1517 for (unsigned ii=0; ii<source_point.size(); ii++)
1518 std::get<Vec<complex_dbl> >(current_space_)(ii) = complex_dbl(source_point(ii));
1519
1520 // The same internals every other conversion re-precisions: the step size, the
1521 // time, its increment, the end time, and the predictor's and corrector's work
1522 // space. Re-precisioning only the end time here left the rest at whatever
1523 // multiple precision the track came down from, so a track's double-precision
1524 // steps depended on the precision history before them (#378).
1525 AdjustInternalsPrecision(DoublePrecision());
1526 }
1527
1533 void MultipleToDouble() const
1534 {
1535 MultipleToDouble(std::get<Vec<complex_mp> >(current_space_));
1536 }
1537
1538
1539
1550 void DoubleToMultiple(unsigned new_precision, Vec<complex_dbl> const& source_point) const
1551 {
1552 #ifndef BERTINI_DISABLE_ASSERTS
1553 assert(source_point.size() == GetSystem().NumVariables() && "source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1554 assert(new_precision > DoublePrecision() && "must convert to precision higher than DoublePrecision when converting to multiple precision");
1555 #endif
1556
1557 AdjustCurrentPrecision(new_precision);
1558 CopyToCurrentSpace(source_point);
1559 AdjustInternalsPrecision(new_precision);
1560 AdjustTemporariesPrecision(new_precision);
1561
1562 #ifndef BERTINI_DISABLE_ASSERTS
1563 PrecisionSanityCheck<complex_mp>();
1564 #endif
1565 }
1566
1567
1568
1576 void DoubleToMultiple(unsigned new_precision) const
1577 {
1578 DoubleToMultiple( new_precision, std::get<Vec<complex_dbl> >(current_space_));
1579 }
1580
1581
1582
1583
1584
1594 void MultipleToMultiple(unsigned new_precision, Vec<complex_mp> const& source_point) const
1595 {
1596 #ifndef BERTINI_DISABLE_ASSERTS
1597 assert(source_point.size() == GetSystem().NumVariables() && "source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1598 assert(new_precision > DoublePrecision() && "must convert to precision higher than DoublePrecision when converting to multiple precision");
1599 #endif
1600
1601 AdjustCurrentPrecision(new_precision);
1602 CopyToCurrentSpace(source_point);
1603 AdjustInternalsPrecision(new_precision);
1604 AdjustTemporariesPrecision(new_precision);
1605
1606 #ifndef BERTINI_DISABLE_ASSERTS
1607 PrecisionSanityCheck<complex_mp>();
1608 #endif
1609 }
1610
1611
1619 void MultipleToMultiple(unsigned new_precision) const
1620 {
1621 MultipleToMultiple( new_precision, std::get<Vec<complex_mp> >(current_space_));
1622 }
1623
1624
1625
1626
1627
1628 void AdjustCurrentPrecision(unsigned new_precision) const
1629 {
1630 previous_precision_ = current_precision_;
1631 current_precision_ = new_precision;
1632 SetThreadPrecision(new_precision);
1633 }
1634
1635
1636 void CopyToCurrentSpace(Vec<complex_dbl> const& source_point) const
1637 {
1638 auto& space = std::get<Vec<complex_mp> >(current_space_);
1639 if (space.size()!=source_point.size())
1640 space.resize(source_point.size());
1641 for (unsigned ii=0; ii<source_point.size(); ii++)
1642 space(ii) = complex_mp(source_point(ii));
1643 }
1644
1645 void CopyToCurrentSpace(Vec<complex_mp> const& source_point) const
1646 {
1647 auto& space = std::get<Vec<complex_mp> >(current_space_);
1648 if (space.size()!=source_point.size())
1649 space.resize(source_point.size());
1650 space = source_point;
1651 }
1652
1653 void AdjustInternalsPrecision(unsigned new_precision) const
1654 {
1655 predictor_.ChangePrecision(new_precision);
1656 corrector_.ChangePrecision(new_precision);
1657
1658 endtime_ = endtime_highest_precision_;
1659
1660 endtime_.precision(new_precision);
1661 current_stepsize_.precision(new_precision);
1662 delta_t_.precision(new_precision);
1663 current_time_.precision(new_precision);
1664
1665 Precision(std::get<Vec<complex_mp> >(current_space_),new_precision);
1666 }
1667
1675 void AdjustTemporariesPrecision(unsigned new_precision) const
1676 {
1677 const auto num_vars = GetSystem().NumVariables();
1678
1679 // the current_space value is adjusted in the appropriate ChangePrecision function
1680 std::get<Vec<complex_mp> >(tentative_space_).resize(static_cast<Eigen::Index>(num_vars));
1681 Precision(std::get<Vec<complex_mp> >(tentative_space_), new_precision);
1682
1683 std::get<Vec<complex_mp> >(temporary_space_).resize(static_cast<Eigen::Index>(num_vars));
1684 Precision(std::get<Vec<complex_mp> >(temporary_space_), new_precision);
1685 }
1686
1687
1688
1689
1695 template<typename ComplexT>
1696 bool PrecisionSanityCheck() const
1697 {
1698
1699 if constexpr (std::is_same<ComplexT, complex_dbl>::value){
1700 return true;
1701 }
1702
1703 if constexpr (std::is_same<ComplexT, complex_mp>::value){
1704 assert(ThreadPrecision()==current_precision_ && "current precision differs from the thread-local default precision");
1705 assert(GetSystem().precision() == current_precision_ && "tracked system is out of precision");
1706
1707 assert(std::get<Vec<complex_mp> >(current_space_)(0).precision() == current_precision_ && "current space out of precision");
1708 assert(std::get<Vec<complex_mp> >(tentative_space_)(0).precision() == current_precision_ && "tentative space out of precision");
1709 assert(std::get<Vec<complex_mp> >(temporary_space_)(0).precision() == current_precision_ && "temporary space out of precision");
1710 assert(Precision(current_stepsize_) == current_precision_ && "current_stepsize_ out of precision");
1711 assert(Precision(delta_t_) == current_precision_ && "delta_t_ out of precision");
1712 assert(Precision(endtime_) == current_precision_ && "endtime_ out of precision");
1713 assert(Precision(current_time_) == current_precision_ && "current_time_ out of precision");
1714 assert(current_precision_ <= MaxPrecisionAllowed() && "current_precision_ exceeds max precision");
1715 assert(predictor_.precision() == current_precision_ && "predictor_ out of precision");
1716 return true;
1717 }
1718
1719 }
1720
1721
1722
1723
1730 //
1731
1732
1733
1734
1735
1737 // state variables
1739 bool preserve_precision_ = false;
1740 std::optional<unsigned> override_start_precision_;
1741
1742 mutable unsigned previous_precision_;
1743 mutable unsigned current_precision_;
1744 mutable unsigned next_precision_;
1745 mutable unsigned num_precision_decreases_;
1746 mutable unsigned initial_precision_;
1747 mutable unsigned num_successful_steps_since_precision_decrease_;
1748
1749 mutable complex_mp endtime_highest_precision_;
1750
1751 public:
1752
1754 unsigned CurrentPrecision() const override
1755 {
1756 return current_precision_;
1757 }
1758 }; // re: class Tracker
1759
1760 } // namespace tracking
1761} // namespace bertini
1762
1763
1764#endif
Contains the abstract base Tracker type, from which all other Trackers inherit.
void NotifyObservers(AnyEvent const &e) const
Definition observable.hpp:185
The fundamental polynomial system class for Bertini2.
Definition system.hpp:106
bool IsPolynomial() const
Checks whether a system is polynomial, overall.
size_t NumVariables() const
Get the total number of variables in this system, including homogenizing variables.
UpsampleRefinementOption
Whether to refine after upsampling precision.
Definition amp_tracker.hpp:418
@ upsample_refine_on
Refine after upsampling.
Definition amp_tracker.hpp:420
@ upsample_refine_off
Do not refine after upsampling.
Definition amp_tracker.hpp:419
unsigned CurrentPrecision() const override
Get the current working precision of the tracker.
Definition amp_tracker.hpp:1754
TrackerTraits< AMPTracker >::EventEmitterType EmitterType
The event-emitter type.
Definition amp_tracker.hpp:414
void SetStartPrecision(std::optional< unsigned > p=std::nullopt)
Override the precision at which tracking starts.
Definition amp_tracker.hpp:472
unsigned GetCurrentPrecision() const
Get the current working precision of the adaptive tracker.
Definition amp_tracker.hpp:450
Vec< complex_mp > CurrentPoint() const override
Get the current space point, returned in multiprecision regardless of the working type.
Definition amp_tracker.hpp:482
void PrecisionSetup(AdaptiveMultiplePrecisionConfig const &AMP_config)
Special additional setup call for the AMPTracker, selecting the config for adaptive precision.
Definition amp_tracker.hpp:443
Tracker< AMPTracker > Base
The base tracker type.
Definition amp_tracker.hpp:413
void PrecisionPreservation(bool should_preseve_precision)
Switch preservation of precision after tracking on / off.
Definition amp_tracker.hpp:461
SuccessCode ChangePrecision(unsigned new_precision) const
Change precision of tracker to next_precision.
Definition amp_tracker.hpp:1419
AMPTracker(class System const &sys)
Construct an Adaptive Precision tracker, associating to it a System.
Definition amp_tracker.hpp:427
virtual ~AMPTracker()=default
TrackPath is initializing the tracker.
Definition events.hpp:295
Event emitted when the tracker's working precision changes.
Definition events.hpp:139
predict::ExplicitRKPredictor predictor_
Definition base_tracker.hpp:815
ComplexT delta_t_
Definition base_tracker.hpp:826
unsigned predictor_order_
Definition base_tracker.hpp:816
Tracker(System const &sys)
Definition base_tracker.hpp:181
virtual void PostTrackCleanup() const
Definition base_tracker.hpp:712
const System & GetSystem() const
Definition base_tracker.hpp:507
unsigned num_successful_steps_since_stepsize_increase_
Definition base_tracker.hpp:837
virtual void OnInfiniteTruncation() const=0
unsigned digits_final_
Definition base_tracker.hpp:822
correct::NewtonCorrector corrector_
Definition base_tracker.hpp:818
ComplexT endtime_
Definition base_tracker.hpp:824
unsigned NumTotalStepsTaken() const
Definition base_tracker.hpp:517
TupOfVec current_space_
Definition base_tracker.hpp:842
RealT current_stepsize_
Definition base_tracker.hpp:827
unsigned num_steps_since_last_condition_number_computation_
Definition base_tracker.hpp:836
bool reinitialize_stepsize_
Definition base_tracker.hpp:790
TupOfVec temporary_space_
Definition base_tracker.hpp:844
void IncrementBaseCountersFail() const
Increment and reset counters after a failed TrackerIteration().
Definition base_tracker.hpp:761
TupOfVec tentative_space_
Definition base_tracker.hpp:843
auto TrackingTolerance() const
Definition base_tracker.hpp:614
RealT next_stepsize_
Definition base_tracker.hpp:831
unsigned NumVariables() const
Definition base_tracker.hpp:891
std::reference_wrapper< const System > tracked_system_
Definition base_tracker.hpp:787
StepMetadata last_step_
Definition base_tracker.hpp:850
unsigned num_consecutive_failed_steps_
Definition base_tracker.hpp:799
void ResetCountersBase() const
Reset the base-class step counters (successes, failures, consecutive runs, total) to zero.
Definition base_tracker.hpp:727
void SetStepSize(RealT const &new_stepsize) const
Definition base_tracker.hpp:595
unsigned DigitsTrackingTolerance() const
Definition base_tracker.hpp:622
void IncrementBaseCountersSuccess() const
Increment and reset counters after a successful TrackerIteration().
Definition base_tracker.hpp:742
ComplexT current_time_
Definition base_tracker.hpp:825
SuccessCode CheckGoingToInfinity() const
Definition base_tracker.hpp:698
double CriterionCRHS(double const &norm_J_inverse, double const &norm_z, NumErrorT const &tracking_tolerance, AdaptiveMultiplePrecisionConfig const &AMP_config)
Evaluate the right hand side of Criterion C.
Definition amp_criteria.hpp:155
double CriterionBRHS(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)
Evaluate the right hand side of the inequality of Criterion B.
Definition amp_criteria.hpp:104
Definition adaptive_precision_utilities.hpp:35
RealT StepsizeSatisfyingCriterionB(unsigned precision, unsigned digits_B, unsigned num_newton_iterations, unsigned predictor_order=0)
Compute a stepsize satisfying AMP Criterion B with a given precision.
Definition amp_tracker.hpp:136
void ApplyPrecisionDecreaseMargin(int &digits_required, unsigned current_digits, unsigned extra)
Apply B1's precision-decrease hysteresis to one digits requirement (B1 AMP2_update).
Definition amp_tracker.hpp:205
unsigned MinDigitsForLogOfStepsize(real_mp const &log_of_stepsize, real_mp const &time_to_go, unsigned safety_digits=3)
The minimum number of digits based on a log10 of a stepsize.
Definition amp_tracker.hpp:156
unsigned MinDigitsForStepsizeInterval(real_mp const &min_stepsize, real_mp const &max_stepsize, real_mp const &time_to_go)
For a given range of stepsizes under consideration, gives the minimum number of digits.
Definition amp_tracker.hpp:172
void MinimizeTrackingCost(unsigned &new_precision, RealT &new_stepsize, unsigned min_precision, RealT const &min_stepsize, unsigned max_precision, RealT const &max_stepsize, unsigned digits_B, unsigned num_newton_iterations, unsigned predictor_order=0)
Compute precision and stepsize minimizing the ArithmeticCost() of tracking.
Definition amp_tracker.hpp:237
real_mp MinStepSizeForPrecision(unsigned precision, real_mp const &time_to_go, int safety_digits=3)
Just another name for MinTimeForCurrentPrecision.
Definition amp_tracker.hpp:83
double ArithmeticCost(unsigned precision)
Compute the cost function for arithmetic versus precision.
Definition amp_tracker.hpp:112
unsigned ExtraDigitsBeforePrecisionDecrease(unsigned current_precision)
Bertini 1's precision-decrease hysteresis margin (from B1's AMP2_update).
Definition amp_tracker.hpp:190
static AdaptiveMultiplePrecisionConfig AMPConfigFrom(System const &sys)
Construct a ready-to-go set of AMP settings from a system.
Definition config.hpp:366
T max(T const &a, T const &b, T const &c)
Three-argument form of max.
Definition mpfr_extensions.hpp:96
real_mp MinTimeForCurrentPrecision(unsigned precision, real_mp const &time_to_go, int safety_digits=3)
The minimum time that can be represented effectively using a given precision.
Definition amp_tracker.hpp:64
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
unsigned PrecisionIncrement()
The number of digits by which adaptive precision is increased at each step.
Definition num_traits.hpp:145
complex_dbl pow(const complex_dbl &z, int power)
Compute +,- integral powers of a std::complex<double> number.
Definition double_extensions.hpp:92
void SetThreadPrecision(unsigned prec)
Set the precision (digits) for the current thread only (does not touch the global default).
Definition mpfr_complex.hpp:176
double NumErrorT
The numeric type used to hold error/tolerance magnitudes throughout Bertini2 – tracking tolerances,...
Definition num_traits.hpp:48
constexpr unsigned MaxPrecisionAllowed()
The maximum precision (digits) the library will escalate to.
Definition num_traits.hpp:166
bmp::number< mpc_complex_backend< 0 >, bmp::et_on > complex_mp
The arbitrary-precision complex number type.
Definition mpfr_complex.hpp:58
auto DefaultPrecision()
Get the global default precision (digits) for multiprecision numbers.
Definition mpfr_complex.hpp:135
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
@ Success
Definition config.hpp:51
@ MaxNumStepsTaken
Definition config.hpp:58
@ GoingToInfinity
Definition config.hpp:54
@ MatrixSolveFailure
Definition config.hpp:56
@ MaxPrecisionReached
Definition config.hpp:59
@ HigherPrecisionNecessary
Definition config.hpp:52
@ 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
constexpr unsigned LowestMultiplePrecision()
The lowest multiple-precision digit count used (20).
Definition num_traits.hpp:159
unsigned ThreadPrecision()
Get the current thread's precision (digits).
Definition mpfr_complex.hpp:183
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object.
Definition eigen_extensions.hpp:339
T max(T const &a, T const &b, T const &c)
Three-argument form of max.
Definition mpfr_extensions.hpp:96
const T & Get() const
Get the held configuration object of type T.
Definition configured.hpp:94
void Set(T const &t)
Definition configured.hpp:101
Holds the program parameters with respect to Adaptive Multiple Precision.
Definition config.hpp:214
Trait lookup mapping a tracker type to its numeric types, event-emitter type, precision config,...
Definition config.hpp:387