Bertini 2 - C++ Core
Software for Numerical Algebraic Geometry
Loading...
Searching...
No Matches
cauchy.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//cauchy_endgame.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//cauchy_endgame.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 cauchy_endgame.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// Tim Hodges, Colorado State University
25
26
27
28#pragma once
29
31
32
39
40namespace bertini{ namespace endgame{
41
42
169template<typename PrecT>
170class CauchyEndgame :
171 public virtual EndgameBase<CauchyEndgame<PrecT>, PrecT>
172{
173public:
174 using BaseEGT = EndgameBase<CauchyEndgame<PrecT>, PrecT>;
175 using FinalEGT = CauchyEndgame<PrecT>;
176 using TrackerType = typename PrecT::TrackerType;
177
178 using BaseComplexType = typename tracking::TrackerTraits<TrackerType>::BaseComplexType;
179 using BaseRealType = typename tracking::TrackerTraits<TrackerType>::BaseRealType;
180
181 using EmitterType = CauchyEndgame<PrecT>;
182
183protected:
184
185 using EndgameBase<CauchyEndgame<PrecT>, PrecT>::NotifyObservers;
186
187
188
189
190 using TupleOfTimes = typename BaseEGT::TupleOfTimes;
191 using TupleOfSamps = typename BaseEGT::TupleOfSamps;
192
193 using BCT = BaseComplexType;
194 using BRT = BaseRealType;
195
196 using Configs = typename AlgoTraits<FinalEGT>::NeededConfigs;
197 using ConfigsAsTuple = typename Configs::ToTuple;
198
202 mutable TupleOfTimes pseg_times_;
206 mutable TupleOfSamps pseg_samples_; //samples used for the first approximation.
210 mutable TupleOfTimes cauchy_times_;
214 mutable TupleOfSamps cauchy_samples_;
215
216
217
218
219
220
221public:
222
223
224
225
229 template<typename CT>
231 {
232 std::get<TimeCont<CT> >(pseg_times_).clear();
233 std::get<TimeCont<CT> >(cauchy_times_).clear();
234 std::get<SampCont<CT> >(pseg_samples_).clear();
235 std::get<SampCont<CT> >(cauchy_samples_).clear();}
236
239 template<typename CT>
240 void SetPSEGTimes(TimeCont<CT> pseg_times_to_set)
241 { std::get<TimeCont<CT> >(pseg_times_) = pseg_times_to_set;}
242
246 template<typename CT>
247 TimeCont<CT>& GetPSEGTimes() {return std::get<TimeCont<CT> >(pseg_times_);}
248 template<typename CT>
249 const TimeCont<CT>& GetPSEGTimes() const {return std::get<TimeCont<CT> >(pseg_times_);}
250
254 template<typename CT>
255 void SetPSEGSamples(SampCont<CT> const& pseg_samples_to_set) { std::get<SampCont<CT> >(pseg_samples_) = pseg_samples_to_set;}
256
262 template<typename CT>
263 SampCont<CT>& GetPSEGSamples() {return std::get<SampCont<CT> >(pseg_samples_);}
264 template<typename CT>
265 const SampCont<CT>& GetPSEGSamples() const {return std::get<SampCont<CT> >(pseg_samples_);}
269 template<typename CT>
270 void SetCauchySamples(SampCont<CT> const& cauchy_samples_to_set)
271 {
272 std::get<SampCont<CT> >(cauchy_samples_) = cauchy_samples_to_set;
273 }
274
280 template<typename CT>
281 SampCont<CT>& GetCauchySamples()
282 {
283 return std::get<SampCont<CT> >(cauchy_samples_);
284 }
285 template<typename CT>
286 const SampCont<CT>& GetCauchySamples() const { return std::get<SampCont<CT> >(cauchy_samples_); }
287
288
292 template<typename CT>
293 void SetCauchyTimes(TimeCont<CT> const& cauchy_times_to_set)
294 {
295 std::get<TimeCont<CT> >(cauchy_times_) = cauchy_times_to_set;
296 }
297
301 template<typename CT>
302 TimeCont<CT>& GetCauchyTimes()
303 {
304 return std::get<TimeCont<CT> >(cauchy_times_);
305 }
306 template<typename CT>
307 const TimeCont<CT>& GetCauchyTimes() const
308 {
309 return std::get<TimeCont<CT> >(cauchy_times_);
310 }
311
312
313 const BCT& LatestTimeImpl() const
314 {
315 return GetPSEGTimes<BCT>().back();
316 }
317
318
322 void SetCauchySettings(CauchyConfig const& new_cauchy_settings)
323 {
324 this->template Set(new_cauchy_settings);
325 }
326
330 const auto& GetCauchySettings() const
331 {
332 return this->template Get<CauchyConfig>();
333 }
334
335
336 explicit CauchyEndgame(TrackerType const& tr,
337 const ConfigsAsTuple& settings )
338 : BaseEGT(tr, settings), EndgamePrecPolicyBase<TrackerType>(tr)
339 { }
340
341 template< typename... Ts >
342 CauchyEndgame(TrackerType const& tr, const Ts&... ts ) : CauchyEndgame(tr, Configs::Unpermute( ts... ) )
343 {}
344
345
346 virtual ~CauchyEndgame() = default;
347
348 void ValidateConfigs()
349 {
350 if (this->EndgameSettings().num_sample_points < 3) // need to make sure we won't track right through the origin.
351 {
352 std::stringstream err_msg;
353 err_msg << "ERROR: The number of sample points " << this->EndgameSettings().num_sample_points << " for circle tracking must be >= 3";
354 throw std::runtime_error(err_msg.str());
355 }
356 }
357
375 template<typename CT>
376 SuccessCode CircleTrack(CT const& target_time)
377 {
378 using bertini::Precision;
379 using RT = typename Eigen::NumTraits<CT>::Real;
380 using std::acos;
381
382 ValidateConfigs();
383
384 auto& circle_times = std::get<TimeCont<CT> >(cauchy_times_);
385 auto& circle_samples = std::get<SampCont<CT> >(cauchy_samples_);
386
387 CT starting_time = circle_times.back(); // take a COPY here, so won't invalidate it later
388
389 // the initial sample has already been added to the sample repo... so don't do that here, please
390
391 const auto num_vars = this->GetSystem().NumVariables();
392
393 for (unsigned ii = 0; ii < this->EndgameSettings().num_sample_points; ++ii)
394 {
395 const Vec<CT>& current_sample = circle_samples.back();
396 const CT& current_time = circle_times.back();
397
398#ifndef BERTINI_DISABLE_PRECISION_CHECKS
399 if (Precision(current_time)!=Precision(current_sample)){
400 std::stringstream err_msg;
401 err_msg << "current time and sample for circle track must be of same precision. respective precisions: " << Precision(current_time) << " " << Precision(current_sample) << std::endl;
402 throw std::runtime_error(err_msg.str());
403 }
404#endif
405
406 //set up the time value for the next sample.
407 using std::polar;
408
409#ifndef USE_BMP_COMPLEX
410 using bertini::polar;
411#endif
412
413 //Generalized since we could have a nonzero target time.
414 using std::arg;
415 RT radius = abs(starting_time - target_time), angle = arg(starting_time - target_time); // generalized for nonzero target_time.
416
417 auto next_sample = Vec<CT>(num_vars);
418 CT next_time = (ii==this->EndgameSettings().num_sample_points-1)
419 ?
420 starting_time
421 :
422 polar(radius, (ii+1)*2*acos(static_cast<RT>(-1)) / (this->EndgameSettings().num_sample_points) + angle) + target_time;
423 // If we are tracking to a nonzero target time we need to shift our values to track to. This is a step that may not be needed if target_time = 0
424 ;
425
426
427 auto tracking_success = this->GetTracker().TrackPath(next_sample, current_time, next_time, current_sample);
428 if (tracking_success != SuccessCode::Success)
429 {
430 return tracking_success;
431 }
432
433 NotifyObservers(CircleAdvanced<EmitterType>(*this, next_sample, next_time));
434
435
436 this->EnsureAtPrecision(next_time,Precision(next_sample)); assert(Precision(next_time)==Precision(next_sample));
437
438 // auto refinement_success = this->RefineSample(next_sample, next_sample, next_time,
439 // this->FinalTolerance() * this->EndgameSettings().sample_point_refinement_factor,
440 // this->EndgameSettings().max_num_newton_iterations);
441 // if (refinement_success != SuccessCode::Success)
442 // {
443 // return refinement_success;
444 // }
445
446 // this->EnsureAtPrecision(next_time,Precision(next_sample));
447 // assert(Precision(next_time)==Precision(next_sample));
448
449 AddToCauchyData(next_time, next_sample);
450
451 // NotifyObservers(SampleRefined<EmitterType>(*this));
452 }
453
454 return SuccessCode::Success;
455
456 }//end CircleTrack
457
458 template<typename CT>
459 void AddToCauchyData(CT const& time, Vec<CT> const& sample)
460 {
461 std::get<TimeCont<CT>>(cauchy_times_).push_back(time);
462 std::get<SampCont<CT>>(cauchy_samples_).push_back(sample);
463 }
464
465 template<typename CT>
466 void AddToPSData(CT const& time, Vec<CT> const& sample)
467 {
468 std::get<TimeCont<CT>>(pseg_times_).push_back(time);
469 std::get<SampCont<CT>>(pseg_samples_).push_back(sample);
470 }
471
489 template<typename CT>
490 auto ComputeCOverK() const -> typename Eigen::NumTraits<CT>::Real
491 {//Obtain samples for computing C over K.
492 using RT = typename Eigen::NumTraits<CT>::Real;
493 using std::abs;
494 using std::log;
495
496 const auto& pseg_samples = std::get<SampCont<CT> >(pseg_samples_);
497
498 assert(pseg_samples.size()>=3);
499 const Vec<CT> & sample0 = pseg_samples[0];
500 const Vec<CT> & sample1 = pseg_samples[1];
501 const Vec<CT> & sample2 = pseg_samples[2];
502
503 Vec<CT> rand_vector = Vec<CT>::Random(sample0.size()); //should be a row vector for ease in multiplying.
504
505
506 // //DO NOT USE Eigen .dot() it will do conjugate transpose which is not what we want.
507 // //Also, the .transpose*rand_vector returns an expression template that we do .norm of since abs is not available for that expression type.
508 RT estimate = abs(log(abs((((sample2 - sample1).transpose()*rand_vector).template lpNorm<Eigen::Infinity>())/(((sample1 - sample0).transpose()*rand_vector).template lpNorm<Eigen::Infinity>()))));
509 estimate = abs(log(RT(this->EndgameSettings().sample_factor)))/estimate;
510 if (estimate < 1)
511 return RT(1);
512 else
513 return estimate;
514
515 }//end ComputeCOverK
516
517
532 template<typename CT>
533 bool CheckForCOverKStabilization(TimeCont<CT> const& c_over_k_array) const
534 {
535 using RT = typename Eigen::NumTraits<CT>::Real;
536 using std::abs;
537
538 assert(c_over_k_array.size()>=GetCauchySettings().num_needed_for_stabilization);
539 for(unsigned ii = 1; ii < GetCauchySettings().num_needed_for_stabilization ; ++ii)
540 {
541 RT a = abs(c_over_k_array[ii-1]);
542 RT b = abs(c_over_k_array[ii]);
543
544 typename Eigen::NumTraits<CT>::Real divide = a;
545
546 if(a < b)
547 divide = a/b;
548 else
549 divide = b/a;
550
551 if(divide < GetCauchySettings().minimum_for_c_over_k_stabilization)
552 return false;
553 }
554 return true;
555
556 }//end CheckForCOverKStabilization
557
558
559 /*
560 Input: A time value and the space value above that time.
561
562 Output: An mpfr_float representing a tolerance threshold for declaring a loop to be closed.
563 Details: Used in Bertini 1 as a heuristic for computing separatedness of roots. Decided to not be used since assumptions for this tolerance are not usually met.
564 template<typename CT>
565 mpfr_float FindToleranceForClosedLoop(CT x_time, Vec<CT> x_sample)
566 {
567 auto degree_max = std::max(this->GetTracker().AMP_config_.degree_bound,mpfr_float("2.0"));
568 auto K = this->GetTracker().AMP_config_.coefficient_bound;
569 mpfr_float N;
570 mpfr_float M;
571 mpfr_float L;
572 if(max_closed_loop_tolerance_ < min_closed_loop_tolerance_)
573 {
574 max_closed_loop_tolerance_ = min_closed_loop_tolerance_;
575 }
576 auto error_tolerance = mpfr_float("1e-13");
577 if(x_sample.size() <= 1)
578 {
579 N = degree_max;
580 }
581 else
582 {
583 N = ComputeCombination(degree_max + x_sample[0].precision() - 1, x_sample[0].precision() - 1);
584 }
585 M = degree_max * (degree_max - 1) * N;
586 auto jacobian_at_current_time = this->GetSystem().Jacobian(x_sample,x_time);
587 auto minimum_singular_value = Eigen::JacobiSVD< Mat<CT> >(jacobian_at_current_time).singularValues()(this->GetSystem().NumVariables() - 1 );
588 auto norm_of_sample = x_sample.norm();
589 L = pow(norm_of_sample,degree_max - 2);
590 auto tol = K * L * M;
591 if (tol == 0) // fail-safe
592 tol = minimum_singular_value;
593 else
594 {
595 tol = mpfr_float("2.0") / tol;
596 tol = tol * minimum_singular_value;
597 }
598 // make sure that tol is between min_tol & max_tol
599 if (tol > max_closed_loop_tolerance_) // tol needs to be <= max_tol
600 tol = max_closed_loop_tolerance_;
601 if (tol < min_closed_loop_tolerance_) // tol needs to be >= min_tol
602 tol = min_closed_loop_tolerance_;
603 return tol;
604 }// end FindToleranceForClosedLoop
605 */
606
607
608
623 template<typename CT>
625 {
626 using RT = typename Eigen::NumTraits<CT>::Real;
627 auto& times = std::get<TimeCont<CT> >(cauchy_times_);
628 auto& samples = std::get<SampCont<CT> >(cauchy_samples_);
629
630 if((samples.front() - samples.back()).template lpNorm<Eigen::Infinity>() < this->GetTracker().TrackingTolerance())
631 {
632 return true;
633 }
634
635 if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
636 {
637 //Ensure all samples are of the same precision.
638 auto new_precision = this->EnsureAtUniformPrecision(times, samples);
639 this->GetSystem().precision(new_precision);
640 }
641
642 this->GetTracker().Refine(samples.front(),samples.front(),times.front(),this->FinalTolerance(),this->EndgameSettings().max_num_newton_iterations);
643 this->GetTracker().Refine(samples.back(),samples.back(),times.back(),this->FinalTolerance(),this->EndgameSettings().max_num_newton_iterations);
644
645 if((samples.front() - samples.back()).template lpNorm<Eigen::Infinity>() < this->GetTracker().TrackingTolerance())
646 {
647 return true;
648 }
649 return false;
650
651 }//end CheckClosedLoop
652
653
654
655
674 template<typename CT>
675 bool RatioEGOperatingZoneTest(CT const& target_time) const
676 {
677 using RT = typename Eigen::NumTraits<CT>::Real;
678 RT min(1e300);
679 RT max(0);
680 auto& times = std::get<TimeCont<CT> >(cauchy_times_);
681 auto& samples = std::get<SampCont<CT> >(cauchy_samples_);
682 if(norm(times.front() - target_time) < GetCauchySettings().ratio_cutoff_time)
683 {
684 return true;
685 }
686 else
687 {
688 RT norm;
689 for(unsigned int ii=0; ii < this->EndgameSettings().num_sample_points; ++ii)
690 {
691 norm = samples[ii].template lpNorm<Eigen::Infinity>();
692 if(norm > max)
693 {
694 max = norm;
695 }
696 if(norm < min)
697 {
698 min = norm;
699 }
700 }
701
702 if(min > this->FinalTolerance() && max > this->FinalTolerance())
703 {
704 norm = min / max;
705 if(norm < GetCauchySettings().maximum_cauchy_ratio && (max - min) > this->FinalTolerance())
706 {
707 return false; // bad ratio and too far apart.
708 }
709 }
710 }
711 return true;
712
713 }//end RatioEGOperatingZoneTest
714
715
716 /*
717 Input: All input needed is available as class data members.
718 Output: SuccessCode declaring if we are successful or not.
719 Details: Computes cauchy samples using Circle Track. Compares the ratios of the maximum and minimum norms of cauchy samples
720 using RatioEGOperatingZoneTest. Then attempts to see if we have closed our loop, otherwise it continues the process outlined.
721 */
722
723
724
740 template<typename CT>
741 SuccessCode InitialCauchyLoops(CT const& target_time)
742 {
743 using std::max;
744 // auto fail_safe_max_cycle_number = max(GetCauchySettings().fail_safe_maximum_cycle_number,this->CycleNumber());
745 auto fail_safe_max_cycle_number = GetCauchySettings().fail_safe_maximum_cycle_number;
746
747 auto initial_cauchy_loop_success = SuccessCode::Success;
748
749 bool loop_hasnt_closed = true;
750 while (loop_hasnt_closed)
751 {
752 this->CycleNumber(0);
753 ClearAndSeedCauchyData<CT>();
754
755 // track around a circle once. we'll use it to measure whether we believe we are in the eg operating zone, based on the ratio of norms of sample points around the circle
756 auto tracking_success = CircleTrack(target_time);
757 this->IncrementCycleNumber(1);
758 if (tracking_success != SuccessCode::Success)
759 return tracking_success;
760
761 // find the ratio of the maximum and minimum coordinate wise for the loop.
762 if (RatioEGOperatingZoneTest<CT>(target_time))
763 { // then we believe we are in the EG operating zone, since the path is relatively flat. i still disbelieve this is a good test (dab 20160310)
764 while (true)
765 {
767 {//error is small enough, exit the loop with success.
768 NotifyObservers(ClosedLoop<EmitterType>(*this));
769 initial_cauchy_loop_success = SuccessCode::Success;
770 loop_hasnt_closed = false;
771 break;
772 }
773 else if(this->CycleNumber() > fail_safe_max_cycle_number)
774 {// too many iterations
775 initial_cauchy_loop_success = SuccessCode::CycleNumTooHigh;
776 loop_hasnt_closed = false;
777 break;
778 }
779
780 //compute next loop, the last sample in times and samples is the sample our loop ended on. Either where we started or on another sheet at the same time value.
781 tracking_success = CircleTrack(target_time);
782 this->IncrementCycleNumber(1);
783 if(tracking_success != SuccessCode::Success)
784 return tracking_success;
785 }
786 }//end if (RatioEGOperatingZoneTest())
787 else
788 {
789 auto advance_success = AdvanceTime<CT>(target_time);
790 if (advance_success!=SuccessCode::Success)
791 return advance_success;
792 }
793 } //end while(loop_hasnt_closed)
794
795 return initial_cauchy_loop_success;
796 }//end InitialCauchyLoops
797
798
799
800 template <typename CT>
801 void RotateOntoPS(CT const& next_time, Vec<CT> const& next_sample)
802 {
803 auto& ps_times = std::get<TimeCont<CT> >(pseg_times_);
804 auto& ps_samples = std::get<SampCont<CT> >(pseg_samples_);
805
806 ps_times.pop_front();
807 ps_samples.pop_front();
808
809 ps_times.push_back(next_time);
810 ps_samples.push_back(next_sample);
811 }
812
813 template <typename CT>
814 void ClearAndSeedCauchyData()
815 {
816 auto& cau_times = std::get<TimeCont<CT> >(cauchy_times_);
817 auto& cau_samples = std::get<SampCont<CT> >(cauchy_samples_);
818 auto& ps_times = std::get<TimeCont<CT> >(pseg_times_);
819 auto& ps_samples = std::get<SampCont<CT> >(pseg_samples_);
820
821 cau_times.clear();
822 cau_samples.clear();
823 cau_samples.push_back(ps_samples.back());
824 cau_times.push_back(ps_times.back());
825 }
826
827
851 template<typename CT>
852 SuccessCode InitialApproximation(CT const& start_time, Vec<CT> const& start_point,
853 CT const& target_time, Vec<CT> & approximation)
854 {
855 auto init_success = GetIntoEGZone(start_time, start_point, target_time);
856 if (init_success!= SuccessCode::Success)
857 return init_success;
858
859 auto cauchy_loop_success = InitialCauchyLoops<CT>(target_time);
860 if (cauchy_loop_success != SuccessCode::Success)
861 return cauchy_loop_success;
862
863 return ComputeCauchyApproximationOfXAtT0(approximation);
864
865 }//end InitialApproximation
866
867
868
869 template<typename CT>
870 SuccessCode GetIntoEGZone(CT const& start_time, Vec<CT> const& start_point, CT const& target_time)
871 {
872 using RT = typename Eigen::NumTraits<CT>::Real;
873
874 //initialize array holding c_over_k estimates
875 std::deque<RT> c_over_k;
876
877 auto& ps_times = std::get<TimeCont<CT> >(pseg_times_);
878 auto& ps_samples = std::get<SampCont<CT> >(pseg_samples_);
879
880 //Compute initial samples for pseg
881 auto initial_sample_success = this->ComputeInitialSamples(start_time, target_time, start_point, ps_times, ps_samples);
882 if (initial_sample_success!=SuccessCode::Success)
883 return initial_sample_success;
884
885 c_over_k.push_back(ComputeCOverK<CT>());
886
887
888 //track until for more c_over_k estimates or until we reach a cutoff time.
889 for (unsigned ii = 0; ii < GetCauchySettings().num_needed_for_stabilization; ++ii)
890 {
891 auto advance_success = AdvanceTime<CT>(target_time);
892 if (advance_success!=SuccessCode::Success)
893 return advance_success;
894 c_over_k.push_back(ComputeCOverK<CT>());
895 }//end while
896
897
898 //have we stabilized yet?
899 while(!CheckForCOverKStabilization(c_over_k) && abs(ps_times.back()-target_time) > GetCauchySettings().cycle_cutoff_time)
900 {
901 auto advance_success = AdvanceTime<CT>(target_time);
902 if (advance_success!=SuccessCode::Success)
903 return advance_success;
904
905 c_over_k.pop_front();
906 c_over_k.push_back(ComputeCOverK<CT>());
907
908 }//end while
909
910 NotifyObservers(InEGOperatingZone<EmitterType>(*this));
911
912 return SuccessCode::Success;
913 }
914
930 template<typename CT>
931 SuccessCode ComputeCauchyApproximationOfXAtT0(Vec<CT>& result)
932 {
933 using RT = typename Eigen::NumTraits<CT>::Real;
934 auto& cau_times = std::get<TimeCont<CT> >(cauchy_times_);
935 auto& cau_samples = std::get<SampCont<CT> >(cauchy_samples_);
936
937 if (cau_samples.size() != this->CycleNumber() * this->EndgameSettings().num_sample_points+1)
938 {
939 std::stringstream err_msg;
940 err_msg << "to compute cauchy approximation, cau_samples must be of size " << this->CycleNumber() * this->EndgameSettings().num_sample_points+1 << " but is of size " << cau_samples.size() << '\n';
941 throw std::runtime_error(err_msg.str());
942 }
943
944
945 //Ensure all samples are of the same precision.
946 if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
947 {
948 auto new_precision = this->EnsureAtUniformPrecision(cau_times, cau_samples);
949 this->GetSystem().precision(new_precision);
950 }
951
952
953 auto total_num_pts = this->CycleNumber() * this->EndgameSettings().num_sample_points;
954 this->template RefineAllSamples(cau_samples, cau_times);
955
956 Precision(result, Precision(cau_samples.back()));
957
958 result = Vec<CT>::Zero(this->GetSystem().NumVariables());
959 for(unsigned int ii = 0; ii < total_num_pts; ++ii)
960 result += cau_samples[ii];
961 result /= this->CycleNumber() * this->EndgameSettings().num_sample_points;
962
963 return SuccessCode::Success;
964
965 }
966
985 template<typename CT>
986 SuccessCode ComputeCauchySamples(CT const& target_time)
987 {
988 using bertini::Precision;
989
990 ClearAndSeedCauchyData<CT>();
991 this->CycleNumber(0);
992
993
994 while( this->CycleNumber() < GetCauchySettings().fail_safe_maximum_cycle_number )
995 {
996 //track around the origin once.
997 auto tracking_success = CircleTrack(target_time);
998 this->IncrementCycleNumber(1);
999
1000 if(tracking_success != SuccessCode::Success)
1001 {
1002 return tracking_success;
1003 }
1004 else if(CheckClosedLoop<CT>())
1005 {
1006 return SuccessCode::Success;
1007 }
1008 }
1009 NotifyObservers(CycleNumTooHigh<EmitterType>(*this));
1010 return SuccessCode::CycleNumTooHigh;
1011 }//end ComputeCauchySamples
1012
1013
1021 template<typename CT>
1022 SuccessCode AdvanceTime(CT const& target_time)
1023 {
1024 using RT = typename Eigen::NumTraits<CT>::Real;
1025
1026 auto& ps_times = std::get<TimeCont<CT> >(pseg_times_);
1027 auto& ps_samples = std::get<SampCont<CT> >(pseg_samples_);
1028
1029 auto& current_time = ps_times.back();
1030 auto& current_sample = ps_samples.back();
1031
1032 //Generalized next_time in case if we are not trying to converge to the t = 0.
1033 CT next_time = (target_time-current_time) * static_cast<RT>(this->EndgameSettings().sample_factor)+current_time;
1034
1035 if (abs(next_time - target_time) < this->EndgameSettings().min_track_time)//we are too close to t = 0 but we do not have the correct tolerance - so we exit
1036 return SuccessCode::MinTrackTimeReached;
1037
1038 // advance in time
1039 Vec<CT> next_sample;
1040 auto time_advance_success = this->GetTracker().TrackPath(next_sample,current_time, next_time, current_sample);
1041 if (time_advance_success != SuccessCode::Success)
1042 {
1043 NotifyObservers(EndgameFailure<EmitterType>(*this));
1044 return time_advance_success;
1045 }
1046
1047 this->EnsureAtPrecision(next_time,Precision(next_sample));
1048 RotateOntoPS(next_time, next_sample);
1049
1050 NotifyObservers(TimeAdvanced<EmitterType>(*this));
1051 return SuccessCode::Success;
1052 }
1053
1075 template<typename CT>
1076 SuccessCode RunImpl(CT const& start_time, Vec<CT> const& start_point, CT const& target_time)
1077 {
1078 if (start_point.size()!=this->GetSystem().NumVariables())
1079 {
1080 std::stringstream err_msg;
1081 err_msg << "number of variables in start point for CauchyEG, " << start_point.size() << ", must match the number of variables in the system, " << this->GetSystem().NumVariables();
1082 throw std::runtime_error(err_msg.str());
1083 }
1084
1085 if (Precision(start_time)!=Precision(start_point))
1086 {
1087 std::stringstream ss;
1088 ss << "CauchyEG Run time and point must be of matching precision. (" << Precision(start_time) << "!=" << Precision(start_point) << ")";
1089 throw std::runtime_error(ss.str());
1090 }
1091
1092 using RT = typename Eigen::NumTraits<CT>::Real;
1093
1094 Vec<CT>& latest_approx = this->final_approximation_;
1095 Vec<CT>& prev_approx = this->previous_approximation_;
1096 NumErrorT& approx_error = this->approximate_error_;
1097
1098
1099 ClearTimesAndSamples<CT>(); //clear times and samples before we begin.
1100 this->CycleNumber(0);
1101 prev_approx = start_point;
1102
1103 auto init_success = GetIntoEGZone(start_time, start_point, target_time);
1104 if (init_success!= SuccessCode::Success)
1105 return init_success;
1106
1107 auto cauchy_loop_success = InitialCauchyLoops<CT>(target_time);
1108 if (cauchy_loop_success != SuccessCode::Success)
1109 return cauchy_loop_success;
1110
1111
1112 RT norm_of_dehom_prev, norm_of_dehom_latest;
1113
1114 if(this->SecuritySettings().level <= 0)
1115 norm_of_dehom_prev = this->GetSystem().DehomogenizePoint(prev_approx).template lpNorm<Eigen::Infinity>();
1116
1117 do
1118 {
1119 //Compute a cauchy approximation. Uses the previously computed samples,
1120 //either from InitialCauchyLoops, or ComputeCauchySamples
1121 auto extrapolation_success = ComputeCauchyApproximationOfXAtT0<CT>(latest_approx);
1122 if (extrapolation_success!=SuccessCode::Success)
1123 return extrapolation_success;
1124
1125 approx_error = static_cast<NumErrorT>((latest_approx - prev_approx).template lpNorm<Eigen::Infinity>());
1126 NotifyObservers(ApproximatedRoot<EmitterType>(*this));
1127
1128 if (approx_error < this->FinalTolerance())
1129 {
1130 NotifyObservers(Converged<EmitterType>(*this));
1131 return SuccessCode::Success;
1132 }
1133
1134 if (this->SecuritySettings().level)
1135 {//we are too large, break out of loop to return error.
1136 norm_of_dehom_latest = this->GetSystem().DehomogenizePoint(latest_approx).template lpNorm<Eigen::Infinity>();
1137
1138 if (norm_of_dehom_prev > this->SecuritySettings().max_norm &&
1139 norm_of_dehom_latest > this->SecuritySettings().max_norm )
1140 {
1141 NotifyObservers(SecurityMaxNormReached<EmitterType>(*this));
1142 return SuccessCode::SecurityMaxNormReached;
1143 }
1144 }
1145
1146 prev_approx = latest_approx;
1147 norm_of_dehom_prev = norm_of_dehom_latest;
1148
1149 auto advance_success = AdvanceTime<CT>(target_time);
1150 if (advance_success != SuccessCode::Success)
1151 return advance_success;
1152
1153 // then compute the next set of cauchy samples used for extrapolating the point at target time
1154 auto cauchy_samples_success = ComputeCauchySamples(target_time);
1155 if (cauchy_samples_success != SuccessCode::Success)
1156 return cauchy_samples_success;
1157
1158 } while (true);
1159
1160 return SuccessCode::Success;
1161 } //end main CauchyEG function
1162};
1163
1164
1165}} // namespaces
Contains parent class, Endgame, the parent class for all endgames.
void NotifyObservers(AnyEvent const &e) const
Sends an Event (more particularly, AnyEvent) to all watching observers of this object.
Definition observable.hpp:90
Class used to finish tracking paths during Homotopy Continuation.
Definition cauchy.hpp:172
TupleOfSamps pseg_samples_
Definition cauchy.hpp:206
bool RatioEGOperatingZoneTest(CT const &target_time) const
After we have used CircleTrack and have successfully closed the loop using CheckClosedLoop we need to...
Definition cauchy.hpp:675
void SetPSEGSamples(SampCont< CT > const &pseg_samples_to_set)
Setter for the space values for the power series approximation of the Cauchy endgame.
Definition cauchy.hpp:255
TimeCont< CT > & GetCauchyTimes()
Getter for the time values for the Cauchy endgame.
Definition cauchy.hpp:302
auto ComputeCOverK() const -> typename Eigen::NumTraits< CT >::Real
A function that uses the assumption of being in the endgame operating zone to compute an approximatio...
Definition cauchy.hpp:490
TimeCont< CT > & GetPSEGTimes()
Getter for the time values for the power series approximation of the Cauchy endgame.
Definition cauchy.hpp:247
bool CheckClosedLoop()
Function that determines if we have closed a loop after calling CircleTrack().
Definition cauchy.hpp:624
SuccessCode InitialApproximation(CT const &start_time, Vec< CT > const &start_point, CT const &target_time, Vec< CT > &approximation)
Definition cauchy.hpp:852
SuccessCode RunImpl(CT const &start_time, Vec< CT > const &start_point, CT const &target_time)
Primary function that runs the Cauchy endgame. To begin, this function will compute a first approxima...
Definition cauchy.hpp:1076
void SetCauchyTimes(TimeCont< CT > const &cauchy_times_to_set)
Setter for the time values for the Cauchy endgame.
Definition cauchy.hpp:293
TupleOfTimes pseg_times_
Definition cauchy.hpp:202
SampCont< CT > & GetPSEGSamples()
Getter for the space values for the power series approximation of the Cauchy endgame.
Definition cauchy.hpp:263
SuccessCode ComputeCauchyApproximationOfXAtT0(Vec< CT > &result)
Function that computes the mean of the samples that were collected while tracking around the origin....
Definition cauchy.hpp:931
SampCont< CT > & GetCauchySamples()
Getter for the space values for the Cauchy endgame.
Definition cauchy.hpp:281
void ClearTimesAndSamples()
Function that clears all samples and times from data members for the Cauchy endgame.
Definition cauchy.hpp:230
void SetCauchySettings(CauchyConfig const &new_cauchy_settings)
Setter for the specific settings in tracking_conifg.hpp under Cauchy.
Definition cauchy.hpp:322
SuccessCode AdvanceTime(CT const &target_time)
Advances time, marching toward the target time.
Definition cauchy.hpp:1022
SuccessCode ComputeCauchySamples(CT const &target_time)
Collects samples while tracking around the target time, until we close the loop, or exceed the limit ...
Definition cauchy.hpp:986
SuccessCode InitialCauchyLoops(CT const &target_time)
Definition cauchy.hpp:741
const auto & GetCauchySettings() const
Getter for the specific settings in tracking_conifg.hpp under Cauchy.
Definition cauchy.hpp:330
void SetPSEGTimes(TimeCont< CT > pseg_times_to_set)
Setter for the time values for the power series approximation of the Cauchy endgame.
Definition cauchy.hpp:240
bool CheckForCOverKStabilization(TimeCont< CT > const &c_over_k_array) const
Function to determine if ratios of c/k estimates are withing a user defined threshold.
Definition cauchy.hpp:533
TupleOfSamps cauchy_samples_
Definition cauchy.hpp:214
void SetCauchySamples(SampCont< CT > const &cauchy_samples_to_set)
Setter for the space values for the Cauchy endgame.
Definition cauchy.hpp:270
SuccessCode CircleTrack(CT const &target_time)
Function to track around the origin.
Definition cauchy.hpp:376
TupleOfTimes cauchy_times_
Definition cauchy.hpp:210
Advanced around the circle around target time.
Definition endgames/events.hpp:93
A common base type for various precision types, fixed and adaptive. The purpose of this is to maintai...
Definition prec_base.hpp:46
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