// 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
// .
//
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
//
// See for a copy of the license,
// as well as COPYING. Bertini2 is provided with permitted
// additional terms in the b2/licenses/ directory.
// individual authors of this file include:
// silviana amethyst, university of wisconsin eau claire
// Tim Hodges, Colorado State University
#pragma once
#include "endgames/base_endgame.hpp"
namespace bertini {
namespace endgame {
/**
\class PowerSeriesEndgame
\brief class used to finish tracking paths during Homotopy Continuation
\ingroup endgame
## 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::BaseRealType; // Real types
using ComplexT = tracking::TrackerTraits::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 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 > 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 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(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::PSEG
my_pseg_endgame(tracker,power_series_settings,tolerances);
std::vector > my_homotopy_solutions;
std::vector > 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()));
}
else
{
my_homotopy_divergent_paths.push_back(my_homotopy.DehomogenizePoint(my_endgame.FinalApproximation()));
}
}
\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
class PowerSeriesEndgame
: public virtual EndgameBase, PrecT> {
public:
using BaseEGT = EndgameBase, PrecT>;
using FinalEGT = PowerSeriesEndgame;
using TrackerType = typename BaseEGT::TrackerType;
using BaseComplexType = typename BaseEGT::BaseComplexType;
using BaseRealType = typename BaseEGT::BaseRealType;
using EmitterType = PowerSeriesEndgame;
protected:
using EndgameBase, PrecT>::NotifyObservers;
using TupleOfTimes = typename BaseEGT::TupleOfTimes;
using TupleOfSamps = typename BaseEGT::TupleOfSamps;
using BCT = BaseComplexType;
using BRT = BaseRealType;
using Configs = typename AlgoTraits::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 rand_vector_;
template
void AssertSizesTimeSpace() const {
const auto num_sample_points = this->EndgameSettings().num_sample_points;
assert(std::get>(samples_).size() ==
std::get>(times_).size() &&
"must have same number of samples in times and spaces");
assert(std::get>(samples_).size() >= num_sample_points &&
"must have sufficient number of samples");
}
template
void AssertSizesTimeSpaceDeriv() const {
const auto num_sample_points = this->EndgameSettings().num_sample_points;
assert(std::get>(samples_).size() ==
std::get>(times_).size() &&
"must have same number of samples in times and spaces");
assert(std::get>(samples_).size() ==
std::get>(derivatives_).size() &&
"must have same number of samples in derivatives and spaces");
assert(std::get>(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
void ClearTimesAndSamples() {
std::get>(times_).clear();
std::get>(samples_).clear();
}
/**
\brief Function to set the times used for the Power Series endgame.
*/
template
void SetTimes(TimeCont const& times_to_set) {
std::get>(times_) = times_to_set;
}
/**
\brief Function to get the times used for the Power Series endgame.
*/
template
const auto& GetTimes() const {
return std::get>(times_);
}
const BCT& LatestTimeImpl() const { return GetTimes().back(); }
/**
\brief Function to set the space values used for the Power Series endgame.
*/
template
void SetSamples(SampCont const& samples_to_set) {
std::get>(samples_) = samples_to_set;
}
/**
\brief Function to get the space values used for the Power Series endgame.
*/
template
const auto& GetSamples() const {
return std::get>(samples_);
}
/**
\brief Function to set the times used for the Power Series endgame.
*/
template
void SetRandVec(int size) {
rand_vector_ = Vec::Random(size);
}
explicit PowerSeriesEndgame(TrackerType const& tr,
const ConfigsAsTuple& settings)
: BaseEGT(tr, settings), EndgamePrecPolicyBase(tr) {}
template
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
unsigned ComputeBoundOnCycleNumber() {
using RT = typename Eigen::NumTraits::Real;
using std::abs;
using std::log;
const auto& samples = std::get>(samples_);
AssertSizesTimeSpace();
auto num_samples = samples.size();
const Vec& sample0 = samples[num_samples - 3];
const Vec& sample1 = samples[num_samples - 2];
const Vec& 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