You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
11 KiB
357 lines
11 KiB
// 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 - 2025 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.
|
|
|
|
\defgroup endgame
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <typeinfo>
|
|
|
|
#include "detail/configured.hpp"
|
|
#include "detail/enable_permuted_arguments.hpp"
|
|
#include "endgames/config.hpp"
|
|
#include "endgames/events.hpp"
|
|
#include "endgames/interpolation.hpp"
|
|
#include "logging.hpp"
|
|
#include "mpfr_complex.hpp"
|
|
#include "system/system.hpp"
|
|
#include "trackers/config.hpp"
|
|
|
|
namespace bertini {
|
|
namespace endgame {
|
|
|
|
/**
|
|
\class Endgame
|
|
|
|
\brief Base endgame class for all endgames offered in Bertini2.
|
|
|
|
\ingroup endgame
|
|
|
|
\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;
|
|
};
|
|
|
|
} // namespace endgame
|
|
} // namespace bertini
|
|
|
|
#endif
|
|
|