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 Var = std::shared_ptr<node::Variable>;
99 std::vector<std::vector<int>> target_multidegrees,
100 std::vector<std::vector<int>> operand_multidegrees,
102 : operand_(std::move(operand)),
103 coefficients_highest_precision_(std::move(coefficients)),
104 target_multidegrees_(std::move(target_multidegrees)),
105 operand_multidegrees_(std::move(operand_multidegrees)),
106 num_groups_(num_groups),
119 : operand_(other.operand_ ? std::make_shared<SystemT>(*other.operand_) : nullptr),
120 coefficients_highest_precision_(other.coefficients_highest_precision_),
121 coefficients_working_(other.coefficients_working_),
122 target_multidegrees_(other.target_multidegrees_),
123 operand_multidegrees_(other.operand_multidegrees_),
124 num_groups_(other.num_groups_),
125 homogenized_(other.homogenized_),
126 hom_vars_(other.hom_vars_),
127 hom_var_index_(other.hom_var_index_),
128 precision_(other.precision_)
136 operand_ = other.operand_ ? std::make_shared<SystemT>(*other.operand_) :
nullptr;
137 coefficients_highest_precision_ = other.coefficients_highest_precision_;
138 coefficients_working_ = other.coefficients_working_;
139 target_multidegrees_ = other.target_multidegrees_;
140 operand_multidegrees_ = other.operand_multidegrees_;
141 num_groups_ = other.num_groups_;
142 homogenized_ = other.homogenized_;
143 hom_vars_ = other.hom_vars_;
144 hom_var_index_ = other.hom_var_index_;
145 precision_ = other.precision_;
156 size_t NumFunctions()
const {
return static_cast<size_t>(coefficients_highest_precision_.rows()); }
164 for (
size_t i = 0; i < target_multidegrees_.size(); ++i)
165 for (
int e : target_multidegrees_[i])
174 const int g = GroupIndex(vars);
178 for (
size_t i = 0; i < target_multidegrees_.size(); ++i)
179 d[i] = target_multidegrees_[i][
static_cast<size_t>(g)];
204 hom_vars_.push_back(hom_var);
205 if (hom_vars_.size() == num_groups_)
211 hom_var_index_.assign(num_groups_, -1);
212 auto const& ordering = operand_->Variables();
213 for (
size_t g = 0; g < num_groups_; ++g)
214 for (
size_t k = 0; k < ordering.size(); ++k)
215 if (ordering[k] == hom_vars_[g]) { hom_var_index_[g] =
static_cast<int>(k);
break; }
228 if (hom_vars.size() != num_groups_)
229 throw std::invalid_argument(
"RandomizationBlock: " + std::to_string(hom_vars.size())
230 +
" homogenizing variables for " + std::to_string(num_groups_) +
" variable groups");
231 hom_vars_ = std::move(hom_vars);
233 hom_var_index_.assign(num_groups_, -1);
234 auto const& ordering = operand_->Variables();
235 for (
size_t g = 0; g < num_groups_; ++g)
236 for (
size_t k = 0; k < ordering.size(); ++k)
237 if (ordering[k] == hom_vars_[g]) { hom_var_index_[g] =
static_cast<int>(k);
break; }
259 std::vector<Var>
const&
HomVars()
const {
return hom_vars_; }
272 for (
auto& v : hom_vars_)
273 v = std::static_pointer_cast<node::Variable>(
node::Reintern(v, memo));
274 operand_->ReinternNodes(memo);
283 const size_t N =
static_cast<size_t>(coefficients_highest_precision_.cols());
286 out <<
" = R . g (R: " << n <<
"x" << N <<
" randomization matrix)\n";
291 auto g = operand_->NaturalFunctionsAsNodes();
292 const size_t gshown = (verbose || g.size() <= cap) ? g.size() : cap;
293 for (
size_t j = 0; j < gshown; ++j)
294 out <<
" g_" << j <<
" = " << g[j] <<
"\n";
295 if (gshown < g.size())
296 out <<
" ... (" << (g.size() - gshown) <<
" more; describe(verbose=True) for all)\n";
301 auto const& R = coefficients_highest_precision_;
303 const Eigen::Index rcap =
static_cast<Eigen::Index
>(cap);
304 const Eigen::Index rshown = (verbose || R.rows() <= rcap) ? R.rows() : rcap;
306 for (Eigen::Index i = 0; i < rshown; ++i)
309 for (Eigen::Index j = 0; j < R.cols(); ++j)
316 if (rshown < R.rows())
317 out <<
" ... (" << (R.rows() - rshown) <<
" more rows; describe(verbose=True) for all)\n";
331 if (precision_==new_precision)
335 auto& wm = std::get<Mat<complex_mp>>(coefficients_working_);
336 for (Eigen::Index r = 0; r < wm.rows(); ++r)
337 for (Eigen::Index c = 0; c < wm.cols(); ++c)
339 wm(r, c).precision(new_precision);
340 if (new_precision > precision_)
341 wm(r, c) = coefficients_highest_precision_(r, c);
345 precision_ = new_precision;
353 template <
typename T>
357 const size_t N =
static_cast<size_t>(coefficients_highest_precision_.cols());
358 const Vec<T> f = operand_->template Eval<T>(vars).head(
static_cast<Eigen::Index
>(N));
359 const auto& C = Working<T>();
365 for (
size_t j = 0; j < N; ++j)
367 const T& c = C(
static_cast<Eigen::Index
>(i),
static_cast<Eigen::Index
>(j));
370 acc += c * f(
static_cast<Eigen::Index
>(j)) * HPower<T>(i, j, vars);
372 result(
static_cast<Eigen::Index
>(i)) = acc;
383 template <
typename T>
387 const size_t N =
static_cast<size_t>(coefficients_highest_precision_.cols());
388 const Vec<T> f = operand_->template Eval<T>(vars).head(
static_cast<Eigen::Index
>(N));
389 const Mat<T> Jf = operand_->template Jacobian<T>(vars).topRows(
static_cast<Eigen::Index
>(N));
390 const auto& C = Working<T>();
395 for (
size_t j = 0; j < N; ++j)
397 const T& c = C(
static_cast<Eigen::Index
>(i),
static_cast<Eigen::Index
>(j));
401 const T W = HPower<T>(i, j, vars);
403 J.row(
static_cast<Eigen::Index
>(i)) += (c * W) * Jf.row(
static_cast<Eigen::Index
>(j));
408 for (
size_t g = 0; g < num_groups_; ++g)
410 const int e = Deficit(i, j, g);
411 if (e <= 0 || hom_var_index_[g] < 0)
414 const T dW = MixedPartial<T>(i, j, g, vars);
415 J(
static_cast<Eigen::Index
>(i), hom_var_index_[g]) += c * f(
static_cast<Eigen::Index
>(j)) * dW;
425 template <
typename T>
437 template <
typename T>
438 void SyncPrecision(
Vec<T> const& vars)
const
440 if constexpr (!std::is_same<T, complex_dbl>::value)
451 template <
typename T>
452 const Mat<T>& Working()
const {
return std::get<Mat<T>>(coefficients_working_); }
455 template <
typename T>
459 if constexpr (!std::is_same<T, complex_dbl>::value) z.precision(precision_);
464 static bool IsZero(
complex_mp const& c) {
return c.real() == 0 && c.imag() == 0; }
467 int Deficit(
size_t i,
size_t j,
size_t g)
const
469 return target_multidegrees_[i][g] - operand_multidegrees_[j][g];
473 template <
typename T>
474 T HPower(
size_t i,
size_t j,
Vec<T> const& vars)
const
477 if constexpr (!std::is_same<T, complex_dbl>::value) w.precision(precision_);
480 for (
size_t g = 0; g < num_groups_; ++g)
482 const int e = Deficit(i, j, g);
483 if (e == 0 || hom_var_index_[g] < 0)
485 w *= IntPow<T>(vars(hom_var_index_[g]), e);
491 template <
typename T>
492 T MixedPartial(
size_t i,
size_t j,
size_t g,
Vec<T> const& vars)
const
494 const int eg = Deficit(i, j, g);
496 if constexpr (!std::is_same<T, complex_dbl>::value) d.precision(precision_);
497 d *= IntPow<T>(vars(hom_var_index_[g]), eg - 1);
498 for (
size_t g2 = 0; g2 < num_groups_; ++g2)
502 const int e2 = Deficit(i, j, g2);
503 if (e2 == 0 || hom_var_index_[g2] < 0)
505 d *= IntPow<T>(vars(hom_var_index_[g2]), e2);
511 template <
typename T>
512 static T IntPow(T
const& base,
int e)
515 if constexpr (!std::is_same<T, complex_dbl>::value) result.precision(
bertini::Precision(base));
516 for (
int k = 0; k < e; ++k)
524 auto const& groups = operand_->VariableGroups();
525 for (
size_t g = 0; g < groups.size(); ++g)
526 if (SameGroup(groups[g], vars))
527 return static_cast<int>(g);
532 if (a.size() != b.size())
534 for (
size_t k = 0; k < a.size(); ++k)
540 void BuildWorking()
const
542 const auto& M = coefficients_highest_precision_;
543 auto& wd = std::get<Mat<complex_dbl>>(coefficients_working_);
544 auto& wm = std::get<Mat<complex_mp>>(coefficients_working_);
545 wd.resize(M.rows(), M.cols());
546 wm.resize(M.rows(), M.cols());
547 for (Eigen::Index r = 0; r < M.rows(); ++r)
548 for (Eigen::Index c = 0; c < M.cols(); ++c)
557 mutable std::tuple<Mat<complex_dbl>,
Mat<complex_mp>> coefficients_working_;
558 std::vector<std::vector<int>> target_multidegrees_;
559 std::vector<std::vector<int>> operand_multidegrees_;
561 bool homogenized_ =
false;
562 std::vector<Var> hom_vars_;
563 std::vector<int> hom_var_index_;
564 mutable unsigned precision_;
570 template <
typename Archive>
571 void save(Archive& ar,
const unsigned )
const
574 ar & coefficients_highest_precision_;
575 ar & std::get<0>(coefficients_working_);
576 ar & std::get<1>(coefficients_working_);
577 ar & target_multidegrees_;
578 ar & operand_multidegrees_;
586 template <
typename Archive>
587 void load(Archive& ar,
const unsigned )
590 ar & coefficients_highest_precision_;
591 ar & std::get<0>(coefficients_working_);
592 ar & std::get<1>(coefficients_working_);
593 ar & target_multidegrees_;
594 ar & operand_multidegrees_;
602 BOOST_SERIALIZATION_SPLIT_MEMBER()
std::vector< std::vector< int > > const & OperandMultidegrees() const
Get the operand multidegrees (per operand function, per variable group).
Definition randomization_block.hpp:263
unsigned Precision() const
Get the block's current working precision.
Definition randomization_block.hpp:321
void Reintern(node::ReinternMemo &memo)
Re-intern this block's nodes after deserialization (ADR-0042): the homogenizing variables rebuild thr...
Definition randomization_block.hpp:270
RandomizationBlock(RandomizationBlock &&)=default
Move constructor.
RandomizationBlock & operator=(RandomizationBlock &&)=default
Move assignment.
void EvalInPlace(Eigen::Ref< Vec< T > > result, Vec< T > const &vars, T const &) const
Evaluate the randomized function values into a caller-provided segment.
Definition randomization_block.hpp:354
RandomizationBlock(OperandPtr operand, Mat< complex_mp > coefficients, std::vector< std::vector< int > > target_multidegrees, std::vector< std::vector< int > > operand_multidegrees, size_t num_groups)
Definition randomization_block.hpp:97
size_t NumFunctions() const
Number of randomized functions (rows this block contributes) = n.
Definition randomization_block.hpp:156
void Homogenize(VariableGroup const &, Var const &hom_var)
Homogenize: thread the owning system's homogenizing variable for this group into the operand,...
Definition randomization_block.hpp:200
size_t NumGroups() const
Get the number of variable groups the multidegree bookkeeping spans.
Definition randomization_block.hpp:265
RandomizationBlock()
Construct an empty randomization block at the current default precision.
Definition randomization_block.hpp:86
bool DependsOnPathVariable() const
The randomization itself adds no path-variable dependence; it inherits the operand's.
Definition randomization_block.hpp:241
void Describe(std::ostream &out, size_t &row, VariableGroup const &, bool verbose) const
Human-facing description: terse shows 'f_a..f_b = R .
Definition randomization_block.hpp:280
RandomizationBlock(RandomizationBlock const &other)
Memory-isolating copy constructor (deep-copies the operand system; ADR-0027).
Definition randomization_block.hpp:118
bool IsHomogeneous(VariableGroup const &) const
Query whether the randomized system is homogeneous (iff homogenized and the operand is).
Definition randomization_block.hpp:188
std::vector< std::vector< int > > const & TargetMultidegrees() const
Get the target multidegrees (per randomized row, per variable group).
Definition randomization_block.hpp:261
RandomizationBlock & operator=(RandomizationBlock const &other)
Memory-isolating copy assignment (deep-copies the operand system; ADR-0027).
Definition randomization_block.hpp:132
void RestoreHomogenization(std::vector< Var > hom_vars)
Mark the block homogenized with the given homogenizing variables, WITHOUT touching the operand – for ...
Definition randomization_block.hpp:226
std::vector< int > Degrees() const
The randomized functions' degrees: the (total) target degree of each row, i.e.
Definition randomization_block.hpp:161
std::shared_ptr< node::Variable > Var
Shorthand for a shared pointer to a variable node.
Definition randomization_block.hpp:82
Mat< complex_mp > const & RandomizationMatrix() const
The randomization matrix R (master, highest precision); n x N, row i column j is c_ij.
Definition randomization_block.hpp:252
bool IsPolynomial(VariableGroup const &) const
The randomized system is polynomial / homogeneous exactly when the operand is (System's IsPolynomial/...
Definition randomization_block.hpp:186
void JacobianInPlace(Eigen::Ref< Mat< T > > J, Vec< T > const &vars, T const &) const
Evaluate the randomized Jacobian into a caller-provided block.
Definition randomization_block.hpp:384
void Precision(unsigned new_precision) const
Set the working precision: recast the mpfr working coefficients from the master and bring the operand...
Definition randomization_block.hpp:326
void Differentiate() const
Analytic block: nothing symbolic to differentiate (the operand differentiates itself).
Definition randomization_block.hpp:247
friend class boost::serialization::access
Definition randomization_block.hpp:566
OperandPtr const & Operand() const
The overdetermined operand, for the function-tree expansion oracle and the matrix getter.
Definition randomization_block.hpp:250
std::shared_ptr< SystemT > OperandPtr
Shorthand for a shared pointer to the operand system.
Definition randomization_block.hpp:83
std::vector< Var > const & HomVars() const
Get the homogenizing variables accumulated, one per affine variable group.
Definition randomization_block.hpp:259
std::vector< int > Degrees(VariableGroup const &vars) const
Per-group target degree.
Definition randomization_block.hpp:172
void TimeDerivInPlace(Eigen::Ref< Vec< T > > result, Vec< T > const &, T const &) const
Time-derivative.
Definition randomization_block.hpp:426
bool HasConstantJacobian() const
The randomized Jacobian varies in x (operand Jacobian times constants, plus h-power terms).
Definition randomization_block.hpp:244
bool IsHomogenized() const
Query whether the operand has been homogenized.
Definition randomization_block.hpp:257
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 PrintCoeff(std::ostream &out, complex_mp const &c, int sig=0)
Print one (complex_mp) coefficient compactly: a real prints as its real part, a pure imaginary as b*i...
Definition describe.hpp:56
int CoeffSig(bool verbose)
The significant-digit count for coefficient printing: 4 for terse (short and legible),...
Definition describe.hpp:68
constexpr size_t kTerseRowCap
How many function rows a block lists in terse (non-verbose) describe before truncating with a ....
Definition describe.hpp:43
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
constexpr unsigned DoublePrecision()
The number of digits considered "double precision" (16).
Definition num_traits.hpp:152
std::complex< double > complex_dbl
The double-precision complex number type.
Definition double_extensions.hpp:47
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
bmp::number< mpc_complex_backend< 0 >, bmp::et_on > complex_mp
The arbitrary-precision complex number type.
Definition mpfr_complex.hpp:58
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).