Add files
This commit is contained in:
169
core/include/bertini2/endgames/amp_endgame.hpp
Normal file
169
core/include/bertini2/endgames/amp_endgame.hpp
Normal file
@@ -0,0 +1,169 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//amp_endgame.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_endgame.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_endgame.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
|
||||
|
||||
/**
|
||||
\file base_endgame.hpp
|
||||
|
||||
\brief Contains parent class, Endgame, the parent class for all endgames.
|
||||
*/
|
||||
|
||||
#include "bertini2/trackers/amp_tracker.hpp"
|
||||
#include "bertini2/trackers/adaptive_precision_utilities.hpp"
|
||||
|
||||
#include "bertini2/endgames/config.hpp"
|
||||
#include "bertini2/endgames/prec_base.hpp"
|
||||
|
||||
#include "bertini2/endgames/events.hpp"
|
||||
#include "bertini2/detail/observable.hpp"
|
||||
namespace bertini{ namespace endgame {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Specifies some necessaries for AMP style endgame implementations, which differ from the fixed precision ones.
|
||||
*/
|
||||
class AMPEndgame : public virtual EndgamePrecPolicyBase<tracking::AMPTracker>
|
||||
{
|
||||
public:
|
||||
using TrackerT = tracking::AMPTracker;
|
||||
using EmitterType = AMPEndgame;
|
||||
|
||||
template<typename... T>
|
||||
static
|
||||
unsigned EnsureAtUniformPrecision(T& ...args)
|
||||
{
|
||||
return tracking::adaptive::EnsureAtUniformPrecision(args...);
|
||||
}
|
||||
|
||||
static
|
||||
void EnsureAtPrecision(double & obj, unsigned prec)
|
||||
{
|
||||
if (prec!=DoublePrecision())
|
||||
throw std::runtime_error("attempting to adjust precision of double to non-double precision");
|
||||
}
|
||||
|
||||
static
|
||||
void EnsureAtPrecision(std::complex<double> & obj, unsigned prec)
|
||||
{
|
||||
if (prec!=DoublePrecision())
|
||||
throw std::runtime_error("attempting to adjust precision of std::complex<double> to non-double precision");
|
||||
}
|
||||
|
||||
static
|
||||
void EnsureAtPrecision(mpfr_float & obj, unsigned prec)
|
||||
{
|
||||
using bertini::Precision;
|
||||
Precision(obj,prec);
|
||||
}
|
||||
|
||||
static
|
||||
void EnsureAtPrecision(mpfr_complex & obj, unsigned prec)
|
||||
{
|
||||
using bertini::Precision;
|
||||
Precision(obj,prec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
SuccessCode RefineSampleImpl(Vec<mpfr_complex> & result, Vec<mpfr_complex> const& current_sample, mpfr_complex const& current_time, NumErrorT tol, unsigned max_iterations) const
|
||||
{
|
||||
|
||||
using bertini::Precision;
|
||||
assert(Precision(current_time)==Precision(current_sample) && "precision of sample and time to be refined in AMP endgame must match");
|
||||
|
||||
using RT = mpfr_float;
|
||||
using std::max;
|
||||
auto& TR = this->GetTracker();
|
||||
TR.ChangePrecision(Precision(current_time));
|
||||
|
||||
auto refinement_success = this->GetTracker().Refine(result,current_sample,current_time,
|
||||
tol,
|
||||
max_iterations);
|
||||
|
||||
|
||||
if (refinement_success==SuccessCode::HigherPrecisionNecessary ||
|
||||
refinement_success==SuccessCode::FailedToConverge)
|
||||
{
|
||||
|
||||
|
||||
using bertini::Precision;
|
||||
|
||||
auto prev_precision = DefaultPrecision();
|
||||
auto higher_precision = max(prev_precision,LowestMultiplePrecision())+ PrecisionIncrement();
|
||||
DefaultPrecision(higher_precision);
|
||||
this->GetTracker().ChangePrecision(higher_precision);
|
||||
|
||||
NotifyObservers(PrecisionChanged<EmitterType>(*this, prev_precision, higher_precision));
|
||||
|
||||
auto next_sample_higher_prec = current_sample;
|
||||
Precision(next_sample_higher_prec, higher_precision);
|
||||
|
||||
auto result_higher_prec = Vec<mpfr_complex>(current_sample.size());
|
||||
|
||||
auto time_higher_precision = current_time;
|
||||
Precision(time_higher_precision,higher_precision);
|
||||
|
||||
assert(time_higher_precision.precision()==DefaultPrecision());
|
||||
refinement_success = this->GetTracker().Refine(result_higher_prec,
|
||||
next_sample_higher_prec,
|
||||
time_higher_precision,
|
||||
tol,
|
||||
max_iterations);
|
||||
|
||||
Precision(result, higher_precision);
|
||||
result = result_higher_prec;
|
||||
|
||||
assert(Precision(result)==DefaultPrecision());
|
||||
}
|
||||
return refinement_success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
explicit
|
||||
AMPEndgame(TrackerT const& new_tracker) : EndgamePrecPolicyBase<TrackerT>(new_tracker)
|
||||
{}
|
||||
|
||||
virtual ~AMPEndgame() = default;
|
||||
|
||||
}; // re: class AMPEndgame
|
||||
|
||||
|
||||
template<>
|
||||
struct EGPrecSelector<tracking::AMPTracker>
|
||||
{
|
||||
using type = AMPEndgame;
|
||||
};
|
||||
|
||||
|
||||
} } // end namespaces
|
||||
|
||||
|
||||
|
||||
381
core/include/bertini2/endgames/base_endgame.hpp
Normal file
381
core/include/bertini2/endgames/base_endgame.hpp
Normal file
@@ -0,0 +1,381 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//base_endgame.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_endgame.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_endgame.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_BASE_ENDGAME_HPP
|
||||
#define BERTINI_BASE_ENDGAME_HPP
|
||||
|
||||
#pragma once
|
||||
/**
|
||||
\file base_endgame.hpp
|
||||
|
||||
\brief Contains base class, Endgame.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
|
||||
#include "bertini2/mpfr_complex.hpp"
|
||||
|
||||
#include "bertini2/system/system.hpp"
|
||||
|
||||
#include "bertini2/detail/enable_permuted_arguments.hpp"
|
||||
|
||||
#include "bertini2/trackers/config.hpp"
|
||||
#include "bertini2/endgames/config.hpp"
|
||||
#include "bertini2/endgames/interpolation.hpp"
|
||||
#include "bertini2/endgames/events.hpp"
|
||||
|
||||
#include "bertini2/logging.hpp"
|
||||
|
||||
#include "bertini2/detail/configured.hpp"
|
||||
|
||||
|
||||
namespace bertini{ namespace endgame {
|
||||
|
||||
|
||||
/**
|
||||
\class Endgame
|
||||
|
||||
\brief Base endgame class for all endgames offered in Bertini2.
|
||||
|
||||
\see PowerSeriesEndgame
|
||||
\see CauchyEndgame
|
||||
|
||||
## Using an endgame
|
||||
|
||||
Endgames in Bertini2 are the engine for finishing homotopy continuation where we may encounter singular solutions.
|
||||
The path is implicitly described by the system being tracked.
|
||||
|
||||
## Purpose
|
||||
|
||||
Since the Bertini Endgames 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 endgames, such as
|
||||
|
||||
ComputeInitialSamples
|
||||
|
||||
Also, there are settings that will be kept at this level to not duplicate code.
|
||||
|
||||
## Creating a new endgame type
|
||||
|
||||
To create a new endgame type, inherit from this class.
|
||||
*/
|
||||
template<class FlavorT, class PrecT>
|
||||
class EndgameBase :
|
||||
public detail::Configured< typename AlgoTraits<FlavorT>::NeededConfigs >,
|
||||
public PrecT,
|
||||
public virtual Observable
|
||||
{
|
||||
public:
|
||||
using TrackerType = typename PrecT::TrackerType;
|
||||
|
||||
using BaseComplexType = typename tracking::TrackerTraits<TrackerType>::BaseComplexType;
|
||||
using BaseRealType = typename tracking::TrackerTraits<TrackerType>::BaseRealType;
|
||||
|
||||
using EmitterType = FlavorT;
|
||||
|
||||
protected:
|
||||
|
||||
using BCT = BaseComplexType;
|
||||
using BRT = BaseRealType;
|
||||
|
||||
|
||||
using Configured = detail::Configured< typename AlgoTraits<FlavorT>::NeededConfigs >;
|
||||
using Configs = typename AlgoTraits<FlavorT>::NeededConfigs;
|
||||
using ConfigsAsTuple = typename Configs::ToTuple;
|
||||
|
||||
// a list of all the needed arithemtic types (complex for complex trackers)
|
||||
using NeededTypes = detail::TypeList<BCT>;
|
||||
using TupOfVec = typename NeededTypes::ToTupleOfVec;
|
||||
using TupOfReal = typename NeededTypes::ToTupleOfReal;
|
||||
using TupleOfTimes = typename NeededTypes::template ToTupleOfCont<TimeCont>;
|
||||
using TupleOfSamps = typename NeededTypes::template ToTupleOfCont<SampCont>;
|
||||
|
||||
|
||||
|
||||
// universal endgame state variables
|
||||
mutable Vec<BCT> final_approximation_;
|
||||
mutable Vec<BCT> previous_approximation_;
|
||||
mutable unsigned int cycle_number_ = 0;
|
||||
mutable NumErrorT approximate_error_;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief convert the base endgame into the derived type.
|
||||
|
||||
This enables the CRPT as used by the endgames
|
||||
*/
|
||||
const FlavorT& AsFlavor() const
|
||||
{
|
||||
return dynamic_cast<const FlavorT&>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Non-const version of AsFlavor
|
||||
*/
|
||||
FlavorT& AsFlavor()
|
||||
{
|
||||
return dynamic_cast<FlavorT&>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
\brief The main function for running an endgame, from time to time, from a given point to a possibly singular solution.
|
||||
*/
|
||||
SuccessCode Run(const BCT & start_time, const Vec<BCT> & start_point, BCT const& target_time)
|
||||
{
|
||||
return this->AsFlavor().RunImpl(start_time, start_point, target_time);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Run the endgame, shooting for default time of t=0.
|
||||
|
||||
\see Run
|
||||
*/
|
||||
SuccessCode Run(BCT const& start_time, Vec<BCT> const& start_point)
|
||||
{
|
||||
return Run(start_time, start_point, static_cast<BCT>(0));
|
||||
}
|
||||
|
||||
|
||||
template<typename CT>
|
||||
SuccessCode RefineAllSamples(SampCont<CT> & samples, TimeCont<CT> & times)
|
||||
{
|
||||
for (size_t ii=0; ii<samples.size(); ++ii)
|
||||
{
|
||||
auto refine_success = this->RefineSample(samples[ii], samples[ii], times[ii],
|
||||
this->FinalTolerance() * this->EndgameSettings().sample_point_refinement_factor,
|
||||
this->EndgameSettings().max_num_newton_iterations);
|
||||
if (refine_success != SuccessCode::Success)
|
||||
{
|
||||
// BOOST_LOG_TRIVIAL(severity_level::trace) << "refining failed, code " << int(refine_success);
|
||||
return refine_success;
|
||||
}
|
||||
NotifyObservers(SampleRefined<EmitterType>(AsFlavor()));
|
||||
}
|
||||
|
||||
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec) // known at compile time
|
||||
{
|
||||
auto max_precision = this->EnsureAtUniformPrecision(times, samples);
|
||||
this->GetSystem().precision(max_precision);
|
||||
}
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
A function passed off to the precision-specific endgame part
|
||||
*/
|
||||
SuccessCode RefineSample(Vec<BCT> & result, Vec<BCT> const& current_sample, BCT const& current_time, NumErrorT tol, unsigned max_iterations) const
|
||||
{
|
||||
return this->RefineSampleImpl(result, current_sample, current_time, tol, max_iterations);
|
||||
}
|
||||
|
||||
void ChangePrecision(unsigned p)
|
||||
{
|
||||
AsFlavor().ChangePrecision(p);
|
||||
PrecT::ChangePrecision(p);
|
||||
ChangePrecision(this->final_approximation_,p);
|
||||
ChangePrecision(this->previous_approximation_,p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief This function is inferior to the templated Get<ConfigT> function provided
|
||||
*/
|
||||
inline
|
||||
const auto & EndgameSettings() const
|
||||
{
|
||||
return Configured::template Get<EndgameConfig>();
|
||||
}
|
||||
|
||||
inline
|
||||
const auto & SecuritySettings() const
|
||||
{
|
||||
return this->template Get<SecurityConfig>();
|
||||
}
|
||||
|
||||
explicit EndgameBase(TrackerType const& tr, const ConfigsAsTuple& settings ) :
|
||||
Configured( settings ), PrecT(tr), EndgamePrecPolicyBase<TrackerType>(tr)
|
||||
{}
|
||||
|
||||
|
||||
template< typename... Ts >
|
||||
explicit
|
||||
EndgameBase(TrackerType const& tr, const Ts&... ts ) : EndgameBase(tr, Configs::Unpermute( ts... ) )
|
||||
{}
|
||||
|
||||
|
||||
inline unsigned CycleNumber() const { return cycle_number_;}
|
||||
inline void CycleNumber(unsigned c) { cycle_number_ = c;}
|
||||
inline void IncrementCycleNumber(unsigned inc) { cycle_number_ += inc;}
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the final tolerance to which we are tracking the solution.
|
||||
*/
|
||||
inline
|
||||
const auto& FinalTolerance() const
|
||||
{
|
||||
return this->template Get<EndgameConfig>().final_tolerance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Setter for the final tolerance.
|
||||
*/
|
||||
inline
|
||||
void SetFinalTolerance(BRT const& ft){this->template Get<EndgameConfig>().final_tolerance = ft;}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the most-recent approximation
|
||||
*/
|
||||
template<typename CT>
|
||||
inline
|
||||
const Vec<CT>& FinalApproximation() const
|
||||
{
|
||||
return final_approximation_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the second-most-recent approximation
|
||||
*/
|
||||
template<typename CT>
|
||||
inline
|
||||
const Vec<CT>& PreviousApproximation() const
|
||||
{
|
||||
return previous_approximation_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the most recent accuracy estimate
|
||||
*/
|
||||
inline
|
||||
NumErrorT ApproximateError() const
|
||||
{
|
||||
return approximate_error_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the latest time at which a point on the path was computed
|
||||
*/
|
||||
inline
|
||||
const BCT& LatestTime() const
|
||||
{
|
||||
return AsFlavor().LatestTimeImpl();
|
||||
}
|
||||
|
||||
// /**
|
||||
// \brief Get the system being tracked on, which is referred to by the tracker.
|
||||
// */
|
||||
// inline
|
||||
// const System& GetSystem() const
|
||||
// {
|
||||
// return GetTracker().GetSystem();
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
\brief Populates time and space samples so that we are ready to start the endgame.
|
||||
|
||||
## Input
|
||||
|
||||
start_time: is the time when we start the endgame process usually this is .1
|
||||
x_endgame_start: is the space value at start_time
|
||||
times: a deque of time values. These values will be templated to be CT
|
||||
samples: a deque of sample values that are in correspondence with the values in times. These values will be vectors with entries of CT.
|
||||
|
||||
## Output
|
||||
|
||||
SuccessCode indicating whether tracking to all samples was successful.
|
||||
|
||||
|
||||
## Details
|
||||
|
||||
The first sample will be (x_endgame_start) and the first time is start_time.
|
||||
From there we do a geometric progression using the sample factor (which by default is 1/2).
|
||||
Hence, next_time = start_time * sample_factor.
|
||||
We track then to the next_time and construct the next_sample.
|
||||
|
||||
\param start_time The time value at which we start the endgame.
|
||||
\param target_time The time value that we are trying to find a solution to.
|
||||
\param x_endgame_start The current space point at start_time.
|
||||
\param times A deque that will hold all the time values of the samples we are going to use to start the endgame.
|
||||
\param samples a deque that will hold all the samples corresponding to the time values in times.
|
||||
|
||||
\tparam CT The complex number type.
|
||||
*/
|
||||
template<typename CT>
|
||||
SuccessCode ComputeInitialSamples(const CT & start_time,const CT & target_time, const Vec<CT> & x_endgame_start, TimeCont<CT> & times, SampCont<CT> & samples) // passed by reference to allow times to be filled as well.
|
||||
{
|
||||
using RT = typename Eigen::NumTraits<CT>::Real;
|
||||
assert(this->template Get<EndgameConfig>().num_sample_points>0 && "number of sample points must be positive");
|
||||
|
||||
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
|
||||
{
|
||||
assert(Precision(start_time)==Precision(x_endgame_start) && "Computing initial samples requires input time and space with uniform precision");
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
times.clear();
|
||||
|
||||
samples.push_back(x_endgame_start);
|
||||
times.push_back(start_time);
|
||||
|
||||
auto num_vars = this->GetSystem().NumVariables();
|
||||
//start at 1, because the input point is the 0th element.
|
||||
for(int ii=1; ii < this->template Get<EndgameConfig>().num_sample_points; ++ii)
|
||||
{
|
||||
times.emplace_back((times[ii-1] + target_time) * RT(this->template Get<EndgameConfig>().sample_factor)); // next time is a point between the previous time and target time.
|
||||
samples.emplace_back(Vec<CT>(num_vars)); // sample_factor gives us some point between the two, usually the midpoint.
|
||||
|
||||
auto tracking_success = this->GetTracker().TrackPath(samples[ii],times[ii-1],times[ii],samples[ii-1]);
|
||||
this->EnsureAtPrecision(times[ii],Precision(samples[ii]));
|
||||
|
||||
if (tracking_success!=SuccessCode::Success)
|
||||
return tracking_success;
|
||||
}
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
virtual ~EndgameBase() = default;
|
||||
};
|
||||
|
||||
} }// end namespaces bertini
|
||||
|
||||
|
||||
#endif
|
||||
1157
core/include/bertini2/endgames/cauchy.hpp
Normal file
1157
core/include/bertini2/endgames/cauchy.hpp
Normal file
File diff suppressed because it is too large
Load Diff
184
core/include/bertini2/endgames/config.hpp
Normal file
184
core/include/bertini2/endgames/config.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//include/bertini2/endgames/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.
|
||||
//
|
||||
//include/bertini2/endgames/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 include/bertini2/endgames/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
|
||||
|
||||
|
||||
/**
|
||||
\file include/bertini2/endgames/config.hpp
|
||||
|
||||
\brief Configs and settings for endgames.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/detail/typelist.hpp"
|
||||
#include "bertini2/common/config.hpp"
|
||||
|
||||
|
||||
namespace bertini{ namespace endgame{
|
||||
|
||||
|
||||
// // some forward declarations
|
||||
// base
|
||||
template<class FlavorT, class PrecT>
|
||||
class EndgameBase;
|
||||
|
||||
// flavors
|
||||
template<typename PrecT>
|
||||
class PowerSeriesEndgame;
|
||||
|
||||
template<typename PrecT>
|
||||
class CauchyEndgame;
|
||||
|
||||
// precision types
|
||||
template<typename TrackerT>
|
||||
class FixedPrecEndgame;
|
||||
|
||||
class AMPEndgame;
|
||||
|
||||
// end forward declarations
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Base empty class
|
||||
*/
|
||||
template <typename TrackerT>
|
||||
struct EGPrecSelector;
|
||||
|
||||
// specialize this in the specific files it goes in, please
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Facilitates lookup of required endgame type based on tracker type
|
||||
|
||||
Your current choices are PSEG or Cauchy.
|
||||
|
||||
To get the Power Series Endgame for Adaptive Precision Tracker, use the following example code:
|
||||
\code
|
||||
using EGT = EndgameSelector<AMPTracker>::PSEG
|
||||
\endcode
|
||||
|
||||
\tparam TrackerT The type of tracker you want to use.
|
||||
*/
|
||||
template<typename TrackerT>
|
||||
struct EndgameSelector
|
||||
{
|
||||
using EGPrecT = typename EGPrecSelector<TrackerT>::type;
|
||||
|
||||
using PSEG = endgame::PowerSeriesEndgame<EGPrecT>;
|
||||
using Cauchy = endgame::CauchyEndgame<EGPrecT>;
|
||||
};
|
||||
|
||||
struct SecurityConfig
|
||||
{
|
||||
int level = 0; //SecurityLevel
|
||||
NumErrorT max_norm = NumErrorT(1e4); //SecurityMaxNorm wrong default value
|
||||
};
|
||||
|
||||
|
||||
struct EndgameConfig
|
||||
{
|
||||
using T = NumErrorT;
|
||||
T sample_point_refinement_factor = 1e-2; ///* Extra amount of tolerance for refining before computing the final approximation, during endgame.
|
||||
unsigned num_sample_points = 3; //NumSamplePoints default = 2
|
||||
T min_track_time = T(1e-100); //nbrh radius in Bertini book. NbhdRadius
|
||||
|
||||
mpq_rational sample_factor = mpq_rational(1,2); //SampleFactor
|
||||
|
||||
unsigned max_num_newton_iterations = 15; // the maximum number allowable iterations during endgames, for points used to approximate the final solution.
|
||||
|
||||
T final_tolerance = 1e-11;///< The tolerance to which to compute the endpoint using the endgame.
|
||||
};
|
||||
|
||||
|
||||
struct PowerSeriesConfig
|
||||
{
|
||||
unsigned max_cycle_number = 6; //MaxCycleNum
|
||||
unsigned cycle_number_amplification = 5;
|
||||
};
|
||||
|
||||
|
||||
struct CauchyConfig
|
||||
{
|
||||
using T = NumErrorT;
|
||||
|
||||
T cycle_cutoff_time = T(1)/T(100000000); //CycleTimeCutoff
|
||||
T ratio_cutoff_time = T(1)/T(100000000000000); //RatioTimeCutoff
|
||||
T minimum_for_c_over_k_stabilization = T(3)/T(4);
|
||||
unsigned int num_needed_for_stabilization = 3;
|
||||
T maximum_cauchy_ratio = T(1)/T(2);
|
||||
unsigned int fail_safe_maximum_cycle_number = 250; //max number of loops before giving up.
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct TrackBackConfig
|
||||
{
|
||||
unsigned minimum_cycle = 4; //MinCycleTrackback, default = 4
|
||||
bool junk_removal_test = 1; //JunkRemovalTest, default = 1
|
||||
unsigned max_depth_LDT = 3; //MaxLDTDepth, default = 3
|
||||
};
|
||||
|
||||
|
||||
// an empty base class
|
||||
template <typename T>
|
||||
struct AlgoTraits;
|
||||
|
||||
/**
|
||||
specialization for PowerSeries, which uses CRTP
|
||||
*/
|
||||
template<typename PrecT>
|
||||
struct AlgoTraits< PowerSeriesEndgame<PrecT>>
|
||||
{
|
||||
using NeededConfigs = detail::TypeList<
|
||||
PowerSeriesConfig,
|
||||
EndgameConfig,
|
||||
SecurityConfig
|
||||
>;
|
||||
|
||||
using EmitterType = PowerSeriesEndgame<PrecT>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
specialization for Cauchy, which uses CRTP
|
||||
*/
|
||||
template<typename PrecT>
|
||||
struct AlgoTraits< CauchyEndgame<PrecT>>
|
||||
{
|
||||
using NeededConfigs = detail::TypeList<
|
||||
CauchyConfig,
|
||||
EndgameConfig,
|
||||
SecurityConfig>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} } // namespaces
|
||||
|
||||
|
||||
188
core/include/bertini2/endgames/events.hpp
Normal file
188
core/include/bertini2/endgames/events.hpp
Normal file
@@ -0,0 +1,188 @@
|
||||
//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 endgames/events.hpp
|
||||
|
||||
\brief Contains the endgames/events base types
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/detail/events.hpp"
|
||||
|
||||
namespace bertini {
|
||||
|
||||
namespace endgame{
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Generic event for Endgames
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(EndgameEvent,ConstEvent);
|
||||
|
||||
/**
|
||||
\brief Generic failure event for Endgames
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(EndgameFailure,ConstEvent);
|
||||
|
||||
/**
|
||||
\brief Generic success event for Endgames
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(EndgameSuccess,ConstEvent);
|
||||
|
||||
/**
|
||||
\brief MinTrackTime reached during endgame
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(MinTrackTimeReached,EndgameFailure);
|
||||
|
||||
/**
|
||||
\brief Refining a sample failed for some reason
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(RefiningFailed,EndgameFailure);
|
||||
|
||||
/**
|
||||
\brief Cycle number computed was too high
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(CycleNumTooHigh,EndgameFailure);
|
||||
|
||||
/**
|
||||
\brief Security max norm reached.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(SecurityMaxNormReached,EndgameFailure);
|
||||
|
||||
/**
|
||||
\brief Started running the endgame
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(Initializing,EndgameEvent);
|
||||
|
||||
|
||||
/**
|
||||
\brief Time advancing
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(TimeAdvanced,EndgameEvent);
|
||||
|
||||
/**
|
||||
\brief Advanced around the circle around target time
|
||||
*/
|
||||
template<class ObservedT>
|
||||
class CircleAdvanced : public EndgameEvent<ObservedT>
|
||||
{ BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
public:
|
||||
|
||||
using CT = typename ObservedT::BaseComplexType;
|
||||
/**
|
||||
\brief The constructor for a CircleAdvanced Event.
|
||||
|
||||
\param obs The observable emitting the event.
|
||||
\param previous The precision before changing.
|
||||
\param next The precision after changing.
|
||||
*/
|
||||
CircleAdvanced(const ObservedT & obs,
|
||||
Vec<CT> const& new_point,
|
||||
CT const& new_time) : EndgameEvent<ObservedT>(obs),
|
||||
new_point_(new_point),
|
||||
new_time_(new_time)
|
||||
{}
|
||||
|
||||
|
||||
virtual ~CircleAdvanced() = default;
|
||||
CircleAdvanced() = delete;
|
||||
|
||||
const auto& NewSample() const {return new_point_;}
|
||||
|
||||
const auto& NewTime() const {return new_time_;}
|
||||
|
||||
private:
|
||||
const Vec<CT>& new_point_;
|
||||
const CT& new_time_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\brief Walked a complete loop around the target time.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(ClosedLoop,EndgameEvent);
|
||||
|
||||
/**
|
||||
\brief Approximated a root at target time.
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(ApproximatedRoot,EndgameEvent);
|
||||
|
||||
/**
|
||||
\brief Converged -- endgame is done!
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(Converged,EndgameSuccess);
|
||||
|
||||
/**
|
||||
\brief Refined a sample
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(SampleRefined,EndgameEvent);
|
||||
|
||||
/**
|
||||
\brief Made it into the EG operating zone, or so we believe
|
||||
*/
|
||||
ADD_BERTINI_EVENT_TYPE(InEGOperatingZone,EndgameEvent);
|
||||
|
||||
|
||||
template<class ObservedT>
|
||||
class PrecisionChanged : public EndgameEvent<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) : EndgameEvent<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_;
|
||||
};
|
||||
|
||||
|
||||
}// re: namespace endgames
|
||||
}// re: namespace bertini
|
||||
|
||||
119
core/include/bertini2/endgames/fixed_prec_endgame.hpp
Normal file
119
core/include/bertini2/endgames/fixed_prec_endgame.hpp
Normal file
@@ -0,0 +1,119 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//fixed_prec_endgame.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_prec_endgame.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_prec_endgame.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
|
||||
|
||||
/**
|
||||
\file fixed_prec_endgame.hpp
|
||||
|
||||
\brief Contains the policy for fixed precision endgame types.
|
||||
*/
|
||||
|
||||
#include "bertini2/trackers/fixed_precision_tracker.hpp"
|
||||
#include "bertini2/trackers/fixed_precision_utilities.hpp"
|
||||
|
||||
#include "bertini2/endgames/config.hpp"
|
||||
#include "bertini2/endgames/prec_base.hpp"
|
||||
|
||||
|
||||
namespace bertini{ namespace endgame {
|
||||
|
||||
template<typename TrackerT>
|
||||
class FixedPrecEndgame : public virtual EndgamePrecPolicyBase<TrackerT>
|
||||
{
|
||||
public:
|
||||
using TrackerType = TrackerT;
|
||||
using BaseComplexType = typename tracking::TrackerTraits<TrackerType>::BaseComplexType;
|
||||
using BaseRealType = typename tracking::TrackerTraits<TrackerType>::BaseRealType;
|
||||
|
||||
using BCT = BaseComplexType;
|
||||
using BRT = BaseRealType;
|
||||
|
||||
template<typename... T>
|
||||
static
|
||||
unsigned EnsureAtUniformPrecision(T& ...args)
|
||||
{
|
||||
return bertini::tracking::fixed::EnsureAtUniformPrecision(args...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static
|
||||
void EnsureAtPrecision(T const & obj, unsigned prec)
|
||||
{
|
||||
using bertini::Precision;
|
||||
if (Precision(obj)!=prec)
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "ensuring precision of object failed; precision is " << Precision(obj) << " and required precision is " << prec;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
SuccessCode RefineSampleImpl(Vec<BCT> & result, Vec<BCT> const& current_sample, BCT const& current_time, double tol, unsigned max_iterations) const
|
||||
{
|
||||
using RT = mpfr_float;
|
||||
using std::max;
|
||||
auto& TR = this->GetTracker();
|
||||
|
||||
auto refinement_success = this->GetTracker().Refine(result,current_sample,current_time,
|
||||
tol,
|
||||
max_iterations);
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
explicit
|
||||
FixedPrecEndgame(TrackerT const& new_tracker) : EndgamePrecPolicyBase<TrackerT>(new_tracker)
|
||||
{}
|
||||
|
||||
virtual ~FixedPrecEndgame() = default;
|
||||
}; // re: fixed prec endgame policy
|
||||
|
||||
template<>
|
||||
struct EGPrecSelector<tracking::DoublePrecisionTracker>
|
||||
{
|
||||
using type = FixedPrecEndgame<tracking::DoublePrecisionTracker>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct EGPrecSelector<tracking::MultiplePrecisionTracker>
|
||||
{
|
||||
using type = FixedPrecEndgame<tracking::MultiplePrecisionTracker>;
|
||||
};
|
||||
|
||||
template<class D>
|
||||
struct EGPrecSelector<tracking::FixedPrecisionTracker<D>>
|
||||
{
|
||||
using type = FixedPrecEndgame<tracking::FixedPrecisionTracker<D>>;
|
||||
};
|
||||
|
||||
}} //re: namespaces
|
||||
|
||||
|
||||
|
||||
|
||||
130
core/include/bertini2/endgames/interpolation.hpp
Normal file
130
core/include/bertini2/endgames/interpolation.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//interpolation.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.
|
||||
//
|
||||
//interpolation.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 interpolation.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 interpolation.hpp Contains interpolation and extrapolation functions used in the endgames for estimating singular (and nonsingular) roots.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/common/config.hpp"
|
||||
|
||||
namespace bertini{
|
||||
namespace endgame{
|
||||
|
||||
/**
|
||||
|
||||
\brief Estimates the root to interpolating polynomial.
|
||||
|
||||
Input:
|
||||
target_time is the time value that we wish to interpolate at.
|
||||
samples are space values that correspond to the time values in times.
|
||||
derivatives are the dx_dt or dx_ds values at the (time,sample) values.
|
||||
|
||||
Output:
|
||||
Since we have a target_time the function returns the corrsponding space value at that time.
|
||||
|
||||
Details:
|
||||
We compare our approximations to the tracked value to come up with the cycle number.
|
||||
Also, we use the Hermite interpolation to interpolate at the origin. Once two interpolants are withing FinalTol we
|
||||
say we have converged.
|
||||
|
||||
\param[out] endgame_tracker_ The tracker used to compute the samples we need to start an endgame.
|
||||
\param endgame_time The time value at which we start the endgame.
|
||||
\param x_endgame_start The current space point at endgame_time.
|
||||
\param times A deque that will hold all the time values of the samples we are going to use to start the endgame.
|
||||
\param samples a deque that will hold all the samples corresponding to the time values in times.
|
||||
|
||||
\tparam CT The complex number type.
|
||||
*/
|
||||
template<typename CT>
|
||||
Vec<CT> HermiteInterpolateAndSolve(CT const& target_time, const unsigned int num_sample_points, const TimeCont<CT> & times, const SampCont<CT> & samples, const SampCont<CT> & derivatives, ContStart shift_from = ContStart::Back)
|
||||
{
|
||||
assert((times.size() >= num_sample_points) && "must have sufficient number of sample times");
|
||||
assert((samples.size() >= num_sample_points) && "must have sufficient number of sample points");
|
||||
assert((derivatives.size() >= num_sample_points) && "must have sufficient number of derivatives");
|
||||
|
||||
|
||||
unsigned num_t, num_s, num_d;
|
||||
if (shift_from == ContStart::Back)
|
||||
{
|
||||
num_t = times.size()-1;
|
||||
num_s = samples.size()-1;
|
||||
num_d = derivatives.size()-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_t = num_s = num_d = num_sample_points-1;
|
||||
}
|
||||
|
||||
Mat< Vec<CT> > space_differences(2*num_sample_points,2*num_sample_points);
|
||||
Vec<CT> time_differences(2*num_sample_points);
|
||||
|
||||
|
||||
for(unsigned int ii=0; ii<num_sample_points; ++ii)
|
||||
{
|
||||
space_differences(2*ii,0) = samples[ num_s-ii]; /* F[2*i][0] = samples[i]; */
|
||||
space_differences(2*ii+1,0) = samples[ num_s-ii]; /* F[2*i+1][0] = samples[i]; */
|
||||
space_differences(2*ii+1,1) = derivatives[num_d-ii]; /* F[2*i+1][1] = derivatives[i]; */
|
||||
time_differences(2*ii) = times[ num_t-ii]; /* z[2*i] = times[i]; */
|
||||
time_differences(2*ii+1) = times[ num_t-ii]; /* z[2*i+1] = times[i]; */
|
||||
}
|
||||
|
||||
//Add first round of finite differences to fill out rest of matrix.
|
||||
for(unsigned int ii=1; ii< num_sample_points; ++ii)
|
||||
{
|
||||
space_differences(2*ii,1) = (space_differences(2*ii,0) - space_differences(2*ii-1,0)) / (time_differences(2*ii) - time_differences(2*ii-1));
|
||||
|
||||
}
|
||||
|
||||
//Filling out finite difference matrix to get the diagonal for hermite interpolation polyonomial.
|
||||
for(unsigned int ii=2; ii < 2*num_sample_points; ++ii)
|
||||
{
|
||||
for(unsigned int jj=2; jj <=ii; ++jj)
|
||||
{
|
||||
space_differences(ii,jj) =
|
||||
(space_differences(ii,jj-1) - space_differences(ii-1,jj-1))
|
||||
/
|
||||
(time_differences(ii) - time_differences(ii-jj));
|
||||
}
|
||||
}
|
||||
|
||||
//Start of Result from Hermite polynomial, this is using the diagonal of the
|
||||
//finite difference matrix.
|
||||
Vec<CT> Result = space_differences(2*num_sample_points - 1,2*num_sample_points - 1);
|
||||
|
||||
|
||||
//This builds the hermite polynomial from the highest term down.
|
||||
//As we multiply the previous result we will construct the highest term down to the last term.
|
||||
for (unsigned ii=num_sample_points-1; ii >= 1; --ii)
|
||||
{
|
||||
Result = ((Result*(target_time - time_differences(ii)) + space_differences(2*ii, 2*ii)) * (target_time - time_differences(ii-1)) + space_differences(2*ii-1, 2*ii-1)).eval();
|
||||
}
|
||||
|
||||
// Last term in hermite polynomial.
|
||||
return (Result * (target_time - time_differences(0)) + space_differences(0,0)).eval();
|
||||
} //re: HermiteInterpolateAndSolve
|
||||
|
||||
}} // re: namespaces
|
||||
113
core/include/bertini2/endgames/observers.hpp
Normal file
113
core/include/bertini2/endgames/observers.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//endgames/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.
|
||||
//
|
||||
//endgames/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 endgames/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 endgames/observers.hpp
|
||||
|
||||
\brief Contains the endgames/observers base types
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/endgames/events.hpp"
|
||||
#include "bertini2/logging.hpp"
|
||||
#include "bertini2/detail/observer.hpp"
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
namespace bertini {
|
||||
|
||||
namespace endgame{
|
||||
|
||||
|
||||
/**
|
||||
\brief Logs the endgame run, with gory detail.
|
||||
|
||||
\ingroup loggers observers
|
||||
*/
|
||||
template <typename EndgameT>
|
||||
struct GoryDetailLogger : public Observer<EndgameT>
|
||||
{BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
|
||||
using EmitterT = EndgameT;
|
||||
using BCT = typename EndgameT::BaseComplexType;
|
||||
|
||||
virtual ~GoryDetailLogger() = default;
|
||||
|
||||
virtual void Observe(AnyEvent const& e) override
|
||||
{
|
||||
if(auto p = dynamic_cast<const TimeAdvanced<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "time advanced " << p->Get().LatestTime();
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const SampleRefined<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "refined a sample, huzzah";
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const CircleAdvanced<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "advanced around the circle, to " << p->NewSample()<< " at time " << p->NewTime();
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const ClosedLoop<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "closed a loop, cycle number " << p->Get().CycleNumber();
|
||||
}
|
||||
else if (auto p = dynamic_cast<const ApproximatedRoot<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "approximated the target root. approximation " << p->Get().template FinalApproximation<BCT>() << " with error " << p->Get().ApproximateError();
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const PrecisionChanged<AMPEndgame>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "precision changed from " << p->Previous() << " to " << p->Next();
|
||||
}
|
||||
|
||||
else if (auto p = dynamic_cast<const InEGOperatingZone<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "made it to the endgame operating zone at time " << p->Get().LatestTime();
|
||||
}
|
||||
|
||||
else if(auto p = dynamic_cast<const Converged<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "converged at time " << p->Get().LatestTime() << " with result " << p->Get().template FinalApproximation<BCT>() << " and residual " << p->Get().ApproximateError();
|
||||
}
|
||||
else if (auto p = dynamic_cast<const Initializing<EmitterT>*>(&e))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "starting running " << boost::typeindex::type_id<EmitterT>().pretty_name();
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(severity_level::debug) << "unprogrammed response for event of type " << boost::typeindex::type_id_runtime(e).pretty_name();
|
||||
}
|
||||
}
|
||||
|
||||
}; // gory detail
|
||||
|
||||
|
||||
} //re: namespace endgames
|
||||
}// re: namespace bertini
|
||||
750
core/include/bertini2/endgames/powerseries.hpp
Normal file
750
core/include/bertini2/endgames/powerseries.hpp
Normal file
@@ -0,0 +1,750 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//powerseries_endgame.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.
|
||||
//
|
||||
//powerseries_endgame.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 powerseries_endgame.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/endgames/base_endgame.hpp"
|
||||
|
||||
|
||||
namespace bertini{ namespace endgame{
|
||||
|
||||
|
||||
/**
|
||||
\class PowerSeriesEndgame
|
||||
|
||||
\brief class used to finish tracking paths during Homotopy Continuation
|
||||
|
||||
|
||||
## Explanation
|
||||
|
||||
The bertini::PowerSeriesEndgame class enables us to finish tracking on possibly singular paths on an arbitrary square homotopy.
|
||||
|
||||
The intended usage is to:
|
||||
|
||||
1. Create a system, tracker, and instantiate some settings.
|
||||
2. Using the tracker created track to the engame boundary, by default this is t = 0.1.
|
||||
3. Create a PowerSeriesEndgame, associating it to the tracker you wish to use. The tracker knows the system being solved.
|
||||
4. For each path being tracked send the PowerSeriesEndgame the time value and other variable values that it should use to start the endgame.
|
||||
5. The PowerSeriesEndgame, if successful, will store the homotopy solutions at t = 0.
|
||||
|
||||
## Example Usage
|
||||
|
||||
Below we demonstrate a basic usage of the PowerSeriesEndgame class to find the singularity at t = 0.
|
||||
|
||||
The pattern is as described above: create an instance of the class, feeding it the system to be used, and the endgame boundary time and other variable values at the endgame boundary.
|
||||
|
||||
\code{.cpp}
|
||||
using namespace bertini::tracking;
|
||||
using RealT = tracking::TrackerTraits<TrackerType>::BaseRealType; // Real types
|
||||
using ComplexT = tracking::TrackerTraits<TrackerType>::BaseComplexType; Complex types
|
||||
|
||||
// 1. Define the polynomial system that we wish to solve.
|
||||
System target_sys;
|
||||
Var x = Variable::Make("x"), t = Variable::Make("t"), y = Variable::Make("y");
|
||||
|
||||
VariableGroup vars{x,y};
|
||||
target_sys.AddVariableGroup(vars);
|
||||
|
||||
target_sys.AddFunction((pow(x-1,3));
|
||||
target_sys.AddFunction((pow(y-1,2));
|
||||
|
||||
// 1b. Homogenize and patch the polynomial system to work over projective space.
|
||||
sys.Homogenize();
|
||||
sys.AutoPatch();
|
||||
|
||||
// 2. Create a start system, for us we will use a total degree start system.
|
||||
auto TD_start_sys = bertini::start_system::TotalDegree(target_sys);
|
||||
|
||||
// 2b. Creating homotopy between the start system and system we wish to solve.
|
||||
auto my_homotopy = (1-t)*target_sys + t*TD_start_sys*Rational::Rand(); //the random number is our gamma for a random path between t = 1 and t = 0.
|
||||
my_homotopy.AddPathVariable(t);
|
||||
|
||||
//Sets up configuration settings for our particular system.
|
||||
auto precision_config = PrecisionConfig(my_homotopy);
|
||||
|
||||
|
||||
// 3. Creating a tracker. For us this is an AMPTracker.
|
||||
AMPTracker tracker(my_homotopy);
|
||||
|
||||
//Tracker setup of settings.
|
||||
SteppingConfig<RealT> stepping_preferences;
|
||||
stepping_preferences.initial_step_size = RealT(1)/RealT(5);// change a stepping preference
|
||||
NewtonConfig newton_preferences;
|
||||
tracker.Setup(TestedPredictor,
|
||||
RealFromString("1e-6"),
|
||||
RealFromString("1e5"),
|
||||
stepping_preferences,
|
||||
newton_preferences);
|
||||
tracker.PrecisionSetup(precision_config);
|
||||
|
||||
//We start at t = 1, and will stop at t = 0.1 before starting the endgames.
|
||||
ComplexT t_start(1), t_endgame_boundary(0.1);
|
||||
|
||||
//This will hold our solutions at t = 0.1
|
||||
std::vector<Vec<ComplexT> > my_homotopy_solutions_at_endgame_boundary;
|
||||
|
||||
// result holds the value we track to at 0.1, and tracking success will report if we are unsucessful.
|
||||
Vec<ComplexT> result;
|
||||
|
||||
//4. Track all points to 0.1
|
||||
for (unsigned ii = 0; ii < TD_start_sys.NumStartPoints(); ++ii)
|
||||
{
|
||||
DefaultPrecision(ambient_precision);
|
||||
my_homotopy.precision(ambient_precision); // making sure our precision is all set up
|
||||
auto start_point = TD_start_sys.StartPoint<ComplexT>(ii);
|
||||
|
||||
tracker.TrackPath(result,t_start,t_endgame_boundary,start_point);
|
||||
|
||||
my_homotopy_solutions_at_endgame_boundary.push_back(result);
|
||||
}
|
||||
|
||||
|
||||
//Settings for the endgames.
|
||||
|
||||
PowerSeriesConfig power_series_settings;
|
||||
power_series_settings.max_cycle_number = 4;
|
||||
|
||||
|
||||
// 5. Create a power series endgame, and use them to get the soutions at t = 0.
|
||||
EndgameSelector<TrackerType>::PSEG my_pseg_endgame(tracker,power_series_settings,tolerances);
|
||||
|
||||
|
||||
std::vector<Vec<ComplexT> > my_homotopy_solutions;
|
||||
|
||||
std::vector<Vec<ComplexT> > my_homotopy_divergent_paths;
|
||||
|
||||
for(auto s : my_homotopy_solutions_at_endgame_boundary)
|
||||
{
|
||||
SuccessCode endgame_success = my_pseg_endgame.Run(t_endgame_boundary,s);
|
||||
|
||||
if(endgame_success == SuccessCode::Success)
|
||||
{
|
||||
my_homotopy_solutions.push_back(my_homotopy.DehomogenizePoint(my_endgame.FinalApproximation<ComplexT>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
my_homotopy_divergent_paths.push_back(my_homotopy.DehomogenizePoint(my_endgame.FinalApproximation<ComplexT>()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
\endcode
|
||||
|
||||
If this documentation is insufficient, please contact the authors with suggestions, or get involved! Pull requests welcomed.
|
||||
|
||||
## Testing
|
||||
|
||||
Test suite driving this class: endgames_test.
|
||||
|
||||
File: test/endgames/generic_pseg_test.hpp
|
||||
File: test/endgames/amp_powerseries_test.cpp
|
||||
File: test/endgames/fixed_double_powerseries_test.cpp
|
||||
FIle: test/endgames/fixed_multiple_powerseries_test.cpp
|
||||
*/
|
||||
|
||||
template<typename PrecT>
|
||||
class PowerSeriesEndgame :
|
||||
public virtual EndgameBase<PowerSeriesEndgame<PrecT>, PrecT>
|
||||
{
|
||||
public:
|
||||
using BaseEGT = EndgameBase<PowerSeriesEndgame<PrecT>, PrecT>;
|
||||
using FinalEGT = PowerSeriesEndgame<PrecT>;
|
||||
using TrackerType = typename BaseEGT::TrackerType;
|
||||
|
||||
using BaseComplexType = typename BaseEGT::BaseComplexType;
|
||||
using BaseRealType = typename BaseEGT::BaseRealType;
|
||||
|
||||
using EmitterType = PowerSeriesEndgame<PrecT>;
|
||||
|
||||
protected:
|
||||
|
||||
using EndgameBase<PowerSeriesEndgame<PrecT>, PrecT>::NotifyObservers;
|
||||
|
||||
using TupleOfTimes = typename BaseEGT::TupleOfTimes;
|
||||
using TupleOfSamps = typename BaseEGT::TupleOfSamps;
|
||||
|
||||
using BCT = BaseComplexType;
|
||||
using BRT = BaseRealType;
|
||||
|
||||
using Configs = typename AlgoTraits<FinalEGT>::NeededConfigs;
|
||||
using ConfigsAsTuple = typename Configs::ToTuple;
|
||||
|
||||
/**
|
||||
\brief State variable representing a computed upper bound on the cycle number.
|
||||
*/
|
||||
mutable unsigned upper_bound_on_cycle_number_;
|
||||
|
||||
/**
|
||||
\brief Holds the time values for different space values used in the Power series endgame.
|
||||
*/
|
||||
mutable TupleOfTimes times_;
|
||||
|
||||
/**
|
||||
\brief Holds the space values used in the Power series endgame.
|
||||
*/
|
||||
mutable TupleOfSamps samples_;
|
||||
|
||||
/**
|
||||
\brief Holds the derivatives at each space point.
|
||||
*/
|
||||
mutable TupleOfSamps derivatives_;
|
||||
|
||||
/**
|
||||
\brief Random vector used in computing an upper bound on the cycle number.
|
||||
*/
|
||||
mutable Vec<BCT> rand_vector_;
|
||||
|
||||
template<typename CT>
|
||||
void AssertSizesTimeSpace() const
|
||||
{
|
||||
const auto num_sample_points = this->EndgameSettings().num_sample_points;
|
||||
assert(std::get<SampCont<CT> >(samples_).size()==std::get<TimeCont<CT> >(times_).size() && "must have same number of samples in times and spaces");
|
||||
assert(std::get<SampCont<CT> >(samples_).size()>=num_sample_points && "must have sufficient number of samples");
|
||||
}
|
||||
|
||||
template<typename CT>
|
||||
void AssertSizesTimeSpaceDeriv() const
|
||||
{
|
||||
const auto num_sample_points = this->EndgameSettings().num_sample_points;
|
||||
assert(std::get<SampCont<CT> >(samples_).size()==std::get<TimeCont<CT> >(times_).size() && "must have same number of samples in times and spaces");
|
||||
assert(std::get<SampCont<CT> >(samples_).size()==std::get<SampCont<CT> >(derivatives_).size() && "must have same number of samples in derivatives and spaces");
|
||||
assert(std::get<SampCont<CT> >(samples_).size()>=num_sample_points && "must have sufficient number of samples");
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
auto UpperBoundOnCycleNumber() const { return upper_bound_on_cycle_number_;}
|
||||
|
||||
|
||||
/**
|
||||
\brief Function that clears all samples and times from data members for the Power Series endgame
|
||||
*/
|
||||
template<typename CT>
|
||||
void ClearTimesAndSamples()
|
||||
{
|
||||
std::get<TimeCont<CT> >(times_).clear();
|
||||
std::get<SampCont<CT> >(samples_).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Function to set the times used for the Power Series endgame.
|
||||
*/
|
||||
template<typename CT>
|
||||
void SetTimes(TimeCont<CT> const& times_to_set) { std::get<TimeCont<CT> >(times_) = times_to_set;}
|
||||
|
||||
/**
|
||||
\brief Function to get the times used for the Power Series endgame.
|
||||
*/
|
||||
template<typename CT>
|
||||
const auto& GetTimes() const {return std::get<TimeCont<CT> >(times_);}
|
||||
|
||||
|
||||
const BCT& LatestTimeImpl() const
|
||||
{
|
||||
return GetTimes<BCT>().back();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Function to set the space values used for the Power Series endgame.
|
||||
*/
|
||||
template<typename CT>
|
||||
void SetSamples(SampCont<CT> const& samples_to_set) { std::get<SampCont<CT> >(samples_) = samples_to_set;}
|
||||
|
||||
/**
|
||||
\brief Function to get the space values used for the Power Series endgame.
|
||||
*/
|
||||
template<typename CT>
|
||||
const auto& GetSamples() const {return std::get<SampCont<CT> >(samples_);}
|
||||
|
||||
/**
|
||||
\brief Function to set the times used for the Power Series endgame.
|
||||
*/
|
||||
template<typename CT>
|
||||
void SetRandVec(int size) {rand_vector_ = Vec<CT>::Random(size);}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
explicit PowerSeriesEndgame(TrackerType const& tr,
|
||||
const ConfigsAsTuple& settings )
|
||||
: BaseEGT(tr, settings), EndgamePrecPolicyBase<TrackerType>(tr)
|
||||
{}
|
||||
|
||||
template< typename... Ts >
|
||||
explicit
|
||||
PowerSeriesEndgame(TrackerType const& tr, const Ts&... ts ) : PowerSeriesEndgame(tr, Configs::Unpermute( ts... ) )
|
||||
{}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Computes an upper bound on the cycle number. Consult page 53 of \cite bertinibook.
|
||||
|
||||
## Input:
|
||||
None: all data needed are class data members.
|
||||
|
||||
## Output:
|
||||
upper_bound_on_cycle_number_: Used for an exhaustive search for the best cycle number for approimating the path to t = 0.
|
||||
|
||||
##Details:
|
||||
\tparam CT The complex number type.
|
||||
*/
|
||||
template<typename CT>
|
||||
unsigned ComputeBoundOnCycleNumber()
|
||||
{
|
||||
using RT = typename Eigen::NumTraits<CT>::Real;
|
||||
using std::log; using std::abs;
|
||||
|
||||
const auto& samples = std::get<SampCont<CT> >(samples_);
|
||||
|
||||
AssertSizesTimeSpace<CT>();
|
||||
|
||||
auto num_samples = samples.size();
|
||||
const Vec<CT> & sample0 = samples[num_samples-3];
|
||||
const Vec<CT> & sample1 = samples[num_samples-2];
|
||||
const Vec<CT> & sample2 = samples[num_samples-1]; // most recent sample. oldest samples at front of the container
|
||||
|
||||
|
||||
// should this only be if the system is homogenized?
|
||||
CT rand_sum1 = ((sample1 - sample0).transpose()*rand_vector_).sum();
|
||||
CT rand_sum2 = ((sample2 - sample1).transpose()*rand_vector_).sum();
|
||||
|
||||
if ( abs(rand_sum1)==0 || abs(rand_sum2)==0) // avoid division by 0
|
||||
{
|
||||
upper_bound_on_cycle_number_ = 1;
|
||||
return upper_bound_on_cycle_number_;
|
||||
}
|
||||
|
||||
RT estimate = log(static_cast<RT>(this->EndgameSettings().sample_factor))/log(abs(rand_sum2/rand_sum1));
|
||||
|
||||
if (estimate < 1) // would be nan if sample points are same as each other
|
||||
upper_bound_on_cycle_number_ = 1;
|
||||
else
|
||||
{
|
||||
using std::max;
|
||||
auto upper_bound = unsigned(round(estimate)*this->template Get<PowerSeriesConfig>().cycle_number_amplification);
|
||||
upper_bound_on_cycle_number_ = max(upper_bound,this->template Get<PowerSeriesConfig>().max_cycle_number);
|
||||
}
|
||||
|
||||
return upper_bound_on_cycle_number_;
|
||||
}//end ComputeBoundOnCycleNumber
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief This function computes the cycle number using an exhaustive search up the upper bound computed by the above function BoundOnCyleNumber.
|
||||
|
||||
## Input:
|
||||
None: all data needed are class data members.
|
||||
|
||||
## Output:
|
||||
cycle_number_: Used to create a hermite interpolation to t = 0.
|
||||
|
||||
##Details:
|
||||
\tparam CT The complex number type.
|
||||
This is done by an exhaustive search from 1 to upper_bound_on_cycle_number. There is a conversion to the s-space from t-space in this function.
|
||||
As a by-product the derivatives at each of the samples is returned for further use.
|
||||
*/
|
||||
|
||||
template<typename CT>
|
||||
unsigned ComputeCycleNumber(CT const& t0)
|
||||
{
|
||||
using RT = typename Eigen::NumTraits<CT>::Real;
|
||||
|
||||
const auto& samples = std::get<SampCont<CT> >(samples_);
|
||||
const auto& times = std::get<TimeCont<CT> >(times_);
|
||||
const auto& derivatives = std::get<SampCont<CT> >(derivatives_);
|
||||
|
||||
AssertSizesTimeSpaceDeriv<CT>();
|
||||
|
||||
const Vec<CT> &most_recent_sample = samples.back();
|
||||
const CT& most_recent_time = times.back();
|
||||
|
||||
//Compute upper bound for cycle number.
|
||||
ComputeBoundOnCycleNumber<CT>();
|
||||
|
||||
|
||||
unsigned num_pts;
|
||||
if (samples.size() > this->EndgameSettings().num_sample_points)
|
||||
num_pts = this->EndgameSettings().num_sample_points;
|
||||
else
|
||||
num_pts = this->EndgameSettings().num_sample_points-1;
|
||||
|
||||
|
||||
auto min_found_difference = Eigen::NumTraits<RT>::highest();
|
||||
|
||||
TimeCont<CT> s_times(num_pts);
|
||||
SampCont<CT> s_derivatives(num_pts);
|
||||
|
||||
auto offset = samples.size() - num_pts - 1; // -1 here to shift away from the back of the container
|
||||
for(unsigned int candidate = 1; candidate <= upper_bound_on_cycle_number_; ++candidate)
|
||||
{
|
||||
using std::pow;
|
||||
|
||||
std::tie(s_times, s_derivatives) = TransformToSPlane(candidate, t0, num_pts, ContStart::Front);
|
||||
RT cand_power{1/static_cast<RT>(candidate)};
|
||||
RT curr_diff = (HermiteInterpolateAndSolve<CT>(
|
||||
pow((most_recent_time-t0)/(times[0]-t0),cand_power), // the target time
|
||||
num_pts,s_times,samples,s_derivatives, ContStart::Front) // the input data
|
||||
-
|
||||
most_recent_sample).template lpNorm<Eigen::Infinity>();
|
||||
|
||||
if (curr_diff < min_found_difference)
|
||||
{
|
||||
min_found_difference = curr_diff;
|
||||
this->cycle_number_ = candidate;
|
||||
}
|
||||
|
||||
}// end cc loop over cycle number possibilities
|
||||
|
||||
return this->cycle_number_;
|
||||
}//end ComputeCycleNumber
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Compute a set of derivatives using internal data to the endgame.
|
||||
|
||||
## Input:
|
||||
None: all data needed are class data members.
|
||||
|
||||
## Output:
|
||||
None: Derivatives are members of this class.
|
||||
|
||||
##Details:
|
||||
\tparam CT The complex number type.
|
||||
*/
|
||||
template<typename CT>
|
||||
void ComputeAllDerivatives()
|
||||
{
|
||||
auto& samples = std::get<SampCont<CT> >(samples_);
|
||||
auto& times = std::get<TimeCont<CT> >(times_);
|
||||
auto& derivatives = std::get<SampCont<CT> >(derivatives_);
|
||||
|
||||
assert((samples.size() == times.size()) && "must have same number of times and samples");
|
||||
|
||||
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec) // known at compile time
|
||||
{
|
||||
auto max_precision = this->EnsureAtUniformPrecision(times, samples);
|
||||
this->GetSystem().precision(max_precision);
|
||||
}
|
||||
|
||||
//Compute dx_dt for each sample.
|
||||
derivatives.clear(); derivatives.resize(samples.size());
|
||||
for(unsigned ii = 0; ii < samples.size(); ++ii)
|
||||
{
|
||||
derivatives[ii] = -this->GetSystem().Jacobian(samples[ii],times[ii]).lu().solve(this->GetSystem().TimeDerivative(samples[ii],times[ii]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\param c The cycle number you want to use
|
||||
|
||||
This function transforms the times and derivatives into the S-plane, scaled by the cycle number.
|
||||
|
||||
this function also transforms them into the interval [0 1]
|
||||
*/
|
||||
template <typename CT>
|
||||
std::tuple<TimeCont<CT>, SampCont<CT>> TransformToSPlane(int cycle_num, CT const& t0, unsigned num_pts, ContStart shift_from)
|
||||
{
|
||||
if (cycle_num==0)
|
||||
throw std::runtime_error("cannot transform to s plane with cycle number 0");
|
||||
AssertSizesTimeSpaceDeriv<CT>();
|
||||
|
||||
|
||||
using RT = typename Eigen::NumTraits<CT>::Real;
|
||||
|
||||
const auto& times = std::get<TimeCont<CT> >(times_);
|
||||
const auto& derivatives = std::get<SampCont<CT> >(derivatives_);
|
||||
|
||||
RT c = static_cast<RT>(cycle_num);
|
||||
RT one_over_c = 1/c;
|
||||
|
||||
unsigned offset_t, offset_d;
|
||||
if (shift_from == ContStart::Back)
|
||||
{
|
||||
offset_t = times.size()-num_pts;
|
||||
offset_d = derivatives.size()-num_pts;
|
||||
}
|
||||
else
|
||||
offset_t = offset_d = 0;
|
||||
|
||||
|
||||
TimeCont<CT> s_times(num_pts);
|
||||
SampCont<CT> s_derivatives(num_pts);
|
||||
|
||||
CT time_shift = times[offset_t] - t0;
|
||||
|
||||
for(unsigned ii = 0; ii < num_pts; ++ii){
|
||||
s_times[ii] = pow((times[ii+offset_t]-t0)/time_shift, one_over_c);
|
||||
s_derivatives[ii] = derivatives[ii+offset_d]*( c*pow(s_times[ii],cycle_num-1))*time_shift;
|
||||
}
|
||||
|
||||
return std::make_tuple(s_times, s_derivatives);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief This function computes an approximation of the space value at the time time_t0.
|
||||
|
||||
## Input:
|
||||
result: Passed by reference this holds the value of the approximation we compute
|
||||
t0: This is the time value for which we wish to compute an approximation at.
|
||||
|
||||
## Output:
|
||||
SuccessCode: This reports back if we were successful in making an approximation.
|
||||
|
||||
##Details:
|
||||
\tparam CT The complex number type.
|
||||
This function handles computing an approximation at the origin.
|
||||
We compute the cycle number best for the approximation, and convert derivatives and times to the s-plane where s = t^(1/c).
|
||||
We use the converted times and derivatives along with the samples to do a Hermite interpolation.
|
||||
*/
|
||||
template<typename CT>
|
||||
SuccessCode ComputeApproximationOfXAtT0(Vec<CT>& result, const CT & t0)
|
||||
{
|
||||
const auto c = ComputeCycleNumber<CT>(t0);
|
||||
|
||||
auto num_pts = this->EndgameSettings().num_sample_points;
|
||||
|
||||
TimeCont<CT> s_times;
|
||||
SampCont<CT> s_derivatives;
|
||||
|
||||
std::tie(s_times, s_derivatives) = TransformToSPlane(c, t0, num_pts, ContStart::Back);
|
||||
// the data was transformed to be on the interval [0 1] so we can hard-code the time-to-solve as 0 here.
|
||||
|
||||
Precision(result, Precision(s_derivatives.back()));
|
||||
result = HermiteInterpolateAndSolve(CT(0), num_pts, s_times, std::get<SampCont<CT> >(samples_), s_derivatives, ContStart::Back);
|
||||
return SuccessCode::Success;
|
||||
}//end ComputeApproximationOfXAtT0
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief The samples used in the power series endgame are collected by advancing time to t = 0, by multiplying the current time by the sample factor.
|
||||
|
||||
## Input:
|
||||
target_time: This is the time we are trying to approximate, default is t = 0.
|
||||
|
||||
## Output:
|
||||
SuccessCode: This reports back if we were successful in advancing time.
|
||||
|
||||
##Details:
|
||||
\tparam CT The complex number type.
|
||||
This function computes the next time value for the power series endgame. After computing this time value,
|
||||
it will track to it and compute the derivative at this time value for further appoximations to be made during the
|
||||
endgame.
|
||||
*/
|
||||
template<typename CT>
|
||||
SuccessCode AdvanceTime(const CT & target_time)
|
||||
{
|
||||
using RT = typename Eigen::NumTraits<CT>::Real;
|
||||
|
||||
auto& samples = std::get<SampCont<CT> >(samples_);
|
||||
auto& times = std::get<TimeCont<CT> >(times_);
|
||||
auto& derivatives = std::get<SampCont<CT> >(derivatives_);
|
||||
|
||||
AssertSizesTimeSpaceDeriv<CT>();
|
||||
|
||||
Vec<CT> next_sample;
|
||||
CT next_time = (times.back() + target_time) * static_cast<RT>(this->EndgameSettings().sample_factor); //setting up next time value using the midpoint formula, sample_factor will give us some
|
||||
|
||||
if (abs(next_time - target_time) < this->EndgameSettings().min_track_time) // generalized for target_time not equal to 0.
|
||||
{
|
||||
NotifyObservers(MinTrackTimeReached<EmitterType>(*this));
|
||||
return SuccessCode::MinTrackTimeReached;
|
||||
}
|
||||
|
||||
SuccessCode tracking_success = this->GetTracker().TrackPath(next_sample,times.back(),next_time,samples.back());
|
||||
if (tracking_success != SuccessCode::Success)
|
||||
return tracking_success;
|
||||
|
||||
NotifyObservers(InEGOperatingZone<EmitterType>(*this));
|
||||
|
||||
this->EnsureAtPrecision(next_time,Precision(next_sample));
|
||||
|
||||
|
||||
times.push_back(next_time);
|
||||
samples.push_back(next_sample);
|
||||
|
||||
|
||||
|
||||
|
||||
auto refine_success = this->RefineSample(samples.back(), next_sample, times.back(),
|
||||
this->FinalTolerance() * this->EndgameSettings().sample_point_refinement_factor,
|
||||
this->EndgameSettings().max_num_newton_iterations);
|
||||
if (refine_success != SuccessCode::Success)
|
||||
{
|
||||
NotifyObservers(RefiningFailed<EmitterType>(*this));
|
||||
return refine_success;
|
||||
}
|
||||
|
||||
this->EnsureAtPrecision(times.back(),Precision(samples.back()));
|
||||
|
||||
NotifyObservers(SampleRefined<EmitterType>(*this));
|
||||
|
||||
// we keep one more samplepoint than needed around, for estimating the cycle number
|
||||
if (times.size() > this->EndgameSettings().num_sample_points+1)
|
||||
{
|
||||
times.pop_front();
|
||||
samples.pop_front();
|
||||
}
|
||||
|
||||
return SuccessCode::Success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Primary function running the Power Series endgame.
|
||||
|
||||
## Input:
|
||||
start_time: This is the time value for which the endgame begins, by default this is t = 0.1
|
||||
start_point: An approximate solution of the homotopy at t = start_time
|
||||
target_time: The time value that we are wishing to approximate to. This is default set to t = 0.
|
||||
|
||||
## Output:
|
||||
SuccessCode: This reports back if we were successful in advancing time.
|
||||
|
||||
##Details:
|
||||
\tparam CT The complex number type.
|
||||
Tracking forward with the number of sample points, this function will make approximations using Hermite interpolation. This process will continue until two consecutive
|
||||
approximations are withing final tolerance of each other.
|
||||
*/
|
||||
template<typename CT>
|
||||
SuccessCode RunImpl(const CT & start_time, const Vec<CT> & start_point, CT const& target_time)
|
||||
{
|
||||
if (start_point.size()!=this->GetSystem().NumVariables())
|
||||
{
|
||||
std::stringstream err_msg;
|
||||
err_msg << "number of variables in start point for PSEG, " << start_point.size() << ", must match the number of variables in the system, " << this->GetSystem().NumVariables();
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
|
||||
DefaultPrecision(Precision(start_point));
|
||||
|
||||
using RT = typename Eigen::NumTraits<CT>::Real;
|
||||
//Set up for the endgame.
|
||||
ClearTimesAndSamples<CT>();
|
||||
|
||||
|
||||
// unpack some references for easy use
|
||||
auto& samples = std::get<SampCont<CT> >(samples_);
|
||||
auto& times = std::get<TimeCont<CT> >(times_);
|
||||
auto& derivatives = std::get<SampCont<CT> >(derivatives_);
|
||||
Vec<CT>& latest_approx = this->final_approximation_;
|
||||
Vec<CT>& prev_approx = this->previous_approximation_;
|
||||
|
||||
// this is for estimating a ... norm?
|
||||
SetRandVec<CT>(start_point.size());
|
||||
|
||||
|
||||
auto initial_sample_success = this->ComputeInitialSamples(start_time, target_time, start_point, times, samples);
|
||||
|
||||
if (initial_sample_success!=SuccessCode::Success)
|
||||
{
|
||||
NotifyObservers(EndgameFailure<EmitterType>(*this));
|
||||
return initial_sample_success;
|
||||
}
|
||||
|
||||
this->template RefineAllSamples<CT>(samples, times);
|
||||
ComputeAllDerivatives<CT>();
|
||||
|
||||
|
||||
|
||||
auto extrapolation_code = ComputeApproximationOfXAtT0(prev_approx, target_time);
|
||||
latest_approx = prev_approx;
|
||||
|
||||
if (extrapolation_code != SuccessCode::Success)
|
||||
return extrapolation_code;
|
||||
|
||||
RT norm_of_dehom_of_latest_approx;
|
||||
RT norm_of_dehom_of_prev_approx;
|
||||
if (this->SecuritySettings().level <= 0)
|
||||
norm_of_dehom_of_prev_approx = this->GetSystem().DehomogenizePoint(prev_approx).template lpNorm<Eigen::Infinity>();
|
||||
|
||||
|
||||
NumErrorT& approx_error = this->approximate_error_;
|
||||
approx_error = 1;
|
||||
|
||||
while (approx_error > this->FinalTolerance())
|
||||
{
|
||||
auto advance_code = AdvanceTime<CT>(target_time);
|
||||
if (advance_code!=SuccessCode::Success)
|
||||
{
|
||||
NotifyObservers(EndgameFailure<EmitterType>(*this));
|
||||
return advance_code;
|
||||
}
|
||||
|
||||
// this code is what bertini1 does... it refines all samples, like, all the time.
|
||||
this->template RefineAllSamples<CT>(samples, times);
|
||||
ComputeAllDerivatives<CT>();
|
||||
|
||||
extrapolation_code = ComputeApproximationOfXAtT0(latest_approx, target_time);
|
||||
if (extrapolation_code!=SuccessCode::Success)
|
||||
{
|
||||
NotifyObservers(EndgameFailure<EmitterType>(*this));
|
||||
return extrapolation_code;
|
||||
}
|
||||
|
||||
approx_error = static_cast<NumErrorT>((latest_approx - prev_approx).template lpNorm<Eigen::Infinity>());
|
||||
NotifyObservers(ApproximatedRoot<EmitterType>(*this));
|
||||
|
||||
|
||||
if(this->SecuritySettings().level <= 0)
|
||||
{
|
||||
norm_of_dehom_of_latest_approx = this->GetSystem().DehomogenizePoint(latest_approx).template lpNorm<Eigen::Infinity>();
|
||||
if(norm_of_dehom_of_latest_approx > this->SecuritySettings().max_norm && norm_of_dehom_of_prev_approx > this->SecuritySettings().max_norm)
|
||||
{
|
||||
NotifyObservers(SecurityMaxNormReached<EmitterType>(*this));
|
||||
return SuccessCode::SecurityMaxNormReached;
|
||||
}
|
||||
norm_of_dehom_of_prev_approx = norm_of_dehom_of_latest_approx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Precision(prev_approx, Precision(latest_approx));
|
||||
prev_approx = latest_approx;
|
||||
} //end while
|
||||
|
||||
NotifyObservers(Converged<EmitterType>(*this));
|
||||
return SuccessCode::Success;
|
||||
|
||||
} //end PSEG
|
||||
|
||||
|
||||
virtual ~PowerSeriesEndgame() = default;
|
||||
}; // end powerseries class
|
||||
|
||||
|
||||
|
||||
|
||||
}} // re: namespaces
|
||||
104
core/include/bertini2/endgames/prec_base.hpp
Normal file
104
core/include/bertini2/endgames/prec_base.hpp
Normal file
@@ -0,0 +1,104 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//prec_base.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.
|
||||
//
|
||||
//prec_base.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 prec_base.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
|
||||
|
||||
|
||||
/**
|
||||
\file include/bertini2/endgames/prec_base.hpp
|
||||
|
||||
\brief Contains a parent class, EndgamePrecPolicyBase (an observable), from which the fixed double, fixed multiple, or adaptive precision endgames are derived.
|
||||
*/
|
||||
|
||||
|
||||
namespace bertini{ namespace endgame {
|
||||
|
||||
|
||||
/**
|
||||
\brief A common base type for various precision types, fixed and adaptive. The purpose of this is to maintain a uniform interface to the tracker that's being used, across endgame types.
|
||||
*/
|
||||
template <typename TrackerT>
|
||||
class EndgamePrecPolicyBase : public virtual Observable
|
||||
{
|
||||
public:
|
||||
|
||||
using TrackerType = TrackerT;
|
||||
|
||||
explicit
|
||||
EndgamePrecPolicyBase(TrackerT const& new_tracker) : tracker_(std::ref(new_tracker))
|
||||
{}
|
||||
|
||||
virtual ~EndgamePrecPolicyBase() = default;
|
||||
|
||||
/**
|
||||
Tell the endgame to use the given tracker. Takes a reference.
|
||||
|
||||
\note Ensure the tracker you are using doesn not go out of scope!
|
||||
*/
|
||||
inline
|
||||
void SetTracker(TrackerT const& new_tracker)
|
||||
{
|
||||
tracker_ = std::ref(new_tracker); // rebind the reference
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Getter for the tracker used inside an instance of the endgame.
|
||||
*/
|
||||
inline
|
||||
const TrackerT& GetTracker() const
|
||||
{
|
||||
return tracker_.get();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the system being tracked on, which is referred to by the tracker.
|
||||
*/
|
||||
inline
|
||||
const System& GetSystem() const
|
||||
{ return GetTracker().GetSystem();}
|
||||
|
||||
void ChangePrecision(unsigned p)
|
||||
{
|
||||
tracker_.ChangePrecision(p);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
\brief A tracker that must be passed into the endgame through a constructor. This tracker is what will be used to track to all time values during the endgame.
|
||||
*/
|
||||
std::reference_wrapper<const TrackerT> tracker_;
|
||||
|
||||
}; //EndgamePrecPolicyBase
|
||||
|
||||
|
||||
|
||||
} } // end namespaces
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user