64#include <boost/serialization/vector.hpp>
65#include <boost/serialization/shared_ptr.hpp>
66#include <boost/serialization/split_member.hpp>
78template <
typename SystemT>
82 using Nd = std::shared_ptr<node::Node>;
83 using Var = std::shared_ptr<node::Variable>;
94 BlendBlock(
Var path_variable, std::vector<Nd> coefficients, std::vector<OperandPtr> operands)
95 : path_variable_(std::move(path_variable)),
96 coefficients_(std::move(coefficients)),
97 operands_(std::move(operands)),
100 assert(!operands_.empty() &&
"BlendBlock needs at least one operand");
101 assert(coefficients_.size() == operands_.size() &&
"one coefficient per operand");
102 derivative_coefficients_.reserve(coefficients_.size());
103 for (
auto const& c : coefficients_)
104 derivative_coefficients_.push_back(c->Differentiate(path_variable_));
115 : path_variable_(other.path_variable_),
116 coefficients_(other.coefficients_),
117 derivative_coefficients_(other.derivative_coefficients_),
118 precision_(other.precision_)
120 operands_.reserve(other.operands_.size());
121 for (
auto const& op : other.operands_)
122 operands_.push_back(std::make_shared<const SystemT>(*op));
131 path_variable_ = other.path_variable_;
132 coefficients_ = other.coefficients_;
133 derivative_coefficients_ = other.derivative_coefficients_;
134 precision_ = other.precision_;
136 operands_.reserve(other.operands_.size());
137 for (
auto const& op : other.operands_)
138 operands_.push_back(std::make_shared<const SystemT>(*op));
139 coefficient_system_.reset();
152 return operands_.empty() ? 0 : operands_.front()->NumNaturalFunctions();
160 std::vector<OperandPtr>
const&
Operands()
const {
return operands_; }
173 for (
size_t i = 0; i < coefficients_.size(); ++i)
174 out << (i ?
" + " :
"") <<
"(" << coefficients_[i] <<
")*"
175 <<
static_cast<char>(
'A' + (i < 26 ? i : 25));
176 out <<
" (blend of " << operands_.size() <<
" systems)\n";
179 for (
size_t i = 0; i < operands_.size(); ++i)
181 const char label =
static_cast<char>(
'A' + (i < 26 ? i : 25));
182 out <<
" " << label <<
":\n";
183 auto f = operands_[i]->NaturalFunctionsAsNodes();
184 for (
size_t j = 0; j < f.size(); ++j)
185 out <<
" " << label <<
"_" << j <<
" = " << f[j] <<
"\n";
198 return std::max(a, b);
207 for (
auto const& op : operands_)
209 auto od = op->Degrees();
210 for (
size_t i = 0; i < d.size() && i < od.size(); ++i) d[i] =
CombineDegrees(d[i], od[i]);
218 for (
auto const& op : operands_)
220 auto od = op->Degrees(vars);
221 for (
size_t i = 0; i < d.size() && i < od.size(); ++i) d[i] =
CombineDegrees(d[i], od[i]);
234 for (
auto const& op : operands_)
if (!op->IsHomogeneous())
return false;
240 for (
auto const& op : operands_)
if (!op->IsPolynomial())
return false;
260 path_variable_ = std::static_pointer_cast<node::Variable>(
node::Reintern(path_variable_, memo));
261 for (
auto& c : coefficients_)
263 derivative_coefficients_.clear();
264 derivative_coefficients_.reserve(coefficients_.size());
265 for (
auto const& c : coefficients_)
266 derivative_coefficients_.push_back(c->Differentiate(path_variable_));
267 for (
auto& op : operands_)
268 std::const_pointer_cast<SystemT>(op)->ReinternNodes(memo);
269 coefficient_system_.reset();
281 if (precision_==new_precision)
289 precision_ = new_precision;
293 template <
typename T>
298 const Eigen::Index k =
static_cast<Eigen::Index
>(
NumFunctions());
299 const Vec<T> coeffs = EvalCoefficients<T>(path_value);
300 for (
size_t i = 0; i < operands_.size(); ++i)
302 const Vec<T> fi = operands_[i]->template Eval<T>(vars);
303 result += coeffs(
static_cast<Eigen::Index
>(i)) * fi.head(k);
308 template <
typename T>
313 const Eigen::Index k =
static_cast<Eigen::Index
>(
NumFunctions());
314 const Vec<T> coeffs = EvalCoefficients<T>(path_value);
315 for (
size_t i = 0; i < operands_.size(); ++i)
317 const Mat<T> Ji = operands_[i]->template Jacobian<T>(vars);
318 J += coeffs(
static_cast<Eigen::Index
>(i)) * Ji.topRows(k);
323 template <
typename T>
328 const Eigen::Index k =
static_cast<Eigen::Index
>(
NumFunctions());
329 const Vec<T> coeffs = EvalCoefficients<T>(path_value);
330 const size_t n = operands_.size();
331 for (
size_t i = 0; i < n; ++i)
333 const Vec<T> fi = operands_[i]->template Eval<T>(vars);
334 result += coeffs(
static_cast<Eigen::Index
>(n + i)) * fi.head(k);
342 template <
typename T>
343 void SyncPrecision(
Vec<T> const& vars)
const
345 if constexpr (!std::is_same<T, complex_dbl>::value)
361 SystemT& EnsureCoefficientSystem()
const
363 if (!coefficient_system_)
365 auto sys = std::make_shared<SystemT>();
366 for (
auto const& c : coefficients_)
368 for (
auto const& c : derivative_coefficients_)
371 coefficient_system_ = sys;
373 return *coefficient_system_;
377 template <
typename T>
378 Vec<T> EvalCoefficients(T
const& path_value)
const
381 auto& cs = EnsureCoefficientSystem();
383 t_point(0) = path_value;
384 return cs.template Eval<T>(t_point);
388 std::vector<Nd> coefficients_;
389 std::vector<Nd> derivative_coefficients_;
390 std::vector<OperandPtr> operands_;
391 mutable unsigned precision_;
395 mutable std::shared_ptr<SystemT> coefficient_system_;
401 template <
typename Archive>
402 void save(Archive& ar,
const unsigned )
const
407 ar & derivative_coefficients_;
408 std::vector<std::shared_ptr<SystemT>> ops;
409 ops.reserve(operands_.size());
410 for (
auto const& o : operands_)
411 ops.push_back(std::const_pointer_cast<SystemT>(o));
415 template <
typename Archive>
416 void load(Archive& ar,
const unsigned )
421 ar & derivative_coefficients_;
422 std::vector<std::shared_ptr<SystemT>> ops;
424 operands_.assign(ops.begin(), ops.end());
427 BOOST_SERIALIZATION_SPLIT_MEMBER()
BlendBlock & operator=(BlendBlock &&)=default
Move assignment.
BlendBlock(BlendBlock &&)=default
Move constructor.
BlendBlock(Var path_variable, std::vector< Nd > coefficients, std::vector< OperandPtr > operands)
Definition blend_block.hpp:94
void Reintern(node::ReinternMemo &memo)
Re-intern this block's nodes after deserialization (ADR-0042): path variable and coefficient nodes (g...
Definition blend_block.hpp:257
bool DependsOnPathVariable() const
A blend always depends on the path variable (through its coefficients).
Definition blend_block.hpp:245
std::vector< OperandPtr > const & Operands() const
Get the operand systems being blended.
Definition blend_block.hpp:160
unsigned Precision() const
Get the block's current working precision.
Definition blend_block.hpp:273
BlendBlock(BlendBlock const &other)
Memory-isolating copy constructor (deep-copies each operand system; ADR-0027).
Definition blend_block.hpp:114
void EvalInPlace(Eigen::Ref< Vec< T > > result, Vec< T > const &vars, T const &path_value) const
H(x,t) = sum_i c_i(t) * f_i(x) (natural functions only).
Definition blend_block.hpp:294
std::vector< int > Degrees(VariableGroup const &vars) const
Per-function degrees with respect to a given variable group.
Definition blend_block.hpp:215
std::vector< int > Degrees() const
The blend c_0(t)f_0 + c_1(t)f_1 + ... has, per function, the max degree of its operands in the space ...
Definition blend_block.hpp:204
BlendBlock()
Construct an empty blend block at the current default precision.
Definition blend_block.hpp:87
void TimeDerivInPlace(Eigen::Ref< Vec< T > > result, Vec< T > const &vars, T const &path_value) const
dH/dt = sum_i c_i'(t) * f_i(x) (operands are autonomous in t)
Definition blend_block.hpp:324
Var const & PathVariable() const
Get the shared path variable the coefficients are functions of.
Definition blend_block.hpp:162
static int CombineDegrees(int a, int b)
Combine two per-function degrees, propagating the not-a-polynomial sentinel.
Definition blend_block.hpp:194
void JacobianInPlace(Eigen::Ref< Mat< T > > J, Vec< T > const &vars, T const &path_value) const
dH/dx = sum_i c_i(t) * (df_i/dx) (natural rows only)
Definition blend_block.hpp:309
std::vector< Nd > const & Coefficients() const
Accessors for the function-tree expansion (System::ExpandToFunctionTree): the blend is H = sum_i coef...
Definition blend_block.hpp:158
std::shared_ptr< node::Node > Nd
Shorthand for a shared pointer to a generic node.
Definition blend_block.hpp:82
size_t NumFunctions() const
The number of (natural) functions the blend contributes; the owning System adds any patch.
Definition blend_block.hpp:150
void Precision(unsigned new_precision) const
Set the block's working precision (propagated to the operand systems).
Definition blend_block.hpp:276
std::shared_ptr< node::Variable > Var
Shorthand for a shared pointer to a variable node.
Definition blend_block.hpp:83
void Differentiate() const
Analytic block: nothing symbolic to differentiate.
Definition blend_block.hpp:251
void Homogenize(VariableGroup const &, std::shared_ptr< node::Variable > const &)
No-op: a blend's operands are already-prepared and cannot be homogenized.
Definition blend_block.hpp:230
friend class boost::serialization::access
Definition blend_block.hpp:397
bool IsHomogeneous(VariableGroup const &) const
Query whether the blend is homogeneous (iff all operands are).
Definition blend_block.hpp:232
bool HasConstantJacobian() const
A blend does not have a constant Jacobian.
Definition blend_block.hpp:248
void Describe(std::ostream &out, size_t &row, VariableGroup const &, bool verbose) const
Human-facing description: terse shows the blend f_a..f_b = c_0(t)*A + c_1(t)*B, with the coefficient ...
Definition blend_block.hpp:167
bool IsPolynomial(VariableGroup const &) const
Query whether the blend is polynomial (iff all operands are).
Definition blend_block.hpp:238
std::shared_ptr< const SystemT > OperandPtr
Shorthand for a shared pointer to a (const) operand system.
Definition blend_block.hpp:84
BlendBlock & operator=(BlendBlock const &other)
Memory-isolating copy assignment (deep-copies each operand system; ADR-0027).
Definition blend_block.hpp:127
Small shared helpers for the per-block Describe methods – the human-facing printing of a block-compos...
Bertini extensions of the Eigen linear algebra library.
Collects the various header files which define the Bertini2 function tree node types.
void PrintRowLabel(std::ostream &out, size_t row, size_t n)
f_k for a single row, or f_a..f_b for a contiguous range of n rows starting at row.
Definition describe.hpp:71
Definition blend_block.hpp:75
std::map< Node const *, std::shared_ptr< Node > > ReinternMemo
Memo for one re-interning pass: loaded node -> its interned replacement.
Definition reintern.hpp:57
std::shared_ptr< Node > Reintern(std::shared_ptr< Node > const &root, ReinternMemo &memo)
Rebuild the DAG rooted at root through the interning factories (memoized, post-order),...
Definition algorithm_builder.hpp:36
Eigen::Matrix< NumT, Eigen::Dynamic, 1 > Vec
A dynamically-sized column vector of NumT.
Definition eigen_extensions.hpp:296
std::vector< std::shared_ptr< node::Variable > > VariableGroup
An ordered group of variables (the unit of homogenization / variable grouping).
Definition node.hpp:69
Eigen::Matrix< NumT, Eigen::Dynamic, Eigen::Dynamic > Mat
A dynamically-sized matrix of NumT.
Definition eigen_extensions.hpp:298
auto DefaultPrecision()
Get the global default precision (digits) for multiprecision numbers.
Definition mpfr_complex.hpp:135
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object.
Definition eigen_extensions.hpp:339
Provides an Eigen-like NumTraits struct for querying traits of a number type.
Re-intern deserialized node DAGs into the live hash-consing tables (ADR-0042).