Add files
This commit is contained in:
181
core/include/bertini2/trackers/adaptive_precision_utilities.hpp
Normal file
181
core/include/bertini2/trackers/adaptive_precision_utilities.hpp
Normal file
@@ -0,0 +1,181 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//include/bertini2/trackers/adaptive_precision_utilities.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.
|
||||
//
|
||||
//include/bertini2/trackers/adaptive_precision_utilities.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 include/bertini2/trackers/adaptive_precision_utilities.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
/**
|
||||
\file include/bertini2/trackers/adaptive_precision_utilities.hpp
|
||||
|
||||
\brief Functions for dealing with precisions of objects, particularly in the context of adaptive precision.
|
||||
|
||||
These definitions are provided for use in trackers and endgames. This allows a uniform interface regardless of tracker details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
|
||||
|
||||
namespace bertini{ namespace tracking { namespace adaptive{
|
||||
|
||||
/**
|
||||
\brief Sets the precision of each space sample to be of input precision.
|
||||
|
||||
\param samples The samples of which to change precision.
|
||||
\param prec The new precision the samples should have.
|
||||
*/
|
||||
inline
|
||||
void SetPrecision(SampCont<mpfr_complex> & samples, unsigned prec)
|
||||
{
|
||||
for (auto& s : samples)
|
||||
for (unsigned ii=0; ii<s.size(); ii++)
|
||||
s(ii).precision(prec);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Sets the precision of each time sample to be of input precision.
|
||||
|
||||
\param times The times of which to change precision.
|
||||
\param prec The new precision the times should have.
|
||||
*/
|
||||
inline
|
||||
void SetPrecision(TimeCont<mpfr_complex> & times, unsigned prec)
|
||||
{
|
||||
for (auto& t : times)
|
||||
t.precision(prec);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the maximum precision among an input set of space samples.
|
||||
|
||||
This is computed based on the first coordinate. Length-zero samples will cause either an assert or a throw (from Eigen, not Bertini2).
|
||||
|
||||
\param samples Some complex samples in space, obtained from tracking probably.
|
||||
\return The maximum precision among those samples.
|
||||
*/
|
||||
inline
|
||||
unsigned MaxPrecision(SampCont<mpfr_complex> const& samples)
|
||||
{
|
||||
unsigned max_precision = 0;
|
||||
for (const auto& s : samples)
|
||||
if(Precision(s(0)) > max_precision)
|
||||
max_precision = Precision(s(0));
|
||||
return max_precision;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Gets the maximum precision among a set of times.
|
||||
|
||||
\param times Some complex times.
|
||||
\return The maximum precision among those times.
|
||||
*/
|
||||
inline
|
||||
unsigned MaxPrecision(TimeCont<mpfr_complex> const& times)
|
||||
{
|
||||
unsigned max_precision = 0;
|
||||
for (const auto& t : times)
|
||||
if(Precision(t) > max_precision)
|
||||
max_precision = Precision(t);
|
||||
return max_precision;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Does not a thing, because cannot.
|
||||
|
||||
Cannot change precision of fixed precision hardware doubles. This function is provided for template lookup, and interface completeness.
|
||||
|
||||
\param times Some times \f$\in \mathbb{C}\f$.
|
||||
\param samples Some space samples \f$\in \mathbb{C}^n\f$.
|
||||
|
||||
\return The precision, which is now uniform.
|
||||
*/
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<dbl> & times, SampCont<dbl> & samples)
|
||||
{
|
||||
return DoublePrecision();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Changes precision of mpfr_complex to highest needed precision for the samples.
|
||||
|
||||
\param times Some times \f$\in \mathbb{C}\f$.
|
||||
\param samples Some space samples \f$\in \mathbb{C}^n\f$.
|
||||
|
||||
\return The precision, which is now uniform.
|
||||
*/
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<mpfr_complex> & times, SampCont<mpfr_complex> & samples)
|
||||
{
|
||||
auto def_prec = DefaultPrecision();
|
||||
if (std::any_of(begin(times),end(times),[=](auto const& p){return Precision(p)!=def_prec;})
|
||||
||
|
||||
std::any_of(begin(samples),end(samples),[=](auto const& p){return Precision(p)!=def_prec;}))
|
||||
{
|
||||
auto max_precision = max(MaxPrecision(samples), MaxPrecision(times));
|
||||
|
||||
DefaultPrecision(max_precision);
|
||||
SetPrecision(times, max_precision);
|
||||
SetPrecision(samples, max_precision);
|
||||
return max_precision;
|
||||
}
|
||||
return def_prec;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Changes precision of mpfr_complex to highest needed precision for the samples.
|
||||
|
||||
This function does NOT do any refinement, it merely changes the precision of default, and of the input objects.
|
||||
|
||||
\param times The times of some space samples
|
||||
\param samples Some spatial samples, probably obtained from an Endgame
|
||||
\param derivatives The derivatives of the space samples, at the time samples. Again, probably obtained from Endgame.
|
||||
|
||||
\return The precision changed to.
|
||||
*/
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<mpfr_complex> & times, SampCont<mpfr_complex> & samples, SampCont<mpfr_complex> & derivatives)
|
||||
{
|
||||
auto def_prec = DefaultPrecision();
|
||||
if (std::any_of(begin(samples),end(samples),[=](auto const& p){return Precision(p)!=def_prec;})
|
||||
||
|
||||
std::any_of(begin(derivatives),end(derivatives),[=](auto const& p){return Precision(p)!=def_prec;}))
|
||||
{
|
||||
auto max_precision = max(MaxPrecision(samples),MaxPrecision(times),MaxPrecision(derivatives));
|
||||
|
||||
DefaultPrecision(max_precision);
|
||||
|
||||
SetPrecision(times, max_precision);
|
||||
SetPrecision(samples, max_precision);
|
||||
SetPrecision(derivatives, max_precision);
|
||||
return max_precision;
|
||||
}
|
||||
return def_prec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}} // re: namespaces
|
||||
217
core/include/bertini2/trackers/amp_criteria.hpp
Normal file
217
core/include/bertini2/trackers/amp_criteria.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//amp_criteria.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.
|
||||
//
|
||||
//amp_criteria.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 amp_criteria.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
#ifndef BERTINI_AMP_CRITERIA_HPP
|
||||
#define BERTINI_AMP_CRITERIA_HPP
|
||||
|
||||
/**
|
||||
\file amp_criteria.hpp
|
||||
|
||||
\brief Provides the Adaptive Multiple Precision criteria functions.
|
||||
|
||||
*/
|
||||
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
|
||||
namespace bertini{
|
||||
namespace tracking{
|
||||
namespace amp{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief The right hand side of Criterion A, from \cite AMP1, \cite AMP2.
|
||||
|
||||
see CriterionA
|
||||
*/
|
||||
inline
|
||||
double CriterionARHS(double const& norm_J, double const& norm_J_inverse, AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return AMP_config.safety_digits_1 + log10(norm_J_inverse * AMP_config.epsilon * (norm_J + AMP_config.Phi ));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Check AMP Criterion A.
|
||||
|
||||
From \cite AMP1, \cite AMP2.
|
||||
|
||||
True means the check passed, and the precision is all good. False means something's gotta change, stepsize or precision.
|
||||
|
||||
\param norm_J The matrix norm of the Jacobian matrix
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\tparam NumT The real number type
|
||||
|
||||
\return True if criteria satisfied, false if violated and precision or step length should be adjusted.
|
||||
*/
|
||||
template<typename NumT>
|
||||
bool CriterionA(double const& norm_J, double const& norm_J_inverse, AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return NumTraits<NumT>::NumDigits() > CriterionARHS(norm_J, norm_J_inverse, AMP_config);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Compute the expression \f$D\f$ from the AMP papers \cite AMP1, \cite AMP2.
|
||||
|
||||
\param norm_J The matrix norm of the Jacobian matrix
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\return a double scalar, the quantity \f$D\f$ from the AMP papers \cite AMP1, \cite AMP2.
|
||||
*/
|
||||
inline
|
||||
double D(double const& norm_J, double const& norm_J_inverse, AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return log10(norm_J_inverse*( (2+AMP_config.epsilon)*norm_J+AMP_config.epsilon*AMP_config.Phi)+1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the right hand side of the inequality of Criterion B
|
||||
|
||||
From \cite AMP1, \cite AMP2.
|
||||
|
||||
\param norm_J The matrix norm of the Jacobian matrix
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param num_newton_iterations_remaining The number of iterations which have yet to perform.
|
||||
\param tracking_tolerance The tightness to which the path should be tracked. This is the raw tracking tolerance (for now)
|
||||
\param norm_of_latest_newton_residual The norm of the length of the most recent Newton step.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\return The value of the right hand side of Criterion B
|
||||
*/
|
||||
inline
|
||||
double CriterionBRHS(double const& norm_J, double const& norm_J_inverse, unsigned num_newton_iterations_remaining, double const& tracking_tolerance, double const& norm_of_latest_newton_residual, AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return AMP_config.safety_digits_1 + D(norm_J, norm_J_inverse, AMP_config) + (-log10(tracking_tolerance) + log10(norm_of_latest_newton_residual)) / (num_newton_iterations_remaining);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Check AMP Criterion B
|
||||
|
||||
This is Criterion B from \cite AMP1, \cite AMP2.
|
||||
True means the check passed, and the precision is all good. False means something's gotta change, stepsize or precision.
|
||||
|
||||
\param norm_J The matrix norm of the Jacobian matrix
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param num_newton_iterations_remaining The number of iterations which have yet to perform.
|
||||
\param tracking_tolerance The tightness to which the path should be tracked. This is the raw tracking tolerance (for now)
|
||||
\param norm_of_latest_newton_residual The norm of the length of the most recent Newton step.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\tparam NumT The numeric type.
|
||||
|
||||
\return True if criteria satisfied, false if violated and precision or step length should be adjusted.
|
||||
*/
|
||||
template<typename NumT>
|
||||
bool CriterionB(double const& norm_J,
|
||||
double const& norm_J_inverse,
|
||||
unsigned num_newton_iterations_remaining,
|
||||
double const& tracking_tolerance,
|
||||
double const& norm_of_latest_newton_residual,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return NumTraits<NumT>::NumDigits() > CriterionBRHS(norm_J, norm_J_inverse, num_newton_iterations_remaining, tracking_tolerance, norm_of_latest_newton_residual, AMP_config);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Evaluate the right hand side of Criterion C
|
||||
|
||||
This is Criterion C, from \cite AMP1, \cite AMP2.
|
||||
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param tracking_tolerance The tightness to which the path should be tracked. This is the raw tracking tolerance
|
||||
\param norm_z The norm of the current space point.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\return The value of the right hand side of the inequality from Criterion C.
|
||||
*/
|
||||
inline
|
||||
double CriterionCRHS(double const& norm_J_inverse,
|
||||
double const& norm_z,
|
||||
double const& tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return AMP_config.safety_digits_2 + -log10(tracking_tolerance) + log10(norm_J_inverse*AMP_config.Psi + norm_z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Evaluate the right hand side of Criterion C
|
||||
|
||||
This is Criterion C from \cite AMP1, \cite AMP2.
|
||||
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param tracking_tolerance The tightness to which the path should be tracked. This is the raw tracking tolerance
|
||||
\param z The current space point.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\return The value of the right hand side of the inequality from Criterion C.
|
||||
*/
|
||||
template<typename Derived>
|
||||
double CriterionCRHS(double const& norm_J_inverse,
|
||||
const Eigen::MatrixBase<Derived>& z,
|
||||
double tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return CriterionCRHS(norm_J_inverse, double(z.norm()), tracking_tolerance, AMP_config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Check AMP Criterion C
|
||||
|
||||
This is Criterion C from \cite AMP1.
|
||||
|
||||
True means the check passed, and the precision is all good. False means something's gotta change, stepsize or precision.
|
||||
|
||||
\param norm_J_inverse An estimate on the norm of the inverse of the Jacobian matrix.
|
||||
\param z The current space point.
|
||||
\param tracking_tolerance The tightness to which the path should be tracked. This is the raw tracking tolerance
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\return A boolean indicating whether the criterion is satisfied. True means path tracking can continue without modifying tracking settings. False means that corrective action should be taken.
|
||||
*/
|
||||
template<typename NumT, typename Derived>
|
||||
bool CriterionC(double const& norm_J_inverse, const Eigen::MatrixBase<Derived>& z, double tracking_tolerance, AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
return NumTraits<NumT>::NumDigits() > CriterionCRHS(norm_J_inverse, z, tracking_tolerance, AMP_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1646
core/include/bertini2/trackers/amp_tracker.hpp
Normal file
1646
core/include/bertini2/trackers/amp_tracker.hpp
Normal file
File diff suppressed because it is too large
Load Diff
476
core/include/bertini2/trackers/base_predictor.hpp
Normal file
476
core/include/bertini2/trackers/base_predictor.hpp
Normal file
@@ -0,0 +1,476 @@
|
||||
//This file is part of Bertini 2.0.
|
||||
//
|
||||
//heun_euler.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.
|
||||
//
|
||||
//heun_euler.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 heun_euler.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// predictor.hpp
|
||||
//
|
||||
// copyright 2015
|
||||
// James B. Collins
|
||||
// West Texas A&M University
|
||||
// Department of Mathematics
|
||||
// Spring 2016
|
||||
|
||||
|
||||
/**
|
||||
\file base_predictor.hpp
|
||||
|
||||
\brief Contains a base class for all ODE predictors.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_BASE_PREDICTORS_HPP
|
||||
#define BERTINI_BASE_PREDICTORS_HPP
|
||||
|
||||
#include "bertini2/trackers/amp_criteria.hpp"
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
|
||||
#include "system.hpp"
|
||||
#include "mpfr_extensions.hpp"
|
||||
#include <Eigen/LU>
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
|
||||
namespace bertini{
|
||||
namespace tracking{
|
||||
namespace predict{
|
||||
|
||||
|
||||
using Predictor = Predictor;
|
||||
|
||||
/**
|
||||
\brief Get the Bertini2 default predictor.
|
||||
|
||||
Currently set to Euler, though this will change in future versions.
|
||||
*/
|
||||
inline
|
||||
Predictor DefaultPredictor()
|
||||
{
|
||||
return Predictor::Euler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The lowest order of the predictor. The order of the error estimate is this plus one.
|
||||
*/
|
||||
inline
|
||||
unsigned Order(Predictor predictor_choice)
|
||||
{
|
||||
switch (predictor_choice)
|
||||
{
|
||||
case (Predictor::Euler):
|
||||
return 1;
|
||||
case (Predictor::HeunEuler):
|
||||
return 1;
|
||||
case (Predictor::RK4):
|
||||
return 4;
|
||||
case (Predictor::RKF45):
|
||||
return 4;
|
||||
case (Predictor::RKCashKarp45):
|
||||
return 4;
|
||||
case (Predictor::RKDormandPrince56):
|
||||
return 5;
|
||||
case (Predictor::RKVerner67):
|
||||
return 6;
|
||||
default:
|
||||
{
|
||||
throw std::runtime_error("incompatible predictor choice in Order");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool HasErrorEstimate(Predictor predictor_choice)
|
||||
{
|
||||
switch (predictor_choice)
|
||||
{
|
||||
case (Predictor::Euler):
|
||||
return false;
|
||||
case (Predictor::HeunEuler):
|
||||
return true;
|
||||
case (Predictor::RK4):
|
||||
return false;
|
||||
case (Predictor::RKF45):
|
||||
return true;
|
||||
case (Predictor::RKCashKarp45):
|
||||
return true;
|
||||
case (Predictor::RKDormandPrince56):
|
||||
return true;
|
||||
case (Predictor::RKVerner67):
|
||||
return true;
|
||||
default:
|
||||
{
|
||||
throw std::runtime_error("incompatible predictor choice in HasErrorEstimate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/class BasePredictor
|
||||
|
||||
\brief An interface for all predictors.
|
||||
|
||||
## Purpose
|
||||
Stores all the information needed to implement the predictor method
|
||||
- Butcher Table
|
||||
- Number of Stages
|
||||
- Order of the method.
|
||||
|
||||
Also stores information computed during implementation of the method.
|
||||
|
||||
|
||||
## Use
|
||||
Implement the following pure functions:
|
||||
- FullStep
|
||||
- SetErrorEstimate
|
||||
- SetSizeProportion
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class BasePredictor
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
BasePredictor(Predictor method){};
|
||||
|
||||
/**
|
||||
\brief Perform a generic predictor step.
|
||||
|
||||
\param next_space The computed prediction.
|
||||
\param method An enum class selecting the predictor method to use.
|
||||
\param S The system being solved.
|
||||
\param current_space The current space variable vector.
|
||||
\param current_time The current time.
|
||||
\param delta_t The size of the time step.
|
||||
\param condition_number_estimate The computed estimate of the condition number of the Jacobian.
|
||||
\param num_steps_since_last_condition_number_computation. Updated in this function.
|
||||
\param frequency_of_CN_estimation How many steps to take between condition number estimates.
|
||||
\param prec_type The operating precision type.
|
||||
\param tracking_tolerance How tightly to track the path.
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename RealType>
|
||||
SuccessCode Predict(Vec<ComplexType> & next_space,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, ComplexType current_time,
|
||||
ComplexType const& delta_t,
|
||||
RealType & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
RealType const& tracking_tolerance)
|
||||
{
|
||||
|
||||
return FullStep<ComplexType, RealType>(next_space, S, current_space, current_time, delta_t);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Perform a generic predictor step and return size_proportion and condition number information
|
||||
|
||||
\param next_space The computed prediction.
|
||||
\param method An enum class selecting the predictor method to use.
|
||||
\param size_proportion $a$ in AMP2 paper.
|
||||
\param norm_J The computed estimate of the norm of the Jacobian matrix.
|
||||
\param norm_J_inverse The computed estimate of the norm of the inverse of the Jacobian matrix.
|
||||
\param S The system being solved.
|
||||
\param current_space The current space variable vector.
|
||||
\param current_time The current time.
|
||||
\param delta_t The size of the time step.
|
||||
\param condition_number_estimate The computed estimate of the condition number of the Jacobian.
|
||||
\param num_steps_since_last_condition_number_computation. Updated in this function.
|
||||
\param frequency_of_CN_estimation How many steps to take between condition number estimates.
|
||||
\param prec_type The operating precision type.
|
||||
\param tracking_tolerance How tightly to track the path.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename RealType>
|
||||
SuccessCode Predict(Vec<ComplexType> & next_space,
|
||||
RealType & size_proportion,
|
||||
RealType & norm_J,
|
||||
RealType & norm_J_inverse,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, ComplexType current_time,
|
||||
ComplexType const& delta_t,
|
||||
RealType & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
RealType const& tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
|
||||
|
||||
auto success_code = Predict<ComplexType, RealType>(next_space, S, current_space, current_time, delta_t,
|
||||
condition_number_estimate, num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation, tracking_tolerance);
|
||||
|
||||
if(success_code != SuccessCode::Success)
|
||||
return success_code;
|
||||
|
||||
// Calculate condition number and updated if needed
|
||||
Eigen::PartialPivLU<Mat<ComplexType>>& dhdxref = std::get< Eigen::PartialPivLU<Mat<ComplexType>> >(dh_dx_);
|
||||
Mat<ComplexType>& LUref = std::get< Mat<ComplexType> >(LU_);
|
||||
|
||||
Vec<ComplexType> randy = RandomOfUnits<ComplexType>(S.NumVariables());
|
||||
Vec<ComplexType> temp_soln = LUref.solve(randy);
|
||||
|
||||
norm_J = dhdxref.norm();
|
||||
norm_J_inverse = temp_soln.norm();
|
||||
|
||||
if (num_steps_since_last_condition_number_computation >= frequency_of_CN_estimation)
|
||||
{
|
||||
condition_number_estimate = norm_J * norm_J_inverse;
|
||||
num_steps_since_last_condition_number_computation = 1; // reset the counter to 1
|
||||
}
|
||||
else // no need to compute the condition number
|
||||
num_steps_since_last_condition_number_computation++;
|
||||
|
||||
|
||||
// Set size_proportion
|
||||
SetSizeProportion<ComplexType,RealType>(size_proportion, delta_t);
|
||||
|
||||
|
||||
|
||||
//AMP Criteria
|
||||
if (!amp::CriterionA(norm_J, norm_J_inverse, AMP_config)) // AMP_criterion_A != ok
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
else if (!amp::CriterionC(norm_J_inverse, current_space, tracking_tolerance, AMP_config)) // AMP_criterion_C != ok
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
|
||||
|
||||
return success_code;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Perform a generic predictor step and return error estimate, size_proportion and condition number information
|
||||
|
||||
\param next_space The computed prediction.
|
||||
\param method An enum class selecting the predictor method to use.
|
||||
\param error_estimate Estimate of the error from an embedded method.
|
||||
\param size_proportion $a$ in AMP2 paper.
|
||||
\param norm_J The computed estimate of the norm of the Jacobian matrix.
|
||||
\param norm_J_inverse The computed estimate of the norm of the inverse of the Jacobian matrix.
|
||||
\param S The system being solved.
|
||||
\param current_space The current space variable vector.
|
||||
\param current_time The current time.
|
||||
\param delta_t The size of the time step.
|
||||
\param condition_number_estimate The computed estimate of the condition number of the Jacobian.
|
||||
\param num_steps_since_last_condition_number_computation. Updated in this function.
|
||||
\param frequency_of_CN_estimation How many steps to take between condition number estimates.
|
||||
\param prec_type The operating precision type.
|
||||
\param tracking_tolerance How tightly to track the path.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename RealType>
|
||||
SuccessCode Predict(Vec<ComplexType> & next_space,
|
||||
RealType & error_estimate,
|
||||
RealType & size_proportion,
|
||||
RealType & norm_J,
|
||||
RealType & norm_J_inverse,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, ComplexType current_time,
|
||||
ComplexType const& delta_t,
|
||||
RealType & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
RealType const& tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
// If this is a method without an error estimator, then can't calculate size proportion and should throw an error
|
||||
|
||||
if(!predict::HasErrorEstimate(predictor_))
|
||||
{
|
||||
throw std::runtime_error("incompatible predictor choice in ExplicitPredict, no error estimator");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
auto success_code = Predict<ComplexType,RealType>(next_space, size_proportion, norm_J, norm_J_inverse,
|
||||
S, current_space, current_time, delta_t,
|
||||
condition_number_estimate, num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation, tracking_tolerance, AMP_config);
|
||||
|
||||
if(success_code != SuccessCode::Success)
|
||||
return success_code;
|
||||
|
||||
SetErrorEstimate<ComplexType,RealType>(error_estimate, delta_t);
|
||||
|
||||
|
||||
return success_code;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/brief Sets the local variables to correspond to a particular predictor method
|
||||
|
||||
\param method Enum class that determines the predictor method
|
||||
|
||||
*/
|
||||
|
||||
virtual void PredictorMethod(Predictor method) = 0;
|
||||
|
||||
Predictor PredictorMethod()
|
||||
{
|
||||
return predictor_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The lowest order of the predictor. The order of the error estimate is this plus one.
|
||||
*/
|
||||
inline
|
||||
unsigned Order()
|
||||
{
|
||||
return p_;
|
||||
}
|
||||
|
||||
|
||||
inline bool HasErrorEstimate()
|
||||
{
|
||||
return predict::HasErrorEstimate(predictor_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
///////////////////////////
|
||||
//
|
||||
// Protected Members Methods
|
||||
//
|
||||
////////////////////
|
||||
|
||||
/**
|
||||
\brief Performs a full prediction step from current_time to current_time + delta_t
|
||||
|
||||
\param next_space The computed prediction space
|
||||
\param S The homotopy system
|
||||
\param current_space The current space values
|
||||
\param current_time The current time values
|
||||
\param delta_t The time step
|
||||
|
||||
\return SuccessCode determining result of the computation
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename RealType>
|
||||
virtual SuccessCode FullStep(Vec<ComplexType> & next_space,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, ComplexType current_time,
|
||||
ComplexType const& delta_t) = 0;
|
||||
|
||||
|
||||
/**
|
||||
\brief Computes the error estimate of this prediction step.
|
||||
|
||||
\param error_estimate Computed error estimate
|
||||
\param delta_t The time step
|
||||
|
||||
\return Success code or the computation
|
||||
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename RealType>
|
||||
virtual SuccessCode SetErrorEstimate(RealType & error_estimate, ComplexType const& delta_t) = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Compute the size proportion variable for AMP computation
|
||||
|
||||
\param size_proportion Computed size proportion
|
||||
\param delta_t The time step
|
||||
|
||||
\return Success code of the computation
|
||||
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename RealType>
|
||||
virtual SuccessCode SetSizeProportion(RealType & size_proportion, ComplexType const& delta_t) = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Evaluates the RHS of the Davidenko differential equation at a particular time and space
|
||||
|
||||
\param S The homotopy system
|
||||
\param space The space variable used to evaluate RHS
|
||||
\param time The time variable used to evaluate RHS
|
||||
\param K Matrix of stage variables
|
||||
\param stage Which stage variable(column of K) should be filled by this computation
|
||||
|
||||
\return Success code of this computation
|
||||
*/
|
||||
|
||||
template<typename ComplexType>
|
||||
virtual SuccessCode EvalRHS(System const& S,
|
||||
Vec<ComplexType> const& space, ComplexType time, Mat<ComplexType> & K, int stage) = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// Protected Data Members
|
||||
//
|
||||
////////////////////
|
||||
|
||||
Predictor predictor_;
|
||||
unsigned p_;
|
||||
std::tuple< Mat<dbl>, Mat<mpfr> > dh_dx_;
|
||||
std::tuple< Eigen::PartialPivLU<Mat<dbl>>, Eigen::PartialPivLU<Mat<mpfr>> > LU_;
|
||||
|
||||
|
||||
|
||||
}; // re: class BasePredictor
|
||||
|
||||
} // re: namespace predict
|
||||
}// re: namespace tracking
|
||||
}// re: namespace bertini
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
684
core/include/bertini2/trackers/base_tracker.hpp
Normal file
684
core/include/bertini2/trackers/base_tracker.hpp
Normal file
@@ -0,0 +1,684 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//base_tracker.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.
|
||||
//
|
||||
//base_tracker.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 base_tracker.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
/**
|
||||
\file base_tracker.hpp
|
||||
|
||||
\brief
|
||||
|
||||
\brief Contains the abstract base Tracker type, from which all other Trackers inherit.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_BASE_TRACKER_HPP
|
||||
#define BERTINI_BASE_TRACKER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
//#include "bertini2/tracking/step.hpp"
|
||||
#include "bertini2/trackers/ode_predictors.hpp"
|
||||
#include "bertini2/trackers/newton_corrector.hpp"
|
||||
#include "bertini2/logging.hpp"
|
||||
|
||||
#include "bertini2/detail/observable.hpp"
|
||||
|
||||
// Must be at the end of the include list
|
||||
#include "bertini2/trackers/events.hpp"
|
||||
|
||||
#include "bertini2/detail/is_template_parameter.hpp"
|
||||
#include "bertini2/detail/configured.hpp"
|
||||
|
||||
namespace bertini{
|
||||
|
||||
namespace tracking{
|
||||
|
||||
/**
|
||||
\class Tracker
|
||||
|
||||
\brief Base tracker class for trackers offered in Bertini2.
|
||||
|
||||
\see AMPTracker
|
||||
|
||||
## Using a tracker
|
||||
|
||||
Trackers in Bertini2 are the engine for tracking a path from one space-time pair to another. The path is implicitly described by the system being tracked.
|
||||
|
||||
1. Create a system.
|
||||
2. Create a tracker, associating it to the system.
|
||||
3. Set the config for the track.
|
||||
4. Track from your start point and time, to the target time.
|
||||
5. Profit.
|
||||
|
||||
Specific examples are given with the implemented tracker types. So far, these types are avaiable:
|
||||
|
||||
* AMPTracker
|
||||
|
||||
Please see their detailed documentation for description of how to use them correctly.
|
||||
|
||||
|
||||
## Purpose
|
||||
|
||||
Since the Bertini trackers have common functionality, and we want to be able to call arbitrary algorithms using and tracker type, we use inheritance. That is, there is common functionality in all trackers, such as
|
||||
|
||||
* Setup
|
||||
* TrackPath
|
||||
* Refine
|
||||
|
||||
which we want all Trackers to be able to do. However, the internal behaviour of a particular tracker varies -- which is why it is a different type. In particular, the fixed precision trackers produce and work in a fixed precision, whereas the AMPTracker varies precision to get around or near branch points while tracking.
|
||||
|
||||
Hence, the use of trackers in Bertini2 is through pointers or references to Trackers, enabling the use of any kind of tracking in any algorithm, and further allowing the development of new tracker types as the theory and practice advance.
|
||||
|
||||
|
||||
## Creating a new tracker type
|
||||
|
||||
To create a new Tracker type, inherit from this, and override the following functions:
|
||||
|
||||
\code
|
||||
|
||||
public:
|
||||
SuccessCode Refine(Vec<mpfr> & new_space,
|
||||
Vec<mpfr> const& start_point, mpfr const& current_time) override
|
||||
{}
|
||||
|
||||
private:
|
||||
|
||||
void TrackerLoopInitialization(mpfr const& start_time, Vec<mpfr> const& start_point) override
|
||||
{}
|
||||
|
||||
SuccessCode InitialRefinement() override
|
||||
{}
|
||||
|
||||
SuccessCode PreIterationCheck() const override
|
||||
{}
|
||||
|
||||
SuccessCode TrackerIteration() override
|
||||
{}
|
||||
|
||||
void CopyFinalSolution(Vec<mpfr> & solution_at_endtime) const override
|
||||
{}
|
||||
|
||||
\endcode
|
||||
|
||||
and optionally override the following functions
|
||||
|
||||
\code
|
||||
void ResetCounters() override
|
||||
{}
|
||||
|
||||
void PostTrackCleanup() override
|
||||
{}
|
||||
\endcode
|
||||
where you probably want to call this base function, which is why it is protected, not private.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
template<class D>
|
||||
class Tracker :
|
||||
public Observable,
|
||||
public detail::Configured<
|
||||
typename TrackerTraits< D >::NeededConfigs
|
||||
>
|
||||
{
|
||||
using NeededTypes = typename TrackerTraits< D >::NeededTypes;
|
||||
using BaseComplexType = typename TrackerTraits<D>::BaseComplexType;
|
||||
using BaseRealType = typename TrackerTraits<D>::BaseRealType;
|
||||
|
||||
using CT = BaseComplexType;
|
||||
using RT = BaseRealType;
|
||||
|
||||
|
||||
public:
|
||||
using Config = detail::Configured< typename TrackerTraits< D >::NeededConfigs >;
|
||||
using Stepping = SteppingConfig;
|
||||
using Newton = NewtonConfig;
|
||||
using PrecConf = typename TrackerTraits< D >::PrecisionConfig;
|
||||
|
||||
Tracker(System const& sys) : tracked_system_(std::ref(sys))
|
||||
{
|
||||
predictor_ = std::make_shared< predict::ExplicitRKPredictor >(predict::DefaultPredictor(), tracked_system_);
|
||||
corrector_ = std::make_shared< correct::NewtonCorrector >(tracked_system_);
|
||||
SetPredictor(predict::DefaultPredictor());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the tracker set up for tracking.
|
||||
|
||||
Pass the tracker the configuration for tracking, to get it set up.
|
||||
*/
|
||||
void Setup(Predictor new_predictor_choice,
|
||||
double const& tracking_tolerance,
|
||||
double const& path_truncation_threshold,
|
||||
SteppingConfig const& stepping,
|
||||
NewtonConfig const& newton)
|
||||
{
|
||||
SetPredictor(new_predictor_choice);
|
||||
corrector_->Settings(newton);
|
||||
|
||||
SetTrackingTolerance(tracking_tolerance);
|
||||
|
||||
path_truncation_threshold_ = path_truncation_threshold;
|
||||
|
||||
this->template Set(stepping);
|
||||
this->template Set(newton);
|
||||
|
||||
current_stepsize_ = BaseRealType(stepping.initial_step_size);
|
||||
}
|
||||
|
||||
|
||||
using Config::Get;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Set how tightly to track the path.
|
||||
|
||||
Smaller values tracks the path more tightly, at the expense of higher computational time.
|
||||
|
||||
\param tracking_tolerance The new value. Newton iterations are performed until the step length is less than this number, or the max number of iterations has been reached, in which case the overall predict-correct step is viewed as a failure, and the step is undone. This number must be positive.
|
||||
*/
|
||||
void SetTrackingTolerance(double const& tracking_tolerance)
|
||||
{
|
||||
if (tracking_tolerance <= 0)
|
||||
throw std::runtime_error("tracking tolerance must be strictly positive");
|
||||
|
||||
tracking_tolerance_ = tracking_tolerance;
|
||||
digits_tracking_tolerance_ = NumTraits<double>::TolToDigits(tracking_tolerance);
|
||||
}
|
||||
|
||||
|
||||
void SetInfiniteTruncationTolerance(double const& tol)
|
||||
{
|
||||
if (tol <= 0)
|
||||
throw std::runtime_error("truncation threshold must be strictly positive");
|
||||
|
||||
path_truncation_threshold_ = tol;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Track a start point through time, from a start time to a target time.
|
||||
|
||||
\param[out] solution_at_endtime The value of the solution at the end time.
|
||||
\param start_time The time at which to start tracking.
|
||||
\param endtime The time to track to.
|
||||
\param start_point The intial space values for tracking.
|
||||
\return A success code indicating whether tracking was successful. Will be SuccessCode::Success if was successful, and something else otherwise.
|
||||
|
||||
The is the fundamental method for the tracker. First, you create and set up the tracker, telling it what system you will solve, and the settings to use. Then, you actually do the tracking.
|
||||
*/
|
||||
SuccessCode TrackPath(Vec<CT> & solution_at_endtime,
|
||||
CT const& start_time, CT const& endtime,
|
||||
Vec<CT> const& start_point
|
||||
) const
|
||||
{
|
||||
if (start_point.size()!=GetSystem().NumVariables())
|
||||
throw std::runtime_error("start point size must match the number of variables in the system to be tracked");
|
||||
|
||||
|
||||
|
||||
SuccessCode initialization_code = TrackerLoopInitialization(start_time, endtime, start_point);
|
||||
if (initialization_code!=SuccessCode::Success)
|
||||
{
|
||||
PostTrackCleanup();
|
||||
return initialization_code;
|
||||
}
|
||||
|
||||
// as precondition to this while loop, the correct container, either dbl or mpfr, must have the correct data.
|
||||
while (!IsSymmRelDiffSmall(current_time_,endtime_, Eigen::NumTraits<CT>::epsilon()))
|
||||
{
|
||||
SuccessCode pre_iteration_code = PreIterationCheck();
|
||||
if (pre_iteration_code!=SuccessCode::Success)
|
||||
{
|
||||
PostTrackCleanup();
|
||||
return pre_iteration_code;
|
||||
}
|
||||
|
||||
using std::abs;
|
||||
// compute the next delta_t
|
||||
if (abs(endtime_-current_time_) < abs(current_stepsize_))
|
||||
delta_t_ = endtime_-current_time_;
|
||||
else
|
||||
delta_t_ = current_stepsize_ * (endtime_ - current_time_)/abs(endtime_ - current_time_);
|
||||
|
||||
|
||||
step_success_code_ = TrackerIteration();
|
||||
|
||||
if (infinite_path_truncation_ && (CheckGoingToInfinity()==SuccessCode::GoingToInfinity))
|
||||
{
|
||||
OnInfiniteTruncation();
|
||||
PostTrackCleanup();
|
||||
return SuccessCode::GoingToInfinity;
|
||||
}
|
||||
else if (step_success_code_==SuccessCode::Success)
|
||||
OnStepSuccess();
|
||||
else
|
||||
OnStepFail();
|
||||
|
||||
}// re: while
|
||||
|
||||
|
||||
CopyFinalSolution(solution_at_endtime);
|
||||
PostTrackCleanup();
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Refine a point to tolerance implicitly internally set.
|
||||
|
||||
Runs Newton's method using the current settings for tracking, including the min and max number of iterations allowed, the tracking tolerance, precision, etc. YOU must ensure that the input point has the correct precision.
|
||||
|
||||
\return The SuccessCode indicating whether the refinement completed.
|
||||
|
||||
\param[out] new_space The result of refinement.
|
||||
\param start_point The seed for Newton's method for refinement.
|
||||
\param current_time The current time value for refinement.
|
||||
*/
|
||||
template<typename C>
|
||||
SuccessCode Refine(Vec<C> & new_space,
|
||||
Vec<C> const& start_point, C const& current_time) const
|
||||
{
|
||||
|
||||
static_assert(detail::IsTemplateParameter<C,NeededTypes>::value,"complex type for refinement must be a used type for the tracker");
|
||||
return this->AsDerived().RefineImpl(new_space, start_point, current_time);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Refine a point to a given tolerance.
|
||||
|
||||
Runs Newton's method using the current settings for tracking, including the min and max number of iterations allowed, precision, etc, EXCEPT for the tracking tolerance and max number of iterations, which you feed in here. YOU must ensure that the input point has the correct precision.
|
||||
|
||||
\return The SuccessCode indicating whether the refinement completed.
|
||||
|
||||
\param[out] new_space The result of refinement.
|
||||
\param start_point The seed for Newton's method for refinement.
|
||||
\param current_time The current time value for refinement.
|
||||
\param tolerance The tolerance to which to refine.
|
||||
\param max_iterations The maximum number of iterations to use to refine.
|
||||
*/
|
||||
template<typename C>
|
||||
SuccessCode Refine(Vec<C> & new_space,
|
||||
Vec<C> const& start_point, C const& current_time, double const& tolerance, unsigned max_iterations) const
|
||||
{
|
||||
static_assert(detail::IsTemplateParameter<C,NeededTypes>::value,"complex type for refinement must be a used type for the tracker");
|
||||
|
||||
return this->AsDerived().RefineImpl(new_space, start_point, current_time, tolerance, max_iterations);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Change tracker to use a predictor
|
||||
|
||||
\param new_predictor_choice The new predictor to be used.
|
||||
|
||||
\see Predictor
|
||||
*/
|
||||
void SetPredictor(Predictor new_predictor_choice)
|
||||
{
|
||||
predictor_->PredictorMethod(new_predictor_choice);
|
||||
predictor_order_ = predictor_->Order();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Query the currently set predictor
|
||||
*/
|
||||
Predictor GetPredictor() const
|
||||
{
|
||||
return predictor_->PredictorMethod();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief get a const reference to the system.
|
||||
*/
|
||||
void SetSystem(const System & new_sys)
|
||||
{
|
||||
tracked_system_ = std::ref(new_sys);
|
||||
predictor_->ChangeSystem(tracked_system_);
|
||||
corrector_->ChangeSystem(tracked_system_);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief get a const reference to the system.
|
||||
*/
|
||||
const System& GetSystem() const
|
||||
{
|
||||
return tracked_system_.get();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief See how many steps have been taken.
|
||||
|
||||
\return The total number of steps taken, including successes and fails.
|
||||
*/
|
||||
unsigned NumTotalStepsTaken () const
|
||||
{
|
||||
return num_failed_steps_taken_ + num_successful_steps_taken_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set how large the stepsize should be.
|
||||
|
||||
\param new_stepsize The new value.
|
||||
*/
|
||||
void SetStepSize(RT const& new_stepsize) const
|
||||
{
|
||||
current_stepsize_ = new_stepsize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Switch resetting of initial step size to that of the stepping settings.
|
||||
|
||||
By default, initial step size is retrieved from the stepping settings at the start of each path track. To turn this off, and re-use the previous step size from the previously tracked path, turn off by calling this function with false.
|
||||
*/
|
||||
void ReinitializeInitialStepSize(bool should_reinitialize_stepsize)
|
||||
{
|
||||
reinitialize_stepsize_ = should_reinitialize_stepsize;
|
||||
}
|
||||
|
||||
virtual ~Tracker() = default;
|
||||
|
||||
auto TrackingTolerance() const
|
||||
{
|
||||
return tracking_tolerance_;
|
||||
}
|
||||
|
||||
auto InfiniteTruncationTolerance() const
|
||||
{
|
||||
return path_truncation_threshold_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// convert the base tracker into the derived type.
|
||||
const D& AsDerived() const
|
||||
{
|
||||
return static_cast<const D&>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set up initialization of the internals for tracking a path.
|
||||
|
||||
\param start_time The time at which to start tracking.
|
||||
\param end_time The time to which to track.
|
||||
\param start_point The point from which to start tracking.
|
||||
*/
|
||||
virtual
|
||||
SuccessCode TrackerLoopInitialization(CT const& start_time, CT const& end_time, Vec<CT> const& start_point) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
\brief Check internal state for whether tracking should continue.
|
||||
|
||||
\return Code for whether to go on. Tracking will terminate if the returned value is not Success.
|
||||
*/
|
||||
virtual
|
||||
SuccessCode PreIterationCheck() const = 0;
|
||||
|
||||
/**
|
||||
\brief A single iteration of the tracker loop.
|
||||
|
||||
\return Whether the tracker loop was successful or not. Incrementing of counters for the base class happens automatically.
|
||||
*/
|
||||
virtual
|
||||
SuccessCode TrackerIteration() const = 0;
|
||||
|
||||
/**
|
||||
\brief Copy the solution from whatever internal variable it is stored in, into the output variable.
|
||||
|
||||
\param solution_at_endtime The output variable into which to copy the final solution.
|
||||
*/
|
||||
virtual
|
||||
void CopyFinalSolution(Vec<CT> & solution_at_endtime) const = 0;
|
||||
|
||||
// virtual
|
||||
// void CopyFinalSolution(Vec<dbl> & solution_at_endtime) const = 0;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename ComplexType>
|
||||
SuccessCode CheckGoingToInfinity() const
|
||||
{
|
||||
if (GetSystem().DehomogenizePoint(std::get<Vec<ComplexType> >(current_space_)).norm() > path_truncation_threshold_)
|
||||
return SuccessCode::GoingToInfinity;
|
||||
else
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Function to be called before exiting the tracker loop.
|
||||
*/
|
||||
virtual
|
||||
void PostTrackCleanup() const
|
||||
{}
|
||||
|
||||
/**
|
||||
\brief Reset counters used during tracking.
|
||||
|
||||
Your custom tracker type should almost certainly call this function.
|
||||
*/
|
||||
virtual
|
||||
void ResetCounters() const = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
void ResetCountersBase() const
|
||||
{
|
||||
// reset a bunch of counters to 0.
|
||||
num_consecutive_successful_steps_ = 0;
|
||||
num_successful_steps_taken_ = 0;
|
||||
num_failed_steps_taken_ = 0;
|
||||
num_consecutive_failed_steps_ = 0;
|
||||
num_total_steps_taken_ = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Increment and reset counters after a successful TrackerIteration()
|
||||
|
||||
Your custom override, if provided, should almost certainly call this function.
|
||||
*/
|
||||
void IncrementBaseCountersSuccess() const
|
||||
{
|
||||
num_successful_steps_taken_++;
|
||||
num_consecutive_successful_steps_++;
|
||||
current_time_ += delta_t_;
|
||||
num_consecutive_failed_steps_ = 0;
|
||||
}
|
||||
|
||||
virtual
|
||||
void OnStepSuccess() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
\brief Increment and reset counters after a failed TrackerIteration()
|
||||
|
||||
Your custom override, if provided, should almost certainly call this function.
|
||||
*/
|
||||
void IncrementBaseCountersFail() const
|
||||
{
|
||||
num_consecutive_successful_steps_=0;
|
||||
num_failed_steps_taken_++;
|
||||
num_consecutive_failed_steps_++;
|
||||
}
|
||||
|
||||
|
||||
virtual
|
||||
void OnStepFail() const = 0;
|
||||
|
||||
/**
|
||||
\brief Check whether the path is going to infinity, as it tracks.
|
||||
|
||||
This check is necessary because a homotopy may be malformed, or may have encountered a probability-0 event. That it is a 0 probability event is why this check is disable-able via a toggle.
|
||||
*/
|
||||
virtual
|
||||
SuccessCode CheckGoingToInfinity() const = 0;
|
||||
|
||||
virtual
|
||||
void OnInfiniteTruncation() const = 0;
|
||||
|
||||
|
||||
std::reference_wrapper<const System> tracked_system_; ///< Reference to the system being tracked.
|
||||
|
||||
bool infinite_path_truncation_ = true; /// Whether should check if the path is going to infinity while tracking. On by default.
|
||||
bool reinitialize_stepsize_ = true; ///< Whether should re-initialize the stepsize with each call to Trackpath. On by default.
|
||||
|
||||
// tracking the numbers of things
|
||||
mutable unsigned num_total_steps_taken_; ///< The number of steps taken, including failures and successes.
|
||||
mutable unsigned num_successful_steps_taken_; ///< The number of successful steps taken so far.
|
||||
mutable unsigned num_consecutive_successful_steps_; ///< The number of CONSECUTIVE successful steps taken in a row.
|
||||
mutable unsigned num_consecutive_failed_steps_; ///< The number of CONSECUTIVE failed steps taken in a row.
|
||||
mutable unsigned num_failed_steps_taken_; ///< The total number of failed steps taken.
|
||||
|
||||
|
||||
// configuration for tracking
|
||||
std::shared_ptr<predict::ExplicitRKPredictor > predictor_; // The predictor to use while tracking
|
||||
unsigned predictor_order_; ///< The order of the predictor -- one less than the error estimate order.
|
||||
|
||||
std::shared_ptr<correct::NewtonCorrector> corrector_;
|
||||
|
||||
|
||||
|
||||
unsigned digits_final_ = 0; ///< The number of digits to track to, due to being in endgame zone.
|
||||
unsigned digits_tracking_tolerance_ = 5; ///< The number of digits required for tracking to given tolerance, condition number notwithstanding.
|
||||
NumErrorT tracking_tolerance_ = 1e-5; ///< The tracking tolerance.
|
||||
NumErrorT path_truncation_threshold_ = 1e5; ///< The threshold for path truncation.
|
||||
|
||||
mutable CT endtime_; ///< The time we are tracking to.
|
||||
mutable CT current_time_; ///< The current time.
|
||||
mutable CT delta_t_; ///< The current delta_t.
|
||||
mutable RT current_stepsize_; ///< The current stepsize.
|
||||
|
||||
|
||||
// permanent temporaries
|
||||
mutable RT next_stepsize_; /// The next stepsize
|
||||
mutable SuccessCode step_success_code_; ///< The code for step success.
|
||||
|
||||
|
||||
|
||||
mutable unsigned num_steps_since_last_condition_number_computation_; ///< How many steps have passed since the most recent condition number estimate.
|
||||
mutable unsigned num_successful_steps_since_stepsize_increase_; ///< How many successful steps have been taken since increased stepsize.
|
||||
mutable unsigned num_successful_steps_since_precision_decrease_; ///< The number of successful steps since decreased precision.
|
||||
|
||||
using TupOfVec = typename NeededTypes::ToTupleOfVec;
|
||||
using TupOfReal = typename NeededTypes::ToTupleOfReal;
|
||||
|
||||
mutable TupOfVec current_space_; ///< The current space value.
|
||||
mutable TupOfVec tentative_space_; ///< After correction, the tentative next space value
|
||||
mutable TupOfVec temporary_space_; ///< After prediction, the tentative next space value.
|
||||
|
||||
|
||||
mutable NumErrorT condition_number_estimate_; ///< An estimate on the condition number of the Jacobian
|
||||
mutable NumErrorT error_estimate_; ///< An estimate on the error of a step.
|
||||
mutable NumErrorT norm_J_; ///< An estimate on the norm of the Jacobian
|
||||
mutable NumErrorT norm_J_inverse_;///< An estimate on the norm of the inverse of the Jacobian
|
||||
mutable NumErrorT norm_delta_z_; ///< The norm of the change in space resulting from a step.
|
||||
mutable NumErrorT size_proportion_; ///< The proportion of the space step size, taking into account the order of the predictor.
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
NumErrorT LatestConditionNumber() const
|
||||
{
|
||||
return this->condition_number_estimate_;
|
||||
}
|
||||
|
||||
|
||||
NumErrorT LatestErrorEstimate() const
|
||||
{
|
||||
return this->error_estimate_;
|
||||
}
|
||||
|
||||
|
||||
NumErrorT LatestNormOfStep() const
|
||||
{
|
||||
return this->norm_delta_z_;
|
||||
}
|
||||
|
||||
void SetInfiniteTruncation(bool b)
|
||||
{
|
||||
infinite_path_truncation_ = b;
|
||||
}
|
||||
|
||||
auto InfiniteTruncation()
|
||||
{
|
||||
return infinite_path_truncation_;
|
||||
}
|
||||
|
||||
unsigned NumVariables() const
|
||||
{
|
||||
return GetSystem().NumVariables();
|
||||
}
|
||||
|
||||
auto CurrentTime() const
|
||||
{
|
||||
return current_time_;
|
||||
}
|
||||
|
||||
auto DeltaT() const
|
||||
{
|
||||
return delta_t_;
|
||||
}
|
||||
|
||||
auto CurrentStepsize() const
|
||||
{
|
||||
return current_stepsize_;
|
||||
}
|
||||
|
||||
|
||||
virtual Vec<CT> CurrentPoint() const = 0;
|
||||
|
||||
|
||||
virtual unsigned CurrentPrecision() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // re: namespace tracking
|
||||
} // re: namespace bertini
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
364
core/include/bertini2/trackers/config.hpp
Normal file
364
core/include/bertini2/trackers/config.hpp
Normal file
@@ -0,0 +1,364 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//trackers/include/bertini2/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/bertini2/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/bertini2/trackers/config.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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/bertini2/trackers/config.hpp
|
||||
|
||||
\brief Configs and settings for tracking.
|
||||
*/
|
||||
#include "bertini2/mpfr_extensions.hpp"
|
||||
#include "bertini2/eigen_extensions.hpp"
|
||||
#include "bertini2/system/system.hpp"
|
||||
#include "bertini2/detail/typelist.hpp"
|
||||
|
||||
#include "bertini2/common/config.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<dbl>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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 D>
|
||||
class Tracker;
|
||||
template<class D>
|
||||
class FixedPrecisionTracker;
|
||||
class MultiplePrecisionTracker;
|
||||
class DoublePrecisionTracker;
|
||||
|
||||
|
||||
// now for the TrackerTraits structs, which enable lookup of correct settings objects and types, etc.
|
||||
template<class T>
|
||||
struct TrackerTraits
|
||||
{};
|
||||
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct TrackerTraits<DoublePrecisionTracker>
|
||||
{
|
||||
using BaseComplexType = dbl;
|
||||
using BaseRealType = double;
|
||||
using EventEmitterType = FixedPrecisionTracker<DoublePrecisionTracker>;
|
||||
using PrecisionConfig = FixedPrecisionConfig;
|
||||
enum {
|
||||
IsFixedPrec = 1,
|
||||
IsAdaptivePrec = 0
|
||||
};
|
||||
|
||||
using NeededTypes = detail::TypeList<dbl>;
|
||||
using NeededConfigs = detail::TypeList<
|
||||
SteppingConfig,
|
||||
NewtonConfig,
|
||||
PrecisionConfig
|
||||
>;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct TrackerTraits<MultiplePrecisionTracker>
|
||||
{
|
||||
using BaseComplexType = mpfr_complex;
|
||||
using BaseRealType = mpfr_float;
|
||||
using EventEmitterType = FixedPrecisionTracker<MultiplePrecisionTracker>;
|
||||
using PrecisionConfig = FixedPrecisionConfig;
|
||||
|
||||
enum {
|
||||
IsFixedPrec = 1,
|
||||
IsAdaptivePrec = 0
|
||||
};
|
||||
|
||||
using NeededTypes = detail::TypeList<mpfr_complex>;
|
||||
|
||||
using NeededConfigs = detail::TypeList<
|
||||
SteppingConfig,
|
||||
NewtonConfig,
|
||||
PrecisionConfig
|
||||
>;
|
||||
};
|
||||
|
||||
|
||||
class AMPTracker; // forward declare
|
||||
template<>
|
||||
struct TrackerTraits<AMPTracker>
|
||||
{
|
||||
using BaseComplexType = mpfr_complex;
|
||||
using BaseRealType = mpfr_float;
|
||||
using EventEmitterType = AMPTracker;
|
||||
using PrecisionConfig = AdaptiveMultiplePrecisionConfig;
|
||||
|
||||
enum {
|
||||
IsFixedPrec = 0,
|
||||
IsAdaptivePrec = 1
|
||||
};
|
||||
|
||||
using NeededTypes = detail::TypeList<dbl, mpfr_complex>;
|
||||
|
||||
using NeededConfigs = detail::TypeList<
|
||||
SteppingConfig,
|
||||
NewtonConfig,
|
||||
PrecisionConfig
|
||||
>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<class D>
|
||||
struct TrackerTraits<FixedPrecisionTracker<D> > : public TrackerTraits<D>
|
||||
{
|
||||
using BaseComplexType = typename TrackerTraits<D>::BaseComplexType;
|
||||
using BaseRealType = typename TrackerTraits<D>::BaseRealType;
|
||||
using EventEmitterType = typename TrackerTraits<D>::EventEmitterType;
|
||||
using PrecisionConfig = typename TrackerTraits<D>::PrecisionConfig;
|
||||
|
||||
enum {
|
||||
IsFixedPrec = 0,
|
||||
IsAdaptivePrec = 1
|
||||
};
|
||||
|
||||
using NeededTypes = typename TrackerTraits<D>::NeededTypes;
|
||||
using NeededConfigs = typename TrackerTraits<D>::NeededConfigs;
|
||||
};
|
||||
|
||||
} // re: namespace tracking
|
||||
} // re: namespace bertini
|
||||
|
||||
|
||||
#endif
|
||||
343
core/include/bertini2/trackers/events.hpp
Normal file
343
core/include/bertini2/trackers/events.hpp
Normal file
@@ -0,0 +1,343 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//events.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.
|
||||
//
|
||||
//events.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 events.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
/**
|
||||
\file include/bertini2/trackers/events.hpp
|
||||
|
||||
\brief Contains the tracker/events base types.
|
||||
|
||||
Derived from these types to make new event types.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "bertini2/detail/events.hpp"
|
||||
#include "bertini2/eigen_extensions.hpp"
|
||||
|
||||
namespace bertini {
|
||||
|
||||
namespace tracking{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Generic event for Tracking
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(TrackingEvent,ConstEvent);
|
||||
|
||||
/**
|
||||
\brief A successful step occurred
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(SuccessfulStep,TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief A failed step occurred
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(FailedStep,TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief Taking a new step -- beginning of procedure for attempting to step forward
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(NewStep,TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief The start point for the TrackPath call was singular
|
||||
|
||||
This is evidenced by step size shrinking too far, or running out of precision.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(SingularStartPoint,TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief The predict part of tracking step was successful.
|
||||
*/
|
||||
template<class ObservedT, typename NumT>
|
||||
class SuccessfulPredict : public TrackingEvent<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
/**
|
||||
\brief The constructor for a SuccessfulPredict Event.
|
||||
|
||||
\param obs The observable emitting the event.
|
||||
\param resulting_point The space point which is the result of the prediction.
|
||||
*/
|
||||
SuccessfulPredict(const ObservedT & obs,
|
||||
Vec<NumT> const& resulting_point) : TrackingEvent<ObservedT>(obs),
|
||||
resulting_point_(resulting_point)
|
||||
{}
|
||||
|
||||
|
||||
virtual ~SuccessfulPredict() = default;
|
||||
SuccessfulPredict() = delete;
|
||||
|
||||
/**
|
||||
\brief Get the resulting point of the prediction.
|
||||
*/
|
||||
const Vec<NumT>& ResultingPoint() const {return resulting_point_;}
|
||||
private:
|
||||
const Vec<NumT>& resulting_point_;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief The correct part of a time step was successful
|
||||
*/
|
||||
template<class ObservedT, typename NumT>
|
||||
class SuccessfulCorrect : public TrackingEvent<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
/**
|
||||
\brief The constructor for a SuccessfulCorrect Event.
|
||||
|
||||
\param obs The observable emitting the event.
|
||||
\param resulting_point The space point which is the result of the Newton correct solve.
|
||||
*/
|
||||
SuccessfulCorrect(const ObservedT & obs,
|
||||
Vec<NumT> const& resulting_point) : TrackingEvent<ObservedT>(obs),
|
||||
resulting_point_(resulting_point)
|
||||
{}
|
||||
|
||||
|
||||
virtual ~SuccessfulCorrect() = default;
|
||||
SuccessfulCorrect() = delete;
|
||||
|
||||
/**
|
||||
\brief Get the resulting point of the correction.
|
||||
*/
|
||||
const Vec<NumT>& ResultingPoint() const {return resulting_point_;}
|
||||
private:
|
||||
const Vec<NumT>& resulting_point_;
|
||||
};
|
||||
|
||||
////////////
|
||||
//
|
||||
// Precision events
|
||||
|
||||
/**
|
||||
\brief A generic event involving precision
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(PrecisionEvent,TrackingEvent);
|
||||
|
||||
template<class ObservedT>
|
||||
class PrecisionChanged : public PrecisionEvent<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
/**
|
||||
\brief The constructor for a PrecisionChanged Event.
|
||||
|
||||
\param obs The observable emitting the event.
|
||||
\param previous The precision before changing.
|
||||
\param next The precision after changing.
|
||||
*/
|
||||
PrecisionChanged(const ObservedT & obs,
|
||||
unsigned previous, unsigned next) : PrecisionEvent<ObservedT>(obs),
|
||||
prev_(previous),
|
||||
next_(next)
|
||||
{}
|
||||
|
||||
|
||||
virtual ~PrecisionChanged() = default;
|
||||
PrecisionChanged() = delete;
|
||||
|
||||
/**
|
||||
\brief Get the previous precision.
|
||||
*/
|
||||
auto Previous() const {return prev_;}
|
||||
|
||||
/**
|
||||
\brief Get the next precision, what it changed to.
|
||||
*/
|
||||
auto Next() const {return next_;}
|
||||
private:
|
||||
const unsigned prev_, next_;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Precision increased during tracking
|
||||
*/
|
||||
template<class ObservedT>
|
||||
class PrecisionIncreased : public PrecisionChanged<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
/**
|
||||
\brief The constructor for a PrecisionIncreased Event.
|
||||
|
||||
\param obs The observable emitting the event.
|
||||
\param previous The precision before changing.
|
||||
\param next The precision after changing.
|
||||
*/
|
||||
PrecisionIncreased(const ObservedT & obs,
|
||||
unsigned previous, unsigned next) : PrecisionChanged<ObservedT>(obs, previous, next)
|
||||
{}
|
||||
virtual ~PrecisionIncreased() = default;
|
||||
PrecisionIncreased() = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Precision decreased during tracking
|
||||
*/
|
||||
template<class ObservedT>
|
||||
class PrecisionDecreased : public PrecisionChanged<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
/**
|
||||
\brief The constructor for a PrecisionDecreased Event.
|
||||
|
||||
\param obs The observable emitting the event.
|
||||
\param previous The precision before changing.
|
||||
\param next The precision after changing.
|
||||
*/
|
||||
PrecisionDecreased(const ObservedT & obs,
|
||||
unsigned previous, unsigned next) : PrecisionChanged<ObservedT>(obs, previous, next)
|
||||
{}
|
||||
virtual ~PrecisionDecreased() = default;
|
||||
PrecisionDecreased() = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief A step failed, because precision needs to increase
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(HigherPrecisionNecessary,PrecisionEvent);
|
||||
|
||||
/**
|
||||
\brief Prediction failed, because precision needs to increase
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(PredictorHigherPrecisionNecessary,HigherPrecisionNecessary);
|
||||
|
||||
/**
|
||||
\brief Correction failed, because precision needs to increase
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(CorrectorHigherPrecisionNecessary,HigherPrecisionNecessary);
|
||||
|
||||
/**
|
||||
\brief Linear algebra declared a failure
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(MatrixSolveFailure,PrecisionEvent);
|
||||
|
||||
/**
|
||||
\brief Linear algebra declared a failure, during prediction
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(PredictorMatrixSolveFailure,MatrixSolveFailure);
|
||||
|
||||
/**
|
||||
\brief Linear algebra declared a failure, during the first step of a multi-point prediction.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(FirstStepPredictorMatrixSolveFailure,MatrixSolveFailure);
|
||||
|
||||
/**
|
||||
\brief Linear algebra declared a failure, during correction
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(CorrectorMatrixSolveFailure,MatrixSolveFailure);
|
||||
////////////
|
||||
//
|
||||
// Stepsize events
|
||||
|
||||
/**
|
||||
\brief Stepsize is changing
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(StepsizeEvent,TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief Stepsize decreased
|
||||
|
||||
This means that the step failed, and decreasing step size was the best thing to do.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(StepsizeDecreased,StepsizeEvent);
|
||||
|
||||
/**
|
||||
\brief Stepsize increased.
|
||||
|
||||
This means steps have been successful lately.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(StepsizeIncreased,StepsizeEvent);
|
||||
|
||||
|
||||
///////////
|
||||
//
|
||||
// beginning and end events
|
||||
|
||||
/**
|
||||
\brief Made a call to TrackPath
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(TrackingStarted,TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief Tracking is stopping for whatever reason.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(TrackingEnded, TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief Tracking terminated because the path was going to infinity.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(InfinitePathTruncation, TrackingEvent);
|
||||
|
||||
/**
|
||||
\brief TrackPath is initializing the tracker.
|
||||
*/
|
||||
template<class ObservedT, typename NumT>
|
||||
class Initializing : public TrackingEvent<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
|
||||
/**
|
||||
\brief Constructor for an Initializing Event
|
||||
|
||||
\param obs The observed object, the tracker. `*this` probably.
|
||||
\param start_time The time \f$t_0\f$ at which tracking is starting.
|
||||
\param end_time The target time for tracking.
|
||||
\param start_point The space point \f$x_0\f$ for starting tracking.
|
||||
*/
|
||||
Initializing(const ObservedT & obs,
|
||||
NumT const& start_time,
|
||||
NumT const& endtime,
|
||||
Vec<NumT> const& start_point) : TrackingEvent<ObservedT>(obs),
|
||||
start_time_(start_time),
|
||||
end_time_(endtime),
|
||||
start_point_(start_point)
|
||||
{}
|
||||
|
||||
|
||||
virtual ~Initializing() = default;
|
||||
Initializing() = delete;
|
||||
|
||||
/**
|
||||
\brief Get the time (tracking wise, not clock wise) at which tracking is starting/
|
||||
*/
|
||||
const NumT& StartTime() const {return start_time_;}
|
||||
|
||||
/**
|
||||
\brief Get the target time for tracking.
|
||||
*/
|
||||
const NumT& EndTime() const {return end_time_;}
|
||||
|
||||
/**
|
||||
\brief Get the start point, the input point for TrackPath
|
||||
*/
|
||||
const Vec<NumT>& StartPoint() const {return start_point_;}
|
||||
private:
|
||||
const NumT& start_time_;
|
||||
const NumT& end_time_;
|
||||
const Vec<NumT>& start_point_;
|
||||
};
|
||||
}// re: namespace tracking
|
||||
}// re: namespace bertini
|
||||
|
||||
1136
core/include/bertini2/trackers/explicit_predictors.hpp
Normal file
1136
core/include/bertini2/trackers/explicit_predictors.hpp
Normal file
File diff suppressed because it is too large
Load Diff
575
core/include/bertini2/trackers/fixed_precision_tracker.hpp
Normal file
575
core/include/bertini2/trackers/fixed_precision_tracker.hpp
Normal file
@@ -0,0 +1,575 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//fixed_precision_tracker.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.
|
||||
//
|
||||
//fixed_precision_tracker.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 fixed_precision_tracker.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
/**
|
||||
\file fixed_precision_tracker.hpp
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_FIXED_PRECISION_TRACKER_HPP
|
||||
#define BERTINI_FIXED_PRECISION_TRACKER_HPP
|
||||
|
||||
#include "bertini2/trackers/base_tracker.hpp"
|
||||
|
||||
|
||||
namespace bertini{
|
||||
|
||||
namespace tracking{
|
||||
|
||||
using std::max;
|
||||
using std::min;
|
||||
using std::pow;
|
||||
|
||||
using bertini::max;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\class FixedPrecisionTracker<prec>
|
||||
|
||||
\brief Functor-like class for tracking paths on a system
|
||||
*/
|
||||
template<class DerivedT>
|
||||
class FixedPrecisionTracker : public Tracker<FixedPrecisionTracker<DerivedT>>
|
||||
{
|
||||
public:
|
||||
|
||||
using BaseComplexType = typename TrackerTraits<DerivedT>::BaseComplexType;
|
||||
using BaseRealType = typename TrackerTraits<DerivedT>::BaseRealType;
|
||||
|
||||
using CT = BaseComplexType;
|
||||
using RT = BaseRealType;
|
||||
|
||||
virtual ~FixedPrecisionTracker() = default;
|
||||
|
||||
using EmitterType = FixedPrecisionTracker<DerivedT>;
|
||||
using Base = Tracker<FixedPrecisionTracker<DerivedT>>;
|
||||
|
||||
using Config = typename Base::Config;
|
||||
FORWARD_GET_CONFIGURED
|
||||
using Stepping = typename Base::Stepping;
|
||||
using Newton = typename Base::Newton;
|
||||
|
||||
FixedPrecisionTracker(System const& sys) : Base(sys){}
|
||||
|
||||
/**
|
||||
\brief An additional no-op call, provided for conformity of interface with AMP tracker in generic code.
|
||||
*/
|
||||
void PrecisionSetup(FixedPrecisionConfig const&)
|
||||
{ }
|
||||
|
||||
|
||||
Vec<CT> CurrentPoint() const override
|
||||
{
|
||||
return std::get<Vec<CT>>(this->current_space_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ResetCounters() const override
|
||||
{
|
||||
Base::ResetCountersBase();
|
||||
|
||||
this->num_successful_steps_since_stepsize_increase_ = 0;
|
||||
// initialize to the frequency so guaranteed to compute it the first try
|
||||
this->num_steps_since_last_condition_number_computation_ = this->Get<Stepping>().frequency_of_CN_estimation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Ensure that number of steps, stepsize, and precision still ok.
|
||||
|
||||
\return Success if ok to keep going, and a different code otherwise.
|
||||
*/
|
||||
SuccessCode PreIterationCheck() const override
|
||||
{
|
||||
if (this->num_successful_steps_taken_ >= Get<Stepping>().max_num_steps)
|
||||
return SuccessCode::MaxNumStepsTaken;
|
||||
if (this->current_stepsize_ < Get<Stepping>().min_step_size)
|
||||
return SuccessCode::MinStepSizeReached;
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void PostTrackCleanup() const override
|
||||
{
|
||||
this->NotifyObservers(TrackingEnded<EmitterType>(*this));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Copy from the internally stored current solution into a final solution.
|
||||
|
||||
If preservation of precision is on, this function first returns to the initial precision.
|
||||
|
||||
\param[out] solution_at_endtime The solution at the end time
|
||||
*/
|
||||
void CopyFinalSolution(Vec<CT> & solution_at_endtime) const override
|
||||
{
|
||||
|
||||
// the current precision is the precision of the output solution point.
|
||||
|
||||
unsigned num_vars = this->GetSystem().NumVariables();
|
||||
solution_at_endtime.resize(num_vars);
|
||||
for (unsigned ii=0; ii<num_vars; ii++)
|
||||
{
|
||||
solution_at_endtime(ii) = std::get<Vec<CT> >(this->current_space_)(ii);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run an iteration of the tracker loop.
|
||||
|
||||
Predict and correct, adjusting precision and stepsize as necessary.
|
||||
|
||||
\return Success if the step was successful, and a non-success code if something went wrong, such as a linear algebra failure or AMP Criterion violation.
|
||||
*/
|
||||
SuccessCode TrackerIteration() const override
|
||||
{
|
||||
static_assert(std::is_same< typename Eigen::NumTraits<RT>::Real,
|
||||
typename Eigen::NumTraits<CT>::Real>::value,
|
||||
"underlying complex type and the type for comparisons must match");
|
||||
|
||||
this->NotifyObservers(NewStep<EmitterType >(*this));
|
||||
|
||||
Vec<CT>& predicted_space = std::get<Vec<CT> >(this->temporary_space_); // this will be populated in the Predict step
|
||||
Vec<CT>& current_space = std::get<Vec<CT> >(this->current_space_); // the thing we ultimately wish to update
|
||||
CT current_time = CT(this->current_time_);
|
||||
CT delta_t = CT(this->delta_t_);
|
||||
|
||||
SuccessCode predictor_code = Predict(predicted_space, current_space, current_time, delta_t);
|
||||
|
||||
if (predictor_code!=SuccessCode::Success)
|
||||
{
|
||||
this->NotifyObservers(FirstStepPredictorMatrixSolveFailure<EmitterType >(*this));
|
||||
|
||||
this->next_stepsize_ = RT(Get<Stepping>().step_size_fail_factor)*this->current_stepsize_;
|
||||
|
||||
UpdateStepsize();
|
||||
|
||||
return predictor_code;
|
||||
}
|
||||
|
||||
this->NotifyObservers(SuccessfulPredict<EmitterType , CT>(*this, predicted_space));
|
||||
|
||||
Vec<CT>& tentative_next_space = std::get<Vec<CT> >(this->tentative_space_); // this will be populated in the Correct step
|
||||
|
||||
CT tentative_next_time = current_time + delta_t;
|
||||
|
||||
SuccessCode corrector_code = Correct(tentative_next_space,
|
||||
predicted_space,
|
||||
tentative_next_time);
|
||||
|
||||
if (corrector_code == SuccessCode::GoingToInfinity)
|
||||
{
|
||||
// there is no corrective action possible...
|
||||
return corrector_code;
|
||||
}
|
||||
else if (corrector_code!=SuccessCode::Success)
|
||||
{
|
||||
this->NotifyObservers(CorrectorMatrixSolveFailure<EmitterType >(*this));
|
||||
|
||||
this->next_stepsize_ = RT(Get<Stepping>().step_size_fail_factor)*this->current_stepsize_;
|
||||
UpdateStepsize();
|
||||
|
||||
return corrector_code;
|
||||
}
|
||||
|
||||
|
||||
this->NotifyObservers(SuccessfulCorrect<EmitterType , CT>(*this, tentative_next_space));
|
||||
|
||||
// copy the tentative vector into the current space vector;
|
||||
current_space = tentative_next_space;
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check whether the path is going to infinity.
|
||||
*/
|
||||
SuccessCode CheckGoingToInfinity() const override
|
||||
{
|
||||
return Base::template CheckGoingToInfinity<CT>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Commit the next stepsize, and adjust internals.
|
||||
*/
|
||||
SuccessCode UpdateStepsize() const
|
||||
{
|
||||
this->SetStepSize(this->next_stepsize_);
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////
|
||||
//
|
||||
// overrides for counter adjustment after a TrackerIteration()
|
||||
//
|
||||
////////////////
|
||||
|
||||
/**
|
||||
\brief Increment and reset counters after a successful TrackerIteration()
|
||||
*/
|
||||
void OnStepSuccess() const override
|
||||
{
|
||||
Base::IncrementBaseCountersSuccess();
|
||||
this->NotifyObservers(SuccessfulStep<EmitterType >(*this));
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Increment and reset counters after a failed TrackerIteration()
|
||||
*/
|
||||
void OnStepFail() const override
|
||||
{
|
||||
Base::IncrementBaseCountersFail();
|
||||
this->num_successful_steps_since_stepsize_increase_ = 0;
|
||||
this->NotifyObservers(FailedStep<EmitterType >(*this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OnInfiniteTruncation() const override
|
||||
{
|
||||
this->NotifyObservers(InfinitePathTruncation<EmitterType>(*this));
|
||||
}
|
||||
|
||||
//////////////
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/**
|
||||
\brief Wrapper function for calling the correct predictor.
|
||||
|
||||
This function computes the next predicted space value, and sets some internals based on the prediction, such as the norm of the Jacobian.
|
||||
|
||||
The real type and complex type must be commensurate.
|
||||
|
||||
\param[out] predicted_space The result of the prediction
|
||||
\param current_space The current space point.
|
||||
\param current_time The current time value.
|
||||
\param delta_t The time differential for this step. Allowed to be complex.
|
||||
*/
|
||||
SuccessCode Predict(Vec<CT> & predicted_space,
|
||||
Vec<CT> const& current_space,
|
||||
CT const& current_time, CT const& delta_t) const
|
||||
{
|
||||
|
||||
return this->predictor_->Predict(
|
||||
predicted_space,
|
||||
this->tracked_system_,
|
||||
current_space, current_time,
|
||||
delta_t,
|
||||
this->condition_number_estimate_,
|
||||
this->num_steps_since_last_condition_number_computation_,
|
||||
Get<Stepping>().frequency_of_CN_estimation,
|
||||
this->tracking_tolerance_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method.
|
||||
|
||||
Wrapper function for calling Correct and getting the error estimates etc directly into the tracker object.
|
||||
|
||||
\param corrected_space[out] The spatial result of the correction loop.
|
||||
\param current_space The start point in space for running the corrector loop.
|
||||
\param current_time The current time value.
|
||||
|
||||
\return A SuccessCode indicating whether the loop was successful in converging in the max number of allowable newton steps, to the current path tolerance.
|
||||
*/
|
||||
SuccessCode Correct(Vec<CT> & corrected_space,
|
||||
Vec<CT> const& current_space,
|
||||
CT const& current_time) const
|
||||
{
|
||||
return this->corrector_->Correct(corrected_space,
|
||||
this->tracked_system_,
|
||||
current_space,
|
||||
current_time,
|
||||
this->tracking_tolerance_,
|
||||
Get<Newton>().min_num_newton_iterations,
|
||||
Get<Newton>().max_num_newton_iterations);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method from a start point with a current time.
|
||||
|
||||
Returns new space point by reference, as new_space. Operates at current precision. The tolerance is the tracking tolerance specified during Setup(...).
|
||||
|
||||
|
||||
\param[out] new_space The result of running the refinement.
|
||||
\param start_point The base point for running Newton's method.
|
||||
\param current_time The current time value.
|
||||
|
||||
\return Code indicating whether was successful or not. Regardless, the value of new_space is overwritten with the correction result.
|
||||
*/
|
||||
SuccessCode RefineImpl(Vec<CT> & new_space,
|
||||
Vec<CT> const& start_point, CT const& current_time) const
|
||||
{
|
||||
return this->corrector_->Correct(new_space,
|
||||
this->tracked_system_,
|
||||
start_point,
|
||||
current_time,
|
||||
this->tracking_tolerance_,
|
||||
Get<Newton>().min_num_newton_iterations,
|
||||
Get<Newton>().max_num_newton_iterations);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method from a start point with a current time.
|
||||
|
||||
Returns new space point by reference, as new_space. Operates at current precision.
|
||||
|
||||
|
||||
\param[out] new_space The result of running the refinement.
|
||||
\param start_point The base point for running Newton's method.
|
||||
\param current_time The current time value.
|
||||
\param tolerance The tolerance for convergence. This is a tolerance on \f$\Delta x\f$, not on function residuals.
|
||||
\param max_iterations The maximum number of permitted Newton iterations.
|
||||
|
||||
\return Code indicating whether was successful or not. Regardless, the value of new_space is overwritten with the correction result.
|
||||
*/
|
||||
SuccessCode RefineImpl(Vec<CT> & new_space,
|
||||
Vec<CT> const& start_point, CT const& current_time,
|
||||
NumErrorT const& tolerance, unsigned max_iterations) const
|
||||
{
|
||||
return this->corrector_->Correct(new_space,
|
||||
this->tracked_system_,
|
||||
start_point,
|
||||
current_time,
|
||||
tolerance,
|
||||
1,
|
||||
max_iterations);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//////////////////////////////////////
|
||||
/////////////////////////////
|
||||
//////////////////// data members stored in this class
|
||||
////////////
|
||||
//////
|
||||
//
|
||||
|
||||
// no additional state variables needed for the FixedPrecision base tracker types
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class DoublePrecisionTracker : public FixedPrecisionTracker<DoublePrecisionTracker>
|
||||
{
|
||||
public:
|
||||
using BaseComplexType = dbl;
|
||||
using BaseRealType = double;
|
||||
|
||||
using EmitterType = typename TrackerTraits<DoublePrecisionTracker>::EventEmitterType;
|
||||
|
||||
|
||||
/**
|
||||
\brief Construct a tracker, associating to it a System.
|
||||
*/
|
||||
DoublePrecisionTracker(class System const& sys) : FixedPrecisionTracker<DoublePrecisionTracker>(sys)
|
||||
{ }
|
||||
|
||||
|
||||
DoublePrecisionTracker() = delete;
|
||||
|
||||
virtual ~DoublePrecisionTracker() = default;
|
||||
|
||||
|
||||
unsigned CurrentPrecision() const override
|
||||
{
|
||||
return DoublePrecision();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Set up the internals of the tracker for a fresh start.
|
||||
|
||||
Copies the start time, current stepsize, and start point. Adjusts the current precision to match the precision of the start point. Zeros counters.
|
||||
|
||||
\param start_time The time at which to start tracking.
|
||||
\param end_time The time to which to track.
|
||||
\param start_point The space values from which to start tracking.
|
||||
*/
|
||||
SuccessCode TrackerLoopInitialization(BaseComplexType const& start_time,
|
||||
BaseComplexType const& end_time,
|
||||
Vec<BaseComplexType> const& start_point) const override
|
||||
{
|
||||
this->NotifyObservers(Initializing<EmitterType,BaseComplexType>(*this,start_time, end_time, start_point));
|
||||
|
||||
// set up the master current time and the current step size
|
||||
this->current_time_ = start_time;
|
||||
this->endtime_ = end_time;
|
||||
std::get<Vec<BaseComplexType> >(this->current_space_) = start_point;
|
||||
if (this->reinitialize_stepsize_)
|
||||
this->SetStepSize(min(BaseRealType(Get<Stepping>().initial_step_size),abs(start_time-end_time)/Get<Stepping>().min_num_steps));
|
||||
|
||||
ResetCounters();
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
}; // re: DoublePrecisionTracker
|
||||
|
||||
|
||||
class MultiplePrecisionTracker : public FixedPrecisionTracker<MultiplePrecisionTracker>
|
||||
{
|
||||
public:
|
||||
using BaseComplexType = mpfr_complex;
|
||||
using BaseRealType = mpfr_float;
|
||||
|
||||
using EmitterType = FixedPrecisionTracker<MultiplePrecisionTracker>;
|
||||
|
||||
|
||||
/**
|
||||
\brief Construct a tracker, associating to it a System.
|
||||
|
||||
The precision of the tracker will be whatever the current default is. The tracker cannot change its precision, and will require the default precision to be this precision whenever tracking is started. That is, the precision is fixed.
|
||||
*/
|
||||
MultiplePrecisionTracker(class System const& sys) : FixedPrecisionTracker<MultiplePrecisionTracker>(sys), precision_(DefaultPrecision())
|
||||
{ }
|
||||
|
||||
|
||||
MultiplePrecisionTracker() = delete;
|
||||
|
||||
virtual ~MultiplePrecisionTracker() = default;
|
||||
|
||||
|
||||
unsigned CurrentPrecision() const override
|
||||
{
|
||||
return precision_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Set up the internals of the tracker for a fresh start.
|
||||
|
||||
Copies the start time, current stepsize, and start point. Adjusts the current precision to match the precision of the start point. Zeros counters.
|
||||
|
||||
\param start_time The time at which to start tracking.
|
||||
\param end_time The time to which to track.
|
||||
\param start_point The space values from which to start tracking.
|
||||
*/
|
||||
SuccessCode TrackerLoopInitialization(BaseComplexType const& start_time,
|
||||
BaseComplexType const& end_time,
|
||||
Vec<BaseComplexType> const& start_point) const override
|
||||
{
|
||||
|
||||
if (start_point(0).precision()!=DefaultPrecision())
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "start point for fixed multiple precision tracker has differing precision from default (" << start_point(0).precision() << "!=" << DefaultPrecision() << "), tracking cannot start";
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
if (start_point(0).precision()!=this->CurrentPrecision())
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "start point for fixed multiple precision tracker has differing precision from tracker's precision (" << start_point(0).precision() << "!=" << this->CurrentPrecision() << "), tracking cannot start";
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
if (DefaultPrecision()!=this->CurrentPrecision())
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "current default precision differs from tracker's precision (" << DefaultPrecision() << "!=" << this->CurrentPrecision() << "), tracking cannot start";
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
|
||||
this->NotifyObservers(Initializing<EmitterType,BaseComplexType>(*this,start_time, end_time, start_point));
|
||||
|
||||
// set up the master current time and the current step size
|
||||
this->current_time_ = start_time;
|
||||
this->endtime_ = end_time;
|
||||
std::get<Vec<BaseComplexType> >(this->current_space_) = start_point;
|
||||
if (this->reinitialize_stepsize_)
|
||||
this->SetStepSize(min(mpfr_float(Get<Stepping>().initial_step_size),mpfr_float(abs(start_time-end_time)/Get<Stepping>().min_num_steps)));
|
||||
|
||||
ResetCounters();
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
bool PrecisionSanityCheck() const
|
||||
{
|
||||
return GetSystem().precision() == precision_ &&
|
||||
DefaultPrecision()==precision_ &&
|
||||
std::get<Vec<mpfr_complex> >(current_space_)(0).precision() == precision_ &&
|
||||
std::get<Vec<mpfr_complex> >(tentative_space_)(0).precision() == precision_ &&
|
||||
std::get<Vec<mpfr_complex> >(temporary_space_)(0).precision() == precision_ &&
|
||||
Precision(this->endtime_)==precision_
|
||||
;
|
||||
}
|
||||
private:
|
||||
|
||||
unsigned precision_;
|
||||
}; // re: MultiplePrecisionTracker
|
||||
} // namespace tracking
|
||||
} // namespace bertini
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
103
core/include/bertini2/trackers/fixed_precision_utilities.hpp
Normal file
103
core/include/bertini2/trackers/fixed_precision_utilities.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//fixed_precision_utilities.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.
|
||||
//
|
||||
//fixed_precision_utilities.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 fixed_precision_utilities.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
|
||||
|
||||
namespace bertini{ namespace tracking {
|
||||
namespace fixed{
|
||||
|
||||
inline
|
||||
void SetPrecision(SampCont<mpfr_complex> & samples, unsigned prec)
|
||||
{
|
||||
for (auto& s : samples)
|
||||
for (unsigned ii=0; ii<s.size(); ii++)
|
||||
s(ii).precision(prec);
|
||||
}
|
||||
|
||||
inline
|
||||
void SetPrecision(TimeCont<mpfr_complex> & times, unsigned prec)
|
||||
{
|
||||
for (auto& t : times)
|
||||
t.precision(prec);
|
||||
}
|
||||
|
||||
inline
|
||||
unsigned MaxPrecision(SampCont<mpfr_complex> const& samples)
|
||||
{
|
||||
unsigned max_precision = 0;
|
||||
for (auto& s : samples)
|
||||
if(Precision(s(0)) > max_precision)
|
||||
max_precision = Precision(s(0));
|
||||
return max_precision;
|
||||
}
|
||||
|
||||
inline
|
||||
unsigned MaxPrecision(TimeCont<mpfr_complex> const& times)
|
||||
{
|
||||
unsigned max_precision = 0;
|
||||
for (auto& t : times)
|
||||
if(Precision(t) > max_precision)
|
||||
max_precision = Precision(t);
|
||||
return max_precision;
|
||||
}
|
||||
|
||||
|
||||
//does not a thing, because cannot.
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<dbl> const & times, SampCont<dbl> const & derivatives)
|
||||
{
|
||||
return DoublePrecision();
|
||||
}
|
||||
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<dbl> const & times, SampCont<dbl> const & samples, SampCont<dbl> const & derivatives)
|
||||
{
|
||||
return DoublePrecision();
|
||||
}
|
||||
|
||||
|
||||
//changes precision of mpfr_complex to highest needed precision for the samples.
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<mpfr_complex> const & times, SampCont<mpfr_complex> const & samples)
|
||||
{
|
||||
return MaxPrecision(samples);
|
||||
}
|
||||
|
||||
|
||||
//returns max precision of all samples.
|
||||
inline
|
||||
unsigned EnsureAtUniformPrecision(TimeCont<mpfr_complex> const & times, SampCont<mpfr_complex> const & samples, SampCont<mpfr_complex> const & derivatives)
|
||||
{
|
||||
return max(MaxPrecision(samples),
|
||||
MaxPrecision(derivatives));
|
||||
}
|
||||
|
||||
|
||||
}}} // re: namespaces
|
||||
|
||||
|
||||
255
core/include/bertini2/trackers/newton_correct.hpp
Normal file
255
core/include/bertini2/trackers/newton_correct.hpp
Normal file
@@ -0,0 +1,255 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//newton_correct.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.
|
||||
//
|
||||
//newton_correct.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 newton_correct.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
/**
|
||||
\file newton_correct.hpp
|
||||
|
||||
\brief Implements Newton's method for square systems
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BERTINI_NEWTON_CORRECT_HPP
|
||||
#define BERTINI_NEWTON_CORRECT_HPP
|
||||
|
||||
|
||||
#include "bertini2/trackers/amp_criteria.hpp"
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
#include "bertini2/system.hpp"
|
||||
|
||||
namespace bertini{
|
||||
namespace tracking{
|
||||
namespace correct{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method in fixed precision.
|
||||
|
||||
Run Newton's method until it converges (\f$\Delta z\f$ < tol), or the next point's norm exceeds the path truncation threshold.
|
||||
|
||||
\return The SuccessCode indicating what happened.
|
||||
|
||||
\tparam ComplexType The complex type for arithmetic
|
||||
\tparam RealType The underlying real number type, used for comparitors.
|
||||
|
||||
\param[out] next_space The computed next space point.
|
||||
\param S The system we are tracking on.
|
||||
\param current_space The base point for newton correcting.
|
||||
\param current_time The current time value. Note it is complex.
|
||||
\param tracking_tolerance The upper threshold for step size. Must iterate correcting until the corrector step is less than this threshold in length.
|
||||
\param path_truncation_threshold Correcting stops the the norm of the current solution exceeds this number.
|
||||
\param min_num_newton_iterations The corrector must take at least this many steps. This should be at least 1.
|
||||
\param max_num_newton_iterations The maximum number of iterations to run Newton's method for.
|
||||
|
||||
*/
|
||||
template <typename ComplexType, typename RealType>
|
||||
SuccessCode NewtonLoop(Vec<ComplexType> & next_space,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, // pass by value to get a copy of it
|
||||
ComplexType const& current_time,
|
||||
RealType const& tracking_tolerance,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations)
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
|
||||
#endif
|
||||
|
||||
|
||||
next_space = current_space;
|
||||
for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
|
||||
{
|
||||
auto f = S.Eval(next_space, current_time);
|
||||
auto J = S.Jacobian(next_space, current_time);
|
||||
auto LU = J.lu();
|
||||
|
||||
if (LUPartialPivotDecompositionSuccessful(LU.matrixLU())!=MatrixSuccessCode::Success)
|
||||
return SuccessCode::MatrixSolveFailure;
|
||||
|
||||
auto delta_z = LU.solve(-f);
|
||||
next_space += delta_z;
|
||||
|
||||
if ( (delta_z.norm() < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
return SuccessCode::FailedToConverge;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method in multiple precision.
|
||||
|
||||
Run Newton's method until it converges (\f$\Delta z\f$ < tol), an AMP criterion (B or C) is violated, or the next point's norm exceeds the path truncation threshold.
|
||||
|
||||
\tparam ComplexType The complex type for arithmetic
|
||||
\tparam RealType The underlying real number type, used for comparitors.
|
||||
|
||||
\param[out] next_space The computed next space point.
|
||||
\param S The system we are tracking on.
|
||||
\param current_space The base point for newton correcting.
|
||||
\param current_time The current time value. Note it is complex.
|
||||
\param tracking_tolerance The upper threshold for step size. Must iterate correcting until the corrector step is less than this threshold in length.
|
||||
\param path_truncation_threshold Correcting stops the the norm of the current solution exceeds this number.
|
||||
\param min_num_newton_iterations The corrector must take at least this many steps. This should be at least 1.
|
||||
\param max_num_newton_iterations The maximum number of iterations to run Newton's method for.
|
||||
\param AMP_config Adaptive multiple precision settings. Using this argument is how Bertini2 knows you want to use adaptive precision.
|
||||
*/
|
||||
template <typename ComplexType, typename RealType>
|
||||
SuccessCode NewtonLoop(Vec<ComplexType> & next_space,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, // pass by value to get a copy of it
|
||||
ComplexType const& current_time,
|
||||
RealType const& tracking_tolerance,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
|
||||
#endif
|
||||
|
||||
|
||||
next_space = current_space;
|
||||
for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
|
||||
{
|
||||
//TODO: wrap these into a single line.
|
||||
auto f = S.Eval(next_space, current_time);
|
||||
auto J = S.Jacobian(next_space, current_time);
|
||||
auto LU = J.lu();
|
||||
|
||||
if (LUPartialPivotDecompositionSuccessful(LU.matrixLU())!=MatrixSuccessCode::Success)
|
||||
return SuccessCode::MatrixSolveFailure;
|
||||
|
||||
|
||||
auto delta_z = LU.solve(-f);
|
||||
next_space += delta_z;
|
||||
|
||||
if ( (delta_z.norm() < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
|
||||
return SuccessCode::Success;
|
||||
|
||||
auto norm_J_inverse = LU.solve(RandomOfUnits<ComplexType>(S.NumVariables())).norm();
|
||||
if (!amp::CriterionB(J.norm(), norm_J_inverse, max_num_newton_iterations - ii, tracking_tolerance, delta_z.norm(), AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
|
||||
if (!amp::CriterionC(norm_J_inverse, next_space, tracking_tolerance, AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
}
|
||||
|
||||
return SuccessCode::FailedToConverge;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method in multiple precision.
|
||||
|
||||
Run Newton's method until it converges (\f$\Delta z\f$ < tol), an AMP criterion (B or C) is violated, or the next point's norm exceeds the path truncation threshold.
|
||||
|
||||
\tparam ComplexType The complex type for arithmetic
|
||||
\tparam RealType The underlying real number type, used for comparitors.
|
||||
|
||||
\param[out] next_space The computed next space point.
|
||||
\param[out] norm_delta_z The norm of the last step size.
|
||||
\param[out] norm_J The matrix norm of the Jacobian matrix.
|
||||
\param[out] norm_J_inverse The matrix norm of the inverse of the Jacobian matrix.
|
||||
\param[out] condition_number_estimate An estimate on the condition number.
|
||||
\param S The system we are tracking on.
|
||||
\param current_space The base point for newton correcting.
|
||||
\param current_time The current time value. Note it is complex.
|
||||
\param tracking_tolerance The upper threshold for step size. Must iterate correcting until the corrector step is less than this threshold in length.
|
||||
\param path_truncation_threshold Correcting stops the the norm of the current solution exceeds this number.
|
||||
\param min_num_newton_iterations The corrector must take at least this many steps. This should be at least 1.
|
||||
\param max_num_newton_iterations The maximum number of iterations to run Newton's method for.
|
||||
\param AMP_config Adaptive multiple precision settings. Using this argument is how Bertini2 knows you want to use adaptive precision.
|
||||
*/
|
||||
template <typename ComplexType, typename RealType>
|
||||
SuccessCode NewtonLoop(Vec<ComplexType> & next_space,
|
||||
RealType & norm_delta_z,
|
||||
RealType & norm_J,
|
||||
RealType & norm_J_inverse,
|
||||
RealType & condition_number_estimate,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, // pass by value to get a copy of it
|
||||
ComplexType const& current_time,
|
||||
RealType const& tracking_tolerance,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
|
||||
#endif
|
||||
|
||||
|
||||
next_space = current_space;
|
||||
for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
|
||||
{
|
||||
//TODO: wrap these into a single line.
|
||||
auto f = S.Eval(next_space, current_time);
|
||||
auto J = S.Jacobian(next_space, current_time);
|
||||
auto LU = J.lu();
|
||||
|
||||
|
||||
if (LUPartialPivotDecompositionSuccessful(LU.matrixLU())!=MatrixSuccessCode::Success)
|
||||
return SuccessCode::MatrixSolveFailure;
|
||||
|
||||
|
||||
auto delta_z = LU.solve(-f);
|
||||
next_space += delta_z;
|
||||
|
||||
|
||||
norm_delta_z = delta_z.norm();
|
||||
norm_J = J.norm();
|
||||
norm_J_inverse = LU.solve(RandomOfUnits<ComplexType>(S.NumVariables())).norm();
|
||||
condition_number_estimate = norm_J*norm_J_inverse;
|
||||
|
||||
|
||||
|
||||
if ( (norm_delta_z < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
|
||||
return SuccessCode::Success;
|
||||
|
||||
if (!amp::CriterionB(norm_J, norm_J_inverse, max_num_newton_iterations - ii, tracking_tolerance, norm_delta_z, AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
|
||||
if (!amp::CriterionC(norm_J_inverse, next_space, tracking_tolerance, AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
}
|
||||
|
||||
return SuccessCode::FailedToConverge;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
392
core/include/bertini2/trackers/newton_corrector.hpp
Normal file
392
core/include/bertini2/trackers/newton_corrector.hpp
Normal file
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// newton_corrector.hpp
|
||||
// Xcode_b2
|
||||
//
|
||||
// Created by Collins, James B. on 4/27/16.
|
||||
// Copyright (c) 2016 West Texas A&M University. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef BERTINI_NEWTON_CORRECTOR_HPP
|
||||
#define BERTINI_NEWTON_CORRECTOR_HPP
|
||||
|
||||
#include "bertini2/trackers/amp_criteria.hpp"
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
#include "bertini2/system/system.hpp"
|
||||
|
||||
|
||||
namespace bertini{
|
||||
namespace tracking{
|
||||
namespace correct{
|
||||
|
||||
|
||||
/**
|
||||
/class NewtonCorrector
|
||||
|
||||
\brief A command class which performs a newton correction step.
|
||||
|
||||
## Purpose
|
||||
|
||||
Stores information computed during implementation of the method.
|
||||
|
||||
|
||||
## Use
|
||||
To perform a correction step, you must instantiate an object and call Correct:
|
||||
|
||||
\code
|
||||
NewtonCorrect<Complex,Real> newton(sys)
|
||||
success_code = newton.Correct( ... )
|
||||
\endcode
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class NewtonCorrector
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
NewtonCorrector(const System& S) : current_precision_(DefaultPrecision())
|
||||
{
|
||||
ChangeSystem(S);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Sets the Newton configuration settings.
|
||||
|
||||
\param newton_settings A Newton struct holding configuration settings.
|
||||
|
||||
*/
|
||||
|
||||
void Settings(const NewtonConfig& newton_settings)
|
||||
{
|
||||
newton_config_ = newton_settings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/brief Change the precision of the predictor variables and reassign the Butcher table variables.
|
||||
|
||||
\param new_precision The new precision.
|
||||
|
||||
*/
|
||||
void ChangePrecision(unsigned new_precision)
|
||||
{
|
||||
Precision(std::get< Vec<mpfr_complex> >(f_temp_), new_precision);
|
||||
Precision(std::get< Vec<mpfr_complex> >(step_temp_), new_precision);
|
||||
Precision(std::get< Mat<mpfr_complex> >(J_temp_), new_precision);
|
||||
|
||||
std::get< Eigen::PartialPivLU<Mat<mpfr_complex>> >(LU_) = Eigen::PartialPivLU<Mat<mpfr_complex>>(numTotalFunctions_);
|
||||
|
||||
current_precision_ = new_precision;
|
||||
}
|
||||
|
||||
|
||||
unsigned precision() const
|
||||
{
|
||||
return current_precision_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Change the system(number of total functions) that the predictor uses.
|
||||
|
||||
\param S New system
|
||||
|
||||
*/
|
||||
void ChangeSystem(const System& S)
|
||||
{
|
||||
numTotalFunctions_ = S.NumTotalFunctions();
|
||||
numVariables_ = S.NumVariables();
|
||||
std::get< Mat<dbl> >(J_temp_).resize(numTotalFunctions_, numVariables_);
|
||||
std::get< Mat<mpfr_complex> >(J_temp_).resize(numTotalFunctions_, numVariables_);
|
||||
std::get< Vec<dbl> >(f_temp_).resize(numTotalFunctions_);
|
||||
std::get< Vec<mpfr_complex> >(f_temp_).resize(numTotalFunctions_);
|
||||
std::get< Vec<dbl> >(step_temp_).resize(numTotalFunctions_);
|
||||
std::get< Vec<mpfr_complex> >(step_temp_).resize(numTotalFunctions_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method in fixed precision.
|
||||
|
||||
Run Newton's method until it converges (\f$\Delta z\f$ < tol), or the next point's norm exceeds the path truncation threshold.
|
||||
|
||||
\return The SuccessCode indicating what happened.
|
||||
|
||||
\tparam ComplexType The complex type for arithmetic
|
||||
|
||||
\param[out] next_space The computed next space point.
|
||||
\param S The system we are tracking on.
|
||||
\param current_space The base point for newton correcting.
|
||||
\param current_time The current time value. Note it is complex.
|
||||
\param tracking_tolerance The upper threshold for step size. Must iterate correcting until the corrector step is less than this threshold in length.
|
||||
\param path_truncation_threshold Correcting stops the the norm of the current solution exceeds this number.
|
||||
\param min_num_newton_iterations The corrector must take at least this many steps. This should be at least 1.
|
||||
\param max_num_newton_iterations The maximum number of iterations to run Newton's method for.
|
||||
|
||||
*/
|
||||
|
||||
template <typename ComplexType>
|
||||
SuccessCode Correct(Vec<ComplexType> & next_space,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, // pass by value to get a copy of it
|
||||
ComplexType const& current_time,
|
||||
NumErrorT const& tracking_tolerance,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations)
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
|
||||
#endif
|
||||
|
||||
Vec<ComplexType>& step_ref = std::get< Vec<ComplexType> >(step_temp_);
|
||||
|
||||
next_space = current_space;
|
||||
for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
|
||||
{
|
||||
//Update the newton iterate by one iteration
|
||||
auto success_code = EvalIterationStep(step_ref, S, next_space, current_time);
|
||||
if(success_code != SuccessCode::Success)
|
||||
return success_code;
|
||||
|
||||
next_space += step_ref;
|
||||
|
||||
if ( (step_ref.template lpNorm<Eigen::Infinity>() < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
return SuccessCode::FailedToConverge;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method in multiple precision.
|
||||
|
||||
Run Newton's method until it converges (\f$\Delta z\f$ < tol), an AMP criterion (B or C) is violated, or the next point's norm exceeds the path truncation threshold.
|
||||
|
||||
\tparam ComplexType The complex type for arithmetic
|
||||
|
||||
\param[out] next_space The computed next space point.
|
||||
\param S The system we are tracking on.
|
||||
\param current_space The base point for newton correcting.
|
||||
\param current_time The current time value. Note it is complex.
|
||||
\param tracking_tolerance The upper threshold for step size. Must iterate correcting until the corrector step is less than this threshold in length.
|
||||
\param path_truncation_threshold Correcting stops the the norm of the current solution exceeds this number.
|
||||
\param min_num_newton_iterations The corrector must take at least this many steps. This should be at least 1.
|
||||
\param max_num_newton_iterations The maximum number of iterations to run Newton's method for.
|
||||
\param AMP_config Adaptive multiple precision settings. Using this argument is how Bertini2 knows you want to use adaptive precision.
|
||||
*/
|
||||
template <typename ComplexType>
|
||||
SuccessCode Correct(Vec<ComplexType> & next_space,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, // pass by value to get a copy of it
|
||||
ComplexType const& current_time,
|
||||
NumErrorT const& tracking_tolerance,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
|
||||
#endif
|
||||
|
||||
Vec<ComplexType>& step_ref = std::get< Vec<ComplexType> >(step_temp_);
|
||||
|
||||
next_space = current_space;
|
||||
for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
|
||||
{
|
||||
//Update the newton iterate by one iteration
|
||||
auto success_code = EvalIterationStep(step_ref, S, next_space, current_time);
|
||||
if(success_code != SuccessCode::Success)
|
||||
return success_code;
|
||||
|
||||
next_space += step_ref;
|
||||
|
||||
Mat<ComplexType>& J_temp_ref = std::get< Mat<ComplexType> >(J_temp_);
|
||||
Eigen::PartialPivLU< Mat<ComplexType> >& LU_ref = std::get< Eigen::PartialPivLU< Mat<ComplexType> > >(LU_);
|
||||
|
||||
if ( (step_ref.template lpNorm<Eigen::Infinity>() < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
|
||||
return SuccessCode::Success;
|
||||
|
||||
NumErrorT norm_J_inverse(LU_ref.solve(RandomOfUnits<ComplexType>(S.NumVariables())).norm());
|
||||
|
||||
if (!amp::CriterionB<ComplexType>(NumErrorT(J_temp_ref.norm()), norm_J_inverse, max_num_newton_iterations - ii, tracking_tolerance, NumErrorT(step_ref.template lpNorm<Eigen::Infinity>()), AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
|
||||
if (!amp::CriterionC<ComplexType>(norm_J_inverse, next_space, tracking_tolerance, AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
}
|
||||
|
||||
return SuccessCode::FailedToConverge;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Run Newton's method in multiple precision.
|
||||
|
||||
Run Newton's method until it converges (\f$\Delta z\f$ < tol), an AMP criterion (B or C) is violated, or the next point's norm exceeds the path truncation threshold.
|
||||
|
||||
\tparam ComplexType The complex type for arithmetic
|
||||
\tparam RealType The underlying real number type, used for comparitors.
|
||||
|
||||
\param[out] next_space The computed next space point.
|
||||
\param[out] norm_delta_z The norm of the last step size.
|
||||
\param[out] norm_J The matrix norm of the Jacobian matrix.
|
||||
\param[out] norm_J_inverse The matrix norm of the inverse of the Jacobian matrix.
|
||||
\param[out] condition_number_estimate An estimate on the condition number.
|
||||
\param S The system we are tracking on.
|
||||
\param current_space The base point for newton correcting.
|
||||
\param current_time The current time value. Note it is complex.
|
||||
\param tracking_tolerance The upper threshold for step size. Must iterate correcting until the corrector step is less than this threshold in length.
|
||||
\param path_truncation_threshold Correcting stops the the norm of the current solution exceeds this number.
|
||||
\param min_num_newton_iterations The corrector must take at least this many steps. This should be at least 1.
|
||||
\param max_num_newton_iterations The maximum number of iterations to run Newton's method for.
|
||||
\param AMP_config Adaptive multiple precision settings. Using this argument is how Bertini2 knows you want to use adaptive precision.
|
||||
*/
|
||||
template <typename ComplexType>
|
||||
SuccessCode Correct(Vec<ComplexType> & next_space,
|
||||
NumErrorT & norm_delta_z,
|
||||
NumErrorT & norm_J,
|
||||
NumErrorT & norm_J_inverse,
|
||||
NumErrorT & condition_number_estimate,
|
||||
System const& S,
|
||||
Vec<ComplexType> const& current_space, // pass by value to get a copy of it
|
||||
ComplexType const& current_time,
|
||||
NumErrorT const& tracking_tolerance,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(max_num_newton_iterations >= min_num_newton_iterations && "max number newton iterations must be at least the min.");
|
||||
#endif
|
||||
|
||||
Vec<ComplexType>& step_ref = std::get< Vec<ComplexType> >(step_temp_);
|
||||
|
||||
next_space = current_space;
|
||||
for (unsigned ii = 0; ii < max_num_newton_iterations; ++ii)
|
||||
{
|
||||
//Update the newton iterate by one iteration
|
||||
auto success_code = EvalIterationStep(step_ref, S, next_space, current_time);
|
||||
if(success_code != SuccessCode::Success)
|
||||
return success_code;
|
||||
|
||||
next_space += step_ref;
|
||||
|
||||
Mat<ComplexType>& J_temp_ref = std::get< Mat<ComplexType> >(J_temp_);
|
||||
Eigen::PartialPivLU< Mat<ComplexType> >& LU_ref = std::get< Eigen::PartialPivLU< Mat<ComplexType> > >(LU_);
|
||||
|
||||
|
||||
norm_delta_z = NumErrorT(step_ref.template lpNorm<Eigen::Infinity>());
|
||||
norm_J = NumErrorT(J_temp_ref.norm());
|
||||
norm_J_inverse = NumErrorT(LU_ref.solve(RandomOfUnits<ComplexType>(S.NumVariables())).norm());
|
||||
condition_number_estimate = NumErrorT(norm_J*norm_J_inverse);
|
||||
|
||||
if ( (norm_delta_z < tracking_tolerance) && (ii >= (min_num_newton_iterations-1)) )
|
||||
return SuccessCode::Success;
|
||||
|
||||
if (!amp::CriterionB<ComplexType>(norm_J, norm_J_inverse, max_num_newton_iterations - ii, tracking_tolerance, norm_delta_z, AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
|
||||
if (!amp::CriterionC<ComplexType>(norm_J_inverse, next_space, tracking_tolerance, AMP_config))
|
||||
return SuccessCode::HigherPrecisionNecessary;
|
||||
}
|
||||
|
||||
return SuccessCode::FailedToConverge;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// Private Data Methods
|
||||
//
|
||||
////////////////////
|
||||
|
||||
|
||||
/**
|
||||
\brief This function computes the newton step for a system given information about the previous iteration
|
||||
|
||||
\param newton_step The computed step for Newton's method
|
||||
\param S The system used in the computations
|
||||
\param current_space The space from the previous Newton iteration
|
||||
\param current_time The time from the previous Newton iteration
|
||||
|
||||
*/
|
||||
|
||||
template<typename ComplexType, typename Derived>
|
||||
SuccessCode EvalIterationStep(Vec<ComplexType> & newton_step,
|
||||
const System& S,
|
||||
const Eigen::MatrixBase<Derived>& current_space, const ComplexType& current_time)
|
||||
{
|
||||
Vec<ComplexType>& f_temp_ref = std::get< Vec<ComplexType> >(f_temp_);
|
||||
Mat<ComplexType>& J_temp_ref = std::get< Mat<ComplexType> >(J_temp_);
|
||||
|
||||
Eigen::PartialPivLU< Mat<ComplexType> >& LU_ref = std::get< Eigen::PartialPivLU< Mat<ComplexType> > >(LU_);
|
||||
|
||||
S.SetAndReset<ComplexType>(current_space, current_time);
|
||||
S.EvalInPlace(f_temp_ref);
|
||||
S.JacobianInPlace(J_temp_ref);
|
||||
LU_ref = J_temp_ref.lu();
|
||||
|
||||
if (LUPartialPivotDecompositionSuccessful(LU_ref.matrixLU())!=MatrixSuccessCode::Success)
|
||||
return SuccessCode::MatrixSolveFailure;
|
||||
|
||||
newton_step = LU_ref.solve(-f_temp_ref);
|
||||
|
||||
return SuccessCode::Success;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////
|
||||
//
|
||||
// Private Data Members
|
||||
//
|
||||
////////////////////
|
||||
|
||||
unsigned numTotalFunctions_; // Number of total functions for the current system
|
||||
unsigned numVariables_; // Number of variables for the current system
|
||||
|
||||
std::tuple< Vec<dbl>, Vec<mpfr_complex> > f_temp_; // Variable to hold temporary evaluation of the system
|
||||
std::tuple< Vec<dbl>, Vec<mpfr_complex> > step_temp_; // Variable to hold temporary evaluation of the newton step
|
||||
std::tuple< Mat<dbl>, Mat<mpfr_complex> > J_temp_; // Variable to hold temporary evaluation of the Jacobian
|
||||
|
||||
std::tuple< Eigen::PartialPivLU<Mat<dbl>>, Eigen::PartialPivLU<Mat<mpfr_complex>> > LU_; // The LU factorization from the Newton iterates
|
||||
|
||||
unsigned current_precision_;
|
||||
|
||||
NewtonConfig newton_config_; // Hold the settings of the Newton iteration
|
||||
|
||||
|
||||
}; //re: class NewtonCorrector
|
||||
|
||||
} //re: namespace correct
|
||||
}// re: namespace tracking
|
||||
}// re: namespace bertini
|
||||
|
||||
#endif
|
||||
359
core/include/bertini2/trackers/observers.hpp
Normal file
359
core/include/bertini2/trackers/observers.hpp
Normal file
@@ -0,0 +1,359 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//trackers/observers.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/observers.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 trackers/observers.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
/**
|
||||
\file include/bertini2/trackers/observers.hpp
|
||||
|
||||
\brief Contains the trackers/observers base types
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/trackers/events.hpp"
|
||||
|
||||
#include "bertini2/detail/observer.hpp"
|
||||
|
||||
#include "bertini2/trackers/base_tracker.hpp"
|
||||
#include "bertini2/logging.hpp"
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
namespace bertini {
|
||||
|
||||
namespace tracking{
|
||||
|
||||
|
||||
template<class TrackerT>
|
||||
class FirstPrecisionRecorder : public Observer<TrackerT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
|
||||
using EmitterT = typename TrackerTraits<TrackerT>::EventEmitterType;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
if(auto p = dynamic_cast<const TrackingStarted<EmitterT>*>(&e))
|
||||
{
|
||||
precision_increased_ = false;
|
||||
starting_precision_ = p->Get().CurrentPrecision();
|
||||
}
|
||||
else if (auto p = dynamic_cast<const PrecisionChanged<EmitterT>*>(&e))
|
||||
{
|
||||
auto& t = p->Get();
|
||||
auto next = p->Next();
|
||||
if (next > p->Previous())
|
||||
{
|
||||
precision_increased_ = true;
|
||||
next_precision_ = next;
|
||||
time_of_first_increase_ = t.CurrentTime();
|
||||
t.RemoveObserver(*this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
unsigned StartPrecision() const
|
||||
{
|
||||
return starting_precision_;
|
||||
}
|
||||
|
||||
unsigned NextPrecision() const
|
||||
{
|
||||
return next_precision_;
|
||||
}
|
||||
|
||||
bool DidPrecisionIncrease() const
|
||||
{
|
||||
return precision_increased_;
|
||||
}
|
||||
|
||||
typename TrackerTraits<TrackerT>::BaseComplexType TimeOfIncrease() const
|
||||
{
|
||||
return time_of_first_increase_;
|
||||
}
|
||||
|
||||
virtual ~FirstPrecisionRecorder() = default;
|
||||
|
||||
private:
|
||||
|
||||
unsigned starting_precision_;
|
||||
unsigned next_precision_;
|
||||
bool precision_increased_;
|
||||
typename TrackerTraits<TrackerT>::BaseComplexType time_of_first_increase_;
|
||||
};
|
||||
|
||||
|
||||
template<class TrackerT>
|
||||
class MinMaxPrecisionRecorder : public Observer<TrackerT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
|
||||
using EmitterT = typename TrackerTraits<TrackerT>::EventEmitterType;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
if (auto p = dynamic_cast<const PrecisionChanged<EmitterT>*>(&e))
|
||||
{
|
||||
auto next_precision = p->Next();
|
||||
if (next_precision < min_precision_)
|
||||
min_precision_ = next_precision;
|
||||
if (next_precision > max_precision_)
|
||||
max_precision_ = next_precision;
|
||||
}
|
||||
else if(auto p = dynamic_cast<const TrackingStarted<EmitterT>*>(&e))
|
||||
{
|
||||
min_precision_ = p->Get().CurrentPrecision();
|
||||
max_precision_ = p->Get().CurrentPrecision();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
unsigned MinPrecision() const
|
||||
{
|
||||
return min_precision_;
|
||||
}
|
||||
|
||||
unsigned MaxPrecision() const
|
||||
{
|
||||
return max_precision_;
|
||||
}
|
||||
|
||||
void MinPrecision(unsigned m)
|
||||
{ min_precision_ = m;}
|
||||
|
||||
void MaxPrecision(unsigned m)
|
||||
{ max_precision_ = m;}
|
||||
|
||||
virtual ~MinMaxPrecisionRecorder() = default;
|
||||
|
||||
private:
|
||||
|
||||
unsigned min_precision_ = std::numeric_limits<unsigned>::max();
|
||||
unsigned max_precision_ = 0;
|
||||
};
|
||||
|
||||
|
||||
template<class TrackerT>
|
||||
class PrecisionAccumulator : public Observer<TrackerT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
|
||||
using EmitterT = typename TrackerTraits<TrackerT>::EventEmitterType;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
const TrackingEvent<EmitterT>* p = dynamic_cast<const TrackingEvent<EmitterT>*>(&e);
|
||||
if (p)
|
||||
{
|
||||
precisions_.push_back(p->Get().CurrentPrecision());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
const std::vector<unsigned>& Precisions() const
|
||||
{
|
||||
return precisions_;
|
||||
}
|
||||
|
||||
virtual ~PrecisionAccumulator() = default;
|
||||
|
||||
private:
|
||||
std::vector<unsigned> precisions_;
|
||||
};
|
||||
|
||||
/**
|
||||
Example usage:
|
||||
PathAccumulator<AMPTracker> path_accumulator;
|
||||
*/
|
||||
template<class TrackerT, template<class> class EventT = SuccessfulStep>
|
||||
class AMPPathAccumulator : public Observer<TrackerT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
|
||||
using EmitterT = typename TrackerTraits<TrackerT>::EventEmitterType;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
const EventT<EmitterT>* p = dynamic_cast<const EventT<EmitterT>*>(&e);
|
||||
if (p)
|
||||
{
|
||||
path_.push_back(p->Get().CurrentPoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
const std::vector<Vec<mpfr_complex> >& Path() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
virtual ~AMPPathAccumulator() = default;
|
||||
|
||||
private:
|
||||
std::vector<Vec<mpfr_complex> > path_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class TrackerT>
|
||||
class GoryDetailLogger : public Observer<TrackerT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
|
||||
using EmitterT = typename TrackerTraits<TrackerT>::EventEmitterType;
|
||||
|
||||
virtual ~GoryDetailLogger() = default;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
|
||||
|
||||
if (auto p = dynamic_cast<const Initializing<EmitterT,dbl>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << std::setprecision(p->Get().GetSystem().precision())
|
||||
<< "initializing in double, tracking path\nfrom\tt = "
|
||||
<< p->StartTime() << "\nto\tt = " << p->EndTime()
|
||||
<< "\n from\tx = \n" << p->StartPoint()
|
||||
<< "\n tracking system " << p->Get().GetSystem() << "\n\n";
|
||||
}
|
||||
else if (auto p = dynamic_cast<const Initializing<EmitterT,mpfr_complex>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << std::setprecision(p->Get().GetSystem().precision())
|
||||
<< "initializing in multiprecision, tracking path\nfrom\tt = " << p->StartTime() << "\nto\tt = " << p->EndTime() << "\n from\tx = \n" << p->StartPoint()
|
||||
<< "\n tracking system " << p->Get().GetSystem() << "\n\n";
|
||||
}
|
||||
|
||||
else if(auto p = dynamic_cast<const TrackingEnded<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "tracking ended";
|
||||
|
||||
else if (auto p = dynamic_cast<const NewStep<EmitterT>*>(&e))
|
||||
{
|
||||
auto& t = p->Get();
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "Tracker iteration " << t.NumTotalStepsTaken() << "\ncurrent precision: " << t.CurrentPrecision();
|
||||
|
||||
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << std::setprecision(t.CurrentPrecision())
|
||||
<< "t = " << t.CurrentTime()
|
||||
<< "\ncurrent stepsize: " << t.CurrentStepsize()
|
||||
<< "\ndelta_t = " << t.DeltaT()
|
||||
<< "\ncurrent x size = " << t.CurrentPoint().size()
|
||||
<< "\ncurrent x = " << t.CurrentPoint();
|
||||
}
|
||||
|
||||
|
||||
|
||||
else if (auto p = dynamic_cast<const SingularStartPoint<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "singular start point";
|
||||
else if (auto p = dynamic_cast<const InfinitePathTruncation<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "tracker iteration indicated going to infinity, truncated path";
|
||||
|
||||
|
||||
|
||||
|
||||
else if (auto p = dynamic_cast<const SuccessfulStep<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "tracker iteration successful\n\n\n";
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const FailedStep<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "tracker iteration unsuccessful\n\n\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else if (auto p = dynamic_cast<const SuccessfulPredict<EmitterT,mpfr_complex>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << std::setprecision(Precision(p->ResultingPoint())) << "prediction successful (mpfr_complex), result:\n" << p->ResultingPoint();
|
||||
}
|
||||
else if (auto p = dynamic_cast<const SuccessfulPredict<EmitterT,dbl>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << std::setprecision(Precision(p->ResultingPoint())) << "prediction successful (dbl), result:\n" << p->ResultingPoint();
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const SuccessfulCorrect<EmitterT,mpfr_complex>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << std::setprecision(Precision(p->ResultingPoint())) << "correction successful (mpfr_complex), result:\n" << p->ResultingPoint();
|
||||
}
|
||||
else if (auto p = dynamic_cast<const SuccessfulCorrect<EmitterT,dbl>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << std::setprecision(Precision(p->ResultingPoint())) << "correction successful (dbl), result:\n" << p->ResultingPoint();
|
||||
}
|
||||
|
||||
|
||||
else if (auto p = dynamic_cast<const PredictorHigherPrecisionNecessary<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "Predictor, higher precision necessary";
|
||||
else if (auto p = dynamic_cast<const CorrectorHigherPrecisionNecessary<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "corrector, higher precision necessary";
|
||||
|
||||
|
||||
|
||||
else if (auto p = dynamic_cast<const CorrectorMatrixSolveFailure<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "corrector, matrix solve failure or failure to converge";
|
||||
else if (auto p = dynamic_cast<const PredictorMatrixSolveFailure<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "predictor, matrix solve failure or failure to converge";
|
||||
else if (auto p = dynamic_cast<const FirstStepPredictorMatrixSolveFailure<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::trace) << "Predictor, matrix solve failure in initial solve of prediction";
|
||||
|
||||
|
||||
else if (auto p = dynamic_cast<const PrecisionChanged<EmitterT>*>(&e))
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "changing precision from " << p->Previous() << " to " << p->Next();
|
||||
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "unlogged event, of type: " << boost::typeindex::type_id_runtime(e).pretty_name();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class TrackerT>
|
||||
class StepFailScreenPrinter : public Observer<TrackerT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
|
||||
using EmitterT = typename TrackerTraits<TrackerT>::EventEmitterType;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
if (auto p = dynamic_cast<const FailedStep<EmitterT>*>(&e))
|
||||
std::cout << "observed step failure" << std::endl;
|
||||
}
|
||||
|
||||
virtual ~StepFailScreenPrinter() = default;
|
||||
};
|
||||
|
||||
} //re: namespace tracking
|
||||
|
||||
}// re: namespace bertini
|
||||
33
core/include/bertini2/trackers/ode_predictors.hpp
Normal file
33
core/include/bertini2/trackers/ode_predictors.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//This file is part of Bertini 2.0.
|
||||
//
|
||||
//newton_correct.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.
|
||||
//
|
||||
//newton_correct.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 newton_correct.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// newton_correct.hpp
|
||||
//
|
||||
// copyright 2015
|
||||
// silviana amethyst
|
||||
|
||||
/**
|
||||
\file ode_predictors.hpp
|
||||
|
||||
\brief Includes for the suite of ODE predictors.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_ODE_PREDICTORS_HPP
|
||||
#define BERTINI_ODE_PREDICTORS_HPP
|
||||
|
||||
#include "bertini2/trackers/explicit_predictors.hpp"
|
||||
|
||||
#endif
|
||||
237
core/include/bertini2/trackers/predict.hpp
Normal file
237
core/include/bertini2/trackers/predict.hpp
Normal file
@@ -0,0 +1,237 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//tracking/predict.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.
|
||||
//
|
||||
//tracking/predict.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/predict.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
/**
|
||||
\file predict.hpp
|
||||
|
||||
\brief Wrapper functions for calling ODE predictors for systems.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_PREDICT_HPP
|
||||
#define BERTINI_PREDICT_HPP
|
||||
|
||||
#include "bertini2/trackers/ode_predictors.hpp"
|
||||
|
||||
namespace bertini{
|
||||
namespace tracking{
|
||||
|
||||
/**
|
||||
Wrapper class for calling an ODE predictor, using fixed precision
|
||||
|
||||
\param predictor_choice The enum class selecting the predictor to be used.
|
||||
\param next_space The computed prediction.
|
||||
\param sys The system being solved.
|
||||
\param current_space The current space variable vector.
|
||||
\param current_time The current time.
|
||||
\param delta_t The size of the time step.
|
||||
\param condition_number_estimate The computed estimate of the condition number of the Jacobian.
|
||||
\param num_steps_since_last_condition_number_computation. Updated in this function.
|
||||
\param frequency_of_CN_estimation How many steps to take between condition number estimates.
|
||||
\param prec_type The operating precision type.
|
||||
\param tracking_tolerance How tightly to track the path.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\tparam ComplexT The complex number type for evaluation.
|
||||
\tparam TolT The numeric type for tolerances and state.
|
||||
*/
|
||||
template <typename ComplexT, typename TolT>
|
||||
SuccessCode Predict(Predictor predictor_choice,
|
||||
Vec<ComplexT> & next_space,
|
||||
System const& sys,
|
||||
Vec<ComplexT> const& current_space, ComplexT const& current_time,
|
||||
ComplexT const& delta_t,
|
||||
TolT & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
TolT const& tracking_tolerance)
|
||||
{
|
||||
predict::ExplicitRKPredictor predictor(predictor_choice);
|
||||
|
||||
return predictor.Predict(next_space,
|
||||
sys,
|
||||
current_space, current_time,
|
||||
delta_t,
|
||||
condition_number_estimate,
|
||||
num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation,
|
||||
tracking_tolerance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
An overload of Predict which returns (by reference) error estimate, and estimates of the norm of \f$J\f$ and \f$J^{-1}\f$ from AMP2 paper \cite AMP2.
|
||||
|
||||
\see Predict
|
||||
*/
|
||||
template <typename ComplexT, typename TolT>
|
||||
SuccessCode Predict(Predictor predictor_choice,
|
||||
Vec<ComplexT> & next_space,
|
||||
TolT & size_proportion, /*\f$a\f$ from the AMP2 paper */
|
||||
TolT & norm_J,
|
||||
TolT & norm_J_inverse,
|
||||
System const& sys,
|
||||
Vec<ComplexT> const& current_space, ComplexT current_time,
|
||||
ComplexT const& delta_t,
|
||||
TolT & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
TolT const& tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
predict::ExplicitRKPredictor<ComplexT, TolT> predictor(predictor_choice);
|
||||
|
||||
return predictor.Predict(next_space,
|
||||
size_proportion,
|
||||
norm_J,
|
||||
norm_J_inverse,
|
||||
sys,
|
||||
current_space, current_time,
|
||||
delta_t,
|
||||
condition_number_estimate,
|
||||
num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation,
|
||||
tracking_tolerance,
|
||||
AMP_config);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
An overload of Predict which returns (by reference) error estimate, and estimates of the norm of \f$J\f$ and \f$J^{-1}\f$, and the size proportion \f$a\f$ from AMP2 paper \cite AMP2.
|
||||
|
||||
\see Predict
|
||||
*/
|
||||
template <typename ComplexT, typename TolT>
|
||||
SuccessCode Predict(Predictor predictor_choice,
|
||||
Vec<ComplexT> & next_space,
|
||||
TolT & error_estimate,
|
||||
TolT & size_proportion, /*\f$a\f$ from the AMP2 paper */
|
||||
TolT & norm_J,
|
||||
TolT & norm_J_inverse,
|
||||
System const& sys,
|
||||
Vec<ComplexT> const& current_space, ComplexT current_time,
|
||||
ComplexT const& delta_t,
|
||||
TolT & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
TolT const& tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
predict::ExplicitRKPredictor<ComplexT, TolT> predictor(predictor_choice);
|
||||
|
||||
return predictor.Predict(next_space,
|
||||
error_estimate,
|
||||
size_proportion,
|
||||
norm_J,
|
||||
norm_J_inverse,
|
||||
sys,
|
||||
current_space, current_time,
|
||||
delta_t,
|
||||
condition_number_estimate,
|
||||
num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation,
|
||||
tracking_tolerance,
|
||||
AMP_config);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Wrapper class for calling an ODE predictor, using adaptive precision, not returning some meta-data about the step.
|
||||
|
||||
\param predictor_choice The enum class selecting the predictor to be used.
|
||||
\param next_space The computed prediction.
|
||||
\param sys The system being solved.
|
||||
\param current_space The current space variable vector.
|
||||
\param current_time The current time.
|
||||
\param delta_t The size of the time step.
|
||||
\param condition_number_estimate The computed estimate of the condition number of the Jacobian.
|
||||
\param num_steps_since_last_condition_number_computation. Updated in this function.
|
||||
\param frequency_of_CN_estimation How many steps to take between condition number estimates.
|
||||
\param prec_type The operating precision type.
|
||||
\param tracking_tolerance How tightly to track the path.
|
||||
\param AMP_config The settings for adaptive multiple precision.
|
||||
|
||||
\tparam ComplexT The complex number type for evaluation.
|
||||
\tparam TolT The complex number type for evaluation.
|
||||
*/
|
||||
template <typename ComplexT, typename TolT>
|
||||
SuccessCode Predict(Predictor predictor_choice,
|
||||
Vec<ComplexT> & next_space,
|
||||
System const& sys,
|
||||
Vec<ComplexT> const& current_space, ComplexT current_time,
|
||||
ComplexT const& delta_t,
|
||||
TolT & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation,
|
||||
TolT const& tracking_tolerance,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
TolT size_proportion, norm_J, norm_J_inverse;
|
||||
|
||||
return Predict(predictor_choice,
|
||||
next_space,
|
||||
size_proportion,
|
||||
norm_J,
|
||||
norm_J_inverse,
|
||||
sys,
|
||||
current_space, current_time,
|
||||
delta_t,
|
||||
condition_number_estimate,
|
||||
num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation,
|
||||
tracking_tolerance,
|
||||
AMP_config);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // re: namespace tracking
|
||||
|
||||
|
||||
} // re: namespace bertini
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
109
core/include/bertini2/trackers/step.hpp
Normal file
109
core/include/bertini2/trackers/step.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//tracking/step.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.
|
||||
//
|
||||
//tracking/step.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/step.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
/**
|
||||
\file step.hpp
|
||||
|
||||
\brief Provides Step wrappers for taking a generic predict-correct step.
|
||||
|
||||
This provides no calls for adaptive precision, those living with the AMPTracker type instead.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BERTINI_STEP_HPP
|
||||
#define BERTINI_STEP_HPP
|
||||
|
||||
#include "bertini2/trackers/predict.hpp"
|
||||
#include "bertini2/trackers/correct.hpp"
|
||||
|
||||
namespace bertini {
|
||||
|
||||
namespace tracking {
|
||||
|
||||
/**
|
||||
|
||||
|
||||
\tparam ComplexType The type of number being used in the algorithm
|
||||
|
||||
*/
|
||||
template <typename ComplexType, typename RealType>
|
||||
SuccessCode Step(Predictor predictor_choice,
|
||||
Vec<ComplexType> & next_space, ComplexType & next_time,
|
||||
System & sys,
|
||||
Vec<ComplexType> const& current_space, ComplexType current_time,
|
||||
ComplexType const& delta_t,
|
||||
RealType & condition_number_estimate,
|
||||
unsigned & num_steps_since_last_condition_number_computation,
|
||||
unsigned frequency_of_CN_estimation, PrecisionType prec_type,
|
||||
RealType const& tracking_tolerance,
|
||||
RealType const& path_truncation_threshold,
|
||||
unsigned min_num_newton_iterations,
|
||||
unsigned max_num_newton_iterations,
|
||||
AdaptiveMultiplePrecisionConfig const& AMP_config)
|
||||
{
|
||||
|
||||
SuccessCode predictor_code = Predict(next_space,
|
||||
sys,
|
||||
current_space, current_time,
|
||||
delta_t,
|
||||
condition_number_estimate,
|
||||
num_steps_since_last_condition_number_computation,
|
||||
frequency_of_CN_estimation, prec_type,
|
||||
tracking_tolerance,
|
||||
AMP_config);
|
||||
|
||||
if (predictor_code!=SuccessCode::Success)
|
||||
return predictor_code;
|
||||
|
||||
next_time = current_time + delta_t;
|
||||
|
||||
SuccessCode corrector_code = Correct(next_space,
|
||||
sys,
|
||||
current_space, // pass by value to get a copy of it
|
||||
next_time,
|
||||
prec_type,
|
||||
tracking_tolerance,
|
||||
path_truncation_threshold,
|
||||
min_num_newton_iterations,
|
||||
max_num_newton_iterations,
|
||||
AMP_config);
|
||||
|
||||
|
||||
if (corrector_code!=SuccessCode::Success)
|
||||
return corrector_code;
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
} // re: namespace tracking
|
||||
|
||||
} // re: namespace bertini
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
40
core/include/bertini2/trackers/tracker.hpp
Normal file
40
core/include/bertini2/trackers/tracker.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//tracking/tracker.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.
|
||||
//
|
||||
//tracking/tracker.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/tracker.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
|
||||
//
|
||||
// See <http://www.gnu.org/licenses/> 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
|
||||
|
||||
|
||||
/**
|
||||
\file tracker.hpp
|
||||
|
||||
\brief Contains the includes for all Tracker types.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_TRACKER_HPP
|
||||
#define BERTINI_TRACKER_HPP
|
||||
|
||||
#include "bertini2/trackers/fixed_precision_tracker.hpp"
|
||||
#include "bertini2/trackers/amp_tracker.hpp"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user