Add files

This commit is contained in:
2025-01-14 01:15:48 +01:00
commit 2f9fcec55b
406 changed files with 87154 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
//This file is part of Bertini 2.
//
//nag_algorithms/common/algorithm_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.
//
//nag_algorithms/common/algorithm_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 nag_algorithms/common/algorithm_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
/**
\file nag_algorithms/common/algorithm_base.hpp
\brief provides a common base type for algorithms to inherit from, for the abstraction layer above for calling them from blackbox-type programs
*/
#pragma once
namespace bertini{
namespace algorithm {
struct AnyAlgorithm
{
virtual
void Run() = 0;
virtual ~AnyAlgorithm() = default;
};
}
}

View File

@@ -0,0 +1,154 @@
//This file is part of Bertini 2.
//
//nag_algorithms/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.
//
//nag_algorithms/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 nag_algorithms/config.hpp. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
//
// See <http://www.gnu.org/licenses/> for a copy of the license,
// as well as COPYING. Bertini2 is provided with permitted
// additional terms in the b2/licenses/ directory.
// individual authors of this file include:
// silviana amethyst, university of wisconsin eau claire
// Tim Hodges, Colorado State University
// jeb collins, west texas a&m
#pragma once
#include "bertini2/system/start_systems.hpp"
#include "bertini2/nag_algorithms/common/policies.hpp"
namespace bertini{
namespace algorithm{
template<typename T>
using SolnCont = std::vector<T>;
namespace classic{
enum class AlgoChoice
{
EvalFunctions = -4,
EvalFunctionJacobian = -3,
NewtonIteration = -2,
NewtonIterationCondNum = -1,
ZeroDim = 0,
NID = 1,
SampleComponent = 2,
MembershipTest = 3,
ExtractWitnessSet = 4,
WitnessSetProjection = 5,
IsosingularStab = 6
};
} // namespace classic
struct TolerancesConfig
{
using T = NumErrorT;
T newton_before_endgame = T(1)/T(100000); //E.4.1
T newton_during_endgame = T(1)/T(1000000); //E.4.2
T final_tolerance = T(1)/T(100000000000); //E.5.1
T path_truncation_threshold = T(100000); //E.4.13
};
struct MidPathConfig
{
using T = NumErrorT;
T same_point_tolerance = T(1)/T(100000);
};
struct AutoRetrackConfig
{
using T = NumErrorT;
T midpath_decrease_tolerance_factor = T(1)/T(2);
};
struct SharpeningConfig
{
using T = NumErrorT;
unsigned sharpendigits; ///< how many digits should be correct after sharpening.
// std::function<Vec<T>> sharpen_method_; ///< function taking a vector, and sharpening it.
T function_residual_tolerance = Eigen::NumTraits<T>::dummy_precision(); ///< A polynomial (or any function, really) evaluated at a point is considered to be 0 if the magnitude is smaller than this value. See also RatioTolerance. **Note that this value depends on the current default precision when this scruct is constructed.**
T ratio_tolerance = T(99)/T(100); ///< A computed value is considered to be zero if the ratio of two different approximations is smaller than this value. See also FunctionTolerance
};
struct RegenerationConfig
{
using T = NumErrorT;
bool remove_infinite_endpoints = true; ///< Bool indicating whether endpoints during the regeneration start point buildup step which are infinite should be discarded. If you are not interested in infinite solutions, ensure this is true. RegenRemoveInf
bool higher_dimension_check = true; ///< RegenHigherDimTest
unsigned start_level = 0;
T newton_before_endgame; ///< The tolerance for tracking before reaching the endgame. SliceTolBeforeEG
T newton_during_endgame; ///< The tolerance for tracking during the endgame. SliceTolDuringEG
T final_tolerance; ///< The final tolerance to track to, using the endgame. SliceFinalTol
};
struct PostProcessingConfig{
using T = NumErrorT;
T real_threshold = T(1)/T(100000000); ///< threshold on the imaginary part of a solution being 0. If the imag part exceeds this, the point is considered complex. Currently, this is the implemented available way in Bertini2 for determining this, but there are other methods. Smale's alpha theory provides ways to prove that a point is real. If this is something you need, please consider adding the method to the library, for all to use! Or, if this is technically beyond your C++ capabilities, add as an issue on the github page, and indicate it as a feature request.
T endpoint_finite_threshold = T(1)/T(100000); ///< The threshold on norm of endpoints being considered infinite. There is another setting in Tolerances, `path_truncation_threshold`, which tells the path tracker to die if exceeded. Another related setting is in Security, `max_norm` -- the endgame dies if the norm of the computed approximation exceeds this twice.
T same_point_tolerance {T(1)/T(10000000000)}; ///< The tolerance for whether two points are the same. This should be *lower* than the accuracy to which you request your solutions be computed. Perhaps by at least two orders of magnitude, but the default value is a factor of 10 less stringent. This also depends on the norm being used to tell whether two points are the same, and the norm used for the convergence condition to terminate tracking.
};
template<typename ComplexT>
struct ZeroDimConfig
{
unsigned initial_ambient_precision = DoublePrecision();
unsigned max_num_crossed_path_resolve_attempts = 2; ///< The maximum number of times to attempt to re-solve crossed paths at the endgame boundary.
ComplexT start_time = ComplexT(1);
ComplexT endgame_boundary = ComplexT(1)/ComplexT(10);
ComplexT target_time = ComplexT(0);
std::string path_variable_name = "ZERO_DIM_PATH_VARIABLE";
};
struct MetaConfig
{
classic::AlgoChoice tracktype = classic::AlgoChoice::ZeroDim;
};
// a forward declare
template <typename T>
struct AlgoTraits;
} } // namespaces

View File

@@ -0,0 +1,320 @@
//This file is part of Bertini 2.
//
//bertini2/nag_algorithms/common/policies.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.
//
//bertini2/nag_algorithms/common/policies.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 bertini2/nag_algorithms/common/policies.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 bertini2/nag_algorithms/common/policies.hpp
\brief Provides some policies for the zero dim algorithm.
You can also provide your own, that's the point of these policies.
*/
#pragma once
namespace bertini {
namespace policy{
/**
\brief A base class for system management for the zero-dim algorithm.
*/
template< typename D,
typename SystemType, typename StartSystemType
,typename StoredSystemType, typename StoredStartSystemType>
struct SysMgmtPolicy
{
using SystemT = SystemType;
using StartSystemT = StartSystemType;
using StoredSystemT = StoredSystemType;
using StoredStartSystemT = StoredStartSystemType;
private:
// convert the base endgame into the derived type.
const D& AsDerived() const
{
return static_cast<const D&>(*this);
}
// convert the base endgame into the derived type.
D& AsDerived()
{
return static_cast<D&>(*this);
}
public:
/**
A getter for the system to be tracked to.
*/
const SystemT& TargetSystem() const
{
return AsDerived().target_system_;
}
/**
A getter for the homotopy being used.
*/
const SystemT& Homotopy() const
{
return AsDerived().homotopy_;
}
/**
A getter for the start system being used.
*/
const StartSystemT & StartSystem() const
{
return AsDerived().start_system_;
}
/**
A setter for the system to be tracked to.
*/
void TargetSystem(StoredSystemT const& sys)
{
AsDerived().target_system_ = sys;
}
/**
A setter for the homotopy being used.
*/
void Homotopy(StoredSystemT const& sys)
{
AsDerived().homotopy_ = sys;
}
/**
A setter for the start system being used.
*/
void StartSystem(StoredStartSystemT const& sys)
{
AsDerived().start_system_ = sys;
}
};
/**
This system management policy makes it so that the zero dim algorithm makes a clone of the supplied system when the algorithm is created. The zerodim algorithm, and others, will homogenize the system (that's why you want a clone, so it leaves your original system untouched), form a start system (of your type, inferred from the template parameter for the zerodim alg), and couple the two together into the homotopy used to track.
If you don't want it to take copies, or homogenize, etc, use a different policy.
\see RefToGiven
*/
template<typename SystemType, typename StartSystemType>
struct CloneGiven : public SysMgmtPolicy<CloneGiven<SystemType, StartSystemType>, SystemType, StartSystemType, SystemType, StartSystemType>
{
using SMP = SysMgmtPolicy<CloneGiven<SystemType, StartSystemType>, SystemType, StartSystemType, SystemType, StartSystemType>;
friend SMP;
using StoredSystemT = typename SMP::StoredSystemT;
using StoredStartSystemT = typename SMP::StoredStartSystemT;
using SMP::TargetSystem;
using SMP::StartSystem;
using SMP::Homotopy;
using SystemT = SystemType;
using StartSystemT = StartSystemType;
private:
StoredSystemT target_system_;
StoredStartSystemT start_system_;
StoredSystemT homotopy_;
public:
/**
Simply forward on the systems for the constructor. The AtConstruct function is to be called by the user of this policy, at construct time.
*/
CloneGiven(SystemType const& target) : target_system_(AtConstruct(target))
{}
static
StoredSystemT AtConstruct(SystemType const& sys)
{
return Clone(sys);
}
/**
In contrast at AtConstruct, the AtSet function copies the given system into the stored system when setting, after construction.
*/
template<typename T>
static
T AtSet(T const& sys)
{
return sys;
}
/**
Homogenize and patch the target system.
*/
static
void PrepareTarget(SystemType & target)
{
// target system came from the constructor
target.Homogenize(); // work over projective coordinates
target.AutoPatch(); // then patch if needed
}
static void FormStart(StartSystemType & start, SystemType const& target)
{
start = StartSystemType(target);
}
static
void FormHomotopy(SystemType & homotopy, SystemType const& target, StartSystemType const& start, std::string const& path_variable_name)
{
auto t = node::Variable::Make(path_variable_name);
homotopy = (1-t)*target + node::Rational::Make(node::Rational::Rand())*t*start;
homotopy.AddPathVariable(t);
}
/**
\brief Sets up the homotopy for the system to be solved.
1. Homogenizes the system,
2. patches it,
3. constructs the start system,
4. stores the number of start points,
5. makes a path variable,
6. forms the straight line homotopy between target and start, with the gamma trick
boom, you're ready to go.
*/
void SystemSetup(std::string const& path_variable_name)
{
PrepareTarget(TargetSystem());
// now we populate the start system
FormStart(StartSystem(), TargetSystem());
FormHomotopy(Homotopy(), TargetSystem(), StartSystem(), path_variable_name);
}
/**
A getter for the system to be tracked to.
*/
SystemT& TargetSystem()
{
return target_system_;
}
/**
A getter for the homotopy being used.
*/
SystemT& Homotopy()
{
return homotopy_;
}
/**
A getter for the start system being used.
*/
StartSystemT & StartSystem()
{
return start_system_;
}
};
/**
This system management policy allows the user to prevent the zero dim algorithm from making clones, and instead the burden of supplying the target system, start system, and homotopy are entirely up to the user.
Using this policy implies the user manages these things entirely.
\see CloneGiven
*/
template<typename SystemType, typename StartSystemType>
struct RefToGiven : public SysMgmtPolicy<RefToGiven<SystemType, StartSystemType>, SystemType, StartSystemType,
std::reference_wrapper< const SystemType>, std::reference_wrapper< const StartSystemType>>
{
using SMP = SysMgmtPolicy<RefToGiven<SystemType, StartSystemType>, SystemType, StartSystemType,
std::reference_wrapper< const SystemType>, std::reference_wrapper< const StartSystemType>>;
friend SMP;
using StoredSystemT = typename SMP::StoredSystemT;
using StoredStartSystemT = typename SMP::StoredStartSystemT;
using SMP::TargetSystem;
using SMP::StartSystem;
using SMP::Homotopy;
private:
StoredSystemT target_system_; ///< The target system which we track to.
StoredStartSystemT start_system_; ///< The start system, which produces start points.
StoredSystemT homotopy_; ///< homotopy, on which we wish the path vanishes.
public:
/**
Simply forward references to the given systems on the stored systems.
*/
RefToGiven(SystemType const& target, StartSystemType const& start, SystemType const& hom)
:
target_system_(std::ref(target)),
start_system_(std::ref(start)),
homotopy_(std::ref(hom))
{}
/**
\brief Store a reference to the argument system.
*/
static
StoredSystemT AtConstruct(SystemType const& sys)
{
return std::ref(sys);
}
/**
\brief Store a reference to the argument system.
*/
template<typename T>
static
T AtSet(T const& sys)
{
return std::ref(sys);
}
void SystemSetup(std::string const& path_variable_name) const
{ }
};
} // ns policy
} // ns bertini

View File

@@ -0,0 +1,218 @@
//This file is part of Bertini 2.
//
//include/bertini2/nag_algorithms/midpath_check.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/nag_algorithms/midpath_check.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/nag_algorithms/midpath_check.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:
// James Collins, West Texas A&M University
// silviana amethyst, university of wisconsin-eau claire
/**
\file include/bertini2/nag_algorithms/midpath_check.hpp
\brief Provides methods for checking for path crossings.
This essentially amounts to being certain that no two points are the same.
*/
#pragma once
#include "bertini2/nag_algorithms/common/config.hpp"
#include "bertini2/detail/configured.hpp"
namespace bertini{
namespace algorithm{
template<typename RealType, typename ComplexType, typename MetaDataType>
struct MidpathChecker : public detail::Configured<MidPathConfig>
{
using MidPathConfT = MidPathConfig;
using AlgConf = detail::Configured<MidPathConfig>;
using BoundaryData = SolnCont< MetaDataType >;
using PathIndT = unsigned long long;
MidpathChecker() = default;
/**
\brief Construct a MidpathChecker, given the system it is checking, and the tolerance which should be used to tell whether two points are the same.
\note The tolerance should be *relaxed* compared to the tracking tolerance used to compute these points.
*/
template<typename ...T>
MidpathChecker( T const& ...config) : AlgConf(config...)
{
passed_ = true;
}
/**
\struct CrossedPath
Stores data for each path that crosses, including the index of the path, all paths that it crosses with, and whether it has the same
starting point as a path it crosses with.
*/
struct CrossedPath{
CrossedPath(PathIndT index, PathIndT crossed_with, bool same_start)
{
index_ = index;
crossed_with_.push_back( std::make_pair(crossed_with, same_start) );
rerun_ = !same_start;
}
PathIndT index() const
{
return index_;
}
void crossed_with(std::pair<PathIndT, bool> crossed)
{
crossed_with_.push_back(crossed);
}
void rerun(bool same_start)
{
rerun_ = rerun_ || !same_start;
}
bool rerun() const
{
return rerun_;
}
private:
PathIndT index_;
std::vector< std::pair<PathIndT, bool> > crossed_with_; // first is index of path crossed with, second is bool = true if had same starting point as crossed path
bool rerun_;
}; //re: struct CrossedPath
bool Passed() const
{
return passed_;
}
const auto& SamePointTol() const
{
return this->template Get<MidPathConfT>().same_point_tolerance;
}
/**
\brief Checks the solution data at the endgame boundary to see if any paths have crossed during tracking before the endgame.
\param boundary_data Solution data at the endgame boundary
\returns A Data object which stores data about crossed paths
*/
template <typename StartSystemT>
bool Check(BoundaryData const& boundary_data, StartSystemT const& start_system)
{
for (PathIndT ii = 0; ii < boundary_data.size(); ++ii)
{
if ( boundary_data[ii].success_code != SuccessCode::Success)
continue;
const Vec<ComplexType>& solution_ii = boundary_data[ii].path_point;
const auto start_ii = start_system.template StartPoint<ComplexType>(ii);
for (PathIndT jj = ii+1; jj < boundary_data.size(); ++jj)
{
if ( boundary_data[jj].success_code != SuccessCode::Success)
continue;
const Vec<ComplexType>& solution_jj = boundary_data[jj].path_point;
const Vec<ComplexType> diff_sol = solution_ii - solution_jj;
if ((diff_sol.template lpNorm<Eigen::Infinity>()/solution_ii.template lpNorm<Eigen::Infinity>()) < SamePointTol())
{
bool i_already_stored = false;
bool j_already_stored = false;
// Check if start points are the same
const auto start_jj = start_system.template StartPoint<ComplexType>(jj);
auto diff_start = start_ii - start_jj;
bool same_start = (diff_start.template lpNorm<Eigen::Infinity>() > SamePointTol());
// Check if path has already been stored in crossed_paths_
for(auto& v : crossed_paths_)
{
if(v.index() == ii)
{
v.crossed_with(std::make_pair(jj,same_start));
i_already_stored = true;
v.rerun(same_start);
}
if(v.index() == jj)
{
v.crossed_with(std::make_pair(ii,same_start));
j_already_stored = true;
v.rerun(same_start);
}
}
// If not already stored, create CrossedPath object and add to crossed_paths_
if(!i_already_stored)
{
CrossedPath tempPath(ii, jj, same_start);
crossed_paths_.push_back(tempPath);
}
if(!j_already_stored)
{
CrossedPath tempPath(jj, ii, same_start);
crossed_paths_.push_back(tempPath);
}
passed_ = false;
}
}
}
return passed_;
};
const std::vector<CrossedPath> GetCrossedPaths() const
{
return crossed_paths_;
}
private:
std::vector<CrossedPath> crossed_paths_; // Data for all paths that crossed on last check
bool passed_; // Did the check pass?
}; //re: struct MidpathChecker
} // re: namespace algorithm
}// re: namespace bertini

View File

@@ -0,0 +1,56 @@
//This file is part of Bertini 2.
//
//bertini2/nag_algorithms/numerical_irreducible_decomposition.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.
//
//bertini2/nag_algorithms/numerical_irreducible_decomposition.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 bertini2/nag_algorithms/numerical_irreducible_decomposition.hpp. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright(C) 2017 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.
/**
\file bertini2/nag_algorithms/numerical_irreducible_decomposition.hpp
\brief Provides the NID algorithms for Bertini2.
*/
#pragma once
#include "bertini2/nag_datatypes/numerical_irreducible_decomposition.hpp"
namespace bertini {
namespace algorithm {
template <typename ComplexT>
struct NumericalIrreducibleDecomposition
{
static
nag_datatype::NumericalIrreducibleDecomposition<ComplexT> RegenerativeCascade()
{
}
};
}
}

View File

@@ -0,0 +1,285 @@
//This file is part of Bertini 2.
//
//bertini2/nag_algorithms/output.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.
//
//bertini2/nag_algorithms/output.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 bertini2/nag_algorithms/output.hpp. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright(C) 2017 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.
/**
\file bertini2/nag_algorithms/output.hpp
\brief Provides some outputting classes for printing results of running algorithms
You can also provide your own, that's the point of these policies.
*/
#pragma once
#include "bertini2/nag_algorithms/zero_dim_solve.hpp"
#include "bertini2/io/generators.hpp"
namespace bertini {
namespace algorithm {
namespace output {
/**
\brief Prints data from algorithms
*/
template <typename AlgoT>
struct Outputter
{ };
template <typename ...T>
struct Classic
{};
template <typename A, typename B, typename C, typename D, template<typename, typename> class E>
struct Classic <ZeroDim<A,B,C,D,E>>
{
using ZDT = ZeroDim<A,B,C,D,E>;
template <typename OutT>
static
void All(OutT & out, ZDT const& zd)
{
out << "\n\n\n MAINDATA \n\n\n";
MainData(out, zd);
out << "\n\n\n RAWDATA \n\n\n";
RawData(out, zd);
}
template <typename OutT>
static
void MainData(OutT & out, ZDT const& zd)
{
NumVariables(out, zd);
Variables(out, zd,"\n\n");
const auto& s = zd.FinalSolutions();
const auto& m = zd.FinalSolutionMetadata();
const auto n = s.size();
for (decltype(s.size()) ii{0}; ii<n; ++ii)
{
if (zd.FinalSolutionMetadata()[ii].endgame_success == SuccessCode::NeverStarted)
continue;
EndPointMDFull(ii, out, zd);
EndPoint(ii, out, zd,"\n\n");
}
out << "\n\n";
TargetSystem(out,zd,"\n\n");
StartSystem(out,zd,"\n\n");
Homotopy(out,zd,"\n\n");
}
template <typename OutT>
static
void RawData(OutT & out, ZDT const& zd)
{
const auto n = zd.FinalSolutions().size();
NumVariables(out, zd,"\n\n");
for (decltype(zd.FinalSolutions().size()) ii{0}; ii<n; ++ii)
{
if (zd.FinalSolutionMetadata()[ii].endgame_success == SuccessCode::NeverStarted)
continue;
EndPointMDRaw(ii,out,zd,"\n\n");
}
out << "\n\n";
TargetSystem(out,zd,"\n\n");
}
template <typename OutT>
static
void NumVariables(OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
const auto& sys = zd.TargetSystem();
out << sys.NumVariables() << additional;
}
template <typename OutT>
static
void Variables(OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
const auto& sys = zd.TargetSystem();
const auto& vars = sys.VariableOrdering();
for (const auto& x : vars)
out << *x << ' ';
out << additional;
}
template <typename OutT>
static
void TargetSystem(OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
out << zd.TargetSystem() << additional;
}
template <typename OutT>
static
void StartSystem(OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
out << zd.StartSystem() << additional;
}
template <typename OutT>
static
void Homotopy(OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
out << zd.Homotopy() << additional;
}
template <typename IndexT, typename OutT>
static
void EndPoint(IndexT const& ind, OutT & out, ZDT const& zd, std::string const& additional = "")
{
generators::Classic::generate(boost::spirit::ostream_iterator(out), zd.FinalSolutions()[ind]);
out << additional;
}
template <typename IndexT, typename OutT>
static
void EndPointDehom(IndexT const& ind, OutT & out, ZDT const& zd, std::string const& additional = "")
{
DefaultPrecision(Precision(zd.FinalSolutions()[ind]));
generators::Classic::generate(boost::spirit::ostream_iterator(out), zd.TargetSystem().DehomogenizePoint(zd.FinalSolutions()[ind]));
out << additional;
}
template <typename IndexT, typename OutT>
static
void EndPointMDFull(IndexT const& ind, OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
const auto& data = zd.FinalSolutionMetadata()[ind];
out << data.path_index << '\n'
<< data.solution_index << '\n'
<< data.condition_number << '\n'
<< data.function_residual << '\n'
<< data.newton_residual << '\n';
generators::Classic::generate(boost::spirit::ostream_iterator(out), data.final_time_used);
out << '\n' << data.max_precision_used << '\n';
generators::Classic::generate(boost::spirit::ostream_iterator(out), data.time_of_first_prec_increase);
out << '\n' << data.accuracy_estimate << '\n'
<< data.accuracy_estimate_user_coords << '\n'
<< data.cycle_num << '\n'
<< data.multiplicity << '\n'
<< data.pre_endgame_success << ' ' << data.endgame_success << '\n';
out << additional;
}
template <typename IndexT, typename OutT>
static
void EndPointMDRaw(IndexT const& ind, OutT & out, ZDT const& zd, std::string const& additional = "\n")
{
const auto& pt = zd.FinalSolutions()[ind];
const auto& data = zd.FinalSolutionMetadata()[ind];
out << data.path_index << '\n'
<< Precision(pt) << '\n';
EndPoint(ind, out, zd);
out << data.function_residual << '\n'
<< data.condition_number << '\n'
<< data.newton_residual << '\n';
generators::Classic::generate(boost::spirit::ostream_iterator(out), data.final_time_used);
out << '\n' << data.accuracy_estimate << '\n';
generators::Classic::generate(boost::spirit::ostream_iterator(out), data.time_of_first_prec_increase);
out << '\n' << data.cycle_num << '\n'
<< data.endgame_success << '\n'
<< additional;
}
};
struct NonsingularSolutions
{
template<typename AlgoT>
static
auto Extract(AlgoT const& alg)
{
using BCT = typename AlgoTraits<AlgoT>::BaseComplexType;
const auto& sys = alg.TargetSystem();
SampCont<BCT> solns;
const auto& s = alg.FinalSolutions();
const auto& m = alg.FinalSolutionMetadata();
const auto n = s.size();
for (decltype(s.size()) ii{0}; ii<n; ++ii)
{
const auto& d = m[ii];
if (d.endgame_success == SuccessCode::Success &&
d.multiplicity==1)
{
solns.push_back(sys.DehomogenizePoint(s[ii]));
}
}
return solns;
}
};
struct AllSolutions
{
template<typename AlgoT>
static
auto Extract(AlgoT const& alg)
{
using BCT = typename AlgoTraits<AlgoT>::BaseComplexType;
const auto& sys = alg.TargetSystem();
SampCont<BCT> solns;
const auto& s = alg.FinalSolutions();
const auto& m = alg.FinalSolutionMetadata();
const auto n = s.size();
for (decltype(s.size()) ii{0}; ii<n; ++ii)
{
solns.push_back(sys.DehomogenizePoint(s[ii]));
}
return solns;
}
};
} // namespace output
} // namespace algorithm
} // namespace bertini

View File

@@ -0,0 +1,64 @@
//This file is part of Bertini 2.
//
//bertini2/nag_algorithms/sharpen.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.
//
//bertini2/nag_algorithms/sharpen.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 bertini2/nag_algorithms/sharpen.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 notre dame
/**
\file bertini2/nag_algorithms/sharpen.hpp
\brief Provides the algorithms for sharpening points.
*/
#pragma once
#include "bertini2/num_traits.hpp"
#include "bertini2/nag_algorithms/common/config.hpp"
#include "bertini2/detail/visitable.hpp"
#include "bertini2/tracking.hpp"
#include "bertini2/nag_algorithms/midpath_check.hpp"
#include "bertini2/io/generators.hpp"
namespace bertini {
namespace algorithm {
namespace output {
struct Sharpen
{
};
} //re: namespace output
template<class SystemType>
struct Sharpen
{
};
} // algo
} // bertini

View File

@@ -0,0 +1,52 @@
//This file is part of Bertini 2.
//
//bertini2/nag_algorithms/trace.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.
//
//bertini2/nag_algorithms/trace.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 bertini2/nag_algorithms/trace.hpp. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright(C) 2017-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 bertini2/nag_algorithms/trace.hpp
\brief Provides methods for computing traces.
*/
#pragma once
#include "bertini2/nag_datatypes/witness_set.hpp"
namespace bertini {
namespace algorithms {
template <typename ComplexT>
ComplexT Trace(nag_datatype::WitnessSet<ComplexT> const& w)
{
return ComplexT(0);
}
} // algorithm
} // bertini

View File

@@ -0,0 +1,855 @@
//This file is part of Bertini 2.
//
//bertini2/nag_algorithms/zero_dim_solve.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.
//
//bertini2/nag_algorithms/zero_dim_solve.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 bertini2/nag_algorithms/zero_dim_solve.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 bertini2/nag_algorithms/zero_dim_solve.hpp
\brief Provides the algorithm for computing all zero-dimensional solutions for an algberaic system.
*/
#pragma once
#include "bertini2/num_traits.hpp"
#include "bertini2/detail/visitable.hpp"
#include "bertini2/tracking.hpp"
#include "bertini2/nag_algorithms/midpath_check.hpp"
#include "bertini2/io/generators.hpp"
#include "bertini2/detail/configured.hpp"
#include "bertini2/detail/observable.hpp"
#include "bertini2/nag_algorithms/common/algorithm_base.hpp"
#include "bertini2/nag_algorithms/common/config.hpp"
#include "bertini2/nag_algorithms/common/policies.hpp"
#include <chrono>
namespace bertini {
namespace algorithm {
/**
forward declare of ZeroDim algorithm
*/
template< typename TrackerType, typename EndgameType,
typename SystemType, typename StartSystemType,
template<typename,typename> class SystemManagementP = policy::CloneGiven >
struct ZeroDim;
/**
specify the traits for the algorithm. this is why we need the forward declare
*/
template<typename TrackerType, typename EndgameType,
typename SystemType, typename StartSystemType,
template<typename,typename> class SystemManagementP>
struct AlgoTraits <ZeroDim<TrackerType, EndgameType, SystemType, StartSystemType, SystemManagementP>>
{
using BaseRealType = typename tracking::TrackerTraits<TrackerType>::BaseRealType;
using BaseComplexType = typename tracking::TrackerTraits<TrackerType>::BaseComplexType;
using NeededConfigs = detail::TypeList<
TolerancesConfig,
PostProcessingConfig,
ZeroDimConfig<BaseComplexType>,
AutoRetrackConfig
>;
};
struct AnyZeroDim : public virtual AnyAlgorithm
{
virtual ~AnyZeroDim() = default;
};
using SolnIndT = typename SolnCont<dbl_complex>::size_type;
/// metadata structs
struct AlgorithmMetaData
{
SolnIndT number_path_failures = 0;
SolnIndT number_path_successes = 0;
SolnIndT number_paths_tracked = 0;
std::chrono::system_clock::time_point start_time;
std::chrono::microseconds elapsed_time;
};
template<typename ComplexType>
struct SolutionMetaData
{
using SolnIndT = typename SolnCont<ComplexType>::size_type;
// only vaguely metadata. artifacts of randomness or ordering
SolnIndT path_index; // path number of the solution
SolnIndT solution_index; // solution number
///// things computed across all of the solve
bool precision_changed = false;
ComplexType time_of_first_prec_increase; // time value of the first increase in precision
decltype(DefaultPrecision()) max_precision_used = 0;
///// things computed in pre-endgame only
SuccessCode pre_endgame_success = SuccessCode::NeverStarted; // success code
///// things computed in endgame only
NumErrorT condition_number; // the latest estimate on the condition number
NumErrorT newton_residual; // the latest newton residual
ComplexType final_time_used; // the final value of time tracked to
NumErrorT accuracy_estimate; // accuracy estimate between extrapolations
NumErrorT accuracy_estimate_user_coords; // accuracy estimate between extrapolations, in natural coordinates
unsigned cycle_num; // cycle number used in extrapolations
SuccessCode endgame_success = SuccessCode::NeverStarted; // success code
///// things added by post-processing
NumErrorT function_residual; // the latest function residual
int multiplicity = 1; // multiplicity
bool is_real; // real flag: 0 - not real, 1 - real
bool is_finite; // finite flag: -1 - no finite/infinite distinction, 0 - infinite, 1 - finite
bool is_singular; // singular flag: 0 - non-sigular, 1 - singular
bool operator==(const SolutionMetaData<ComplexType> & other){
bool result =
this->path_index == other.path_index
&& this->solution_index == other.solution_index
&& this->precision_changed == other.precision_changed
&& this->time_of_first_prec_increase == other.time_of_first_prec_increase
&& this->max_precision_used == other.max_precision_used
&& this->pre_endgame_success == other.pre_endgame_success
&& this->condition_number == other.condition_number
&& this->newton_residual == other.newton_residual
&& this->final_time_used == other.final_time_used
&& this->accuracy_estimate == other.accuracy_estimate
&& this->accuracy_estimate_user_coords == other.accuracy_estimate_user_coords
&& this->cycle_num == other.cycle_num
&& this->endgame_success == other.endgame_success
&& this->function_residual == other.function_residual
&& this->multiplicity == other.multiplicity
&& this->is_real == other.is_real
&& this->is_finite == other.is_finite
&& this->is_singular == other.is_singular
;
return result; }
};
// this is for interoperability with vectors of these in the Python bindings, for better or for worse.
template<typename NumT>
std::ostream& operator<<(std::ostream & out, const SolutionMetaData<NumT> & meta){
out << "path_index = " << meta.path_index << std::endl;
out << "solution_index = " << meta.solution_index << std::endl;
out << "precision_changed = " << meta.precision_changed << std::endl;
out << "time_of_first_prec_increase = " << meta.time_of_first_prec_increase << std::endl;
out << "max_precision_used = " << meta.max_precision_used << std::endl;
out << "pre_endgame_success = " << meta.pre_endgame_success << std::endl;
out << "condition_number = " << meta.condition_number << std::endl;
out << "newton_residual = " << meta.newton_residual << std::endl;
out << "final_time_used = " << meta.final_time_used << std::endl;
out << "accuracy_estimate = " << meta.accuracy_estimate << std::endl;
out << "accuracy_estimate_user_coords = " << meta.accuracy_estimate_user_coords << std::endl;
out << "cycle_num = " << meta.cycle_num << std::endl;
out << "endgame_success = " << meta.endgame_success << std::endl;
out << "function_residual = " << meta.function_residual << std::endl;
out << "multiplicity = " << meta.multiplicity << std::endl;
out << "is_real = " << meta.is_real << std::endl;
out << "is_finite = " << meta.is_finite << std::endl;
out << "is_singular = " << meta.is_singular << std::endl;
return out;
}
template<typename ComplexType>
struct EGBoundaryMetaData
{
using RealType = typename NumTraits<ComplexType>::Real;
Vec<ComplexType> path_point;
SuccessCode success_code = SuccessCode::NeverStarted;
RealType last_used_stepsize;
EGBoundaryMetaData() = default;
EGBoundaryMetaData(EGBoundaryMetaData const&) = default;
EGBoundaryMetaData(Vec<ComplexType> const& pt, SuccessCode const& code, RealType const& ss) :
path_point(pt), success_code(code), last_used_stepsize(ss)
{}
bool operator==(const EGBoundaryMetaData<ComplexType> & other){
bool result =
this->path_point == other.path_point
&& this->success_code == other.success_code
&& this->last_used_stepsize == other.last_used_stepsize
;
return result;
}
};
// this is for interoperability with vectors of these in the Python bindings, for better or for worse.
template<typename NumT>
std::ostream& operator<<(std::ostream & out, const EGBoundaryMetaData<NumT> & meta){
out << "path_point = " << meta.path_point << std::endl;
out << "success_code = " << meta.success_code << std::endl;
out << "last_used_stepsize = " << meta.last_used_stepsize << std::endl;
return out;
}
/**
\brief the basic zero dim algorithm, which solves a system.
*/
template< typename TrackerType, typename EndgameType,
typename SystemType, typename StartSystemType,
template<typename,typename> class SystemManagementP>
struct ZeroDim :
public virtual AnyZeroDim,
public Observable,
public SystemManagementP<SystemType, StartSystemType>,
public detail::Configured<
typename AlgoTraits< ZeroDim<TrackerType, EndgameType, SystemType, StartSystemType, SystemManagementP>>::NeededConfigs>
{
// these usings are for getters in python
using TrackerT = TrackerType;
using EndgameT = EndgameType;
using SystemT = SystemType;
using StartSystemT = StartSystemType;
/// a bunch of using statements to reduce typing.
using BaseComplexType = typename tracking::TrackerTraits<TrackerType>::BaseComplexType;
using BaseRealType = typename tracking::TrackerTraits<TrackerType>::BaseRealType;
using PrecisionConfig = typename tracking::TrackerTraits<TrackerType>::PrecisionConfig;
using SolnIndT = typename SolnCont<BaseComplexType>::size_type;
using SystemManagementPolicy = SystemManagementP<SystemType, StartSystemType>;
using StoredSystemT = typename SystemManagementPolicy::StoredSystemT;
using StoredStartSystemT = typename SystemManagementPolicy::StoredStartSystemT;
using Config = detail::Configured<
typename AlgoTraits<ZeroDim<TrackerType, EndgameType, SystemType, StartSystemType, SystemManagementP>>::NeededConfigs>;
using Config::Get;
using Tolerances = TolerancesConfig;
using PostProcessing = PostProcessingConfig;
using ZeroDimConf = ZeroDimConfig<BaseComplexType>;
using AutoRetrack = AutoRetrackConfig;
using EGBoundaryMetaDataT = EGBoundaryMetaData<BaseComplexType>;
using SolutionMetaDataT = SolutionMetaData<BaseComplexType>;
// a few more using statements
using MidpathType = MidpathChecker<BaseRealType, BaseComplexType, EGBoundaryMetaData<BaseComplexType>>;
using SystemManagementPolicy::TargetSystem;
using SystemManagementPolicy::StartSystem;
using SystemManagementPolicy::Homotopy;
/// constructors
/**
Construct a ZeroDim algorithm object.
You must at least pass in the system used to track, though the particular arguments required depend on the policies used in your instantiation of ZeroDim.
\see RefToGiven, CloneGiven
*/
template<typename ... SysTs>
ZeroDim(SysTs const& ...sys) : SystemManagementPolicy(sys...), tracker_(TargetSystem()), endgame_(tracker_)
{
ConsistencyCheck();
DefaultSetup();
}
/**
\brief Main Run() function provided for calling from the blackbox mode
*/
void Run() override
{}
virtual ~ZeroDim() = default;
/// setup functions
/**
\brief Check to ensure that target system is valid for solving.
*/
void ConsistencyCheck() const
{
if (TargetSystem().HavePathVariable())
throw std::runtime_error("unable to perform zero dim solve on target system -- has path variable, use user homotopy instead.");
if (TargetSystem().NumVariables() > TargetSystem().NumTotalFunctions())
throw std::runtime_error("unable to perform zero dim solve on target system -- underconstrained, so has no zero dimensional solutions.");
if (!TargetSystem().IsPolynomial())
throw std::runtime_error("unable to perform zero dim solve on target system -- system is non-polynomial, use user homotopy instead.");
}
void DefaultSetup()
{
DefaultSettingsSetup();
DefaultSystemSetup();
DefaultTrackerSetup();
DefaultMidpathSetup();
}
void DefaultSystemSetup()
{
SystemManagementPolicy::SystemSetup(this->template Get<ZeroDimConf>().path_variable_name);
num_start_points_ = StartSystem().NumStartPoints(); // populate the internal variable
}
/**
Fills the tolerances and retrack settings from default values.
*/
void DefaultSettingsSetup()
{
// this code can be made generic using Boost.Hana.
// see https://stackoverflow.com/questions/28764085/how-to-create-an-element-for-each-type-in-a-typelist-and-add-it-to-a-vector-in-c,
// for example
//
// all that would need to be done is to extract a hana::tuple_t from the
// typelist contained in this::Config, and then hana::for_each() over it.
this->template Set<Tolerances>(Tolerances());
this->template Set<PostProcessing>(PostProcessing());
this->template Set<ZeroDimConf>(ZeroDimConf());
this->template Set<AutoRetrack>(AutoRetrack());
}
void SetMidpathRetrackTol(NumErrorT const& rt)
{
midpath_retrack_tolerance_ = rt;
}
const auto& MidpathRetrackTol() const
{
return midpath_retrack_tolerance_;
}
/**
call this after setting up the tolerances, etc.
*/
void DefaultMidpathSetup()
{
midpath_ = MidpathType(MidPathConfig());
}
void SetMidpath(MidPathConfig const& mp)
{
midpath_.Set(mp);
}
/**
\brief Takes the default action to set up the zero dim algorithm with the default constructed tracker.
\note should be called after the homotopy is set up, ideally.
*/
void DefaultTrackerSetup()
{
tracker_.SetSystem(Homotopy());
tracker_.Setup(tracking::predict::DefaultPredictor(),
this->template Get<Tolerances>().newton_before_endgame,
this->template Get<Tolerances>().path_truncation_threshold,
tracking::SteppingConfig(), tracking::NewtonConfig());
tracker_.PrecisionSetup(PrecisionConfig(Homotopy()));
}
/**
\brief Sets the tracker to one you supply to this function.
Setting the tracker associates the endgame with the tracker you pass in, too. If this is a problem, and you need this generalized so you can use a different tracker for the pre/endgame zones, please file an issue requesting this feature.
Assumes you have done all necessary setup to it, including associating it with the homotopy for the ZeroDim algorithm.
Again, YOU must ensure the tracker is associated with the correct homotopy
*/
void SetTracker(TrackerType const& new_tracker)
{
tracker_ = new_tracker;
endgame_.SetTracker(tracker_);
}
/**
\brief Gets the tracker
This version gets a const reference to it.
*/
const TrackerType & GetTracker() const
{
return tracker_;
}
/**
\brief Gets the tracker
This version gets a mutable reference to it.
*/
TrackerType & GetTracker()
{
return tracker_;
}
/// endgame specific stuff
/**
\brief Sets the endgame to one you supply to this function.
Assumes you have done all necessary setup to it, including associating it with the homotopy for the ZeroDim algorithm.
Also assumes that you have made the tracker inside the ZeroDim algorithm be the self-same tracker object as is used for the endgame you are setting here.
*/
void SetEndgame(EndgameType const& new_endgame)
{
endgame_ = new_endgame;
}
/**
\brief Gets the endgame
This version gets a `const` reference to it.
*/
const EndgameType & GetEndgame() const
{
return endgame_;
}
/**
\brief Gets the endgame
This version gets a mutable reference to it.
*/
EndgameType & GetEndgame()
{
return endgame_;
}
template<typename T>
const T & GetFromEndgame() const
{
return endgame_.template Get<T>();
}
template<typename T>
void SetToEndgame(T const& t)
{
endgame_.Set(t);
}
/// the main functions
/**
\brief Perform the basic Zero Dim solve algorithm.
This function iterates over all start points to the start system, tracking from each to the endgame boundary. At the endgame boundary, path crossings are checked for. Multiple paths which jump onto each other will not be detected, unless you are using a certified tracker, in which case this is prevented in the first place.
Paths which have crossed are re-run, up to a certain number of times.
Then, the points at the endgame boundary are tracked using the prescribed endgame toward the final time.
Finally, results are post-processed.
It is up to you to put the output somewhere.
*/
void Solve()
{
PreSolveChecks();
PreSolveSetup();
TrackBeforeEG();
EGBoundaryAction();
TrackDuringEG();
PostEGAction();
}
/**
\brief Get the final computed solutions
*/
const auto& FinalSolutions() const
{
return solutions_post_endgame_;
}
/**
\brief Get the metadat associated with the final computed solutions
*/
const auto& FinalSolutionMetadata() const
{
return solution_final_metadata_;
}
/**
\brief Get the solutions as computed at the endgame boundary
*/
const auto& EndgameBoundaryData() const
{
return solutions_at_endgame_boundary_;
}
private:
/**
\brief Check that the solver functor is ready to go.
*/
void PreSolveChecks() const
{
if (num_start_points_ > solutions_at_endgame_boundary_.max_size())
throw std::runtime_error("start system has more solutions than container for results. I refuse to continue until this has been addressed.");
}
void PreSolveSetup()
{
auto num_as_size_t = static_cast<SolnIndT>(num_start_points_);
solution_final_metadata_.resize(num_as_size_t);
solutions_at_endgame_boundary_.resize(num_as_size_t);
solutions_post_endgame_.resize(num_as_size_t);
SetMidpathRetrackTol(this->template Get<Tolerances>().newton_before_endgame);
}
/**
\brief Track from the start point in time, from each start point of the start system, to the endgame boundary.
Results are accumulated into an internally stored variable, solutions_at_endgame_boundary_.
The point at the endgame boundary, as well as the success flag, and the stepsize, are all stored.
*/
void TrackBeforeEG()
{
DefaultPrecision(this->template Get<ZeroDimConf>().initial_ambient_precision);
GetTracker().SetTrackingTolerance(this->template Get<Tolerances>().newton_before_endgame);
auto t_start = this->template Get<ZeroDimConf>().start_time;
auto t_endgame_boundary = this->template Get<ZeroDimConf>().endgame_boundary;
for (decltype(num_start_points_) ii{0}; ii < num_start_points_; ++ii)
{
TrackSinglePathBeforeEG(static_cast<SolnIndT>(ii));
}
}
/**
/brief Track a single path before we reach the endgame boundary.
*/
void TrackSinglePathBeforeEG(SolnIndT soln_ind)
{
// if you can think of a way to replace this `if` with something meta, please do so.
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
{
GetTracker().AddObserver(first_prec_rec_);
GetTracker().AddObserver(min_max_prec_);
}
auto& smd = solution_final_metadata_[soln_ind];
smd.path_index = soln_ind;
smd.solution_index = soln_ind;
DefaultPrecision(this->template Get<ZeroDimConf>().initial_ambient_precision);
auto t_start = this->template Get<ZeroDimConf>().start_time;
auto t_endgame_boundary = this->template Get<ZeroDimConf>().endgame_boundary;
auto start_point = StartSystem().template StartPoint<BaseComplexType>(soln_ind);
Vec<BaseComplexType> result;
auto tracking_success = GetTracker().TrackPath(result, t_start, t_endgame_boundary, start_point);
solutions_at_endgame_boundary_[soln_ind] = EGBoundaryMetaDataT({ result, tracking_success, GetTracker().CurrentStepsize() });
smd.pre_endgame_success = tracking_success;
// if you can think of a way to replace this `if` with something meta, please do so.
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
{
if (first_prec_rec_.DidPrecisionIncrease())
{
smd.precision_changed = true;
smd.time_of_first_prec_increase = first_prec_rec_.TimeOfIncrease();
}
else
GetTracker().RemoveObserver(first_prec_rec_);
GetTracker().RemoveObserver(min_max_prec_);
using std::max;
smd.max_precision_used =
max(smd.max_precision_used, min_max_prec_.MaxPrecision());
}
}
void EGBoundaryAction()
{
auto midcheckpassed = midpath_.Check(solutions_at_endgame_boundary_, StartSystem());
unsigned num_resolve_attempts = 0;
while (!midcheckpassed && num_resolve_attempts < this->template Get<ZeroDimConf>().max_num_crossed_path_resolve_attempts)
{
MidpathResolve();
midcheckpassed = midpath_.Check(solutions_at_endgame_boundary_, StartSystem());
num_resolve_attempts++;
}
}
void MidpathResolve()
{
ShrinkMidpathTolerance();
for(auto const& v : midpath_.GetCrossedPaths())
{
if(v.rerun())
{
unsigned long long index = v.index();
auto soln_ind = static_cast<SolnIndT>(index);
TrackSinglePathBeforeEG(soln_ind);
}
}
}
void ShrinkMidpathTolerance()
{
midpath_retrack_tolerance_ *= this->template Get<AutoRetrack>().midpath_decrease_tolerance_factor;
GetTracker().SetTrackingTolerance(midpath_retrack_tolerance_);
}
void TrackDuringEG()
{
GetTracker().SetTrackingTolerance(this->template Get<Tolerances>().newton_during_endgame);
for (decltype(num_start_points_) ii{0}; ii < num_start_points_; ++ii)
{
auto soln_ind = static_cast<SolnIndT>(ii);
if (solution_final_metadata_[soln_ind].pre_endgame_success != SuccessCode::Success)
continue;
TrackSinglePathDuringEG(soln_ind);
}
}
void TrackSinglePathDuringEG(SolnIndT soln_ind)
{
auto& smd = solution_final_metadata_[soln_ind];
// if you can think of a way to replace this `if` with something meta, please do so.
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
{
if (!smd.precision_changed)
GetTracker().AddObserver(first_prec_rec_);
GetTracker().AddObserver(min_max_prec_);
}
const auto& bdry_point = solutions_at_endgame_boundary_[soln_ind].path_point;
GetTracker().SetStepSize(solutions_at_endgame_boundary_[soln_ind].last_used_stepsize);
GetTracker().ReinitializeInitialStepSize(false);
DefaultPrecision(Precision(bdry_point));
// we make these fresh so they are in the correct precision to start.
BaseComplexType t_end = this->template Get<ZeroDimConf>().target_time;
BaseComplexType t_endgame_boundary = this->template Get<ZeroDimConf>().endgame_boundary;
auto eg_success = GetEndgame().Run(t_endgame_boundary, bdry_point, t_end);
solutions_post_endgame_[soln_ind] = GetEndgame().template FinalApproximation<BaseComplexType>();
// finally, store the metadata as necessary
smd.endgame_success = eg_success;
// if you can think of a way to replace this `if` with something meta, please do so.
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
{
if (!smd.precision_changed)
{
if (first_prec_rec_.DidPrecisionIncrease())
{
smd.precision_changed = true;
smd.time_of_first_prec_increase = first_prec_rec_.TimeOfIncrease();
}
}
GetTracker().RemoveObserver(first_prec_rec_);
GetTracker().RemoveObserver(min_max_prec_);
using std::max;
smd.max_precision_used =
max(smd.max_precision_used, min_max_prec_.MaxPrecision());
}
if (tracking::TrackerTraits<TrackerType>::IsAdaptivePrec)
{
assert(Precision(solutions_post_endgame_[soln_ind])==Precision(GetEndgame().template FinalApproximation<BaseComplexType>()));
DefaultPrecision(Precision(solutions_post_endgame_[soln_ind]));
TargetSystem().precision(Precision(solutions_post_endgame_[soln_ind]));
}
smd.function_residual = static_cast<NumErrorT>(TargetSystem().Eval(solutions_post_endgame_[soln_ind]).template lpNorm<Eigen::Infinity>());
smd.final_time_used = GetEndgame().LatestTime();
smd.condition_number = GetTracker().LatestConditionNumber();
smd.newton_residual = GetTracker().LatestNormOfStep();
smd.accuracy_estimate = GetEndgame().ApproximateError();
smd.accuracy_estimate_user_coords =
static_cast<NumErrorT>( (TargetSystem().DehomogenizePoint(solutions_post_endgame_[soln_ind]) -
TargetSystem().DehomogenizePoint(GetEndgame().template PreviousApproximation<BaseComplexType>())).template lpNorm<Eigen::Infinity>() );
smd.cycle_num = GetEndgame().CycleNumber();
// end metadata gathering
}
void PostEGAction()
{
ComputePostTrackMetadata();
}
/**
\brief Populates the result_ member, with the post-processed results of the zero dim solve.
output: result_ member variable.
*/
void ComputePostTrackMetadata()
{
ComputeMultiplicities();
}
void ComputeMultiplicities()
{
std::vector<std::vector<int>> multiplicity_indices(num_start_points_);
for (decltype(num_start_points_) ii{0}; ii < num_start_points_; ++ii)
{
if (solution_final_metadata_[ii].endgame_success!=SuccessCode::Success)
continue;
for (decltype(num_start_points_) jj{ii+1}; jj < num_start_points_; ++jj)
{
if (solution_final_metadata_[jj].endgame_success!=SuccessCode::Success)
continue;
if ( (solutions_post_endgame_[ii] - solutions_post_endgame_[jj]).norm() < this->template Get<PostProcessing>().same_point_tolerance)
{
multiplicity_indices[ii].push_back(jj);
multiplicity_indices[jj].push_back(ii);
++solution_final_metadata_[ii].multiplicity;
++solution_final_metadata_[jj].multiplicity;
}
}
}
}
///////
// private data members
///////
unsigned long long num_start_points_;
NumErrorT midpath_retrack_tolerance_;
/// observers used during tracking
// i feel like these should be factored out into some policy class which prescribes how they are used, so that the actions taken are customizable.
tracking::FirstPrecisionRecorder<TrackerType> first_prec_rec_;
tracking::MinMaxPrecisionRecorder<TrackerType> min_max_prec_;
/// function objects used during the algorithm
TrackerType tracker_;
EndgameType endgame_;
MidpathType midpath_;
/// computed data
SolnCont< EGBoundaryMetaDataT > solutions_at_endgame_boundary_; // the BaseRealType is the last used stepsize
SolnCont<Vec<BaseComplexType> > solutions_post_endgame_;
SolnCont<SolutionMetaDataT> solution_final_metadata_;
}; // struct ZeroDim
} // ns algo
} // ns bertini