Bertini 2 - C++ Core
Software for Numerical Algebraic Geometry
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) 2015 - 2021 by 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
22// individual authors of this file include:
23// silviana amethyst, university of wisconsin eau claire
24
25
33
34#ifndef BERTINI_AMP_TRACKER_HPP
35#define BERTINI_AMP_TRACKER_HPP
36
37#include <assert.h>
38
39#pragma once
40
42
43
44namespace bertini{
45
46 namespace tracking{
47
48
49 using std::max;
50 using std::min;
51 using std::pow;
52
53 using bertini::max;
54
66 inline
67 mpfr_float MinTimeForCurrentPrecision(unsigned precision, mpfr_float const& time_to_go, int safety_digits = 3)
68 {
69 mpfr_float t = pow( mpfr_float(10), safety_digits-long(precision)) * time_to_go;
70 if (precision==DoublePrecision() && t<1e-150)
71 return mpfr_float("1e-150");
72 else
73 return t;
74 }
75
85 inline
86 mpfr_float MinStepSizeForPrecision(unsigned precision, mpfr_float const& time_to_go, int safety_digits = 3)
87 {
88 return MinTimeForCurrentPrecision(precision, time_to_go, safety_digits);
89 }
90
91
105 inline
106 double ArithmeticCost(unsigned precision)
107 {
108 if (precision==DoublePrecision())
109 return 1;
110 else
111 return 10.35 + 0.13 * precision;
112 }
113
114
115
116
129 inline
130 mpfr_float StepsizeSatisfyingCriterionB(unsigned precision,
131 unsigned digits_B,
132 unsigned num_newton_iterations,
133 unsigned predictor_order = 0)
134 {
135 return pow(mpfr_float(10), -( digits_B - precision )*num_newton_iterations/(predictor_order+1));
136 }
137
138
148 inline
149 unsigned MinDigitsForLogOfStepsize(mpfr_float const& log_of_stepsize, mpfr_float const& time_to_go, unsigned safety_digits = 3)
150 {
151 return (ceil(log_of_stepsize) + ceil(log10(abs(time_to_go))) + safety_digits).convert_to<unsigned>();
152 }
153
164 inline
165 unsigned MinDigitsForStepsizeInterval(mpfr_float const& min_stepsize, mpfr_float const& max_stepsize, mpfr_float const& time_to_go)
166 {
167 return max(MinDigitsForLogOfStepsize(-log10(min_stepsize),time_to_go),
168 MinDigitsForLogOfStepsize(-log10(max_stepsize),time_to_go));
169 }
170
171
192 template<typename RealT>
193 void MinimizeTrackingCost(unsigned & new_precision, RealT & new_stepsize,
194 unsigned min_precision, RealT const& min_stepsize,
195 unsigned max_precision, RealT const& max_stepsize,
196 unsigned digits_B,
197 unsigned num_newton_iterations,
198 unsigned predictor_order = 0)
199 {
200 double min_cost = Eigen::NumTraits<double>::highest();
201 new_precision = MaxPrecisionAllowed()+1; // initialize to an impossible value.
202 new_stepsize = min_stepsize; // initialize to minimum permitted step size.
203
204 auto minimizer_routine =
205 [&min_cost, &new_stepsize, &new_precision, &digits_B, num_newton_iterations, predictor_order, max_stepsize](unsigned p)
206 {
207 RealT candidate_stepsize = min(StepsizeSatisfyingCriterionB(p, digits_B, num_newton_iterations, predictor_order),
208 max_stepsize);
209 using std::abs;
210 double current_cost = ArithmeticCost(p) / abs(double(candidate_stepsize));
211
212 if (current_cost < min_cost)
213 {
214 min_cost = current_cost;
215 new_stepsize = candidate_stepsize;
216 new_precision = p;
217 }
218 };
219
220 unsigned lowest_mp_precision_to_test = min_precision;
221
222 if (min_precision<=DoublePrecision())
223 minimizer_routine(DoublePrecision());
224
225
226 if (lowest_mp_precision_to_test < LowestMultiplePrecision())
227 lowest_mp_precision_to_test = LowestMultiplePrecision();
228 else
229 lowest_mp_precision_to_test = (lowest_mp_precision_to_test/PrecisionIncrement()) * PrecisionIncrement(); // use integer arithmetic to round.
230
231
232 if (max_precision < LowestMultiplePrecision())
233 max_precision = LowestMultiplePrecision();
234 else
235 max_precision = (max_precision/PrecisionIncrement()) * PrecisionIncrement(); // use integer arithmetic to round.
236
237 for (unsigned p = lowest_mp_precision_to_test; p <= max_precision; p+=PrecisionIncrement())
238 minimizer_routine(p);
239 }
240
241
242
243
244
245
246
247
345 class AMPTracker : public Tracker<AMPTracker>
346 {
347 friend class Tracker<AMPTracker>;
348 public:
349
350 typedef Tracker<AMPTracker> Base;
351 typedef typename TrackerTraits<AMPTracker>::EventEmitterType EmitterType;
352
353 enum UpsampleRefinementOption
354 {
355 upsample_refine_off = 0,
356 upsample_refine_on = 1
357 };
358
359
363 AMPTracker(class System const& sys) : Tracker(sys), current_precision_(DefaultPrecision())
364 {
365 Set<PrecConf>(AMPConfigFrom(sys));
366 }
367
368
373 {
374 Set<PrecConf>(AMP_config);
375 }
376
377
378 const unsigned GetCurrentPrecision() const
379 {
380 return current_precision_;
381 }
382
383
389 void PrecisionPreservation(bool should_preseve_precision)
390 {
391 preserve_precision_ = should_preseve_precision;
392 }
393
394
395 virtual ~AMPTracker() = default;
396
397
398 Vec<mpfr_complex> CurrentPoint() const override
399 {
400 if (this->CurrentPrecision()==DoublePrecision())
401 {
402 const auto& curr_vector = std::get<Vec<dbl>>(this->current_space_);
403 Vec<mpfr_complex> returnme(NumVariables());
404 for (unsigned ii = 0; ii < NumVariables(); ++ii)
405 {
406 returnme(ii) = mpfr_complex(curr_vector(ii));
407 }
408 return returnme;
409 }
410 else
411 return std::get<Vec<mpfr_complex>>(this->current_space_);
412 }
413
414
415
416 private:
417
427 SuccessCode TrackerLoopInitialization(mpfr_complex const& start_time,
428 mpfr_complex const& end_time,
429 Vec<mpfr_complex> const& start_point) const override
430 {
431 #ifndef BERTINI_DISABLE_ASSERTS
432 assert(
433 (!preserve_precision_
434 ||
435 -log10(tracking_tolerance_) <= start_point(0).precision())
436 && "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"
437 );
438 #endif
439
440 NotifyObservers(Initializing<AMPTracker,mpfr_complex>(*this,start_time, end_time, start_point));
441
442 initial_precision_ = Precision(start_point(0));
443 DefaultPrecision(initial_precision_);
444 // set up the master current time and the current step size
445
446 current_time_ = start_time;
447 current_time_.precision(initial_precision_);
448
449
450 endtime_highest_precision_ = end_time;
451 endtime_highest_precision_.precision(initial_precision_);
452
453 endtime_ = end_time;
454 endtime_.precision(initial_precision_);
455
456 current_stepsize_.precision(initial_precision_);
458 {
459 mpfr_float segment_length = abs(start_time-end_time)/Get<Stepping>().min_num_steps;
460 SetStepSize(min(NumTraits<mpfr_float>::FromRational(Get<Stepping>().initial_step_size, current_precision_),segment_length));
461 }
462
463 // populate the current space value with the start point, in appropriate precision
464 if (initial_precision_==DoublePrecision())
465 MultipleToDouble(start_point);
466 else
467 MultipleToMultiple(initial_precision_, start_point);
468
469 ChangePrecision<upsample_refine_off>(initial_precision_);
470
471 ResetCounters();
472
473 ChangePrecision<upsample_refine_off>(start_point(0).precision());
474
475
476 auto initial_refinement_code = InitialRefinement();
477
478 #ifndef BERTINI_DISABLE_ASSERTS
479 if (initial_precision_==DoublePrecision()){
480 PrecisionSanityCheck<dbl>();
481 }
482 else{
483 PrecisionSanityCheck<mpfr_complex>();
484 }
485 #endif
486
487 return initial_refinement_code;
488 }
489
490
491
492
493
494 void ResetCounters() const override
495 {
496 Tracker::ResetCountersBase();
497 num_precision_decreases_ = 0;
499 num_successful_steps_since_precision_decrease_ = 0;
500 // initialize to the frequency so guaranteed to compute it the first try
501 num_steps_since_last_condition_number_computation_ = this->Get<Stepping>().frequency_of_CN_estimation;
502 }
503
509 SuccessCode InitialRefinement() const
510 {
511 SuccessCode initial_refinement_code = RefineStoredPoint();
512 if (initial_refinement_code!=SuccessCode::Success)
513 {
514 do {
515 if (current_precision_ > Get<PrecConf>().maximum_precision)
516 {
517 NotifyObservers(SingularStartPoint<EmitterType>(*this));
518 return SuccessCode::SingularStartPoint;
519 }
520
521 if (current_precision_==DoublePrecision())
522 initial_refinement_code = ChangePrecision<upsample_refine_on>(LowestMultiplePrecision());
523 else
524 initial_refinement_code = ChangePrecision<upsample_refine_on>(current_precision_+PrecisionIncrement());
525 }
526 while (initial_refinement_code!=SuccessCode::Success);
527 }
528 return SuccessCode::Success;
529 }
530
531
532
533
539 SuccessCode PreIterationCheck() const override
540 {
541 if (num_successful_steps_taken_ >= Get<Stepping>().max_num_steps)
542 return SuccessCode::MaxNumStepsTaken;
543 if (current_stepsize_ < Get<Stepping>().min_step_size)
544 return SuccessCode::MinStepSizeReached;
545 if (current_precision_ > Get<PrecConf>().maximum_precision)
546 return SuccessCode::MaxPrecisionReached;
547
548 return SuccessCode::Success;
549 }
550
551
552
553
554
555
556
557 void PostTrackCleanup() const override
558 {
559 if (preserve_precision_)
560 ChangePrecision(initial_precision_);
561 NotifyObservers(TrackingEnded<EmitterType>(*this));
562 }
563
571 void CopyFinalSolution(Vec<mpfr_complex> & solution_at_endtime) const override
572 {
573
574 // the current precision is the precision of the output solution point.
575 if (current_precision_==DoublePrecision())
576 {
577 unsigned num_vars = GetSystem().NumVariables();
578 solution_at_endtime.resize(num_vars);
579 for (unsigned ii=0; ii<num_vars; ii++)
580 solution_at_endtime(ii) = mpfr_complex(std::get<Vec<dbl> >(current_space_)(ii));
581 }
582 else
583 {
584 unsigned num_vars = GetSystem().NumVariables();
585 solution_at_endtime.resize(num_vars);
586 for (unsigned ii=0; ii<num_vars; ii++)
587 {
588 solution_at_endtime(ii) = std::get<Vec<mpfr_complex> >(current_space_)(ii);
589 solution_at_endtime(ii).precision(current_precision_);
590 }
591 }
592 }
593
594
595
596
604 SuccessCode TrackerIteration() const override
605 {
606 if (current_precision_==DoublePrecision())
607 return TrackerIteration<dbl>();
608 else
609 return TrackerIteration<mpfr_complex>();
610 }
611
612
620 template <typename ComplexType>
621 SuccessCode TrackerIteration() const // not an override, because it is templated
622 {
623
624 using RealType = typename Eigen::NumTraits<ComplexType>::Real;
625
626 #ifndef BERTINI_DISABLE_ASSERTS
627 assert(PrecisionSanityCheck<ComplexType>() && "precision sanity check failed. some internal variable is not in correct precision");
628 #endif
629
630 NotifyObservers(NewStep<EmitterType>(*this));
631
632 Vec<ComplexType>& predicted_space = std::get<Vec<ComplexType> >(temporary_space_); // this will be populated in the Predict step
633 Vec<ComplexType>& current_space = std::get<Vec<ComplexType> >(current_space_); // the thing we ultimately wish to update
634 ComplexType current_time = ComplexType(current_time_);
635 ComplexType delta_t = ComplexType(delta_t_);
636
637 #ifndef BERTINI_DISABLE_ASSERTS
638 PrecisionSanityCheck<ComplexType>();
639 #endif
640
641 SuccessCode predictor_code = Predict<ComplexType, RealType>(predicted_space, current_space, current_time, delta_t);
642 if (predictor_code==SuccessCode::MatrixSolveFailureFirstPartOfPrediction)
643 {
644 NotifyObservers(FirstStepPredictorMatrixSolveFailure<EmitterType>(*this));
645 InitialMatrixSolveError();
646 return predictor_code;
647 }
648 else if (predictor_code==SuccessCode::MatrixSolveFailure)
649 {
650 NotifyObservers(PredictorMatrixSolveFailure<EmitterType>(*this));
651 NewtonConvergenceError();// decrease stepsize, and adjust precision as necessary
652 return predictor_code;
653 }
654 else if (predictor_code==SuccessCode::HigherPrecisionNecessary)
655 {
656 NotifyObservers(PredictorHigherPrecisionNecessary<EmitterType>(*this));
657 AMPCriterionError<ComplexType>();
658 return predictor_code;
659 }
660
661
662 NotifyObservers(SuccessfulPredict<AMPTracker, ComplexType>(*this, predicted_space));
663
664 Vec<ComplexType>& tentative_next_space = std::get<Vec<ComplexType> >(tentative_space_); // this will be populated in the Correct step
665
666 ComplexType tentative_next_time = current_time + delta_t;
667
668 SuccessCode corrector_code = Correct<ComplexType, RealType>(tentative_next_space,
669 predicted_space,
670 tentative_next_time);
671
672 #ifndef BERTINI_DISABLE_ASSERTS
673 assert(PrecisionSanityCheck<ComplexType>() && "precision sanity check failed. some internal variable is not in correct precision");
674 #endif
675
676 if (corrector_code==SuccessCode::MatrixSolveFailure || corrector_code==SuccessCode::FailedToConverge)
677 {
678 NotifyObservers(CorrectorMatrixSolveFailure<EmitterType>(*this));
679 NewtonConvergenceError();
680 return corrector_code;
681 }
682 else if (corrector_code == SuccessCode::HigherPrecisionNecessary)
683 {
684 NotifyObservers(CorrectorHigherPrecisionNecessary<EmitterType>(*this));
685 AMPCriterionError<ComplexType>();
686 return corrector_code;
687 }
688 else if (corrector_code == SuccessCode::GoingToInfinity)
689 {
690 // there is no corrective action possible...
691 return corrector_code;
692 }
693
694 NotifyObservers(SuccessfulCorrect<AMPTracker, ComplexType>(*this, tentative_next_space));
695
696 // copy the tentative vector into the current space vector;
697 current_space = tentative_next_space;
698 return AdjustAMPStepSuccess<ComplexType>();
699 }
700
701
705 SuccessCode CheckGoingToInfinity() const override
706 {
707 if (current_precision_ == DoublePrecision())
708 return Base::CheckGoingToInfinity<dbl>();
709 else
710 return Base::CheckGoingToInfinity<mpfr_complex>();
711 }
712
720 template <UpsampleRefinementOption refine_if_necessary = upsample_refine_off>
721 SuccessCode UpdatePrecisionAndStepsize() const
722 {
723 SetStepSize(next_stepsize_);
724 return ChangePrecision<refine_if_necessary>(next_precision_);
725 }
726
727
728
729
730
731
732
743 template <typename ComplexType>
744 SuccessCode AdjustAMPStepSuccess() const
745 {
746 // TODO: think about why we consider reducing the stepsize? this is despite documentation stating that it can only increase
747 mpfr_float min_stepsize = current_stepsize_ * NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_fail_factor, current_precision_);
748 mpfr_float max_stepsize = min( current_stepsize_ * NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_success_factor, current_precision_), NumTraits<mpfr_float>::FromRational(Get<Stepping>().max_step_size, current_precision_));
749
750
751 unsigned min_precision = MinRequiredPrecision_BCTol<ComplexType>();
752 unsigned max_precision = max(min_precision,current_precision_);
753
754 if (num_successful_steps_since_stepsize_increase_ < Get<Stepping>().consecutive_successful_steps_before_stepsize_increase)
755 max_stepsize = current_stepsize_; // disallow stepsize changing
756
757
758 if ( (num_successful_steps_since_precision_decrease_ < Get<PrecConf>().consecutive_successful_steps_before_precision_decrease)
759 ||
760 (num_precision_decreases_ >= Get<PrecConf>().max_num_precision_decreases))
761 min_precision = max(min_precision, current_precision_); // disallow precision changing
762
763
764 MinimizeTrackingCost(next_precision_, next_stepsize_,
765 min_precision, min_stepsize,
766 max_precision, max_stepsize,
767 DigitsB<ComplexType>(),
768 Get<NewtonConfig>().max_num_newton_iterations,
770
771
772 if ( (next_stepsize_ > current_stepsize_) || (next_precision_ < current_precision_) )
774 else
776
777
778 if (next_precision_ < current_precision_)
779 {
780 ++num_precision_decreases_;
781 num_successful_steps_since_precision_decrease_ = 0;
782 }
783 else
784 ++num_successful_steps_since_precision_decrease_;
785
786 return UpdatePrecisionAndStepsize();
787 }
788
789
790
791 void InitialMatrixSolveError() const
792 {
793 next_stepsize_ = current_stepsize_;
794
795 if (current_precision_==DoublePrecision())
796 next_precision_ = LowestMultiplePrecision();
797 else
798 next_precision_ = current_precision_+(1+num_consecutive_failed_steps_) * PrecisionIncrement();
799
800 UpdatePrecisionAndStepsize();
801 }
802
814 void NewtonConvergenceError() const
815 {
816 next_precision_ = current_precision_;
817
818 next_stepsize_ = mpfr_float(Get<Stepping>().step_size_fail_factor, CurrentPrecision())*current_stepsize_;
819 while (next_stepsize_ < MinStepSizeForPrecision(next_precision_, abs(current_time_ - endtime_)))
820 {
821 if (next_precision_==DoublePrecision())
822 next_precision_=LowestMultiplePrecision();
823 else
824 next_precision_+=PrecisionIncrement();
825 }
826
827 UpdatePrecisionAndStepsize();
828 }
829
830
831
832
833
834
835
845 template<typename ComplexType>
846 void AMPCriterionError() const
847 {
848 using RealT = typename Eigen::NumTraits<ComplexType>::Real;
849
850 unsigned min_next_precision; // sure, i could use a trigraph here, but it'd be terrible
851 if (current_precision_==DoublePrecision())
852 min_next_precision = LowestMultiplePrecision(); // precision increases
853 else
854 min_next_precision = current_precision_ + (1+num_consecutive_failed_steps_)*PrecisionIncrement(); // precision increases
855
856
857 mpfr_float min_stepsize = MinStepSizeForPrecision(current_precision_, abs(current_time_ - endtime_));
858 mpfr_float max_stepsize = current_stepsize_ * NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_fail_factor,current_precision_); // Stepsize decreases.
859
860 if (min_stepsize > max_stepsize)
861 {
862 // stepsizes are incompatible, must increase precision
863 next_precision_ = min_next_precision;
864 // decrease stepsize somewhat less than the fail factor
865 next_stepsize_ = max(current_stepsize_ * (1+NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_fail_factor,current_precision_))/2, min_stepsize);
866 }
867 else
868 {
869 unsigned digits_B = DigitsB<ComplexType>();
870
871 unsigned min_precision = max(min_next_precision,
872 digits_B,
873 DigitsC<ComplexType>(),
874 MinDigitsForStepsizeInterval(min_stepsize, max_stepsize, abs(current_time_ - endtime_)),
876 );
877
878 unsigned a = ceil(digits_B - (predictor_order_+1)* -log10(max_stepsize)/Get<NewtonConfig>().max_num_newton_iterations).convert_to<unsigned>();
879
880 unsigned max_precision = max(min_precision, a);
881
882 MinimizeTrackingCost(next_precision_, next_stepsize_,
883 min_precision, min_stepsize,
884 Get<PrecConf>().maximum_precision, max_stepsize,
885 digits_B,
886 Get<NewtonConfig>().max_num_newton_iterations,
888 }
889
890 UpdatePrecisionAndStepsize();
891 }
892
893
894
895
896
900 template<typename ComplexType>
901 NumErrorT B_RHS() const
902 {
903 return max(amp::CriterionBRHS(this->norm_J_,
904 this->norm_J_inverse_,
905 Get<NewtonConfig>().max_num_newton_iterations,
907 this->size_proportion_,
908 Get<PrecConf>()), NumErrorT(0));
909 }
910
911
912
913
929 template<typename ComplexType>
930 unsigned DigitsB() const
931 {
932 return unsigned(B_RHS<ComplexType>());
933 }
934
935
936
937
938
942 template<typename ComplexType>
943 NumErrorT C_RHS() const
944 {
945 return max(amp::CriterionCRHS(this->norm_J_inverse_,
946 NumErrorT(std::get<Vec<ComplexType> > (current_space_).norm()),
948 Get<PrecConf>()), NumErrorT(0));
949 }
950
951
952
966 template<typename ComplexType>
967 unsigned DigitsC() const
968 {
969 return unsigned(C_RHS<ComplexType>());
970 }
971
972
973
974
975
996 template <typename ComplexType>
997 unsigned MinRequiredPrecision_BCTol() const
998 {
999 return max(DigitsB<ComplexType>(),
1000 DigitsC<ComplexType>(),
1002 DoublePrecision());
1003 }
1004
1005
1006
1007
1008
1009
1010
1012 //
1013 // overrides for counter adjustment after a TrackerIteration()
1014 //
1016
1020 void OnStepSuccess() const override
1021 {
1023 NotifyObservers(SuccessfulStep<EmitterType>(*this));
1024 }
1025
1029 void OnStepFail() const override
1030 {
1032 num_successful_steps_since_precision_decrease_ = 0;
1034 NotifyObservers(FailedStep<EmitterType>(*this));
1035 }
1036
1037
1038
1039 void OnInfiniteTruncation() const override
1040 {
1041 NotifyObservers(InfinitePathTruncation<EmitterType>(*this));
1042 }
1043
1044
1046 //
1047 // Predict and Correct functions
1048 //
1050
1051
1052
1053
1054
1070 template<typename ComplexType, typename RealType>
1071 SuccessCode Predict(Vec<ComplexType> & predicted_space,
1072 const Vec<ComplexType>& current_space,
1073 ComplexType const& current_time, ComplexType const& delta_t) const
1074 {
1075
1076
1077
1078
1079 static_assert(std::is_same< typename Eigen::NumTraits<RealType>::Real,
1080 typename Eigen::NumTraits<ComplexType>::Real>::value,
1081 "underlying complex type and the type for comparisons must match");
1082
1083
1084 if (predictor_->HasErrorEstimate())
1085 return predictor_->Predict(predicted_space,
1086 this->error_estimate_,
1087 this->size_proportion_,
1088 this->norm_J_,
1089 this->norm_J_inverse_,
1091 current_space, current_time,
1092 delta_t,
1095 Get<Stepping>().frequency_of_CN_estimation,
1097 Get<PrecConf>());
1098 else
1099 return predictor_->Predict(predicted_space,
1100 this->size_proportion_,
1101 this->norm_J_,
1102 this->norm_J_inverse_,
1104 current_space, current_time,
1105 delta_t,
1108 Get<Stepping>().frequency_of_CN_estimation,
1110 Get<PrecConf>());
1111 }
1112
1113
1114
1129 template<typename ComplexType, typename RealType>
1130 SuccessCode Correct(Vec<ComplexType> & corrected_space,
1131 Vec<ComplexType> const& current_space,
1132 ComplexType const& current_time) const
1133 {
1134 static_assert(std::is_same< typename Eigen::NumTraits<RealType>::Real,
1135 typename Eigen::NumTraits<ComplexType>::Real>::value,
1136 "underlying complex type and the type for comparisons must match");
1137
1138
1139
1140
1141 return corrector_->Correct(corrected_space,
1142 this->norm_delta_z_,
1143 this->norm_J_,
1144 this->norm_J_inverse_,
1147 current_space,
1148 current_time,
1150 Get<NewtonConfig>().min_num_newton_iterations,
1151 Get<NewtonConfig>().max_num_newton_iterations,
1152 Get<PrecConf>());
1153 }
1154
1155
1156
1164 SuccessCode RefineStoredPoint() const
1165 {
1166 SuccessCode code;
1167 if (current_precision_==DoublePrecision())
1168 {
1169 code = RefineImpl<dbl>(std::get<Vec<dbl> >(temporary_space_),std::get<Vec<dbl> >(current_space_), dbl(current_time_));
1170 if (code == SuccessCode::Success)
1171 std::get<Vec<dbl> >(current_space_) = std::get<Vec<dbl> >(temporary_space_);
1172 }
1173 else
1174 {
1175 code = RefineImpl<mpfr_complex>(std::get<Vec<mpfr_complex> >(temporary_space_),std::get<Vec<mpfr_complex> >(current_space_), current_time_);
1176 if (code == SuccessCode::Success)
1177 std::get<Vec<mpfr_complex> >(current_space_) = std::get<Vec<mpfr_complex> >(temporary_space_);
1178 }
1179 return code;
1180 }
1181
1182
1183
1198 template <typename ComplexType>
1199 SuccessCode RefineImpl(Vec<ComplexType> & new_space,
1200 Vec<ComplexType> const& start_point, ComplexType const& current_time) const
1201 {
1202 using RealType = typename Eigen::NumTraits<ComplexType>::Real;
1203
1204 static_assert(std::is_same< typename Eigen::NumTraits<RealType>::Real,
1205 typename Eigen::NumTraits<ComplexType>::Real>::value,
1206 "underlying complex type and the type for comparisons must match");
1207
1208 auto target_precision = Precision(current_time);
1209 assert(Precision(start_point)==target_precision);
1210 ChangePrecision(target_precision);
1211 Precision(new_space,target_precision);
1212
1213
1214
1215
1216 return corrector_->Correct(new_space,
1217 this->norm_delta_z_,
1218 this->norm_J_,
1219 this->norm_J_inverse_,
1222 start_point,
1223 current_time,
1225 Get<NewtonConfig>().min_num_newton_iterations,
1226 Get<NewtonConfig>().max_num_newton_iterations,
1227 Get<PrecConf>());
1228 }
1229
1230
1231
1232
1233
1234
1250 template <typename ComplexType>
1251 SuccessCode RefineImpl(Vec<ComplexType> & new_space,
1252 Vec<ComplexType> const& start_point, ComplexType const& current_time,
1253 NumErrorT const& tolerance, unsigned max_iterations) const
1254 {
1255 auto target_precision = Precision(current_time);
1256 assert(Precision(start_point)==target_precision);
1257 ChangePrecision(target_precision);
1258 Precision(new_space,target_precision);
1259
1260 return corrector_->Correct(new_space,
1261 this->norm_delta_z_,
1262 this->norm_J_,
1263 this->norm_J_inverse_,
1266 start_point,
1267 current_time,
1268 tolerance,
1269 1,
1270 max_iterations,
1271 Get<PrecConf>());
1272 }
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1288 //
1289 // Functions for converting between precision types
1290 //
1292
1293 public:
1302 template <UpsampleRefinementOption refine_if_necessary = upsample_refine_off>
1303 SuccessCode ChangePrecision(unsigned new_precision) const
1304 {
1305 if (new_precision==current_precision_) // no op
1306 return SuccessCode::Success;
1307
1308 NotifyObservers(PrecisionChanged<EmitterType>(*this,current_precision_,new_precision));
1309
1310
1311 bool upsampling_needed = new_precision > current_precision_;
1312 // reset the counter for estimating the condition number.
1313 num_steps_since_last_condition_number_computation_ = this->Get<Stepping>().frequency_of_CN_estimation;
1314
1315 if (new_precision==DoublePrecision() && current_precision_>DoublePrecision())
1316 {
1317 // convert from multiple precision to double precision
1318 MultipleToDouble();
1319 }
1320 else if(new_precision > DoublePrecision() && current_precision_ == DoublePrecision())
1321 {
1322 // convert from double to multiple precision
1323 DoubleToMultiple(new_precision);
1324 #ifndef BERTINI_DISABLE_ASSERTS
1325 assert(PrecisionSanityCheck<mpfr_complex>() && "precision sanity check failed. some internal variable is not in correct precision");
1326 #endif
1327 }
1328 else
1329 {
1330 MultipleToMultiple(new_precision);
1331 #ifndef BERTINI_DISABLE_ASSERTS
1332 assert(PrecisionSanityCheck<mpfr_complex>() && "precision sanity check failed. some internal variable is not in correct precision");
1333 #endif
1334 }
1335
1336 if (refine_if_necessary && upsampling_needed)
1337 return RefineStoredPoint();
1338 else
1339 return SuccessCode::Success;
1340 }
1341
1342
1343
1344
1345
1346 private:
1347
1355 void DoubleToDouble(Vec<dbl> const& source_point) const
1356 {
1357 #ifndef BERTINI_DISABLE_ASSERTS
1358 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.");
1359 #endif
1360
1361 current_precision_ = DoublePrecision();
1362 DefaultPrecision(DoublePrecision());
1363
1364 GetSystem().precision(16);
1365
1366 std::get<Vec<dbl> >(current_space_) = source_point;
1367 }
1368
1374 void DoubleToDouble() const
1375 {
1376 DoubleToDouble(std::get<Vec<dbl> >(current_space_));
1377 }
1378
1379
1380
1388 void MultipleToDouble(Vec<mpfr_complex> const& source_point) const
1389 {
1390 #ifndef BERTINI_DISABLE_ASSERTS
1391 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.");
1392 #endif
1393
1394 AdjustCurrentPrecision(DoublePrecision());
1395
1396 GetSystem().precision(DoublePrecision());
1397
1398 // copy the current space in.
1399 if (std::get<Vec<dbl> >(current_space_).size()!=source_point.size())
1400 std::get<Vec<dbl> >(current_space_).resize(source_point.size());
1401
1402 for (unsigned ii=0; ii<source_point.size(); ii++)
1403 std::get<Vec<dbl> >(current_space_)(ii) = dbl(source_point(ii));
1404
1405 endtime_.precision(DoublePrecision()); // i question this one 2021-04-12
1406 }
1407
1413 void MultipleToDouble() const
1414 {
1415 MultipleToDouble(std::get<Vec<mpfr_complex> >(current_space_));
1416 }
1417
1418
1419
1430 void DoubleToMultiple(unsigned new_precision, Vec<dbl> const& source_point) const
1431 {
1432 #ifndef BERTINI_DISABLE_ASSERTS
1433 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.");
1434 assert(new_precision > DoublePrecision() && "must convert to precision higher than DoublePrecision when converting to multiple precision");
1435 #endif
1436
1437 AdjustCurrentPrecision(new_precision);
1438 CopyToCurrentSpace(source_point);
1439 AdjustInternalsPrecision(new_precision);
1440 AdjustTemporariesPrecision(new_precision);
1441
1442 #ifndef BERTINI_DISABLE_ASSERTS
1443 PrecisionSanityCheck<mpfr_complex>();
1444 #endif
1445 }
1446
1447
1448
1456 void DoubleToMultiple(unsigned new_precision) const
1457 {
1458 DoubleToMultiple( new_precision, std::get<Vec<dbl> >(current_space_));
1459 }
1460
1461
1462
1463
1464
1474 void MultipleToMultiple(unsigned new_precision, Vec<mpfr_complex> const& source_point) const
1475 {
1476 #ifndef BERTINI_DISABLE_ASSERTS
1477 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.");
1478 assert(new_precision > DoublePrecision() && "must convert to precision higher than DoublePrecision when converting to multiple precision");
1479 #endif
1480
1481 AdjustCurrentPrecision(new_precision);
1482 CopyToCurrentSpace(source_point);
1483 AdjustInternalsPrecision(new_precision);
1484 AdjustTemporariesPrecision(new_precision);
1485
1486 #ifndef BERTINI_DISABLE_ASSERTS
1487 PrecisionSanityCheck<mpfr_complex>();
1488 #endif
1489 }
1490
1491
1499 void MultipleToMultiple(unsigned new_precision) const
1500 {
1501 MultipleToMultiple( new_precision, std::get<Vec<mpfr_complex> >(current_space_));
1502 }
1503
1504
1505
1506
1507
1508 void AdjustCurrentPrecision(unsigned new_precision) const
1509 {
1510 previous_precision_ = current_precision_;
1511 current_precision_ = new_precision;
1512 DefaultPrecision(new_precision);
1513 }
1514
1515
1516 void CopyToCurrentSpace(Vec<dbl> const& source_point) const
1517 {
1518 auto& space = std::get<Vec<mpfr_complex> >(current_space_);
1519 if (space.size()!=source_point.size())
1520 space.resize(source_point.size());
1521 for (unsigned ii=0; ii<source_point.size(); ii++)
1522 space(ii) = mpfr_complex(source_point(ii));
1523 }
1524
1525 void CopyToCurrentSpace(Vec<mpfr_complex> const& source_point) const
1526 {
1527 auto& space = std::get<Vec<mpfr_complex> >(current_space_);
1528 if (space.size()!=source_point.size())
1529 space.resize(source_point.size());
1530 space = source_point;
1531 }
1532
1533 void AdjustInternalsPrecision(unsigned new_precision) const
1534 {
1535 GetSystem().precision(new_precision);
1536 predictor_->ChangePrecision(new_precision);
1537 corrector_->ChangePrecision(new_precision);
1538
1539 endtime_ = endtime_highest_precision_;
1540
1541 endtime_.precision(new_precision);
1542 current_stepsize_.precision(new_precision);
1543 delta_t_.precision(new_precision);
1544 current_time_.precision(new_precision);
1545
1546 Precision(std::get<Vec<mpfr_complex> >(current_space_),new_precision);
1547 }
1548
1556 void AdjustTemporariesPrecision(unsigned new_precision) const
1557 {
1558 const auto num_vars = GetSystem().NumVariables();
1559
1560 // the current_space value is adjusted in the appropriate ChangePrecision function
1561 std::get<Vec<mpfr_complex> >(tentative_space_).resize(num_vars);
1562 Precision(std::get<Vec<mpfr_complex> >(tentative_space_), new_precision);
1563
1564 std::get<Vec<mpfr_complex> >(temporary_space_).resize(num_vars);
1565 Precision(std::get<Vec<mpfr_complex> >(temporary_space_), new_precision);
1566 }
1567
1568
1569
1570
1576 template<typename ComplexType>
1577 bool PrecisionSanityCheck() const
1578 {
1579
1580 if constexpr (std::is_same<ComplexType, dbl>::value){
1581 return true;
1582 }
1583
1584 if constexpr (std::is_same<ComplexType, mpfr_complex>::value){
1585 assert(DefaultPrecision()==current_precision_ && "current precision differs from the default precision");
1586 assert(GetSystem().precision() == current_precision_ && "tracked system is out of precision");
1587
1588 assert(std::get<Vec<mpfr_complex> >(current_space_)(0).precision() == current_precision_ && "current space out of precision");
1589 assert(std::get<Vec<mpfr_complex> >(tentative_space_)(0).precision() == current_precision_ && "tentative space out of precision");
1590 assert(std::get<Vec<mpfr_complex> >(temporary_space_)(0).precision() == current_precision_ && "temporary space out of precision");
1591 assert(Precision(current_stepsize_) == current_precision_ && "current_stepsize_ out of precision");
1592 assert(Precision(delta_t_) == current_precision_ && "delta_t_ out of precision");
1593 assert(Precision(endtime_) == current_precision_ && "endtime_ out of precision");
1594 assert(Precision(current_time_) == current_precision_ && "current_time_ out of precision");
1595 assert(current_precision_ <= MaxPrecisionAllowed() && "current_precision_ exceeds max precision");
1596 assert(predictor_->precision() == current_precision_ && "predictor_ out of precision");
1597 return true;
1598 }
1599
1600 }
1601
1602
1603
1604
1611 //
1612
1613
1614
1615
1616
1618 // state variables
1620 bool preserve_precision_ = false;
1621
1622 mutable unsigned previous_precision_;
1623 mutable unsigned current_precision_;
1624 mutable unsigned next_precision_;
1625 mutable unsigned num_precision_decreases_;
1626 mutable unsigned initial_precision_;
1627 mutable unsigned num_successful_steps_since_precision_decrease_;
1628
1629 mutable mpfr_complex endtime_highest_precision_;
1630
1631 public:
1632
1633 unsigned CurrentPrecision() const override
1634 {
1635 return current_precision_;
1636 }
1637 }; // re: class Tracker
1638
1639 } // namespace tracking
1640} // namespace bertini
1641
1642
1643#endif
1644
1645
1646
unsigned MinDigitsForLogOfStepsize(mpfr_float const &log_of_stepsize, mpfr_float const &time_to_go, unsigned safety_digits=3)
The minimum number of digits based on a log10 of a stepsize.
Definition amp_tracker.hpp:149
unsigned MinDigitsForStepsizeInterval(mpfr_float const &min_stepsize, mpfr_float const &max_stepsize, mpfr_float const &time_to_go)
For a given range of stepsizes under consideration, gives the minimum number of digits.
Definition amp_tracker.hpp:165
mpfr_float MinTimeForCurrentPrecision(unsigned precision, mpfr_float const &time_to_go, int safety_digits=3)
Definition amp_tracker.hpp:67
mpfr_float MinStepSizeForPrecision(unsigned precision, mpfr_float const &time_to_go, int safety_digits=3)
Just another name for MinTimeForCurrentPrecision.
Definition amp_tracker.hpp:86
mpfr_float 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:130
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:193
double ArithmeticCost(unsigned precision)
Compute the cost function for arithmetic versus precision.
Definition amp_tracker.hpp:106
T max(T const &a, T const &b, T const &c)
Three-argument form of max.
Definition mpfr_extensions.hpp:98
Contains the abstract base Tracker type, from which all other Trackers inherit.
void NotifyObservers(AnyEvent const &e) const
Sends an Event (more particularly, AnyEvent) to all watching observers of this object.
Definition observable.hpp:90
The fundamental polynomial system class for Bertini2.
Definition system/system.hpp:99
void precision(unsigned new_precision) const
size_t NumVariables() const
Functor-like class for tracking paths on a system.
Definition amp_tracker.hpp:346
void PrecisionSetup(AdaptiveMultiplePrecisionConfig const &AMP_config)
Special additional setup call for the AMPTracker, selecting the config for adaptive precision.
Definition amp_tracker.hpp:372
void PrecisionPreservation(bool should_preseve_precision)
Switch preservation of precision after tracking on / off.
Definition amp_tracker.hpp:389
SuccessCode ChangePrecision(unsigned new_precision) const
Definition amp_tracker.hpp:1303
AMPTracker(class System const &sys)
Construct an Adaptive Precision tracker, associating to it a System.
Definition amp_tracker.hpp:363
unsigned predictor_order_
Definition base_tracker.hpp:574
NumErrorT error_estimate_
Definition base_tracker.hpp:610
CT current_time_
Definition base_tracker.hpp:586
const System & GetSystem() const
Definition base_tracker.hpp:373
unsigned num_successful_steps_since_stepsize_increase_
Definition base_tracker.hpp:598
NumErrorT size_proportion_
Definition base_tracker.hpp:614
unsigned digits_final_
Definition base_tracker.hpp:580
CT endtime_
Definition base_tracker.hpp:585
RT current_stepsize_
Definition base_tracker.hpp:588
NumErrorT condition_number_estimate_
Definition base_tracker.hpp:609
TupOfVec current_space_
Definition base_tracker.hpp:604
unsigned num_steps_since_last_condition_number_computation_
Definition base_tracker.hpp:597
bool reinitialize_stepsize_
Definition base_tracker.hpp:562
NumErrorT norm_J_inverse_
Definition base_tracker.hpp:612
TupOfVec temporary_space_
Definition base_tracker.hpp:606
void IncrementBaseCountersFail() const
Increment and reset counters after a failed TrackerIteration()
Definition base_tracker.hpp:536
CT delta_t_
Definition base_tracker.hpp:587
void SetStepSize(RT const &new_stepsize) const
Definition base_tracker.hpp:393
unsigned num_successful_steps_taken_
Definition base_tracker.hpp:566
TupOfVec tentative_space_
Definition base_tracker.hpp:605
unsigned digits_tracking_tolerance_
Definition base_tracker.hpp:581
std::reference_wrapper< const System > tracked_system_
Definition base_tracker.hpp:559
unsigned num_consecutive_failed_steps_
Definition base_tracker.hpp:568
NumErrorT tracking_tolerance_
Definition base_tracker.hpp:582
NumErrorT norm_delta_z_
Definition base_tracker.hpp:613
NumErrorT norm_J_
Definition base_tracker.hpp:611
void IncrementBaseCountersSuccess() const
Increment and reset counters after a successful TrackerIteration()
Definition base_tracker.hpp:519
dbl pow(const dbl &z, int power)
Definition double_extensions.hpp:88
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object. If the object is empty, it's the precision of a default-constru...
Definition eigen_extensions.hpp:292
T max(T const &a, T const &b, T const &c)
Three-argument form of max.
Definition mpfr_extensions.hpp:98
Definition trackers/config.hpp:154