Add files
This commit is contained in:
545
core/include/bertini2/system/patch.hpp
Normal file
545
core/include/bertini2/system/patch.hpp
Normal file
@@ -0,0 +1,545 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//include/bertini2/system/patch.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/system/patch.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/system/patch.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/system/patch.hpp
|
||||
|
||||
\brief Provides the bertini::Patch class.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_PATCH_HPP
|
||||
#define BERTINI_PATCH_HPP
|
||||
|
||||
#include "bertini2/mpfr_complex.hpp"
|
||||
|
||||
#include "bertini2/mpfr_extensions.hpp"
|
||||
#include "bertini2/num_traits.hpp"
|
||||
#include "bertini2/eigen_extensions.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
|
||||
#include <boost/serialization/vector.hpp>
|
||||
|
||||
namespace bertini {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\class Patch
|
||||
|
||||
\brief An affine chart on a product of projective spaces.
|
||||
|
||||
This class provides an adjustable-precision patch on a working space for solving a polynomial system using homotopy continuation.
|
||||
|
||||
The constant values for the patch are unity.
|
||||
|
||||
## Example code, not using a bertini::System to generate the patch.
|
||||
\code
|
||||
|
||||
std::vector<unsigned> s{2,3};
|
||||
|
||||
Patch p(s);
|
||||
|
||||
Vec<mpfr_complex> v(5);
|
||||
v << mpfr_complex(1), mpfr_complex(1), mpfr_complex(1), mpfr_complex(1), mpfr_complex(1);
|
||||
|
||||
auto v_rescaled = p.RescalePoint(v);
|
||||
|
||||
auto f = p.Eval(v_rescaled);
|
||||
|
||||
\endcode
|
||||
|
||||
At the end of the above example, the patch evaluates to 0 in the container \f$f\f$.
|
||||
|
||||
## Other ways of patching
|
||||
|
||||
Patches can also be applied to a system, which should first be homogenized.
|
||||
*/
|
||||
class Patch
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
\brief Default constructor.
|
||||
|
||||
Makes an empty patch.
|
||||
*/
|
||||
Patch() : precision_(DefaultPrecision())
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
Custom copy constructor, ensuring the max-precision coefficients are copied in highest precision
|
||||
*/
|
||||
Patch(Patch const& other)
|
||||
{
|
||||
variable_group_sizes_ = other.variable_group_sizes_;
|
||||
precision_ = DefaultPrecision();
|
||||
|
||||
// a little shorthand unpacking the tuple
|
||||
std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(this->coefficients_working_);
|
||||
std::vector<Vec<dbl> >& coefficients_dbl = std::get<std::vector<Vec<dbl> > >(this->coefficients_working_);
|
||||
|
||||
coefficients_highest_precision_.resize(other.NumVariableGroups());
|
||||
coefficients_mpfr.resize(variable_group_sizes_.size());
|
||||
coefficients_dbl.resize(variable_group_sizes_.size());
|
||||
|
||||
for (unsigned ii(0); ii<other.NumVariableGroups(); ++ii)
|
||||
{
|
||||
auto curr_size = variable_group_sizes_[ii];
|
||||
|
||||
coefficients_highest_precision_[ii].resize(curr_size);
|
||||
coefficients_dbl[ii].resize(curr_size);
|
||||
coefficients_mpfr[ii].resize(curr_size);
|
||||
|
||||
for (unsigned jj(0); jj<curr_size; jj++)
|
||||
{
|
||||
coefficients_highest_precision_[ii](jj).precision(other.coefficients_highest_precision_[ii](jj).precision());
|
||||
|
||||
coefficients_highest_precision_[ii](jj) = other.coefficients_highest_precision_[ii](jj);
|
||||
|
||||
coefficients_dbl[ii](jj) = dbl(coefficients_highest_precision_[ii](jj));
|
||||
coefficients_mpfr[ii](jj) = mpfr_complex(coefficients_highest_precision_[ii](jj));
|
||||
|
||||
assert(coefficients_highest_precision_[ii](jj) == other.coefficients_highest_precision_[ii](jj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Constructor making a random complex patch on a space whose structure is described by the input argument.
|
||||
|
||||
The sizes input give the number of total variables, including homogenizing variables, for the product of spaces forming the total space to be patched. The patch has no idea whether the underlying space is projective or affine -- that is handled somewhere else, likely in a bertini::System.
|
||||
|
||||
The initial precision of the patch is set to current default precision, and the precision of the highest precision coefficients are set to the current default as well.
|
||||
|
||||
\param sizes The sizes of the variable groups, including homogenizing variables if present.
|
||||
*/
|
||||
Patch(std::vector<unsigned> const& sizes) : variable_group_sizes_(sizes), coefficients_highest_precision_(sizes.size()), precision_(DefaultPrecision())
|
||||
{
|
||||
using bertini::Precision;
|
||||
using bertini::multiprecision::RandomComplex;
|
||||
|
||||
std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(coefficients_working_);
|
||||
std::vector<Vec<dbl> >& coefficients_dbl = std::get<std::vector<Vec<dbl> > >(coefficients_working_);
|
||||
|
||||
coefficients_highest_precision_.resize(sizes.size());
|
||||
coefficients_dbl.resize(sizes.size());
|
||||
coefficients_mpfr.resize(sizes.size());
|
||||
|
||||
for (size_t ii=0; ii<sizes.size(); ++ii)
|
||||
{
|
||||
// this produces coefficients at maximum precision.
|
||||
coefficients_highest_precision_[ii].resize(sizes[ii]);
|
||||
for (unsigned jj=0; jj<sizes[ii]; ++jj)
|
||||
{
|
||||
multiprecision::RandomComplexAssign(coefficients_highest_precision_[ii](jj), MaxPrecisionAllowed());
|
||||
}
|
||||
|
||||
coefficients_dbl[ii].resize(sizes[ii]);
|
||||
for (unsigned jj=0; jj<sizes[ii]; ++jj)
|
||||
{
|
||||
coefficients_dbl[ii](jj) = dbl(coefficients_highest_precision_[ii](jj));
|
||||
}
|
||||
|
||||
// assignment preserves precision of source.
|
||||
// https://github.com/boostorg/multiprecision/issues/75
|
||||
coefficients_mpfr[ii].resize(sizes[ii]);
|
||||
for (unsigned jj=0; jj<sizes[ii]; ++jj)
|
||||
{
|
||||
coefficients_mpfr[ii](jj) = coefficients_highest_precision_[ii](jj);
|
||||
coefficients_mpfr[ii](jj).precision(precision_);
|
||||
}
|
||||
|
||||
assert(Precision(coefficients_mpfr[ii](0))==precision_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Construct a random complex patch on a space
|
||||
*/
|
||||
static Patch Random(std::vector<unsigned> const& sizes)
|
||||
{
|
||||
return Patch(sizes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Construct random REAL patch on a space.
|
||||
*/
|
||||
static Patch RandomReal(std::vector<unsigned> const& sizes)
|
||||
{
|
||||
using bertini::multiprecision::RandomReal;
|
||||
using bertini::Precision;
|
||||
|
||||
Patch p;
|
||||
|
||||
p.variable_group_sizes_ = sizes;
|
||||
|
||||
|
||||
|
||||
std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(p.coefficients_working_);
|
||||
std::vector<Vec<dbl> >& coefficients_dbl = std::get<std::vector<Vec<dbl> > >(p.coefficients_working_);
|
||||
|
||||
p.coefficients_highest_precision_.resize(sizes.size());
|
||||
coefficients_mpfr.resize(sizes.size());
|
||||
coefficients_dbl.resize(sizes.size());
|
||||
|
||||
for (size_t ii=0; ii<sizes.size(); ++ii)
|
||||
{
|
||||
p.coefficients_highest_precision_[ii].resize(sizes[ii]);
|
||||
for (unsigned jj=0; jj<sizes[ii]; ++jj)
|
||||
multiprecision::RandomRealAssign(p.coefficients_highest_precision_[ii](jj), MaxPrecisionAllowed());
|
||||
|
||||
coefficients_mpfr[ii] = p.coefficients_highest_precision_[ii];
|
||||
Precision(coefficients_mpfr[ii],DefaultPrecision());
|
||||
assert(Precision(coefficients_mpfr[ii](0))==DefaultPrecision());
|
||||
|
||||
coefficients_dbl[ii].resize(sizes[ii]);
|
||||
for (unsigned jj=0; jj<sizes[ii]; ++jj)
|
||||
coefficients_dbl[ii](jj) = dbl(p.coefficients_highest_precision_[ii](jj));
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the current precision of the patch.
|
||||
|
||||
\return The current precision, in digits.
|
||||
*/
|
||||
unsigned Precision() const
|
||||
{
|
||||
return precision_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set the precision of the patch.
|
||||
|
||||
Copies the patch coefficients into correct precision for subsequent precision.
|
||||
|
||||
\param new_precision The precision to change to.
|
||||
*/
|
||||
void Precision(unsigned new_precision) const
|
||||
{
|
||||
if (precision_==new_precision)
|
||||
return;
|
||||
|
||||
using bertini::Precision;
|
||||
std::vector<Vec<mpfr_complex> >& coefficients_mpfr = std::get<std::vector<Vec<mpfr_complex> > >(coefficients_working_);
|
||||
|
||||
for (unsigned ii = 0; ii < NumVariableGroups(); ++ii)
|
||||
{
|
||||
for (unsigned jj=0; jj<variable_group_sizes_[ii]; ++jj)
|
||||
{
|
||||
if (new_precision>precision_)
|
||||
{
|
||||
coefficients_mpfr[ii](jj) = coefficients_highest_precision_[ii](jj);
|
||||
coefficients_mpfr[ii](jj).precision(new_precision);
|
||||
}
|
||||
else
|
||||
coefficients_mpfr[ii](jj).precision(new_precision);
|
||||
|
||||
assert(Precision(coefficients_mpfr[ii](jj))==new_precision);
|
||||
}
|
||||
}
|
||||
|
||||
precision_ = new_precision;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Evaluate the patch at a point, in place.
|
||||
|
||||
\param function_values The vector to populate. Must be at least as long as the number of variable groups.
|
||||
\param x The current space point at which to evaluate.
|
||||
|
||||
\todo Rewrite this code to use Eigen sub-vectors, if possible. If not, take this off the todo list. See
|
||||
http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html
|
||||
|
||||
*/
|
||||
template<typename Derived, typename T>
|
||||
void EvalInPlace(Eigen::MatrixBase<Derived> & function_values, Vec<T> const& x) const
|
||||
{
|
||||
static_assert(std::is_same<typename Derived::Scalar,T>::value,"scalar types must match");
|
||||
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
if (! (function_values.size()>=NumVariableGroups()) )
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "container for function values must be of length at least as long as the number of variable groups. the input vector into which to write is of length " << function_values.size();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
// assert((bertini::Precision(x(0))==DoublePrecision() || bertini::Precision(x(0)) == Precision())
|
||||
// && "precision of input vector must match current working precision of patch during evaluation"
|
||||
// );
|
||||
#endif
|
||||
|
||||
// unpack from the tuple of working coefficients
|
||||
const std::vector<Vec<T> >& coefficients = std::get<std::vector<Vec<T> > >(coefficients_working_);
|
||||
|
||||
unsigned offset(function_values.size() - NumVariableGroups()); // by precondition this number is at least 0. the precondition is ensured by the public wrapper
|
||||
unsigned counter(0);
|
||||
for (unsigned ii = 0; ii < NumVariableGroups(); ++ii)
|
||||
{
|
||||
T& value = function_values(ii+offset);
|
||||
value = T(-1);
|
||||
for (unsigned jj=0; jj<variable_group_sizes_[ii]; ++jj)
|
||||
{
|
||||
value += x(counter)*coefficients[ii](jj);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the patch at a point.
|
||||
|
||||
\return The values of the patch at the point.
|
||||
\param x The current space point at which to evaluate.
|
||||
*/
|
||||
template<typename T>
|
||||
Vec<T> Eval(Vec<T> const& x) const
|
||||
{
|
||||
Vec<T> function_values = Vec<T>::Zero(NumVariableGroups());
|
||||
EvalInPlace(function_values, x);
|
||||
return function_values;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the Jacobian matrix, in place.
|
||||
|
||||
\param jacobian Matrix to populate with the Jacobian. Must be large enough (NumVariableGroups x NumVariables).
|
||||
\param x Point at which to evaluate. Not technically needed, because the Jacobian is simply the matrix of coefficients.
|
||||
|
||||
\todo Rewrite this code to use Eigen sub-vectors, if possible. If not, take this off the todo list. See
|
||||
http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html
|
||||
|
||||
*/
|
||||
template<typename Derived, typename T>
|
||||
void JacobianInPlace(Eigen::MatrixBase<Derived> & jacobian, Vec<T> const& x) const
|
||||
{
|
||||
static_assert(std::is_same<typename Derived::Scalar,T>::value,"scalar types must match");
|
||||
|
||||
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(jacobian.rows()>=NumVariableGroups() && "input jacobian must have at least as many rows as variable groups");
|
||||
assert(jacobian.cols()==NumVariables() && "input jacobian must have as many columns as the patch has variables");
|
||||
assert(
|
||||
(bertini::Precision(x(0))==DoublePrecision() || bertini::Precision(x(0)) == Precision())
|
||||
&& "precision of input vector must match current working precision of patch during evaluation"
|
||||
);
|
||||
#endif
|
||||
|
||||
const std::vector<Vec<T> >& coefficients = std::get<std::vector<Vec<T> > >(coefficients_working_);
|
||||
|
||||
unsigned offset(jacobian.rows() - NumVariableGroups()); // by precondition this number is at least 0. the precondition is ensured by the public wrapper
|
||||
unsigned counter(0);
|
||||
for (unsigned ii = 0; ii < NumVariableGroups(); ++ii)
|
||||
for (unsigned jj=0; jj<variable_group_sizes_[ii]; ++jj)
|
||||
jacobian(ii+offset,counter++) = coefficients[ii](jj);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the Jacobian matrix, in place.
|
||||
|
||||
\param x Point at which to evaluate. Not technically needed, because the Jacobian is simply the matrix of coefficients.
|
||||
\return Jacobian matrix, of size (NumVariableGroups x NumVariables).
|
||||
*/
|
||||
template<typename T>
|
||||
Mat<T> Jacobian(Vec<T> const& x) const
|
||||
{
|
||||
Mat<T> jacobian = Mat<T>::Zero(NumVariableGroups(), NumVariables());
|
||||
JacobianInPlace(jacobian, x);
|
||||
return jacobian;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Rescale a point so that it satisfies the patch equations herein contained.
|
||||
|
||||
The point must be as long as there are total variables.
|
||||
|
||||
This function modifies the vector in place, so ensure you have a copy stored somewhere else if you feel it necessary to still have the pre-rescaled vector around.
|
||||
|
||||
\param x The point to rescale
|
||||
\tparam T The number type.
|
||||
*/
|
||||
template<typename T>
|
||||
void RescalePointToFitInPlace(Vec<T> & x) const
|
||||
{
|
||||
#ifndef BERTINI_DISABLE_ASSERTS
|
||||
assert(x.size() == NumVariables() && "input point for rescaling to fit a patch must have same length as total number of variables being patched, in all variable groups.");
|
||||
assert((bertini::Precision(x(0))==DoublePrecision() || bertini::Precision(x(0)) == Precision())
|
||||
&& "precision of input vector must match current working precision of patch during rescaling"
|
||||
);
|
||||
#endif
|
||||
|
||||
const std::vector<Vec<T> >& coefficients = std::get<std::vector<Vec<T> > >(coefficients_working_);
|
||||
|
||||
unsigned starting_index_counter(0);
|
||||
for (unsigned ii=0; ii<NumVariableGroups(); ii++)
|
||||
{
|
||||
auto subvec = x.segment(starting_index_counter,variable_group_sizes_[ii]);
|
||||
subvec /= subvec.transpose() * coefficients[ii];
|
||||
starting_index_counter += variable_group_sizes_[ii];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Rescale a point so that it satisfies the patch equations herein contained.
|
||||
|
||||
\return Point \f$x\f$ rescaled to fit the patch. \f$x\f$ cannot be the zero vector -- zero is a degenerate point in projective space.
|
||||
\param x The point to rescale.
|
||||
\tparam T The number type.
|
||||
*/
|
||||
template <typename T>
|
||||
Vec<T> RescalePoint(Vec<T> const& x) const
|
||||
{
|
||||
Vec<T> x_rescaled = x;
|
||||
RescalePointToFitInPlace(x_rescaled);
|
||||
return x_rescaled;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the number of variable groups
|
||||
|
||||
\return The number of variable groups in the problem.
|
||||
*/
|
||||
unsigned NumVariableGroups() const
|
||||
{
|
||||
return variable_group_sizes_.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the number of variables in the patch.
|
||||
*/
|
||||
unsigned NumVariables() const
|
||||
{
|
||||
unsigned num_vars(0);
|
||||
for (auto v : variable_group_sizes_)
|
||||
num_vars += v;
|
||||
return num_vars;
|
||||
}
|
||||
|
||||
|
||||
friend std::ostream& operator<<(std::ostream & out, Patch const& p)
|
||||
{
|
||||
out << p.NumVariableGroups() << " variable groups being patched\n";
|
||||
unsigned counter(0);
|
||||
for (auto& c : p.coefficients_highest_precision_)
|
||||
{
|
||||
out << "patch " << counter++ << " has " << c.size() << " coefficients:\n";
|
||||
out << c << "\n";
|
||||
}
|
||||
out << "current patch precision: " << p.Precision() << "\n";
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Check whether two patches are the same.
|
||||
|
||||
\return true If have the same variable structure and coefficients. Otherwise, false.
|
||||
*/
|
||||
bool operator==(Patch const& rhs) const
|
||||
{
|
||||
if (NumVariableGroups()!=rhs.NumVariableGroups())
|
||||
return false;
|
||||
if (NumVariables()!=rhs.NumVariables())
|
||||
return false;
|
||||
for (unsigned ii=0; ii<NumVariableGroups(); ii++)
|
||||
if (variable_group_sizes_[ii]!=rhs.variable_group_sizes_[ii])
|
||||
return false;
|
||||
for (unsigned ii=0; ii<NumVariableGroups(); ii++)
|
||||
if (coefficients_highest_precision_[ii]!=rhs.coefficients_highest_precision_[ii])
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Check whether two patches are different.
|
||||
*/
|
||||
bool operator!=(Patch const& rhs) const
|
||||
{
|
||||
return !(*this==rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/////////////////
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
//////////////////
|
||||
|
||||
std::vector< Vec< mpfr_complex > > coefficients_highest_precision_; ///< the highest-precision coefficients for the patch
|
||||
|
||||
mutable std::tuple< std::vector< Vec< mpfr_complex > >, std::vector< Vec< dbl > > > coefficients_working_; ///< the current working coefficients of the patch. changing precision affects these, particularly the mpfr_complex coefficients, which are down-sampled from the highest_precision coefficients. the doubles are only down-sampled at time of creation or modification.
|
||||
|
||||
std::vector<unsigned> variable_group_sizes_; ///< the sizes of the groups. In principle, these must be at least 2.
|
||||
|
||||
mutable unsigned precision_; ///< the current working precision of the patch.
|
||||
|
||||
// add serialization support through boost.
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & precision_;
|
||||
|
||||
ar & coefficients_highest_precision_;
|
||||
|
||||
ar & std::get<0>(coefficients_working_);
|
||||
ar & std::get<1>(coefficients_working_);
|
||||
ar & variable_group_sizes_;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // re: include guards
|
||||
|
||||
|
||||
74
core/include/bertini2/system/precon.hpp
Normal file
74
core/include/bertini2/system/precon.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//bertini2/system/precon.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/system/precon.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/system/precon.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 2015 - 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/system/precon.hpp
|
||||
|
||||
\brief Provides preconstructed systems for use around the home and office.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "bertini2/system/system.hpp"
|
||||
|
||||
|
||||
|
||||
namespace bertini{
|
||||
namespace system{
|
||||
|
||||
struct Precon{
|
||||
|
||||
/**
|
||||
Creates the Griewank-Osborn system.
|
||||
|
||||
From the returned system, you can unpack the variables, etc.
|
||||
*/
|
||||
static
|
||||
System GriewankOsborn();
|
||||
|
||||
|
||||
/**
|
||||
Creates system with crossed paths at t = 1/3 and t = 2/3.
|
||||
|
||||
From the returned system, you can unpack the variables, etc.
|
||||
*/
|
||||
static
|
||||
System CrossedPaths();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Constructs a system describing the 2-sphere, in variables x, y, z.
|
||||
|
||||
System has one affine variable group: x, y, z;
|
||||
One function: x^2 + y^2 + z^2 - 1;
|
||||
*/
|
||||
static
|
||||
System Sphere();
|
||||
|
||||
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
341
core/include/bertini2/system/slice.hpp
Normal file
341
core/include/bertini2/system/slice.hpp
Normal file
@@ -0,0 +1,341 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//slice.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.
|
||||
//
|
||||
//slice.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 slice.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/system/slice.hpp
|
||||
|
||||
\brief Provides the bertini::LinearSlice class.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BERTINI_SLICE_HPP
|
||||
#define BERTINI_SLICE_HPP
|
||||
|
||||
#include "bertini2/function_tree.hpp"
|
||||
#include "bertini2/num_traits.hpp"
|
||||
#include "bertini2/eigen_extensions.hpp"
|
||||
|
||||
|
||||
namespace bertini {
|
||||
|
||||
|
||||
/**
|
||||
\brief Base class for other Slices.
|
||||
|
||||
\see LinearSlice
|
||||
*/
|
||||
class Slice
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Slice an affine or projective space with a LinearSlice today!
|
||||
*/
|
||||
class LinearSlice : public Slice
|
||||
{
|
||||
|
||||
|
||||
mutable std::tuple<Mat<dbl>, Mat<mpfr_complex> > coefficients_working_;
|
||||
Mat< mpfr_complex > coefficients_highest_precision_; ///< the highest-precision coefficients for the patch
|
||||
|
||||
mutable std::tuple<Vec<dbl>, Vec<mpfr_complex> > constants_working_;
|
||||
Vec< mpfr_complex > constants_highest_precision_; ///< the highest-precision coefficients for the patch
|
||||
|
||||
VariableGroup sliced_vars_;
|
||||
unsigned num_dims_sliced_;
|
||||
mutable unsigned precision_; ///< the current working precision of the patch.
|
||||
|
||||
bool is_homogeneous_;
|
||||
public:
|
||||
|
||||
/**
|
||||
Produce a random real slice on a variable group, slicing a given number of dimensions.
|
||||
*/
|
||||
static LinearSlice RandomReal(VariableGroup const& v, unsigned dim, bool homogeneous = false, bool orthogonal = true)
|
||||
{
|
||||
typedef void (*funtype) (mpfr_complex&, unsigned); // the type for number generation
|
||||
funtype gen = bertini::multiprecision::RandomRealAssign;
|
||||
return Make(v, dim, homogeneous, orthogonal, gen);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Generate a random complex slice.
|
||||
*/
|
||||
static LinearSlice RandomComplex(VariableGroup const& v, unsigned dim, bool homogeneous = false, bool orthogonal = true)
|
||||
{
|
||||
typedef void (*funtype) (mpfr_complex&, unsigned); // the type for number generation
|
||||
funtype gen = bertini::multiprecision::RandomComplexAssign;
|
||||
return Make(v, dim, homogeneous, orthogonal, gen);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Evaluate the function values of the LinearSlice, in-place
|
||||
*/
|
||||
template<typename NumT>
|
||||
void Eval(Vec<NumT> & result, Vec<NumT> const& x) const
|
||||
{
|
||||
result = std::get<Mat<NumT> >(coefficients_working_) * x;
|
||||
|
||||
if (!is_homogeneous_)
|
||||
result += std::get<Vec<NumT> >(constants_working_);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the function values of the LinearSlice
|
||||
*/
|
||||
template<typename NumT>
|
||||
Vec<NumT> Eval(Vec<NumT> const& x) const
|
||||
{
|
||||
if (!is_homogeneous_)
|
||||
return std::get<Mat<NumT> >(coefficients_working_) * x + std::get<Vec<NumT> >(constants_working_);
|
||||
else
|
||||
return std::get<Mat<NumT> >(coefficients_working_) * x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Evaluate the Jacobian of the LinearSlice, in-place
|
||||
*/
|
||||
template<typename NumT>
|
||||
void Jacobian(Mat<NumT> & result, Mat<NumT> const& x) const
|
||||
{
|
||||
result = std::get<Mat<NumT> >(coefficients_working_);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Evaluate the Jacobian of the LinearSlice
|
||||
*/
|
||||
template<typename NumT>
|
||||
Mat<NumT> Jacobian(Mat<NumT> const& x) const
|
||||
{
|
||||
return std::get<Mat<NumT> >(coefficients_working_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the current precision of the slice.
|
||||
|
||||
\return The current precision, in digits.
|
||||
*/
|
||||
unsigned Precision() const
|
||||
{
|
||||
return precision_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Set the precision of the slice.
|
||||
|
||||
Copies the slice coefficients into correct precision for subsequent precision.
|
||||
|
||||
\param new_precision The precision to change to.
|
||||
*/
|
||||
void Precision(unsigned new_precision) const
|
||||
{
|
||||
if (new_precision > DoublePrecision())
|
||||
{
|
||||
Mat<mpfr_complex>& coefficients_mpfr = std::get<Mat<mpfr_complex> >(coefficients_working_);
|
||||
Vec<mpfr_complex>& constants_mpfr = std::get<Vec<mpfr_complex> >(constants_working_);
|
||||
for (unsigned ii = 0; ii < Dimension(); ++ii)
|
||||
{
|
||||
for (unsigned jj=0; jj<NumVariables(); ++jj)
|
||||
{
|
||||
coefficients_mpfr(ii,jj).precision(new_precision);
|
||||
if (new_precision>precision_)
|
||||
coefficients_mpfr(ii,jj) = coefficients_highest_precision_(ii,jj);
|
||||
}
|
||||
|
||||
if (!is_homogeneous_)
|
||||
{
|
||||
constants_mpfr(ii).precision(new_precision);
|
||||
if (new_precision>precision_)
|
||||
constants_mpfr(ii) = constants_highest_precision_(ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
precision_ = new_precision;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the dimension of the slice
|
||||
*/
|
||||
unsigned Dimension() const
|
||||
{
|
||||
return num_dims_sliced_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Get the number of variables sliced.
|
||||
*/
|
||||
unsigned NumVariables() const
|
||||
{
|
||||
return sliced_vars_.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief the default constructor for linear slices.
|
||||
|
||||
Make an empty linear slice.
|
||||
*/
|
||||
LinearSlice() :
|
||||
sliced_vars_(),
|
||||
precision_(DefaultPrecision()),
|
||||
num_dims_sliced_(0),
|
||||
coefficients_highest_precision_(0, 0),
|
||||
is_homogeneous_(false),
|
||||
constants_highest_precision_(static_cast<unsigned>(0))
|
||||
{
|
||||
std::get<Mat<dbl> > (coefficients_working_).resize(Dimension(), NumVariables());
|
||||
std::get<Mat<mpfr_complex> >(coefficients_working_).resize(Dimension(), NumVariables());
|
||||
|
||||
std::get<Vec<dbl> > (constants_working_).resize(Dimension());
|
||||
std::get<Vec<mpfr_complex> >(constants_working_).resize(Dimension());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief the constructor for linear slices.
|
||||
*/
|
||||
LinearSlice(VariableGroup const& v, unsigned dim, bool homogeneous) : sliced_vars_(v), precision_(DefaultPrecision()), num_dims_sliced_(dim), coefficients_highest_precision_(dim, v.size()), is_homogeneous_(homogeneous), constants_highest_precision_(dim)
|
||||
{
|
||||
std::get<Mat<dbl> > (coefficients_working_).resize(Dimension(), NumVariables());
|
||||
std::get<Mat<mpfr_complex> >(coefficients_working_).resize(Dimension(), NumVariables());
|
||||
|
||||
if (!homogeneous)
|
||||
{
|
||||
std::get<Vec<dbl> > (constants_working_).resize(Dimension());
|
||||
std::get<Vec<mpfr_complex> >(constants_working_).resize(Dimension());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief factory function for generating slices
|
||||
*/
|
||||
static
|
||||
LinearSlice Make(VariableGroup const& v, unsigned dim, bool homogeneous, bool orthogonal, std::function<void(mpfr_complex&, unsigned)> gen)
|
||||
{
|
||||
LinearSlice s(v, dim, homogeneous);
|
||||
|
||||
|
||||
|
||||
if (orthogonal)
|
||||
{
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
auto mindim = min(s.Dimension(),s.NumVariables());
|
||||
auto maxdim = max(s.Dimension(),s.NumVariables());
|
||||
|
||||
bool need_transpose = s.Dimension() < s.NumVariables();
|
||||
|
||||
s.coefficients_highest_precision_.resize(maxdim,mindim);
|
||||
|
||||
for (unsigned ii(0); ii<maxdim; ++ii)
|
||||
for (unsigned jj(0); jj<mindim; ++jj)
|
||||
gen(s.coefficients_highest_precision_(ii,jj), MaxPrecisionAllowed());
|
||||
|
||||
auto prev_precision = DefaultPrecision();
|
||||
DefaultPrecision(MaxPrecisionAllowed());
|
||||
|
||||
auto QR_factorization = Eigen::HouseholderQR<Mat<mpfr_complex> >(s.coefficients_highest_precision_);
|
||||
s.coefficients_highest_precision_ = QR_factorization.householderQ()*Mat<mpfr_complex>::Identity(maxdim, mindim);
|
||||
|
||||
if (need_transpose)
|
||||
s.coefficients_highest_precision_.transposeInPlace();
|
||||
|
||||
DefaultPrecision(prev_precision);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned ii(0); ii<s.Dimension(); ++ii)
|
||||
for (unsigned jj(0); jj<s.NumVariables(); ++jj)
|
||||
gen(s.coefficients_highest_precision_(ii,jj), MaxPrecisionAllowed());
|
||||
}
|
||||
|
||||
for (unsigned ii(0); ii<s.Dimension(); ++ii)
|
||||
for (unsigned jj(0); jj<s.NumVariables(); ++jj)
|
||||
{
|
||||
std::get<Mat<dbl> >(s.coefficients_working_)(ii,jj) = dbl(s.coefficients_highest_precision_(ii,jj));
|
||||
std::get<Mat<mpfr_complex> >(s.coefficients_working_)(ii,jj) = s.coefficients_highest_precision_(ii,jj);
|
||||
}
|
||||
|
||||
if (!homogeneous)
|
||||
{
|
||||
s.constants_highest_precision_.resize(s.Dimension());
|
||||
std::get<Vec<dbl> >(s.constants_working_).resize(s.Dimension());
|
||||
std::get<Vec<mpfr_complex> >(s.constants_working_).resize(s.Dimension());
|
||||
|
||||
for (unsigned ii(0); ii<s.Dimension(); ++ii)
|
||||
{
|
||||
gen(s.constants_highest_precision_(ii), MaxPrecisionAllowed());
|
||||
std::get<Vec<dbl> >(s.constants_working_)(ii) = dbl(s.constants_highest_precision_(ii));
|
||||
std::get<Vec<mpfr_complex> >(s.constants_working_)(ii) = s.constants_highest_precision_(ii);
|
||||
}
|
||||
}
|
||||
|
||||
assert(s.coefficients_highest_precision_.rows()==s.Dimension());
|
||||
assert(s.coefficients_highest_precision_.cols()==s.NumVariables());
|
||||
|
||||
if (!homogeneous)
|
||||
assert(s.constants_highest_precision_.size()==s.Dimension());
|
||||
else
|
||||
assert(s.constants_highest_precision_.size()==0);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & precision_;
|
||||
|
||||
ar & coefficients_highest_precision_;
|
||||
|
||||
ar & std::get<0>(coefficients_working_);
|
||||
ar & std::get<1>(coefficients_working_);
|
||||
ar & sliced_vars_;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream&, LinearSlice const&);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Provides output streaming for LinearSlice
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& out, LinearSlice const& s);
|
||||
} // re: namespace bertini
|
||||
|
||||
#endif
|
||||
|
||||
146
core/include/bertini2/system/start/mhom.hpp
Normal file
146
core/include/bertini2/system/start/mhom.hpp
Normal file
@@ -0,0 +1,146 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//mhom.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.
|
||||
//
|
||||
//mhom.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 mhom.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:
|
||||
// Tim Hodges, Colorado State University
|
||||
// silviana amethyst, university of wisconsin eau claire
|
||||
|
||||
/**
|
||||
\file mhom.hpp
|
||||
|
||||
\brief Defines the MHomogeneous start system type.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/system/start_base.hpp"
|
||||
#include "bertini2/system/start/utility.hpp"
|
||||
|
||||
namespace bertini
|
||||
{
|
||||
namespace start_system
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
\brief The $m$-homogeneous start system for Numerical Algebraic Geometry
|
||||
|
||||
|
||||
*/
|
||||
class MHomogeneous : public StartSystem
|
||||
{
|
||||
public:
|
||||
MHomogeneous() = default;
|
||||
virtual ~MHomogeneous() = default;
|
||||
|
||||
/**
|
||||
Constructor for making a multi-homogeneous start system from a polynomial system
|
||||
|
||||
\throws std::runtime_error, if the input target system is not square, is not polynomial, has a path variable already.
|
||||
|
||||
Constructor can take in a non-homogeneous system or homogeneous system.
|
||||
*/
|
||||
MHomogeneous(System const& s);
|
||||
|
||||
/**
|
||||
\brief Creates a degree matrix for constructing the multi-homogeneous start system.
|
||||
*/
|
||||
void CreateDegreeMatrix(System const& s);
|
||||
|
||||
/**
|
||||
\brief Creates all valid partitions for multi-homogeneous start system to create start points.
|
||||
*/
|
||||
void GenerateValidPartitions(System const& s);
|
||||
|
||||
/**
|
||||
\brief Helper function that is used to find valid partitions in the degree matrix.
|
||||
*/
|
||||
int ChooseColumnInRow(System const& s,Vec<int>& variable_group_counter, int row, int column);
|
||||
|
||||
/**
|
||||
Get the number of start points for this m-homogeneous start system. This is the Bezout bound for the target system. Provided here for your convenience.
|
||||
*/
|
||||
unsigned long long NumStartPoints() const override;
|
||||
|
||||
unsigned long long NumStartPointsForPartition(Vec<int> partition) const;
|
||||
|
||||
MHomogeneous& operator*=(Nd const& n);
|
||||
|
||||
MHomogeneous& operator+=(System const& sys) = delete;
|
||||
|
||||
/**
|
||||
\brief Degree matrix holding degrees for all functions in terms of all variable groups
|
||||
*/
|
||||
Mat<int> degree_matrix_; // stores degrees of all functions in all homogeneous variable groups.
|
||||
|
||||
/**
|
||||
\brief Partitions used for creating start points in the multi-homogeneous start system.
|
||||
*/
|
||||
std::deque< Vec<int> > valid_partitions_;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
Get the ith start point, in double precision.
|
||||
|
||||
Called by the base StartSystem's StartPoint(index) method.
|
||||
*/
|
||||
Vec<dbl> GenerateStartPoint(dbl,unsigned long long index) const override;
|
||||
|
||||
/**
|
||||
Get the ith start point, in current default precision.
|
||||
|
||||
Called by the base StartSystem's StartPoint(index) method.
|
||||
*/
|
||||
Vec<mpfr_complex> GenerateStartPoint(mpfr_complex,unsigned long long index) const override;
|
||||
|
||||
/**
|
||||
A local version of GenerateStartPoint that can be templated
|
||||
*/
|
||||
template<typename T>
|
||||
void GenerateStartPointT(Vec<T>& start_point, unsigned long long index) const;
|
||||
|
||||
|
||||
|
||||
|
||||
std::vector<unsigned long long> degrees_; ///< stores the degrees of the functions.
|
||||
std::vector< VariableGroup > var_groups_;
|
||||
Mat<std::shared_ptr<node::LinearProduct>> linprod_matrix_; ///< All the linear products for each entry in the degree matrix.
|
||||
std::vector< std::vector<size_t> > variable_cols_; ///< The columns associated with each variable. The first index is the variable group, the second index is the particular variable in the group.
|
||||
|
||||
mutable Vec<mpfr_complex> temp_v_mp_;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version)
|
||||
{
|
||||
ar & boost::serialization::base_object<StartSystem>(*this);
|
||||
ar & degrees_;
|
||||
}
|
||||
|
||||
};
|
||||
}//end start_system namespace
|
||||
}//end bertini namespace
|
||||
|
||||
|
||||
|
||||
148
core/include/bertini2/system/start/total_degree.hpp
Normal file
148
core/include/bertini2/system/start/total_degree.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//total_degree.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.
|
||||
//
|
||||
//total_degree.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 total_degree.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 total_degree.hpp
|
||||
|
||||
\brief Defines the TotalDegree start system type.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/system/start_base.hpp"
|
||||
#include "bertini2/system/start/utility.hpp"
|
||||
|
||||
namespace bertini
|
||||
{
|
||||
namespace start_system{
|
||||
|
||||
|
||||
/**
|
||||
\brief Total degree start system for 1-homogeneous polynomial systems.
|
||||
|
||||
The most basic and easy-to-construct start system in Numerical Algebraic Geometry.
|
||||
|
||||
The total degree start system uses functions of the form \f$x_i^{d_i} - r_i\f$, where \f$i\f$ is the index of the function relative to the system, \f$d_i\f$ is the degree of that function, and \f$r_i\f$ is a random complex number. This is very similar to the roots of unity, except that they are moved away from being centered around the origin, to being centered around a random complex number.
|
||||
|
||||
Note that the corresponding target system MUST be square -- have the same number of functions and variables. The start system cannot be constructed otherwise, particularly because it is written to throw at the moment if not square.
|
||||
|
||||
The start points are accesses by index (unsigned long long), instead of being generated all at once.
|
||||
*/
|
||||
class TotalDegree : public StartSystem
|
||||
{
|
||||
public:
|
||||
TotalDegree() = default;
|
||||
virtual ~TotalDegree() = default;
|
||||
|
||||
/**
|
||||
Constructor for making a total degree start system from a polynomial system
|
||||
|
||||
\throws std::runtime_error, if the input target system is not square, is not polynomial, has a path variable already, has more than one variable group, or has any homogeneous variable groups.
|
||||
*/
|
||||
TotalDegree(System const& s);
|
||||
|
||||
|
||||
/**
|
||||
Get the random value for start function with index
|
||||
|
||||
\param index The index of the start function for which you want the corresponding random value.
|
||||
*/
|
||||
template<typename NumT>
|
||||
NumT RandomValue(size_t index) const
|
||||
{
|
||||
return random_values_[index]->Eval<NumT>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get all the random values, in their Node form.
|
||||
*/
|
||||
std::vector<std::shared_ptr<node::Rational> > const& RandomValues()
|
||||
{
|
||||
return random_values_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the number of start points for this total degree start system. This is the Bezout bound for the target system. Provided here for your convenience.
|
||||
*/
|
||||
unsigned long long NumStartPoints() const override;
|
||||
|
||||
TotalDegree& operator*=(Nd const& n);
|
||||
|
||||
TotalDegree& operator+=(System const& sys) = delete;
|
||||
|
||||
void SanityChecks(System const& s);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
Copy the degrees from another system into this one
|
||||
*/
|
||||
void CopyDegrees(System const& s);
|
||||
|
||||
/**
|
||||
Populate the random values of this system.
|
||||
*/
|
||||
void SeedRandomValues(int num_functions);
|
||||
|
||||
/**
|
||||
Generate the functions for this total degree start system. Assumes the random values, degrees, and variables are already g2g.
|
||||
*/
|
||||
void GenerateFunctions();
|
||||
|
||||
|
||||
/**
|
||||
Get the ith start point, in double precision.
|
||||
|
||||
Called by the base StartSystem's StartPoint(index) method.
|
||||
*/
|
||||
Vec<dbl> GenerateStartPoint(dbl,unsigned long long index) const override;
|
||||
|
||||
/**
|
||||
Get the ith start point, in current default precision.
|
||||
|
||||
Called by the base StartSystem's StartPoint(index) method.
|
||||
*/
|
||||
Vec<mpfr_complex> GenerateStartPoint(mpfr_complex,unsigned long long index) const override;
|
||||
|
||||
std::vector<std::shared_ptr<node::Rational> > random_values_; ///< stores the random values for the start functions. x^d-r, where r is stored in this vector.
|
||||
std::vector<unsigned long long> degrees_; ///< stores the degrees of the functions.
|
||||
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & boost::serialization::base_object<StartSystem>(*this);
|
||||
ar & random_values_;
|
||||
ar & degrees_;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
157
core/include/bertini2/system/start/user.hpp
Normal file
157
core/include/bertini2/system/start/user.hpp
Normal file
@@ -0,0 +1,157 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//bertini2/system/start/user.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/system/start/user.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/system/start/user.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/system/start/user.hpp
|
||||
|
||||
\brief Defines the User-defined start system type.
|
||||
|
||||
the user provided start system is merely their system, evaluated at the start time.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/system/start_base.hpp"
|
||||
#include "bertini2/system/start/utility.hpp"
|
||||
#include "bertini2/common/config.hpp"
|
||||
|
||||
// these next two blobs solve a problem of private-ness.
|
||||
// see https://stackoverflow.com/questions/4112075/trouble-overriding-save-construct-data-when-serializing-a-pointer-to-a-class-wit
|
||||
|
||||
// forward declare the User start system
|
||||
namespace bertini{ namespace start_system{
|
||||
class User;
|
||||
}}
|
||||
|
||||
// forward declare the function, so we can friend it below.
|
||||
namespace boost { namespace serialization {
|
||||
template<class Archive>
|
||||
inline void save_construct_data(Archive & ar, const bertini::start_system::User * t, const unsigned int file_version);
|
||||
}}
|
||||
// end nonsense for friends. so lonely, but c++ friends don't solve the irl problem at all.
|
||||
|
||||
namespace bertini
|
||||
{
|
||||
namespace start_system{
|
||||
|
||||
|
||||
/**
|
||||
\brief The user-provided start system for Numerical Algebraic Geometry
|
||||
|
||||
|
||||
*/
|
||||
class User : public StartSystem
|
||||
{
|
||||
public:
|
||||
User() = delete; // deleted because requires a reference to a System to construct
|
||||
virtual ~User() = default;
|
||||
|
||||
/**
|
||||
Constructor for making a user-provided start system from another.
|
||||
*/
|
||||
User(System const& s, SampCont<dbl> const& solns);
|
||||
User(System const& s, SampCont<mpfr_complex> const& solns);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Get the number of start points for this start system.
|
||||
*/
|
||||
unsigned long long NumStartPoints() const override;
|
||||
|
||||
User& operator*=(Nd const& n) = delete;
|
||||
|
||||
User& operator+=(System const& sys) = delete;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
Get the ith start point, in double precision.
|
||||
|
||||
Called by the base StartSystem's StartPoint(index) method.
|
||||
*/
|
||||
Vec<dbl> GenerateStartPoint(dbl,unsigned long long index) const override;
|
||||
|
||||
/**
|
||||
Get the ith start point, in current default precision.
|
||||
|
||||
Called by the base StartSystem's StartPoint(index) method.
|
||||
*/
|
||||
Vec<mpfr_complex> GenerateStartPoint(mpfr_complex,unsigned long long index) const override;
|
||||
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive> friend void boost::serialization::save_construct_data(Archive & ar, const User * t, const unsigned int file_version);
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & boost::serialization::base_object<StartSystem>(*this);
|
||||
}
|
||||
|
||||
const bertini::System& user_system_;
|
||||
std::tuple<SampCont<dbl>, SampCont<mpfr_complex>> solns_;
|
||||
bool solns_in_dbl_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost { namespace serialization {
|
||||
template<class Archive>
|
||||
inline void save_construct_data(
|
||||
Archive & ar, const bertini::start_system::User * t, const unsigned int file_version
|
||||
){
|
||||
// save data required to construct instance
|
||||
ar << t->user_system_;
|
||||
ar << t->solns_in_dbl_;
|
||||
|
||||
ar << std::get<0>(t->solns_);
|
||||
ar << std::get<1>(t->solns_);
|
||||
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
inline void load_construct_data(
|
||||
Archive & ar, bertini::start_system::User * t, const unsigned int file_version
|
||||
){
|
||||
// retrieve data from archive required to construct new instance
|
||||
bertini::System sys;
|
||||
ar >> sys;
|
||||
|
||||
bool solns_in_dbl;
|
||||
ar >> solns_in_dbl;
|
||||
|
||||
if (solns_in_dbl)
|
||||
{
|
||||
bertini::SampCont<bertini::dbl> solns;
|
||||
ar >> solns;
|
||||
::new(t)bertini::start_system::User(sys, solns);
|
||||
}
|
||||
else
|
||||
{
|
||||
bertini::SampCont<bertini::mpfr_complex> solns;
|
||||
ar >> solns;
|
||||
::new(t)bertini::start_system::User(sys, solns);
|
||||
}
|
||||
}
|
||||
}}
|
||||
94
core/include/bertini2/system/start/utility.hpp
Normal file
94
core/include/bertini2/system/start/utility.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//bertini2/system/start/utility.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/system/start/utility.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/system/start/utility.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/system/start/utility.hpp
|
||||
|
||||
\brief utilities for start system code.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_START_SYSTEM_UTILITIES_HPP
|
||||
#define BERTINI_START_SYSTEM_UTILITIES_HPP
|
||||
|
||||
|
||||
|
||||
namespace bertini{
|
||||
|
||||
|
||||
/**
|
||||
\brief Convert a zero-based index to a zero-based subscript vector.
|
||||
|
||||
Throws `std::out_of_range` if the index is out-of-range based on the dimensions.
|
||||
|
||||
This goes from front to back, top to bottom. So
|
||||
|
||||
[0 2 4 [(0,0) (0,1) (0,2)
|
||||
1 3 5] (1,0) (1,1) (1,2)]
|
||||
|
||||
etc for higher-dimensional arrays. The functionality here is identical to that of Matlab's analagous call.
|
||||
|
||||
\param index The index you want to convert.
|
||||
\param dimensions The dimensions of the object you are subscripting or indexing into.
|
||||
\return A vector containing the subscripts for the input index.
|
||||
\throws std::out_of_range, if the index is impossible to convert.
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<T> IndexToSubscript(T index, std::vector<T> const& dimensions)
|
||||
{
|
||||
|
||||
std::vector< T > subscripts(dimensions.size());//for forming a subscript from an index
|
||||
|
||||
std::vector<T> k(dimensions.size(),1);
|
||||
for (int ii = 0; ii < dimensions.size()-1; ++ii)
|
||||
k[ii+1] = k[ii]*dimensions[ii];
|
||||
|
||||
|
||||
if (index >= k.back()*dimensions.back())
|
||||
throw std::out_of_range("in IndexToSubscript, index exceeds max based on dimension sizes");
|
||||
|
||||
|
||||
for (int ii = dimensions.size()-1; ii >= 0; --ii)
|
||||
{
|
||||
T I = index%k[ii];
|
||||
T J = (index - I) / k[ii];
|
||||
subscripts[ii] = J;
|
||||
index = I;
|
||||
}
|
||||
|
||||
return subscripts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // re: namespace bertini
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
81
core/include/bertini2/system/start_base.hpp
Normal file
81
core/include/bertini2/system/start_base.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//start_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.
|
||||
//
|
||||
//start_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 start_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 notre dame
|
||||
|
||||
/**
|
||||
\file b2/core/include/bertini2/system/start_base.hpp
|
||||
|
||||
\brief Defines generic start system type.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/system/system.hpp"
|
||||
|
||||
|
||||
namespace bertini
|
||||
{
|
||||
namespace start_system{
|
||||
|
||||
/**
|
||||
\brief Abstract base class for other start systems.
|
||||
|
||||
Abstract base class for other start systems. Start systems are special types of systems, to which we know solutions. We also know how to construct various types of start systems from arbitrary polynomial systems.
|
||||
|
||||
This class provides the empty virtual declarations for necessary override functions for specific start systems, including NumStartPoints (provides an upper bound on the number of solutions to the target system), and the private functions GenerateStartPoint(index), in double and multiple precision. These two Generate functions are called by the templated non-overridden function StartPoint(index), which calls the appropriate one based on template type.
|
||||
*/
|
||||
class StartSystem : public System
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
|
||||
virtual unsigned long long NumStartPoints() const = 0;
|
||||
|
||||
template<typename T>
|
||||
Vec<T> StartPoint(unsigned long long index) const
|
||||
{
|
||||
return GenerateStartPoint(T(),index);
|
||||
}
|
||||
|
||||
virtual ~StartSystem() = default;
|
||||
|
||||
private:
|
||||
virtual Vec<dbl> GenerateStartPoint(dbl,unsigned long long index) const = 0;
|
||||
virtual Vec<mpfr_complex> GenerateStartPoint(mpfr_complex,unsigned long long index) const = 0;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & boost::serialization::base_object<System>(*this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
37
core/include/bertini2/system/start_systems.hpp
Normal file
37
core/include/bertini2/system/start_systems.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//start_systems.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.
|
||||
//
|
||||
//start_systems.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 start_systems.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 b2/core/include/bertini2/system/start_systems.hpp
|
||||
|
||||
\brief Aggregate include for the various start systems in Bertini2.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bertini2/system/start/total_degree.hpp"
|
||||
#include "bertini2/system/start/mhom.hpp"
|
||||
#include "bertini2/system/start/user.hpp"
|
||||
|
||||
|
||||
770
core/include/bertini2/system/straight_line_program.hpp
Normal file
770
core/include/bertini2/system/straight_line_program.hpp
Normal file
@@ -0,0 +1,770 @@
|
||||
|
||||
//This file is part of Bertini 2.
|
||||
//
|
||||
//straight_line_program.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.
|
||||
//
|
||||
//straight_line_program.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 straight_line_program.hpp. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Copyright(C) 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
|
||||
// michael mumm, university of wisconsin eau claire
|
||||
|
||||
/**
|
||||
\file straight_line_program.hpp
|
||||
|
||||
\brief Provides the bertini::StraightLineProgram class.
|
||||
*/
|
||||
|
||||
#ifndef BERTINI_SLP_HPP
|
||||
#define BERTINI_SLP_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "bertini2/mpfr_complex.hpp"
|
||||
#include "bertini2/mpfr_extensions.hpp"
|
||||
#include "bertini2/eigen_extensions.hpp"
|
||||
#include "bertini2/function_tree/forward_declares.hpp"
|
||||
#include "bertini2/detail/visitor.hpp"
|
||||
|
||||
#include <boost/serialization/utility.hpp>
|
||||
|
||||
// code copied from Bertini1's file include/bertini.h
|
||||
|
||||
|
||||
/*
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int num_funcs;
|
||||
int num_hom_var_gp;
|
||||
int num_var_gp;
|
||||
int *type; // 0 - hom_var_gp, 1 - var_gp
|
||||
int *size; // size of the group of the user listed variables (total size = size + type)
|
||||
} preproc_data;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
point_d funcVals;
|
||||
point_d parVals;
|
||||
vec_d parDer;
|
||||
mat_d Jv;
|
||||
mat_d Jp;
|
||||
} eval_struct_d;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
point_mp funcVals;
|
||||
point_mp parVals;
|
||||
vec_mp parDer;
|
||||
mat_mp Jv;
|
||||
mat_mp Jp;
|
||||
} eval_struct_mp;
|
||||
|
||||
|
||||
The straight-line program structure. This is the way that polynomials are stored internally.
|
||||
typedef struct {
|
||||
int *prog; // The program instructions. (a big integer array)
|
||||
int size; // size of the instruction program.
|
||||
int memSize; // Amount of memory it needs in workspace (for temp and final results).
|
||||
num_t *nums; // The array of real numbers.
|
||||
int precision; // The precision at which evaluation should occur
|
||||
|
||||
// INFO NEEDED FOR M-HOM:
|
||||
int num_var_gps; // The total number of variable groups (i.e., m from m-hom).
|
||||
int *var_gp_sizes; // The size of each of the groups.
|
||||
int index_of_first_number_for_proj_trans; // The address of the first number used in the projective transformation polynomials.
|
||||
|
||||
// STOP LOCATIONS:
|
||||
int numInstAtEndUpdate; // instruction number at end of update. i.e. i = 0; while (i < numInstAtEndUpdate) ..
|
||||
int numInstAtEndParams; // instruction number at end of params. i.e. i = numInstAtEndUpdate; while (i < numInstAtEndParams) ..
|
||||
int numInstAtEndFnEval; // instruction number at end of function eval. i.e. i = numInstAtEndParams; while (i < numInstAtEndFnEval) ..
|
||||
int numInstAtEndPDeriv; // instruction number at end of param diff. i.e. i = numInstAtEndFnEval; while (i < numInstAtEndPDeriv) ..
|
||||
int numInstAtEndJvEval; // instruction number at end of Jv eval. i.e. i = numInstAtEndPDeriv; while (i < numInstAtEndJvEval) ..
|
||||
// for Jp eval: i = numInstAtEndJvEval; while (i < size) ..
|
||||
|
||||
// INPUT AMOUNTS:
|
||||
int numVars; // Number of variables in the function being computed.
|
||||
int numPathVars; // Number of path variables. Ought to be 1 usually.
|
||||
int numNums; // Number of real numbers used in evaluation.
|
||||
int numConsts; // Number of constants.
|
||||
|
||||
// OUTPUT AMOUNTS:
|
||||
int numPars; // Number of parameters
|
||||
int numFuncs; // Number of coordinate functions in the homotopy.
|
||||
int numSubfuncs; // Number of subfunctions.
|
||||
|
||||
// INPUT LOCATIONS:
|
||||
int inpVars; // Where the input variable values are stored.
|
||||
int inpPathVars; // Where the values of the path variables are stored.
|
||||
int IAddr; // Where the constant I is stored.
|
||||
int numAddr; // Where the first num_t is stored.
|
||||
int constAddr; // Where the first constant is stored.
|
||||
|
||||
// OUTPUT LOCATIONS:
|
||||
int evalPars; // Where U(t), for given t, is stored.
|
||||
int evalDPars; // Where the derivatives of the parameters are stored.
|
||||
int evalFuncs; // Where H(x,t) is stored.
|
||||
int evalJVars; // Where the Jacobian w.r.t. vars is stored.
|
||||
int evalJPars; // Where the Jacobian w.r.t. pars is stored.
|
||||
int evalSubs; // Where the subfunctions are stored
|
||||
int evalJSubsV; // Where the derivatives of the subfunctions w.r.t. vars are stored.
|
||||
int evalJSubsP; // Where the derivatives of the subfunctions w.r.t. pars are stored.
|
||||
} prog_t;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
namespace bertini {
|
||||
|
||||
class SLPCompiler;
|
||||
class System; // a forward declaration, solving the circular inclusion problem
|
||||
|
||||
|
||||
enum Operation { // we'll start with the binary ones
|
||||
Add= 1 << 0,
|
||||
Subtract= 1 << 1,
|
||||
Multiply= 1 << 2,
|
||||
Divide= 1 << 3,
|
||||
Power= 1 << 4,
|
||||
Exp= 1 << 5,
|
||||
Log= 1 << 6,
|
||||
Negate= 1 << 7,
|
||||
Sqrt= 1 << 8,
|
||||
Sin= 1 << 9,
|
||||
Cos= 1 << 10,
|
||||
Tan= 1 << 11,
|
||||
Asin= 1 << 12,
|
||||
Acos= 1 << 13,
|
||||
Atan= 1 << 14,
|
||||
Assign= 1 << 15,
|
||||
IntPower= 1 << 16,
|
||||
};
|
||||
|
||||
const int BinaryOperations = Add|Subtract | Multiply|Divide | Power | IntPower;
|
||||
const int TrigOperations = Sin|Cos|Tan | Asin|Acos|Atan;
|
||||
const int UnaryOperations = Exp|Log | Negate | Assign | TrigOperations | Sqrt;
|
||||
|
||||
constexpr bool IsUnary(Operation op)
|
||||
{
|
||||
return op & UnaryOperations;
|
||||
}
|
||||
|
||||
constexpr bool IsBinary(Operation op)
|
||||
{
|
||||
return op & BinaryOperations;
|
||||
}
|
||||
|
||||
std::string OpcodeToString(Operation op);
|
||||
|
||||
/**
|
||||
\class StraightLineProgram
|
||||
|
||||
An implementation of straight-line programs, implemented with strong inspiration from Bertini1's implementation.
|
||||
|
||||
One constructs a SLP from a system, like
|
||||
|
||||
```
|
||||
System my_system();
|
||||
StraightLineProgram slp(my_system);
|
||||
```
|
||||
|
||||
Maybe you don't need to know this, but in construction the SLP uses a helper class, the SLPCompiler
|
||||
|
||||
Patches are just functions in this framework. The variables appear at the front of the memory, then functions, then derivatives. This should make copying data out easy, because it's all in one place.
|
||||
|
||||
In contrast to Bertini1 SLP's, we don't put all the numbers at the front -- they just get scattered through the SLP's memory.
|
||||
*/
|
||||
class StraightLineProgram{
|
||||
friend SLPCompiler;
|
||||
|
||||
private:
|
||||
using Nd = std::shared_ptr<const node::Node>;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
\struct OutputLocations
|
||||
|
||||
A struct encapsulating the starting locations of things in the SLP
|
||||
*/
|
||||
struct OutputLocations{
|
||||
size_t Functions{0};
|
||||
size_t Jacobian{0};
|
||||
size_t TimeDeriv{0};
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & Functions;
|
||||
ar & Jacobian;
|
||||
ar & TimeDeriv;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
\struct InputLocations
|
||||
|
||||
A struct encapsulating the starting locations of things in the SLP
|
||||
*/
|
||||
struct InputLocations{
|
||||
size_t Variables{0};
|
||||
size_t Time{0};
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & Variables;
|
||||
ar & Time;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\struct NumberOf
|
||||
|
||||
A struct encapsulating the numbers of things appearing in the SLP
|
||||
*/
|
||||
struct NumberOf{
|
||||
size_t Functions{0};
|
||||
size_t Variables{0};
|
||||
size_t Jacobian{0};
|
||||
size_t TimeDeriv{0};
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
ar & Functions;
|
||||
ar & Variables;
|
||||
ar & Jacobian;
|
||||
ar & TimeDeriv;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
The constructor -- how to make a SLP from a System.
|
||||
*/
|
||||
StraightLineProgram(System const & sys);
|
||||
|
||||
StraightLineProgram() = default;
|
||||
|
||||
template<typename Derived>
|
||||
void Eval(Eigen::MatrixBase<Derived> const& variable_values) const
|
||||
{
|
||||
|
||||
using NumT = typename Derived::Scalar;
|
||||
SetVariableValues(variable_values);
|
||||
|
||||
Eval<NumT>();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
\brief copies the variable values into the Matrix base and the path variables into the complex type time
|
||||
|
||||
\tparam Derived derived type
|
||||
|
||||
\tparam ComplexT complex type
|
||||
|
||||
\param variable_values dervied matrixBase of variable values
|
||||
|
||||
\param time complex type for time
|
||||
|
||||
*/
|
||||
template<typename Derived, typename ComplexT>
|
||||
void Eval(Eigen::MatrixBase<Derived> const& variable_values, ComplexT const& time) const
|
||||
{
|
||||
using NumT = typename Derived::Scalar;
|
||||
static_assert(std::is_same<NumT, ComplexT>::value, "scalar types must be the same");
|
||||
|
||||
// 1. copy variable values into memory locations they're supposed to go in
|
||||
SetVariableValues(variable_values);
|
||||
SetPathVariable(time);
|
||||
Eval<NumT>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief loops through the instructions in memory and evaluates each operation
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
uses a switch to find different operations from memory to make sure its performing the correct evaluations
|
||||
|
||||
todo: implement a compile-time version of this using Boost.Hana
|
||||
*/
|
||||
template<typename NumT>
|
||||
void Eval() const; // this definition is in cpp, along with the lines that instantiate the needed versions.
|
||||
|
||||
|
||||
|
||||
// a placeholder function that needs to be written. now just calls eval, since the eval functionality is both functions and jacobian wrapped together -- we don't keep arrays of their locations separately yet, so that would be the starting point.
|
||||
template <typename T>
|
||||
void EvalFunctions() const{
|
||||
this->Eval<T>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// a placeholder function that needs to be written. now just calls eval, since the eval functionality is both functions and jacobian wrapped together -- we don't keep arrays of their locations separately yet, so that would be the starting point.
|
||||
template <typename T>
|
||||
void EvalJacobian() const{
|
||||
this->Eval<T>();
|
||||
}
|
||||
|
||||
|
||||
// a placeholder function that needs to be written. now just calls eval, since the eval functionality is both functions and jacobian wrapped together -- we don't keep arrays of their locations separately yet, so that would be the starting point.
|
||||
template <typename T>
|
||||
void EvalTimeDeriv() const{
|
||||
this->Eval<T>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief assignts the computed values of functions into the given vector
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
\param result The vector you're going to store the values into
|
||||
|
||||
the function will NOT automatically resize your vector for you to be the correct size
|
||||
|
||||
*/
|
||||
template<typename NumT>
|
||||
void GetFuncValsInPlace(Vec<NumT> & result) const{
|
||||
if (!is_evaluated_)
|
||||
this->EvalFunctions<NumT>();
|
||||
|
||||
auto& memory = std::get<std::vector<NumT>>(memory_);
|
||||
|
||||
// copy content
|
||||
for (int ii = 0; ii < number_of_.Functions; ++ii) {
|
||||
result(ii) = memory[ii + output_locations_.Functions];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief retrieves the computed values of jacobians
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
\param result The vector you're going to store the values into
|
||||
|
||||
the function will NOT automatically resize your vector for you to be the correct size
|
||||
|
||||
*/
|
||||
|
||||
template<typename NumT>
|
||||
void GetJacobianInPlace(Mat<NumT> & result) const{
|
||||
if (!is_evaluated_)
|
||||
this->EvalJacobian<NumT>();
|
||||
|
||||
auto& memory = std::get<std::vector<NumT>>(memory_);
|
||||
|
||||
// copy content
|
||||
for (int jj =0; jj < number_of_.Variables; ++jj) {
|
||||
for (int ii = 0; ii < number_of_.Functions; ++ii) {
|
||||
result(ii, jj) = memory[ii+jj*number_of_.Functions + output_locations_.Jacobian];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief copies the values of the time derivatives into your given vector
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
\param result The vector you're going to store the values into
|
||||
|
||||
the function will automatically resize your vector for you to be the correct size
|
||||
|
||||
*/
|
||||
|
||||
template<typename NumT>
|
||||
void GetTimeDerivInPlace(Vec<NumT> & result) const{
|
||||
if (!is_evaluated_)
|
||||
this->EvalTimeDeriv<NumT>();
|
||||
|
||||
auto& memory = std::get<std::vector<NumT>>(memory_);
|
||||
// 1. make container, size correctly.
|
||||
// 2. copy content
|
||||
for (int ii = 0; ii < number_of_.Functions; ++ii) {
|
||||
result(ii) = memory[ii + output_locations_.TimeDeriv];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief creates the Vec<NumT> to be used in the overloaded function
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
*/
|
||||
template<typename NumT>
|
||||
Vec<NumT> GetFuncVals() const{
|
||||
Vec<NumT> return_me(this->NumFunctions());
|
||||
GetFuncValsInPlace(return_me);
|
||||
return return_me;
|
||||
}
|
||||
/**
|
||||
\brief creates the Vec<NumT> to be used in the overloaded function
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
*/
|
||||
template<typename NumT>
|
||||
Mat<NumT> GetJacobian() const{
|
||||
Mat<NumT> return_me(this->NumFunctions(), this->NumVariables());
|
||||
GetJacobianInPlace(return_me);
|
||||
return return_me;
|
||||
}
|
||||
/**
|
||||
\brief creates the Vec<NumT> to be used in the overloaded function
|
||||
|
||||
\tparam NumT numeric type
|
||||
|
||||
*/
|
||||
template<typename NumT>
|
||||
Vec<NumT> GetTimeDeriv() const{
|
||||
Vec<NumT> return_me(this->NumFunctions());
|
||||
GetTimeDerivInPlace(return_me);
|
||||
return return_me;
|
||||
}
|
||||
|
||||
|
||||
inline unsigned NumFunctions() const{ return number_of_.Functions;}
|
||||
|
||||
inline unsigned NumVariables() const{ return number_of_.Variables;}
|
||||
|
||||
|
||||
/**
|
||||
\brief Get the current precision of the SLP.
|
||||
|
||||
\return The number of digits
|
||||
*/
|
||||
inline
|
||||
unsigned precision() const
|
||||
{
|
||||
return precision_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief change the precision of the SLP.
|
||||
|
||||
Downsamples from the true values.
|
||||
|
||||
\param new_precision The new number of digits
|
||||
*/
|
||||
void precision(unsigned new_precision) const;
|
||||
|
||||
/**
|
||||
\brief Does this SLP have a path variable?
|
||||
|
||||
\return Well, does it?
|
||||
*/
|
||||
bool HavePathVariable() const {
|
||||
return this->has_path_variable_;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Overloaded operator for printing to an arbirtary out stream.
|
||||
*/
|
||||
friend std::ostream& operator <<(std::ostream& out, const StraightLineProgram & s);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief Copy the values of the variables from the passed in vector to memory
|
||||
|
||||
\param variable_values The vector of current variable values.
|
||||
*/
|
||||
template<typename Derived>
|
||||
void SetVariableValues(Eigen::MatrixBase<Derived> const& variable_values) const{
|
||||
using NumT = typename Derived::Scalar;
|
||||
|
||||
#ifndef BERTINI_DISABLE_PRECISION_CHECKS
|
||||
if (!std::is_same<NumT,dbl_complex>::value && Precision(variable_values)!=this->precision_){
|
||||
std::stringstream err_msg;
|
||||
err_msg << "variable_values and SLP must be of same precision. respective precisions: " << Precision(variable_values) << " " << this->precision_ << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
using NumT = typename Derived::Scalar;
|
||||
auto& memory = std::get<std::vector<NumT>>(memory_); // unpack for local reference
|
||||
|
||||
for (int ii = 0; ii < number_of_.Variables; ++ii) {
|
||||
//assign to memory
|
||||
memory[ii + input_locations_.Variables] = variable_values(ii);
|
||||
}
|
||||
is_evaluated_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Copy the current time value to memory
|
||||
|
||||
\param time The current time
|
||||
\tparam ComplexT the complex numeric type.
|
||||
|
||||
If the SLP doesn't have a path variable, then this will throw.
|
||||
*/
|
||||
template<typename ComplexT>
|
||||
void SetPathVariable(ComplexT const& time) const{
|
||||
|
||||
#ifndef BERTINI_DISABLE_PRECISION_CHECKS
|
||||
if (Precision(time)!= DoublePrecision() && Precision(time)!=this->precision_){
|
||||
std::stringstream err_msg;
|
||||
err_msg << "time value and SLP must be of same precision. respective precisions: " << Precision(time) << " " << this->precision_ << std::endl;
|
||||
throw std::runtime_error(err_msg.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!this->HavePathVariable())
|
||||
throw std::runtime_error("calling Eval with path variable, but this StraightLineProgram doesn't have one.");
|
||||
// then actually copy the path variable into where it goes in memory
|
||||
|
||||
auto& memory = std::get<std::vector<ComplexT>>(memory_); // unpack for local reference
|
||||
|
||||
memory[input_locations_.Time] = time;
|
||||
is_evaluated_ = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using IntT = int; // this needs to co-vary on the stored type inside the node. node should stop using mpz, it's slow.
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
\brief Add an instruction to memory. This one's for binary operations
|
||||
|
||||
\param binary_op The opcode, from the enum.
|
||||
\param in_loc1 The location of the first operand
|
||||
\param in_loc2 The locatiion in memory of the second operand
|
||||
\param out_loc Where in memory to put the result of the operation.
|
||||
*/
|
||||
void AddInstruction(Operation binary_op, size_t in_loc1, size_t in_loc2, size_t out_loc);
|
||||
|
||||
/**
|
||||
\brief Add an instruction to memory. This one's for unary operations
|
||||
|
||||
\param unary_op The opcode, from the enum.
|
||||
\param in_loc The location of the one and only operand
|
||||
\param out_loc Where in memory to put the result of the operation.
|
||||
*/
|
||||
void AddInstruction(Operation unary_op, size_t in_loc, size_t out_loc);
|
||||
|
||||
|
||||
/**
|
||||
\brief Add a number to the memory at location, and memoize it for precision changing later.
|
||||
*/
|
||||
void AddNumber(Nd const num, size_t loc);
|
||||
|
||||
template<typename NumT>
|
||||
auto& GetMemory() const{
|
||||
return std::get<std::vector<NumT>>(this->memory_);
|
||||
}
|
||||
|
||||
|
||||
template<typename NumT>
|
||||
void CopyNumbersIntoMemory() const;
|
||||
|
||||
|
||||
mutable unsigned precision_ = 16; //< The current working number of digits
|
||||
bool has_path_variable_ = false; //< Does this SLP have a path variable?
|
||||
|
||||
NumberOf number_of_; //< Quantities of things
|
||||
OutputLocations output_locations_; //< Where to find outputs, like functions and derivatives
|
||||
InputLocations input_locations_; //< Where to find inputs, like variables and time
|
||||
|
||||
mutable std::tuple< std::vector<dbl_complex>, std::vector<mpfr_complex> > memory_; //< The memory of the object. Numbers and variables, plus temp results and output locations. It's all one block. That's why it's called a SLP!
|
||||
std::vector<IntT> integers_;
|
||||
|
||||
std::vector<size_t> instructions_; //< The instructions. The opcodes are stored as size_t's, as well as the locations of operands and results.
|
||||
std::vector< std::pair<Nd,size_t> > true_values_of_numbers_; //< the size_t is where in memory to downsample to.
|
||||
|
||||
mutable bool is_evaluated_ = false;
|
||||
|
||||
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned version) {
|
||||
|
||||
ar & precision_;
|
||||
ar & has_path_variable_;
|
||||
|
||||
ar & number_of_;
|
||||
ar & output_locations_;
|
||||
ar & input_locations_;
|
||||
|
||||
ar & std::get<std::vector<dbl_complex>>(memory_);
|
||||
ar & std::get<std::vector<mpfr_complex>>(memory_);
|
||||
ar & integers_;
|
||||
|
||||
ar & instructions_;
|
||||
ar & true_values_of_numbers_;
|
||||
|
||||
ar & is_evaluated_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class SLPCompiler : public VisitorBase,
|
||||
|
||||
// IF YOU ADD A THING HERE, YOU MUST ADD IT ABOVE AND IN THE CPP SOURCE
|
||||
|
||||
|
||||
// symbols and roots
|
||||
public Visitor<node::Variable>,
|
||||
public Visitor<node::Integer>,
|
||||
public Visitor<node::Float>,
|
||||
public Visitor<node::Rational>,
|
||||
public Visitor<node::Function>,
|
||||
public Visitor<node::Jacobian>,
|
||||
public Visitor<node::Differential>,
|
||||
|
||||
// arithmetic
|
||||
public Visitor<node::SumOperator>,
|
||||
public Visitor<node::MultOperator>,
|
||||
public Visitor<node::IntegerPowerOperator>,
|
||||
public Visitor<node::PowerOperator>,
|
||||
public Visitor<node::ExpOperator>,
|
||||
public Visitor<node::LogOperator>,
|
||||
public Visitor<node::NegateOperator>,
|
||||
public Visitor<node::SqrtOperator>,
|
||||
|
||||
// the trig operators
|
||||
public Visitor<node::SinOperator>,
|
||||
public Visitor<node::ArcSinOperator>,
|
||||
public Visitor<node::CosOperator>,
|
||||
public Visitor<node::ArcCosOperator>,
|
||||
public Visitor<node::TanOperator>,
|
||||
public Visitor<node::ArcTanOperator>,
|
||||
|
||||
public Visitor<node::special_number::Pi>,
|
||||
public Visitor<node::special_number::E>
|
||||
|
||||
// also missing -- linears and difflinears.
|
||||
|
||||
// these abstract base types left out,
|
||||
|
||||
// but commented here to explain why
|
||||
// public Visitor<node::Operator>,// abstract
|
||||
// public Visitor<node::UnaryOperator>,// abstract
|
||||
// public Visitor<node::NaryOperator>,// abstract
|
||||
// public Visitor<node::TrigOperator>,// abstract
|
||||
{
|
||||
private:
|
||||
using Nd = std::shared_ptr<const node::Node>;
|
||||
using SLP = StraightLineProgram;
|
||||
|
||||
public:
|
||||
|
||||
SLP Compile(System const& sys);
|
||||
|
||||
|
||||
// IF YOU ADD A THING HERE, YOU MUST ADD IT ABOVE AND IN THE CPP SOURCE
|
||||
|
||||
// symbols and roots
|
||||
virtual void Visit(node::Variable const& n);
|
||||
virtual void Visit(node::Integer const& n);
|
||||
virtual void Visit(node::Float const& n);
|
||||
virtual void Visit(node::Rational const& n);
|
||||
virtual void Visit(node::Function const& n);
|
||||
virtual void Visit(node::Jacobian const& n);
|
||||
virtual void Visit(node::Differential const& n);
|
||||
|
||||
// arithmetic
|
||||
virtual void Visit(node::SumOperator const& n);
|
||||
virtual void Visit(node::MultOperator const& n);
|
||||
virtual void Visit(node::IntegerPowerOperator const& n);
|
||||
virtual void Visit(node::PowerOperator const& n);
|
||||
virtual void Visit(node::ExpOperator const& n);
|
||||
virtual void Visit(node::LogOperator const& n);
|
||||
virtual void Visit(node::NegateOperator const& n);
|
||||
virtual void Visit(node::SqrtOperator const& n);
|
||||
|
||||
|
||||
// the trig operators
|
||||
virtual void Visit(node::SinOperator const& n);
|
||||
virtual void Visit(node::ArcSinOperator const& n);
|
||||
virtual void Visit(node::CosOperator const& n);
|
||||
virtual void Visit(node::ArcCosOperator const& n);
|
||||
virtual void Visit(node::TanOperator const& n);
|
||||
virtual void Visit(node::ArcTanOperator const& n);
|
||||
|
||||
virtual void Visit(node::special_number::Pi const& n);
|
||||
virtual void Visit(node::special_number::E const& n);
|
||||
// missing -- linear and difflinear
|
||||
private:
|
||||
|
||||
|
||||
/**
|
||||
\brief Provides a uniform interface for dealing with all numeric node types.
|
||||
*/
|
||||
template<typename NodeT>
|
||||
void DealWithNumber(NodeT const& n){
|
||||
auto nd=n.shared_from_this(); // make a shared pointer to the node, so that it survives, and we get polymorphism
|
||||
this->slp_under_construction_.AddNumber(nd, next_available_complex_); // register the number with the SLP
|
||||
this->locations_encountered_nodes_[nd] = next_available_complex_++; // add to found symbols in the compiler, increment counter.
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Reset the compiler to compile another SLP from another system.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
size_t next_available_complex_ = 0; //< Where should the next complex number go in memory?
|
||||
size_t next_available_int_ = 0; //< Where should the next integer go?
|
||||
|
||||
using IntT = int; // this needs to co-vary on the stored type inside the node. node should stop using mpz, it's slow.
|
||||
|
||||
std::map<Nd, size_t> locations_encountered_nodes_; //< A registry of pointers-to-nodes and location in memory on where to find *their results*
|
||||
std::map<IntT, size_t> locations_integers_;
|
||||
std::map<Nd, size_t> locations_top_level_functions_and_derivatives_;
|
||||
|
||||
SLP slp_under_construction_; //< the under-construction SLP. will be returned at end of `compile`
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace bertini
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // for the ifndef include guards
|
||||
1908
core/include/bertini2/system/system.hpp
Normal file
1908
core/include/bertini2/system/system.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user