// This file is part of Bertini 2. // // trackers/include/trackers/config.hpp is free software: you can redistribute // it and/or modify it under the terms of the GNU General Public License as // published by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // trackers/include/trackers/config.hpp is distributed in the hope that it will // be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with tracking/include/trackers/config.hpp. If not, see // . // // Copyright(C) 2015 - 2021 by Bertini2 Development Team // // See for a copy of the license, // as well as COPYING. Bertini2 is provided with permitted // additional terms in the b2/licenses/ directory. // individual authors of this file include: // silviana amethyst, university of wisconsin eau claire // Tim Hodges, Colorado State University #ifndef BERTINI_TRACKING_CONFIG_HPP #define BERTINI_TRACKING_CONFIG_HPP /** \file include/trackers/config.hpp \brief Configs and settings for tracking. */ #include "common/config.hpp" #include "detail/typelist.hpp" #include "eigen_extensions.hpp" #include "mpfr_extensions.hpp" #include "system/system.hpp" namespace bertini { namespace tracking { enum class PrecisionType // E.2.1 { Fixed, Adaptive }; enum class Predictor // E.4.3 { Constant, Euler, Heun, RK4, HeunEuler, RKNorsett34, RKF45, RKCashKarp45, RKDormandPrince56, RKVerner67 }; struct SteppingConfig { using T = mpq_rational; T initial_step_size = T(1) / T(10); ///< The length of the first time step when calling TrackPath. You ///< can turn it resetting, so subsequent calls use the same ///< stepsize, too. You make a call to the Tracker itself. T max_step_size = T(1) / T(10); ///< The largest allowed step size. MaxStepSize T min_step_size = T(1) / T(1e100); ///< The mimum allowed step size. MinStepSize T step_size_success_factor = T(2); ///< Factor by which to dilate the time step when triggered. ///< StepSuccessFactor T step_size_fail_factor = T(1) / T(2); ///< Factor by which to contract the time step when ///< triggered. StepFailFactor unsigned consecutive_successful_steps_before_stepsize_increase = 5; ///< What it says. If you can come up with a better name, please ///< suggest it. StepsForIncrease unsigned min_num_steps = 1; ///< The minimum number of steps allowed during tracking. unsigned max_num_steps = 1e5; ///< The maximum number of steps allowed during tracking. This is ///< per call to TrackPath. MaxNumberSteps unsigned frequency_of_CN_estimation = 1; ///< Estimate the condition number every so many steps. Eh. }; struct NewtonConfig { unsigned max_num_newton_iterations = 2; // MaxNewtonIts unsigned min_num_newton_iterations = 1; }; struct FixedPrecisionConfig { using RealType = double; /** \brief Construct a ready-to-go set of fixed precision settings from a system. */ explicit FixedPrecisionConfig(System const& sys) {} FixedPrecisionConfig() = default; }; inline std::ostream& operator<<(std::ostream& out, FixedPrecisionConfig const& fpc) { return out; } /** Holds the program parameters with respect to Adaptive Multiple Precision. These criteria are developed in \cite AMP1, \cite AMP2. Let: \f$J\f$ be the Jacobian matrix of the square system being solved. \f$d\f$ is the latest Newton residual. \f$N\f$ is the maximum number of Newton iterations to perform. Criterion A: \f$ P > \sigma_1 + \log_{10} [ ||J^{-1}|| \epsilon (||J|| + \Phi) ] \f$ Criterion B: \f$ P > \sigma_1 + D + (\tau + \log_{10} ||d||) / (N-i) \f$ where \f$ D = \log_{10} [||J^{-1}||((2 + \epsilon)||J|| + \epsilon \Phi) | 1] \f$ Criterion C: \f$ P > \sigma_2 + \tau + \log_{10}(||J^{-1}|| \Psi + ||z||) \f$ */ struct AdaptiveMultiplePrecisionConfig { NumErrorT coefficient_bound; ///< User-defined bound on the sum of the abs ///< vals of the coeffs for any polynomial in ///< the system (for adaptive precision). NumErrorT degree_bound; ///< User-set bound on degrees of polynomials in the ///< system - tricky to compute for factored polys, ///< subfuncs, etc. (for adaptive precision). NumErrorT epsilon; ///< Bound on growth in error from linear solves. This is ///< \f$\epsilon\f$ in \cite AMP1, \cite AMP2, and is used ///< for AMP criteria A and B. See top of page 13 of ///< \cite AMP1. A pessimistic bound is \f$2^n\f$. // rename to linear_solve_error_bound. NumErrorT Phi; ///< Bound on \f$\Phi\f$ (an error bound). Used for AMP ///< criteria A, B. // \f$\Phi\f$ is error in Jacobian evaluation divided by the unit roundoff // error, \f$10^{-P}\f$ rename to jacobian_eval_error_bound NumErrorT Psi; ///< Bound on \f$\Psi\f$ (an error bound). Used for AMP ///< criterion C. // Error in function evaluation, divided by the precision-dependent unit // roundoff error. rename to function_eval_error_bound int safety_digits_1 = 1; ///< User-chosen setting for the number of safety ///< digits used during Criteria A & B. int safety_digits_2 = 1; ///< User-chosen setting for the number of safety ///< digits used during Criterion C. unsigned int maximum_precision = 300; ///< User-chosed setting for the maximum allowable precision. Paths ///< will die if their precision is requested to be set higher than ///< this threshold. unsigned consecutive_successful_steps_before_precision_decrease = 10; unsigned max_num_precision_decreases = 10; ///< The maximum number of times precision can be lowered during ///< tracking of a segment of path. /** \brief Set epsilon, degree bound, and coefficient bound from system. * Epsilon is set as the square of the number of variables. * Bound on degree is set from a call to System class. Let this be \f$D\f$ \see System::DegreeBound(). * Bound on absolute values of coeffs is set from a call to System class. Let this be \f$B\f$. \see System::CoefficientBound(). */ void SetBoundsAndEpsilonFrom(System const& sys) { using std::pow; epsilon = pow(NumErrorT(sys.NumVariables()), 2); degree_bound = sys.DegreeBound(); coefficient_bound = sys.CoefficientBound(); } /** Sets values epsilon, Phi, Psi, degree_bound, and coefficient_bound from input system. * Phi becomes \f$ D*(D-1)*B \f$. * Psi is set as \f$ D*B \f$. */ void SetPhiPsiFromBounds() { Phi = degree_bound * (degree_bound - NumErrorT(1)) * coefficient_bound; Psi = degree_bound * coefficient_bound; // Psi from the AMP paper. } void SetAMPConfigFrom(System const& sys) { SetBoundsAndEpsilonFrom(sys); SetPhiPsiFromBounds(); } AdaptiveMultiplePrecisionConfig() : coefficient_bound(1000), degree_bound(5), safety_digits_1(1), safety_digits_2(1), maximum_precision(300) {} explicit AdaptiveMultiplePrecisionConfig(System const& sys) : AdaptiveMultiplePrecisionConfig() { SetAMPConfigFrom(sys); } }; // re: AdaptiveMultiplePrecisionConfig inline std::ostream& operator<<(std::ostream& out, AdaptiveMultiplePrecisionConfig const& AMP) { out << "coefficient_bound: " << AMP.coefficient_bound << "\n"; out << "degree_bound: " << AMP.degree_bound << "\n"; out << "epsilon: " << AMP.epsilon << "\n"; out << "Phi: " << AMP.Phi << "\n"; out << "Psi: " << AMP.Psi << "\n"; out << "safety_digits_1: " << AMP.safety_digits_1 << "\n"; out << "safety_digits_2: " << AMP.safety_digits_2 << "\n"; out << "consecutive_successful_steps_before_precision_decrease" << AMP.consecutive_successful_steps_before_precision_decrease << "\n"; return out; } /** \brief Construct a ready-to-go set of AMP settings from a system. \see AdaptiveMultiplePrecisionConfig::SetBoundsAndEpsilonFrom \see AdaptiveMultiplePrecisionConfig::SetPhiPsiFromBounds \see AdaptiveMultiplePrecisionConfig::SetAMPConfigFrom */ inline static AdaptiveMultiplePrecisionConfig AMPConfigFrom(System const& sys) { AdaptiveMultiplePrecisionConfig AMP; AMP.SetAMPConfigFrom(sys); return AMP; } // forward declarations template class Tracker; template class FixedPrecisionTracker; class MultiplePrecisionTracker; class DoublePrecisionTracker; // now for the TrackerTraits structs, which enable lookup of correct settings // objects and types, etc. template struct TrackerTraits {}; template <> struct TrackerTraits { using BaseComplexType = dbl; using BaseRealType = double; using EventEmitterType = FixedPrecisionTracker; using PrecisionConfig = FixedPrecisionConfig; enum { IsFixedPrec = 1, IsAdaptivePrec = 0 }; using NeededTypes = detail::TypeList; using NeededConfigs = detail::TypeList; }; template <> struct TrackerTraits { using BaseComplexType = mpfr_complex; using BaseRealType = mpfr_float; using EventEmitterType = FixedPrecisionTracker; using PrecisionConfig = FixedPrecisionConfig; enum { IsFixedPrec = 1, IsAdaptivePrec = 0 }; using NeededTypes = detail::TypeList; using NeededConfigs = detail::TypeList; }; class AMPTracker; // forward declare template <> struct TrackerTraits { using BaseComplexType = mpfr_complex; using BaseRealType = mpfr_float; using EventEmitterType = AMPTracker; using PrecisionConfig = AdaptiveMultiplePrecisionConfig; enum { IsFixedPrec = 0, IsAdaptivePrec = 1 }; using NeededTypes = detail::TypeList; using NeededConfigs = detail::TypeList; }; template struct TrackerTraits > : public TrackerTraits { using BaseComplexType = typename TrackerTraits::BaseComplexType; using BaseRealType = typename TrackerTraits::BaseRealType; using EventEmitterType = typename TrackerTraits::EventEmitterType; using PrecisionConfig = typename TrackerTraits::PrecisionConfig; enum { IsFixedPrec = 0, IsAdaptivePrec = 1 }; using NeededTypes = typename TrackerTraits::NeededTypes; using NeededConfigs = typename TrackerTraits::NeededConfigs; }; } // namespace tracking } // namespace bertini #endif