Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
system.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//system.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8//system.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with system.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// Copyright(C) Bertini2 Development Team
17//
18// See <http://www.gnu.org/licenses/> for a copy of the license,
19// as well as COPYING. Bertini2 is provided with permitted
20// additional terms in the b2/licenses/ directory.
21
27
28#ifndef BERTINI_SYSTEM_HPP
29#define BERTINI_SYSTEM_HPP
30
31#include <assert.h>
32#include <optional>
33#include <vector>
34#include <set>
35#include <string>
36
37
38#include <boost/archive/text_oarchive.hpp>
39#include <boost/archive/text_iarchive.hpp>
40#include <boost/serialization/export.hpp>
41#include <boost/serialization/shared_ptr.hpp>
42#include <boost/serialization/vector.hpp>
43#include <boost/serialization/deque.hpp>
44#include <boost/serialization/std_variant.hpp>
45#include <boost/type_index.hpp>
46
50
51
57
60
61#include <boost/archive/binary_oarchive.hpp>
62#include <boost/archive/binary_iarchive.hpp>
63#include <boost/iostreams/stream_buffer.hpp>
64#include <boost/iostreams/stream.hpp>
65#include <boost/iostreams/device/back_inserter.hpp>
66
67namespace bertini {
68
69 // (included above) so the evaluation blocks can see them.
70
71 namespace node { struct EncodingContext; } // function_tree/canonical_encoding.hpp (ADR-0042)
72
73 class Slice; // system/slice.hpp -- a thin wrapper over a LinearFormsBlock; System::Slices()
74 // recovers them from a slice-derived system without binding the block variant.
75
84 {
85 std::vector<std::shared_ptr<node::Node>> entries;
86 size_t rows = 0;
87 size_t cols = 0;
88 };
89
96 NodeMatrix SymbolicJacobian(std::vector<std::shared_ptr<node::Node>> const& functions,
97 VariableGroup const& variables);
98
106 class System{
107
108 public:
109 // a few local using statements to reduce typing etc.
110 using NE = std::shared_ptr<node::NamedExpression>;
111 using Var = std::shared_ptr<node::Variable>;
112 using Nd = std::shared_ptr<node::Node>;
113
117 System() : have_path_variable_(false), is_patched_(false), is_differentiated_(false), have_ordering_(false)
118 {}
119
131 explicit
132 System(std::vector<Nd> const& functions);
133
137 explicit
138 System(std::string const& input);
139
143 System(System const& other);
144
148 System(System && other) : System()
149 {
150 swap(*this, other);
151 }
152
156 System& operator=(const System & other);
157
161 System& operator=(System && other) = default;
162
166 friend void swap(System & a, System & b);
167
168 // There is deliberately NO way to set a precision on a System, and nothing to fan out.
169 // Every evaluable type -- each block, the patch, the SLP -- self-aligns to the precision
170 // of the point it is handed, under SyncPrecision. See ADR-0057.
171
172 // There is deliberately NO precision() accessor. A System carries no precision of its
173 // own: evaluation happens at the precision of the point it is handed, and the objects
174 // that actually hold multiprecision values -- each block's working coefficients, the
175 // patch, the SLP's memory -- each keep their own "materialized at" tag and short-circuit
176 // when already there. A System-level copy was a duplicate of those, and exposing it
177 // invited callers to read it, compute a target, and hand it back, which is exactly the
178 // hand-alignment ADR-0057 removes.
179
183 void Differentiate() const;
184
202 NodeMatrix SymbolicJacobian(bool usercoordinates = true) const;
203
204
212 template<typename T>
213 void EvalInPlace(Vec<T> & function_values) const
214 {
215
216 if (function_values.size() != static_cast<Eigen::Index>(NumTotalFunctions()))
217 {
218 std::stringstream ss;
219 ss << "trying to evaluate system in-place, but number length of vector into which to write the values (" << function_values.size() << ") doesn't match number of system user-defined functions plus patches ( " << NumNaturalFunctions() << "+" << NumPatches() << ") = " << NumTotalFunctions() << "). Use System.NumTotalFunctions() to make the container for in-place evaluation";
220 throw std::runtime_error(ss.str());
221 }
222
223 if (!is_differentiated_)
224 Differentiate(); // syncs + (for the polynomial block) compiles the SLP
225
226 EvalBlocksInPlace<T>(function_values);
227 if (IsPatched())
228 patch_.EvalInPlace(function_values,
229 std::get<Vec<T> >(current_variable_values_));
230 CoerceBlockOutputPrecision(function_values);
231 }
232
233
234
235
236
244 template<typename T>
245 Vec<T> Eval() const
246 {
247 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
248 EvalInPlace(function_values);
249
250 return function_values;
251 }
252
253
254
255
267 template<typename T, typename Derived>
268 void EvalInPlace(Vec<T>& function_values, const Eigen::MatrixBase<Derived>& variable_values) const
269 {
270 static_assert(std::is_same<typename Derived::Scalar,T>::value,"scalar types must match");
271
272 if (variable_values.size()!=static_cast<Eigen::Index>(NumVariables()))
273 {
274 std::stringstream ss;
275 ss << "trying to evaluate system, but number of input variables (" << variable_values.size() << ") doesn't match number of system variables (" << NumVariables() << ").";
276 throw std::runtime_error(ss.str());
277 }
278 if (have_path_variable_)
279 throw std::runtime_error("not using a time value for evaluation of system, but path variable IS defined.");
280
281 SetVariables(variable_values.eval());
282 EvalInPlace(function_values);
283 }
284
285
286
287
298 template<typename Derived>
299 typename Derived::PlainObject Eval(const Eigen::MatrixBase<Derived>& variable_values) const
300 {
301 typedef typename Derived::Scalar T;
302
303 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
304 EvalInPlace(function_values, variable_values);
305 return function_values;
306
307 }
308
316 template<typename T>
317 Vec<T> Eval(const Vec<T> & variable_values) const
318 {
319 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
320 EvalInPlace(function_values, variable_values);
321 return function_values;
322 }
323
324
325
326
327
340 template<typename Derived, typename T>
341 void EvalInPlace(Vec<T> & function_values, const Eigen::MatrixBase<Derived>& variable_values, const T & path_variable_value) const
342 {
343 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
344
345 if (variable_values.size()!=static_cast<Eigen::Index>(NumVariables()))
346 throw std::runtime_error("trying to evaluate system, but number of variables doesn't match.");
347 if (!have_path_variable_)
348 throw std::runtime_error("trying to use a time value for evaluation of system, but no path variable defined.");
349
350 SetVariables(variable_values.eval());
351 SetPathVariable(path_variable_value);
352
353
354 EvalInPlace(function_values);
355 }
356
357
358
359
360
361
362
363
364
376 template<typename Derived, typename T>
377 Vec<T> Eval(const Eigen::MatrixBase<Derived>& variable_values, const T & path_variable_value) const
378 {
379 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
380 EvalInPlace(function_values, variable_values, path_variable_value);
381 return function_values;
382 }
383
384
393 template<typename T>
394 Vec<T> Eval(const Vec<T> & variable_values, const T & path_variable_value) const
395 {
396 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
397 EvalInPlace(function_values, variable_values, path_variable_value);
398 return function_values;
399 }
400
401
402
412 template <typename T>
413 void JacobianInPlace(Mat<T> & J) const
414 {
415
416
417 if(J.rows() != static_cast<Eigen::Index>(NumTotalFunctions()) || J.cols() != static_cast<Eigen::Index>(NumVariables()))
418 {
419 throw std::runtime_error("trying to evaluate jacobian of system in place, but input J doesn't have right number of columns or rows");
420 }
421
422 if (!is_differentiated_)
424
425 JacobianBlocksInPlace<T>(J);
426 if (IsPatched())
427 patch_.JacobianInPlace(J, std::get<Vec<T> >(current_variable_values_));
428 CoerceBlockOutputPrecision(J);
429 }
430
431
432
433
434
435
436
437
443 template<typename T>
445 {
446
449
450 return J;
451 }
452
453
454
455
465 template<typename T>
466 void JacobianInPlace(Mat<T> & J, const Vec<T> & variable_values) const
467 {
468
469 if (variable_values.size()!=static_cast<Eigen::Index>(NumVariables()))
470 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
471
472 if (HavePathVariable())
473 throw std::runtime_error("not using a time value for computation of jacobian, but a path variable is defined.");
474
475 SetAndReset(variable_values);
476
478 }
479
480
481
482
483
484
493 template<typename T>
494 Mat<T> Jacobian(const Vec<T> & variable_values) const
495 {
496 if (variable_values.size()!=static_cast<Eigen::Index>(NumVariables()))
497 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
498
499 if (HavePathVariable())
500 throw std::runtime_error("not using a time value for computation of jacobian, but a path variable is defined.");
501
503 JacobianInPlace(J,variable_values);
504 return J;
505 }
506
507
508
509
521 template<typename Derived, typename T>
522 void JacobianInPlace(Mat<T> & J, const Eigen::MatrixBase<Derived> & variable_values, const T & path_variable_value) const
523 {
524 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
525
526 if (variable_values.size()!=static_cast<Eigen::Index>(NumVariables()))
527 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
528
529 if (!HavePathVariable())
530 throw std::runtime_error("trying to use a time value for computation of jacobian, but no path variable defined.");
531
532 SetVariables(variable_values.eval());
533 SetPathVariable(path_variable_value);
535 }
536
537
538
539
540
552 template<typename Derived, typename T>
553 Mat<T> Jacobian(const Eigen::MatrixBase<Derived> & variable_values, const T & path_variable_value) const
554 {
555 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
556
557 if (variable_values.size()!=NumVariables())
558 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
559
560 if (!HavePathVariable())
561 throw std::runtime_error("trying to use a time value for computation of jacobian, but no path variable defined.");
562
564 JacobianInPlace(J,variable_values, path_variable_value);
565 return J;
566 }
567
568
577 template<typename T>
578 Mat<T> Jacobian(const Vec<T> & variable_values, const T & path_variable_value) const
579 {
580 if (variable_values.size()!=static_cast<Eigen::Index>(NumVariables()))
581 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
582
583 if (!HavePathVariable())
584 throw std::runtime_error("using a time value for computation of jacobian, but no path variable is defined.");
585
587 JacobianInPlace(J,variable_values,path_variable_value);
588 return J;
589 }
590
591
600 template<typename Derived, typename T>
602 const Eigen::MatrixBase<Derived> & variable_values,
603 const T & path_variable_value) const
604 {
605 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
606
607 SetVariables(variable_values.eval());
608 SetPathVariable(path_variable_value);
610 }
611
612
613
614
615
616
625 template<typename Derived, typename T>
626 Vec<T> TimeDerivative(const Eigen::MatrixBase<Derived> & variable_values, const T & path_variable_value) const
627 {
628 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
629
630 Vec<T> ds_dt(NumTotalFunctions());
631 TimeDerivativeInPlace(ds_dt, variable_values, path_variable_value);
632 return ds_dt;
633 }
634
635
636
637
638
639
640
641
649 template<typename Derived, typename T>
651 const Eigen::MatrixBase<Derived> & variable_values) const
652 {
653 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
654
655 SetVariables(variable_values.eval());
657 }
658
659
660
661
662
663
672 template<typename Derived, typename T>
673 Vec<T> TimeDerivative(const Eigen::MatrixBase<Derived> & variable_values) const
674 {
675 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
676
677 Vec<T> ds_dt(NumTotalFunctions());
678 TimeDerivativeInPlace(ds_dt, variable_values);
679 return ds_dt;
680 }
681
682
690 template<typename T>
691 void TimeDerivativeInPlace(Vec<T> & ds_dt) const
692 {
693
694 if(ds_dt.size() < static_cast<Eigen::Index>(NumNaturalFunctions()))
695 {
696 std::stringstream ss;
697 ss << "trying to evaluate system in place, but number of input functions (" << ds_dt.size() << ") doesn't match number of system functions (" << NumNaturalFunctions() << ").";
698 throw std::runtime_error(ss.str());
699 }
700
701 if (!HavePathVariable())
702 throw std::runtime_error("computing time derivative of system with no path variable defined");
703
704 if (!is_differentiated_)
706
707 TimeDerivBlocksInPlace<T>(ds_dt);
708 // the patch doesn't move with time. derivatives 0.
709 if (IsPatched())
710 for (size_t ii = 0; ii < NumTotalVariableGroups(); ++ii)
711 ds_dt(static_cast<Eigen::Index>(ii + NumNaturalFunctions())) = T(0);
712 CoerceBlockOutputPrecision(ds_dt);
713 }
714
715
716
717
718
719
728 template<typename T>
730 {
731 if (!HavePathVariable())
732 throw std::runtime_error("computing time derivative of system with no path variable defined");
733
734 Vec<T> ds_dt(NumTotalFunctions());
736 return ds_dt;
737 }
738
745
756 void Homogenize(VariableGroup const& provided_hom_vars);
757
764 bool IsHomogeneous() const;
765
772 bool IsPolynomial() const;
773
774
776 //
777 // Nummers -- functions which get the numbers of things.
778 //
780
781
785 size_t NumNaturalFunctions() const;
786
790 size_t NumPatches() const
791 {
792 return patch_.NumVariableGroups();
793 }
794
798 size_t NumTotalFunctions() const;
799
803 size_t NumVariables() const;
804
808 size_t NumNaturalVariables() const;
809
813 size_t NumHomVariables() const;
814
819 VariableGroup const& HomogenizingVariables() const { return homogenizing_variables_; }
820
825 VariableGroup const& UngroupedVariables() const { return ungrouped_variables_; }
826
831
835 size_t NumVariableGroups() const;
836
837
841 size_t NumUngroupedVariables() const;
842
846 size_t NumHomVariableGroups() const;
847
848
852 size_t NumConstants() const;
853
857 size_t NumParameters() const;
858
859
863 size_t NumImplicitParameters() const;
864
865
866
867
868
870 //
871 // Setters -- templated.
872 //
874
893 template<typename T>
894 void SetVariables(const Vec<T> & new_values) const
895 {
896 if (new_values.size()!= static_cast<Eigen::Index>(NumVariables()))
897 {
898 throw std::runtime_error("variable vector of different length from system-owned variables in SetVariables");
899 }
900
901 // ALIGN to the incoming point rather than refusing it (#377). A System's
902 // precision is not an invariant the caller must maintain by hand: the caller's
903 // intent is always just "evaluate f at x", and x carries the precision that
904 // evaluation should happen at. Aligning here pushes the new precision down to
905 // every block (each block re-tags its SLP's memory and rebuilds its constants
906 // from their exact recipes), to the stored path value, and to the patch, so the
907 // whole System is consistent for the evaluation that follows.
908 //
909 // Refusing was not merely unergonomic, it was inescapable in one direction: a
910 // block's SLP takes its memory precision from the ambient DefaultPrecision() at
911 // lazy compile time while the System keeps whatever it was told, and once those
912 // diverge, System::precision(n) cannot repair it -- both it and
913 // StraightLineProgram::precision(n) short-circuit when handed the value they
914 // already hold. See the SLP-side note in SetVariableValues.
915 //
916 // Deliberately NOT behind BERTINI_DISABLE_PRECISION_CHECKS: this is required
917 // behaviour, not a debug assertion. A system with no variables (a constant) has
918 // an empty point and so carries no precision to read.
919 // NO fan-out. Every evaluable type self-aligns from the point it is handed --
920 // each block, the patch and the SLP all do it under SyncPrecision -- so there is
921 // nothing to push down from here and nothing to keep in sync (ADR-0057).
922
923 // Blocks are value-in: the polynomial block feeds this stored vector into its SLP, the
924 // structured blocks compute on it directly, and the patch reads it too (see
925 // EvalBlocksInPlace). The shared Variable nodes are no longer written during evaluation
926 // (ADR-0027), so the node DAG stays read-only across threads.
927 std::get<Vec<T> >(current_variable_values_) = new_values;
928 }
929
930
931
940 template<typename T>
941 void SetPathVariable(T const& new_value) const
942 {
943 if (!have_path_variable_)
944 throw std::runtime_error("trying to set the value of the path variable, but one is not defined for this system");
945
946 // Store the path value in the System's own per-thread buffer, NOT the shared node.
947 // Blocks are value-in and receive the path value as an argument (see EvalBlocksInPlace /
948 // CurrentPathValue), so the path-variable node is never read during evaluation (ADR-0027).
949 std::get<T>(current_path_value_) = new_value;
950 }
951
952
963 template<typename T>
964 void SetAndReset(Vec<T> const& new_space, T const& new_time) const
965 {
966 SetVariables(new_space);
967 SetPathVariable(new_time);
968 }
969
976 template<typename T>
977 void SetAndReset(Vec<T> const& new_space) const
978 {
979 SetVariables(new_space);
980 }
981
982
983
984
985
986
987
988
989
991 //
992 // Adders -- functions which add things to the system.
993 //
995
996
1003
1004
1015 void SetVariableGroups(std::vector<VariableGroup> const& groups);
1016
1017
1024
1025
1026
1033
1034
1041
1042
1049
1050
1057
1058
1059
1060
1066 void AddParameter(NE const& F);
1067
1068
1069
1075 void AddFunction(Nd const& F);
1076
1077
1083 void AddFunctions(std::vector<Nd> const& F);
1084
1092 void AddBlock(Block b) { ThrowIfSealed("AddBlock"); blocks_.push_back(std::move(b)); }
1093
1097 std::vector<Block> const& Blocks() const { return blocks_; }
1098
1103 std::vector<Slice> Slices() const;
1104
1110 {
1111 ThrowIfSealed("ClearFunctions");
1112 for (auto it = blocks_.begin(); it != blocks_.end(); )
1113 {
1114 if (std::holds_alternative<blocks::PolynomialBlock>(*it))
1115 it = blocks_.erase(it);
1116 else
1117 ++it;
1118 }
1119 InvalidateDifferentiation();
1120 }
1121
1123 bool HasBlocks() const { return !blocks_.empty(); }
1124
1130 {
1131 for (auto const& b : blocks_)
1132 if (!std::holds_alternative<blocks::PolynomialBlock>(b))
1133 return true;
1134 return false;
1135 }
1136
1139 void ClearBlocks() { ThrowIfSealed("ClearBlocks"); blocks_.clear(); }
1140
1141
1143 //
1144 // content identity (ADR-0042)
1145 //
1147
1159 std::string CanonicalEncodingText() const;
1160
1181 static System FromCanonicalEncoding(std::string const& text);
1182
1190
1196 std::size_t Hash() const;
1197
1204 bool IsSame(System const& other) const;
1205
1216 void Seal();
1217
1219 bool IsSealed() const;
1220
1239
1250
1254 std::vector<Nd> NaturalFunctionsAsNodes() const;
1255
1256
1278
1295 System Randomize(int codimension) const;
1296
1305
1313
1314
1315
1316
1317
1318
1319
1325 void AddConstant(NE const& C);
1326
1327
1328
1329
1335 void AddPathVariable(Var const& v);
1336
1337
1343 bool HavePathVariable() const;
1344
1346 const Var& GetPathVariable() const;
1347
1362 std::set<std::string> VariableNameSet() const;
1363
1376
1377
1383 const VariableGroup& Variables() const;
1384
1390 VariableGroup const& AffineVariableGroup(size_t index) const
1391 {
1392 return variable_groups_[index];
1393 }
1394
1397 std::vector<unsigned> VariableGroupSizes() const
1398 {
1399 return VariableGroupSizesFIFO();
1400 }
1401
1409 template<typename T>
1411 {
1412
1413 if (x.size()!=static_cast<Eigen::Index>(NumVariables())){
1414 std::stringstream message;
1415 message << "dehomogenizing point with incorrect number of coordinates. input has ";
1416 message << x.size();
1417 message << " but system expects ";
1418 message << NumVariables();
1419 throw std::runtime_error(message.str());
1420 }
1421
1422 if (!have_ordering_)
1423 ConstructOrdering();
1424
1425 return DehomogenizePointFIFO(x);
1426 }
1427
1428
1442 template<typename T>
1444 {
1445 auto const d = DehomogenizePoint(x);
1447 return d.template lpNorm<Eigen::Infinity>();
1448
1449 // the value type, not decltype(abs(...)): a multiprecision abs() is an expression
1450 // template, and a variable of that type cannot be reassigned in the loop
1451 using std::abs;
1452 using RealT = typename NumTraits<T>::Real;
1453 RealT biggest{0};
1454 for (Eigen::Index k{0}; k < d.size(); ++k)
1455 if (!CoordinateIsAuxiliary(static_cast<unsigned>(k)))
1456 {
1457 RealT const a = abs(d(k));
1458 if (a > biggest) biggest = a;
1459 }
1460 return biggest;
1461 }
1462
1463
1479 template<typename T, typename R>
1480 bool IsFinite(Vec<T> const& x, R const& threshold) const
1481 {
1482 return InfinityNormOfDehomogenized(x) <= threshold;
1483 }
1484
1485
1499 template<typename T, typename R>
1500 bool IsReal(Vec<T> const& x, R const& threshold) const
1501 {
1502 using std::abs; using std::imag;
1503 using RealT = typename NumTraits<T>::Real;
1504 auto const d = DehomogenizePoint(x);
1505 RealT biggest{0};
1506 for (Eigen::Index k{0}; k < d.size(); ++k)
1507 if (!CoordinateIsAuxiliary(static_cast<unsigned>(k)))
1508 {
1509 RealT const a = abs(imag(d(k)));
1510 if (a > biggest) biggest = a;
1511 }
1512 return biggest <= threshold;
1513 }
1514
1515
1536 void SetAuxiliaryVariableGroups(std::vector<unsigned> groups);
1537
1538
1552 void SetAuxiliaryCoordinates(std::vector<unsigned> coordinates);
1553
1554
1556 std::vector<unsigned> const& AuxiliaryVariableGroups() const
1557 {
1558 return auxiliary_variable_groups_;
1559 }
1560
1562 std::vector<unsigned> const& AuxiliaryCoordinates() const
1563 {
1564 return auxiliary_coordinates_;
1565 }
1566
1569 {
1570 return !auxiliary_variable_groups_.empty() || !auxiliary_coordinates_.empty();
1571 }
1572
1579 bool CoordinateIsAuxiliary(unsigned index) const;
1580
1584
1585
1603 template<typename T>
1605 {
1606
1607 if (x.size()!=static_cast<Eigen::Index>(NumNaturalVariables())){
1608 std::stringstream message;
1609 message << "homogenizing point with incorrect number of coordinates. input has ";
1610 message << x.size();
1611 message << " but system expects ";
1612 message << NumNaturalVariables();
1613 throw std::runtime_error(message.str());
1614 }
1615
1616 if (!have_ordering_)
1617 ConstructOrdering();
1618
1619 auto x_homogenized = HomogenizePointFIFO(x);
1620
1621 if (IsPatched())
1622 RescalePointToFitPatchInPlace(x_homogenized);
1623
1624 return x_homogenized;
1625 }
1626
1627
1628
1629
1645 auto Function(unsigned index) const
1646 {
1647 auto fns = GetFunctions();
1648 if (index >= fns.size())
1649 throw std::out_of_range("System::Function index out of range");
1650 return fns[index];
1651 }
1652
1653
1661 std::vector<Nd> GetNaturalFunctions() const
1662 {
1663 return NaturalFunctionsAsNodes();
1664 }
1665
1666
1674 std::vector<Nd> GetFunctions() const
1675 {
1676 auto fns = NaturalFunctionsAsNodes();
1677 auto patches = PatchFunctionsAsNodes();
1678 fns.insert(fns.end(), patches.begin(), patches.end());
1679 return fns;
1680 }
1681
1682
1690 std::vector<Nd> PatchFunctionsAsNodes() const;
1691
1692
1702 void CopyFunctions(System const& other)
1703 {
1705 }
1706
1707
1717 unsigned FIFOIndexOfGroup(VariableGroup const& g) const
1718 {
1719 unsigned affine_counter = 0, hom_counter = 0, fifo_i = 0;
1720 for (auto const& iter : time_order_of_variable_groups_)
1721 {
1722 bool match = false;
1723 switch (iter)
1724 {
1725 case VariableGroupType::Affine: match = (variable_groups_[affine_counter++] == g); break;
1726 case VariableGroupType::Homogeneous: match = (hom_variable_groups_[hom_counter++] == g); break;
1727 case VariableGroupType::Ungrouped: break;
1728 default: throw std::runtime_error("unacceptable VariableGroupType in FIFOIndexOfGroup");
1729 }
1730 if (match)
1731 return fifo_i;
1732 ++fifo_i;
1733 }
1734 throw std::runtime_error("FIFOIndexOfGroup: the given variable group is not a group of this system");
1735 }
1736
1737
1753 template<typename T>
1754 Vec<T> CoordinatesOfGroup(Vec<T> const& user_point, unsigned group_fifo_index) const
1755 {
1756 auto const span = SpanOfGroup(group_fifo_index);
1757 if (span.first + span.second > static_cast<unsigned>(user_point.size()))
1758 throw std::runtime_error("CoordinatesOfGroup: point is shorter than the system's variable structure implies");
1759 return user_point.segment(span.first, span.second);
1760 }
1761
1762
1773 std::pair<unsigned, unsigned> SpanOfGroup(unsigned group_fifo_index) const
1774 {
1775 unsigned affine_counter = 0, hom_counter = 0, fifo_i = 0, offset = 0;
1776 for (auto const& iter : time_order_of_variable_groups_)
1777 {
1778 unsigned group_size;
1779 switch (iter)
1780 {
1781 case VariableGroupType::Affine: group_size = static_cast<unsigned>(variable_groups_[affine_counter++].size()); break;
1782 case VariableGroupType::Homogeneous: group_size = static_cast<unsigned>(hom_variable_groups_[hom_counter++].size()); break;
1783 case VariableGroupType::Ungrouped: group_size = 1; break;
1784 default: throw std::runtime_error("unacceptable VariableGroupType in SpanOfGroup");
1785 }
1786 if (fifo_i == group_fifo_index)
1787 return {offset, group_size};
1788 offset += group_size;
1789 ++fifo_i;
1790 }
1791 throw std::out_of_range("SpanOfGroup: group index out of range");
1792 }
1793
1794
1795
1799 auto VariableGroups() const
1800 {
1801 return variable_groups_;
1802 }
1803
1808 {
1809 return hom_variable_groups_;
1810 }
1811
1812
1814 const Var& PathVariable() const
1815 {
1816 return path_variable_;
1817 }
1818
1819
1831 std::vector< Nd > GetSpaceDerivatives() const;
1832
1838 std::vector< Nd > GetTimeDerivatives() const;
1839
1840
1842 //
1843 // Functions involving coefficients of the system
1844 //
1846
1847
1854 template <typename NumT>
1855 typename Eigen::NumTraits<NumT>::Real CoefficientBound(unsigned num_evaluations = 1) const;
1856
1857
1858
1864 int DegreeBound() const;
1865
1871 std::vector<int> Degrees() const;
1872
1879 std::vector<int> Degrees(VariableGroup const& vars) const;
1880
1885
1886
1891
1892
1893
1894
1895
1897 //
1898 // Functions regarding patches.
1899 //
1901
1902
1903
1904
1905
1914 {
1915 AutoPatchFIFO();
1916 }
1917
1921 void CopyPatches(System const& other);
1922
1923
1926 {
1927 return patch_;
1928 }
1929
1933 bool IsPatched() const
1934 {
1935 return is_patched_;
1936 }
1937
1938
1943 template <typename T>
1945 {
1946 return patch_.RescalePoint(x);
1947 }
1948
1949
1953 template<typename T>
1955 {
1956 patch_.RescalePointToFitInPlace(x);
1957 }
1958
1966 void Describe(std::ostream& out, bool verbose = false) const;
1967
1971 friend std::ostream& operator <<(std::ostream& out, const System & s);
1972
1973
1978
1979
1980
1981
1982
1983
1993 void CopyVariableStructure(System const& other);
1994
1995 // The Please/Dont AssumeUniformPrecision family was removed: the setter had
1996 // ignored its argument (always storing false) for ages, so the early-out it was
1997 // meant to enable was dead code, and skipping the propagation is unsound anyway.
1998 // A System no longer carries a precision at all, and there is nothing to fan out
1999 // (ADR-0057): every evaluable type self-aligns to the point it is handed.
2000
2007
2014
2020 void Simplify();
2021
2022
2023
2024
2025
2034
2042 friend const System operator+(System lhs, System const& rhs);
2043
2050
2056 friend const System operator*(System s, Nd const& N);
2057
2063 friend const System operator*(Nd const& N, System const& s);
2064 private:
2065
2069 System AssembleRandomized(std::shared_ptr<System> operand, Mat<complex_mp> coefficients) const;
2070
2079 Mat<complex_mp> BuildRandomizationMatrix(std::shared_ptr<System> operand, std::size_t codimension) const;
2080
2084 std::vector<unsigned> VariableGroupSizesFIFO() const;
2085
2086
2090 void AutoPatchFIFO();
2091
2092
2093
2101 template<typename T>
2102 Vec<T> DehomogenizePointFIFO(Vec<T> const& x) const
2103 {
2104 #ifndef BERTINI_DISABLE_ASSERTS
2105 assert(homogenizing_variables_.size()==0 || homogenizing_variables_.size()==NumVariableGroups() && "must have either 0 homogenizing variables, or the number of homogenizing variables must match the number of affine variable groups.");
2106 #endif
2107
2108 bool is_homogenized = homogenizing_variables_.size()!=0;
2109 Vec<T> x_dehomogenized(NumNaturalVariables());
2110
2111 unsigned affine_group_counter = 0;
2112 unsigned hom_group_counter = 0;
2113
2114 unsigned hom_index = 0; // index into x, the point we are dehomogenizing
2115 unsigned dehom_index = 0; // index into x_dehomogenized, the point we are computing
2116
2117 for (auto& iter : time_order_of_variable_groups_)
2118 {
2119 switch (iter){
2121 {
2122 if (is_homogenized)
2123 {
2124 auto h = x(hom_index++);
2125 for (unsigned ii = 0; ii < variable_groups_[affine_group_counter].size(); ++ii)
2126 x_dehomogenized(dehom_index++) = x(hom_index++) / h;
2127 affine_group_counter++;
2128 }
2129 else
2130 {
2131 for (unsigned ii = 0; ii < variable_groups_[affine_group_counter].size(); ++ii)
2132 x_dehomogenized(dehom_index++) = x(hom_index++);
2133 }
2134 break;
2135 }
2137 {
2138 for (unsigned ii = 0; ii < hom_variable_groups_[hom_group_counter].size(); ++ii)
2139 x_dehomogenized(dehom_index++) = x(hom_index++);
2140 hom_group_counter++; // was missing; mattered only for multiple hom groups of differing sizes
2141 break;
2142 }
2144 {
2145 x_dehomogenized(dehom_index++) = x(hom_index++);
2146 break;
2147 }
2148 default:
2149 {
2150 throw std::runtime_error("unacceptable VariableGroupType in FIFOVariableOrdering");
2151 }
2152 }
2153 }
2154
2155 return x_dehomogenized;
2156 }
2157
2158
2165 template<typename T>
2166 Vec<T> HomogenizePointFIFO(Vec<T> const& x) const
2167 {
2168 #ifndef BERTINI_DISABLE_ASSERTS
2169 assert(homogenizing_variables_.size()==0 || homogenizing_variables_.size()==NumVariableGroups() && "must have either 0 homogenizing variables, or the number of homogenizing variables must match the number of affine variable groups.");
2170 #endif
2171
2172 bool is_homogenized = homogenizing_variables_.size()!=0;
2173 if (!is_homogenized)
2174 return x;
2175
2176 Vec<T> x_homogenized(NumVariables());
2177
2178 unsigned affine_group_counter = 0;
2179 unsigned hom_group_counter = 0;
2180
2181 unsigned dehom_index = 0; // index into x, the user-coordinates point
2182 unsigned hom_index = 0; // index into x_homogenized, the point we are computing
2183
2184 for (auto& iter : time_order_of_variable_groups_)
2185 {
2186 switch (iter){
2188 {
2189 x_homogenized(hom_index++) = T(1);
2190 for (unsigned ii = 0; ii < variable_groups_[affine_group_counter].size(); ++ii)
2191 x_homogenized(hom_index++) = x(dehom_index++);
2192 affine_group_counter++;
2193 break;
2194 }
2196 {
2197 for (unsigned ii = 0; ii < hom_variable_groups_[hom_group_counter].size(); ++ii)
2198 x_homogenized(hom_index++) = x(dehom_index++);
2199 hom_group_counter++;
2200 break;
2201 }
2203 {
2204 x_homogenized(hom_index++) = x(dehom_index++);
2205 break;
2206 }
2207 default:
2208 {
2209 throw std::runtime_error("unacceptable VariableGroupType in HomogenizePointFIFO");
2210 }
2211 }
2212 }
2213
2214 return x_homogenized;
2215 }
2216
2217 // --- the System's polynomial block (its functions live here after the fold) ---
2218
2220 blocks::PolynomialBlock& PolyBlock()
2221 {
2222 for (auto& b : blocks_)
2223 if (auto* p = std::get_if<blocks::PolynomialBlock>(&b))
2224 return *p;
2225 blocks_.emplace_back(blocks::PolynomialBlock{});
2226 return std::get<blocks::PolynomialBlock>(blocks_.back());
2227 }
2228
2231 blocks::PolynomialBlock const* PolyBlockPtr() const
2232 {
2233 for (auto const& b : blocks_)
2234 if (auto* p = std::get_if<blocks::PolynomialBlock>(&b))
2235 return p;
2236 return nullptr;
2237 }
2238
2240 std::vector<Nd> const& PolyFunctions() const
2241 {
2242 static const std::vector<Nd> none;
2243 auto* p = PolyBlockPtr();
2244 return p ? p->Functions() : none;
2245 }
2246
2248 void InvalidateDifferentiation() const
2249 {
2250 is_differentiated_ = false;
2251 if (auto* p = PolyBlockPtr())
2252 p->Invalidate();
2253 }
2254
2258 void SyncPolyBlock() const
2259 {
2260 if (auto* p = PolyBlockPtr())
2261 {
2262 p->SetVariableOrdering(Variables());
2263 if (have_path_variable_) p->SetPathVariable(path_variable_);
2264 else p->ClearPathVariable();
2265 }
2266 }
2267
2271 void ConstructOrdering() const;
2272
2274 template <typename T>
2275 T CurrentPathValue() const
2276 {
2277 if (have_path_variable_)
2278 return std::get<T>(current_path_value_);
2279 return T(0);
2280 }
2281
2297 template <typename Derived>
2298 void CoerceBlockOutputPrecision(Eigen::MatrixBase<Derived>& result) const
2299 {
2300 using Scalar = typename Derived::Scalar;
2301 if constexpr (!std::is_same<Scalar, complex_dbl>::value)
2302 {
2303 using bertini::Precision;
2304 // the working precision IS the staged point's -- derived, not stored (ADR-0057)
2305 auto const& staged = std::get<Vec<complex_mp> >(current_variable_values_);
2306 Precision(result, staged.size() ? Precision(staged) : DefaultPrecision());
2307 }
2308 }
2309
2311 template <typename T>
2312 void EvalBlocksInPlace(Vec<T>& function_values) const
2313 {
2314 const auto& vars = std::get<Vec<T> >(current_variable_values_);
2315 const T t = CurrentPathValue<T>();
2316 Eigen::Index row = 0;
2317 for (auto const& blk : blocks_)
2318 std::visit([&](auto const& b){
2319 const Eigen::Index n = static_cast<Eigen::Index>(b.NumFunctions());
2320 b.template EvalInPlace<T>(function_values.segment(row, n), vars, t);
2321 row += n;
2322 }, blk);
2323 }
2324
2326 template <typename T>
2327 void JacobianBlocksInPlace(Mat<T>& J) const
2328 {
2329 const auto& vars = std::get<Vec<T> >(current_variable_values_);
2330 const T t = CurrentPathValue<T>();
2331 Eigen::Index row = 0;
2332 for (auto const& blk : blocks_)
2333 std::visit([&](auto const& b){
2334 const Eigen::Index n = static_cast<Eigen::Index>(b.NumFunctions());
2335 Mat<T> jb(n, J.cols()); // blocks write into a contiguous target
2336 b.template JacobianInPlace<T>(jb, vars, t);
2337 J.block(row, 0, n, J.cols()) = jb;
2338 row += n;
2339 }, blk);
2340 }
2341
2343 template <typename T>
2344 void TimeDerivBlocksInPlace(Vec<T>& ds_dt) const
2345 {
2346 const auto& vars = std::get<Vec<T> >(current_variable_values_);
2347 const T t = CurrentPathValue<T>();
2348 Eigen::Index row = 0;
2349 for (auto const& blk : blocks_)
2350 std::visit([&](auto const& b){
2351 const Eigen::Index n = static_cast<Eigen::Index>(b.NumFunctions());
2352 b.template TimeDerivInPlace<T>(ds_dt.segment(row, n), vars, t);
2353 row += n;
2354 }, blk);
2355 }
2356
2357
2358 // Append this system's canonical encoding to `out`, sharing `ctx` so operand systems
2359 // (randomization / blend) and cross-function node sharing back-reference deterministically
2360 // within one encoding unit. The public CanonicalEncodingText() wraps this with a fresh
2361 // context; the recursion for operand systems passes the same one. (ADR-0042)
2362 void EncodeCanonical(std::ostream& out, node::EncodingContext& ctx) const;
2363
2364 // Read this system's canonical encoding from `cursor` (the inverse of EncodeCanonical,
2365 // section by section), sharing `ctx` so back-references into operand systems resolve
2366 // the way the encoder numbered them. Replaces this system's content wholesale.
2367 void DecodeCanonicalFrom(node::DecodingCursor& cursor, node::DecodingContext& ctx);
2368
2369 // Guard for structural mutators: throws std::logic_error naming `operation` if the
2370 // system is sealed (ADR-0042). First line of every structural mutator.
2371 void ThrowIfSealed(char const* operation) const;
2372
2373 bool is_sealed_ = false;
2374 mutable std::optional<detail::Digest256> sealed_digest_;
2375
2376 VariableGroup ungrouped_variables_;
2377 std::vector< VariableGroup > variable_groups_;
2378 std::vector< VariableGroup > hom_variable_groups_;
2379
2380 VariableGroup homogenizing_variables_;
2381
2382 std::vector<unsigned> auxiliary_variable_groups_;
2383 std::vector<unsigned> auxiliary_coordinates_;
2384
2385 std::vector<Nd> pre_homogenization_functions_;
2386
2387
2388 bool have_path_variable_ = false;
2389 Var path_variable_;
2390
2391 VariableGroup implicit_parameters_;
2392 std::vector< NE > explicit_parameters_;
2393
2394 // The polynomial path -- functions_, subfunctions_, constant_subfunctions_, their
2395 // derivatives, the SLP, and eval_method_ -- has been folded into a
2396 // blocks::PolynomialBlock held in blocks_ (see PolyBlock()/PolyBlockPtr()). The System
2397 // is now a thin orchestrator over blocks + variable groups + patch.
2398
2399 class Patch patch_;
2400 bool is_patched_ = false;
2401
2402 mutable bool is_differentiated_ = false;
2403
2404 std::vector<Block> blocks_;
2405
2406 std::vector< VariableGroupType > time_order_of_variable_groups_;
2407
2408 mutable std::tuple< Vec<complex_dbl>, Vec<complex_mp> > current_variable_values_;
2409 mutable std::tuple< complex_dbl, complex_mp > current_path_value_{};
2410
2411 mutable VariableGroup variable_ordering_;
2412 mutable bool have_ordering_ = false;
2413
2414
2415
2416
2417
2418
2419
2420
2422
2423 /*definition of serialize function*/
2424 template<class Archive>
2425 void serialize(Archive & ar, const unsigned int /*version*/){
2426 ar & ungrouped_variables_;
2427 ar & variable_groups_;
2428 ar & hom_variable_groups_;
2429
2430 ar & homogenizing_variables_;
2431
2432 ar & auxiliary_variable_groups_;
2433 ar & auxiliary_coordinates_;
2434
2435 ar & have_path_variable_;
2436 ar & path_variable_;
2437
2438 ar & implicit_parameters_;
2439 ar & explicit_parameters_;
2440
2441 ar & patch_;
2442 ar & is_patched_;
2443
2444 // The polynomial path (functions / subfunctions / derivatives / SLP / eval+deriv
2445 // methods) now lives inside the PolynomialBlock, which is archived as part of blocks_.
2446 ar & blocks_;
2447
2448
2449 // now for the cached / mutable things
2450 // precision_ is gone (ADR-0057): a System has no precision of its own, and
2451 // transient evaluation state is not archived (see current_variable_values_ below)
2452
2453 ar & is_differentiated_;
2454
2455 ar & time_order_of_variable_groups_;
2456
2457 ar & pre_homogenization_functions_;
2458
2459 // seal flag round-trips; the memoized digest is recomputed on demand after load
2460 // (guards against archives written under an older encoding version) (ADR-0042)
2461 ar & is_sealed_;
2462
2463 // if (Archive::is_loading::value == true){
2464 // have_ordering_ = false;}
2465 // else
2466 // {
2467 ar & have_ordering_;
2468 ar & variable_ordering_;
2469 // }
2470
2471
2472 // if (Archive::is_loading::value == true){
2473 // std::get<Vec<complex_dbl>>(current_variable_values_).resize(NumVariables());
2474 // std::get<Vec<complex_mp>>(current_variable_values_).resize(NumVariables());
2475 // }
2476 // // next two lines no matter what
2477 // ar & std::get<Vec<complex_dbl>>(current_variable_values_);
2478 // ar & std::get<Vec<complex_mp>>(current_variable_values_);
2479
2480 // A loaded system joins the live node universe (ADR-0068). An archive builds nodes
2481 // through their default constructors, never through Make, so what comes out is
2482 // content-equal to the original and shares none of its nodes: its x is not THE x,
2483 // and it could not be combined with the system it was copied from. Every load
2484 // goes through here -- pickle, copy, deepcopy, the MPI broadcast, the records
2485 // loader -- so the repair is made here rather than asked of each of them.
2486 if (Archive::is_loading::value)
2487 {
2488 node::ReinternMemo memo;
2489 ReinternNodes(memo);
2490 }
2491 }
2492
2493
2494 public:
2495 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
2496 };
2497
2498
2511 System Concatenate(System sys1, System const& sys2);
2512
2513
2514
2529 std::string UniquePathVariableName(System const& target, std::string base = "t");
2530
2551 System MakeHomotopy(System const& target, System const& start,
2552 std::string const& path_variable_name = "",
2553 std::shared_ptr<node::Node> const& gamma = nullptr);
2554
2582 std::string const& operation,
2583 std::string const& a_name, std::string const& b_name);
2584
2596 void AdoptVariableStructure(System& into, System const& from);
2597
2627 System MakeMovingHomotopy(System const& fixed, System const& start_moving, System const& end_moving,
2628 std::string const& path_variable_name = "",
2629 std::shared_ptr<node::Node> const& gamma = nullptr);
2630
2634 System Clone(System const& sys);
2635
2639 void Simplify(System & sys);
2640
2654 std::shared_ptr<const System> InternSystem(std::shared_ptr<System> const& candidate);
2655
2668 std::shared_ptr<const System> LoadSystemUnified(std::istream& in);
2669
2680 inline constexpr char SystemEncodingVersion[] = "b2sysenc/2";
2681
2683 // Explicit instantiation declarations for the two concrete numeric types.
2684 // Definitions live in core/src/system/system.cpp.
2685 // Suppresses re-instantiation of the heavy Eval/Jacobian/Set template bodies
2686 // (with their eval_method_ switch trees) in every including TU.
2687
2688 extern template void System::EvalInPlace<complex_dbl>(Vec<complex_dbl>&) const;
2689 extern template void System::EvalInPlace<complex_mp>(Vec<complex_mp>&) const;
2690
2691 extern template Vec<complex_dbl> System::Eval<complex_dbl>() const;
2692 extern template Vec<complex_mp> System::Eval<complex_mp>() const;
2693
2694 extern template void System::JacobianInPlace<complex_dbl>(Mat<complex_dbl>&) const;
2695 extern template void System::JacobianInPlace<complex_mp>(Mat<complex_mp>&) const;
2696
2697 extern template Mat<complex_dbl> System::Jacobian<complex_dbl>() const;
2698 extern template Mat<complex_mp> System::Jacobian<complex_mp>() const;
2699
2701 extern template Mat<complex_mp> System::Jacobian<complex_mp>(const Vec<complex_mp>&) const;
2702
2703 extern template void System::JacobianInPlace<complex_dbl>(Mat<complex_dbl>&, const Vec<complex_dbl>&) const;
2704 extern template void System::JacobianInPlace<complex_mp>(Mat<complex_mp>&, const Vec<complex_mp>&) const;
2705
2708
2711
2712 extern template void System::SetVariables<complex_dbl>(const Vec<complex_dbl>&) const;
2713 extern template void System::SetVariables<complex_mp>(const Vec<complex_mp>&) const;
2714
2715 extern template void System::SetPathVariable<complex_dbl>(complex_dbl const&) const;
2716 extern template void System::SetPathVariable<complex_mp>(complex_mp const&) const;
2717
2718 extern template void System::SetAndReset<complex_dbl>(Vec<complex_dbl> const&, complex_dbl const&) const;
2719 extern template void System::SetAndReset<complex_mp>(Vec<complex_mp> const&, complex_mp const&) const;
2720
2721 extern template void System::SetAndReset<complex_dbl>(Vec<complex_dbl> const&) const;
2722 extern template void System::SetAndReset<complex_mp>(Vec<complex_mp> const&) const;
2724
2725}
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735#endif // for the ifndef include guards
The evaluation-block contract for the block-composed System.
The reader for the canonical exact text encoding of expression trees – the inverse of canonical_encod...
An affine chart on a product of projective spaces.
Definition patch.hpp:85
A linear slice of affine or projective space: a stack of linear forms, M [x ; 1].
Definition slice.hpp:68
The fundamental polynomial system class for Bertini2.
Definition system.hpp:106
const Var & GetPathVariable() const
Get the system's path variable (throws if none is defined).
static System FromCanonicalEncoding(std::string const &text)
Rebuild a system from its canonical encoding text – the inverse of CanonicalEncodingText(),...
friend void swap(System &a, System &b)
The free swap function for systems.
auto HomVariableGroups() const
Get the homogeneous (projective) variable groups in the problem.
Definition system.hpp:1807
void SetPathVariable(T const &new_value) const
Set the current value of the path variable.
Definition system.hpp:941
void AddParameter(NE const &F)
Add an explicit parameter to the system.
size_t NumAuxiliaryCoordinates() const
How many of this system's user coordinates are auxiliary (a coordinate covered both by a group and in...
friend const System operator*(System s, Nd const &N)
Multiply a system by an arbitrary node.
void AddUngroupedVariable(Var const &v)
Add variables to the system which are in neither a regular variable group, nor in a homogeneous group...
void ReinternNodes(node::ReinternMemo &memo)
Re-intern every node this system holds after deserialization (ADR-0042).
friend std::ostream & operator<<(std::ostream &out, const System &s)
Overloaded operator for printing to an arbirtary out stream.
void SimplifyDerivatives() const
Simplify the derivatives / jacobian / etc contained in the system.
void TimeDerivativeInPlace(Vec< T > &ds_dt, const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Compute the time-derivative of a system.
Definition system.hpp:601
Patch GetPatch() const
Get a copy of the system's patch.
Definition system.hpp:1925
void SetAndReset(Vec< T > const &new_space, T const &new_time) const
Stage the system's current point (variables and path value) for a subsequent Eval/Jacobian.
Definition system.hpp:964
void Seal()
Seal this system: memoize its ContentDigest() and forbid structural mutation (hashcons-on-freeze,...
void EvalInPlace(Vec< T > &function_values) const
Evaluate the system using the previously set variable (and time) values, in place.
Definition system.hpp:213
std::vector< int > Degrees() const
Get the degrees of the functions in the system, with respect to all variables.
bool IsPatched() const
Query whether a system is patched.
Definition system.hpp:1933
void AddImplicitParameters(VariableGroup const &v)
Add some implicit parameters to the system.
Vec< T > DehomogenizePoint(Vec< T > const &x) const
Dehomogenize a point, using the variable grouping / structure of the system.
Definition system.hpp:1410
std::size_t Hash() const
In-process hash derived from ContentDigest() (its first 8 bytes).
System Randomize() const
Randomize an overdetermined system down to a square one, returning a NEW system.
std::pair< unsigned, unsigned > SpanOfGroup(unsigned group_fifo_index) const
Where one variable group sits in a user-coordinate point: (offset, size).
Definition system.hpp:1773
bool HasBlocks() const
Whether this system is evaluated from blocks rather than the function tree.
Definition system.hpp:1123
void JacobianInPlace(Mat< T > &J, const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Evaluate the Jacobian of the system, provided a path variable is defined for the system,...
Definition system.hpp:522
bool HaveAuxiliaryCoordinates() const
Whether this system has any auxiliary coordinates at all (the fast path: usually not).
Definition system.hpp:1568
auto Function(unsigned index) const
Get a function by its index, as a function-tree node.
Definition system.hpp:1645
std::vector< unsigned > const & AuxiliaryVariableGroups() const
The auxiliary variable groups, by FIFO index.
Definition system.hpp:1556
System & operator=(const System &other)
The assignment operator.
std::vector< unsigned > VariableGroupSizes() const
Get the sizes of the variable groups, according to the current ordering.
Definition system.hpp:1397
System Randomize(Mat< complex_mp > const &R) const
Randomize using a caller-supplied (exact) coefficient matrix R, leaving the functions in their curren...
void AddFunctions(std::vector< Nd > const &F)
Add some functions to the system.
Vec< T > RescalePointToFitPatch(Vec< T > const &x) const
Rescale a point so it lies on the system's patch, returning the rescaled copy.
Definition system.hpp:1944
void TimeDerivativeInPlace(Vec< T > &ds_dt, const Eigen::MatrixBase< Derived > &variable_values) const
Compute the time-derivative of the system in place, after setting the variable values.
Definition system.hpp:650
Vec< T > Eval(const Vec< T > &variable_values, const T &path_variable_value) const
Evaluate the system at the given variable values and path-variable value.
Definition system.hpp:394
void ReorderFunctionsByDegreeIncreasing()
Sort the functions so they are in INcreasing order by degree.
size_t NumConstants() const
Get the number of constants in this system.
System(std::vector< Nd > const &functions)
Construct a system from a list of functions.
std::vector< int > Degrees(VariableGroup const &vars) const
Get the degrees of the functions in the system, with respect to a group of variables.
void Describe(std::ostream &out, bool verbose=false) const
Human-facing description of the system, block by block.
void CopyFunctions(System const &other)
Append another system's functions to this one (issue #297).
Definition system.hpp:1702
size_t NumImplicitParameters() const
Get the number of implicit parameters in this system.
size_t NumNaturalFunctions() const
Get the number of functions in this system, excluding patches.
bool IsFinite(Vec< T > const &x, R const &threshold) const
Is this point of mine finite, at the given threshold?
Definition system.hpp:1480
VariableGroup VariableOrdering() const
Order the variables, by the order in which the groups were added.
bool IsSealed() const
Whether this system has been sealed against structural mutation (ADR-0042).
VariableGroup const & UngroupedVariables() const
Get the ungrouped variables: those declared to the system but placed in no affine and no projective g...
Definition system.hpp:825
friend const System operator*(Nd const &N, System const &s)
Multiply a system by an arbitrary node.
std::vector< Nd > GetSpaceDerivatives() const
Get the space derivatives.
void JacobianInPlace(Mat< T > &J, const Vec< T > &variable_values) const
Evaluate the Jacobian matrix of the system, provided the system has no path variable defined.
Definition system.hpp:466
Mat< T > Jacobian() const
Evaluate the Jacobian matrix of the system, using the previous space and time values.
Definition system.hpp:444
System()
The default constructor for a system.
Definition system.hpp:117
System ExpandToFunctionTree() const
Build an equivalent pure function-tree System: every block's functions expressed as function-tree nod...
NodeMatrix SymbolicJacobian(bool usercoordinates=true) const
The symbolic Jacobian of the system, as a matrix of expression-tree nodes.
const Var & PathVariable() const
Get the system's path variable node (the raw stored pointer; may be null if unset).
Definition system.hpp:1814
Vec< T > TimeDerivative() const
Compute the time-derivative of a system.
Definition system.hpp:729
Eigen::NumTraits< NumT >::Real CoefficientBound(unsigned num_evaluations=1) const
Compute an estimate of an upper bound of the absolute values of the coefficients in the system.
void AddUngroupedVariables(VariableGroup const &v)
Add variables to the system which are in neither a regular variable group, nor in a homogeneous group...
bool IsSame(System const &other) const
Content equality: equal ContentDigest().
void ReorderFunctionsByDegreeDecreasing()
Sort the functions so they are in DEcreasing order by degree.
bool IsReal(Vec< T > const &x, R const &threshold) const
Is this point of mine real, at the given threshold?
Definition system.hpp:1500
System & operator*=(Nd const &N)
Multiply a system by an arbitrary node.
size_t NumVariableGroups() const
Get the number of affine variable groups in the system.
bool IsPolynomial() const
Checks whether a system is polynomial, overall.
std::vector< unsigned > const & AuxiliaryCoordinates() const
The individually auxiliary coordinates, by index into a user-coordinate point.
Definition system.hpp:1562
Vec< T > Eval(const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Evaluate the system, provided a path variable is defined for the system.
Definition system.hpp:377
void ClearFunctions()
Remove the polynomial block (the System's natural functions), leaving any structured blocks and the v...
Definition system.hpp:1109
int DegreeBound() const
Compute an upper bound on the degree of the system.
System & operator+=(System const &rhs)
Add two systems together.
Vec< T > HomogenizePoint(Vec< T > const &x) const
Take a point in user (dehomogenized) coordinates into this system's internal coordinates.
Definition system.hpp:1604
std::vector< Nd > PatchFunctionsAsNodes() const
The patch equations, as function-tree nodes: one per variable group, or none when the system is unpat...
size_t NumTotalVariableGroups() const
Get the total number of variable groups in the system, including both affine and homogenous.
friend const System operator+(System lhs, System const &rhs)
Add two systems together.
std::vector< Nd > GetNaturalFunctions() const
Get the functions as authored, as function-tree nodes, without the patch.
Definition system.hpp:1661
size_t NumNaturalVariables() const
Get the number of variables in this system, NOT including homogenizing variables.
void AddFunction(Nd const &F)
Add a function to the system, as a bare expression.
std::vector< Slice > Slices() const
Recover the linear-form slices embedded in this system, one per LinearFormsBlock (empty if the system...
System(System const &other)
The copy operator.
void AddBlock(Block b)
Append an evaluation block (products-of-linears, blend, ...).
Definition system.hpp:1092
void AddConstant(NE const &C)
Add a constant function to the system.
void AutoPatch()
Let the system patch itself by the selected variable ordering, using the current variable groups.
Definition system.hpp:1913
std::vector< Block > const & Blocks() const
Read-only access to the system's evaluation blocks (in evaluation order).
Definition system.hpp:1097
void JacobianInPlace(Mat< T > &J) const
Evaluate the Jacobian matrix of the system, using the previous space and time values,...
Definition system.hpp:413
VariableGroup const & AffineVariableGroup(size_t index) const
Get an affine variable group the class has defined.
Definition system.hpp:1390
void Homogenize(VariableGroup const &provided_hom_vars)
Homogenize the system reusing externally-supplied homogenizing variables – one per affine variable gr...
bool HavePathVariable() const
Query whether a path variable is set for this system.
Vec< T > CoordinatesOfGroup(Vec< T > const &user_point, unsigned group_fifo_index) const
Project a user-coordinate point onto one variable group: return just that group's coordinates.
Definition system.hpp:1754
detail::Digest256 ContentDigest() const
The persistent content digest: SHA-256 of CanonicalEncodingText().
Mat< T > Jacobian(const Vec< T > &variable_values) const
Evaluate the Jacobian matrix of the system, provided the system has no path variable defined.
Definition system.hpp:494
Vec< T > TimeDerivative(const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Compute the time-derivative of a system.
Definition system.hpp:626
Vec< T > Eval(const Vec< T > &variable_values) const
Evaluate the system at the given variable values (no path variable defined).
Definition system.hpp:317
size_t NumPatches() const
Get the number of patches in this system.
Definition system.hpp:790
auto InfinityNormOfDehomogenized(Vec< T > const &x) const
The infinity norm of a point after dehomogenization.
Definition system.hpp:1443
Vec< T > TimeDerivative(const Eigen::MatrixBase< Derived > &variable_values) const
Compute the time-derivative of a system.
Definition system.hpp:673
const VariableGroup & Variables() const
Get the variables in the problem.
size_t NumVariables() const
Get the total number of variables in this system, including homogenizing variables.
void Simplify()
Simplify as many aspects of the system as possible.
void SetVariables(const Vec< T > &new_values) const
Set the values of the variables to be equal to the input values.
Definition system.hpp:894
System Randomize(int codimension) const
Randomize down to a chosen number of functions, returning a NEW system.
void EvalInPlace(Vec< T > &function_values, const Eigen::MatrixBase< Derived > &variable_values) const
Evaluate the system, provided the system has no path variable defined, in place.
Definition system.hpp:268
auto VariableGroups() const
Get the affine variable groups in the problem.
Definition system.hpp:1799
void AddHomVariableGroup(VariableGroup const &v)
Add a homogeneous (projective) variable group to the system.
size_t NumUngroupedVariables() const
get the number of variables which are ungrouped.
void ClearBlocks()
Remove all evaluation blocks (the system reverts to its function-tree functions).
Definition system.hpp:1139
std::vector< Nd > NaturalFunctionsAsNodes() const
The system's natural (pre-patch) functions as function-tree expression nodes, expanding any structure...
VariableGroup const & HomogenizingVariables() const
Get the homogenizing variables, one per affine variable group (in group order), or an empty container...
Definition system.hpp:819
size_t NumHomVariableGroups() const
Get the number of homogeneous variable groups in the system.
std::shared_ptr< node::Node > Nd
Shorthand for a shared pointer to a generic expression-tree node.
Definition system.hpp:112
void SetAndReset(Vec< T > const &new_space) const
Stage the system's current point (variables only) for a subsequent Eval/Jacobian.
Definition system.hpp:977
void SetAuxiliaryCoordinates(std::vector< unsigned > coordinates)
Declare individual coordinates auxiliary, for a system whose grouping does not separate them.
friend class boost::serialization::access
Definition system.hpp:2421
std::vector< Nd > GetTimeDerivatives() const
Get the time derivatives of all functions.
void EvalInPlace(Vec< T > &function_values, const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Evaluate the system, provided a path variable is defined for the system, in place.
Definition system.hpp:341
void SetAuxiliaryVariableGroups(std::vector< unsigned > groups)
Declare whole variable groups auxiliary: excluded from every judgement about a point.
Vec< T > Eval() const
Evaluate the system using the previously set variable (and time) values, creating vector of function ...
Definition system.hpp:245
size_t NumParameters() const
Get the number of explicit parameters in this system.
size_t NumTotalFunctions() const
Get the total number of functions, including patches.
bool IsHomogeneous() const
Checks whether a system is homogeneous, overall.
void ClearVariables()
Clear the entire structure of variables in a system.
std::shared_ptr< node::Variable > Var
Shorthand for a shared pointer to a variable node.
Definition system.hpp:111
Mat< T > Jacobian(const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Evaluate the Jacobian of the system, provided a path variable is defined for the system.
Definition system.hpp:553
std::set< std::string > VariableNameSet() const
Collect the names of every variable the user could reference.
bool HasStructuredBlocks() const
Does the system have any non-polynomial (structured) block – products-of-linears, linear-forms,...
Definition system.hpp:1129
std::vector< Nd > GetFunctions() const
Get every row this system evaluates, as function-tree nodes.
Definition system.hpp:1674
unsigned FIFOIndexOfGroup(VariableGroup const &g) const
The FIFO index (0-based) of a variable group – its position in the canonical FIFO ordering (time_orde...
Definition system.hpp:1717
void AddPathVariable(Var const &v)
Add a variable as the Path Variable to a System.
void CopyPatches(System const &other)
Copy the patches from another system into this one.
void CopyVariableStructure(System const &other)
Copy the entire structure of variables from within one system to another.
void AddVariableGroup(VariableGroup const &v)
Add a variable group to the system.
void AddImplicitParameter(Var const &v)
Add an implicit parameter to the system.
System(System &&other)
The move copy operator.
Definition system.hpp:148
void RescalePointToFitPatchInPlace(Vec< T > &x) const
Rescale a point in place so it lies on the system's patch.
Definition system.hpp:1954
bool CoordinateIsAuxiliary(unsigned index) const
Whether one coordinate of a user-coordinate point is auxiliary.
void SimplifyFunctions()
Simplify the functions contained in the system.
std::string CanonicalEncodingText() const
The canonical exact text encoding of this system – the persistent-identity substrate (ADR-0042).
size_t NumHomVariables() const
Get the number of homogenizing variables in this system.
std::shared_ptr< node::NamedExpression > NE
Shorthand for a shared pointer to a named expression (a function of the system).
Definition system.hpp:110
void TimeDerivativeInPlace(Vec< T > &ds_dt) const
Compute the time-derivative of the system in place, using the currently set variable values.
Definition system.hpp:691
Derived::PlainObject Eval(const Eigen::MatrixBase< Derived > &variable_values) const
Evaluate the system, provided the system has no path variable defined.
Definition system.hpp:299
System & operator=(System &&other)=default
The move assignment operator.
Mat< complex_mp > RandomizationMatrix() const
The randomization matrix R of a system produced by Randomize() (its first RandomizationBlock's n x N ...
Mat< T > Jacobian(const Vec< T > &variable_values, const T &path_variable_value) const
Compute the Jacobian of the system at the given variable and path-variable values.
Definition system.hpp:578
void Homogenize()
Homogenize the system, adding new homogenizing variables for each VariableGroup defined for the syste...
void SetVariableGroups(std::vector< VariableGroup > const &groups)
Replace the entire variable-group structure of the system.
void Differentiate() const
Compute and internally store the symbolic Jacobian of the system.
Bertini extensions of the Eigen linear algebra library.
Collects the various header files which define the Bertini2 function tree node types.
The main multiprecision complex number type.
Extensions to the Boost.Multiprecision library.
Definition canonical.hpp:56
std::map< Node const *, std::shared_ptr< Node > > ReinternMemo
Memo for one re-interning pass: loaded node -> its interned replacement.
Definition reintern.hpp:57
Definition algorithm_builder.hpp:36
constexpr char SystemEncodingVersion[]
The version token of the System canonical encoding – the first word of every encoding text and the sc...
Definition system.hpp:2680
System Concatenate(System sys1, System const &sys2)
Concatenate two compatible systems.
@ Ungrouped
Variables not assigned to any group.
Definition node.hpp:81
@ Homogeneous
A projective (homogeneous) variable group.
Definition node.hpp:79
@ Affine
An affine variable group (to be homogenized).
Definition node.hpp:80
std::variant< blocks::PolynomialBlock, blocks::ProductsOfLinearsBlock, blocks::LinearFormsBlock, blocks::BlendBlock< System >, blocks::RandomizationBlock< System > > Block
The closed set of evaluation blocks a System can be composed of.
Definition block.hpp:135
System Clone(System const &sys)
Do a deep clone of the system.
std::complex< double > complex_dbl
The double-precision complex number type.
Definition double_extensions.hpp:47
System MakeMovingHomotopy(System const &fixed, System const &start_moving, System const &end_moving, std::string const &path_variable_name="", std::shared_ptr< node::Node > const &gamma=nullptr)
Form a homotopy that moves ONLY some rows, leaving the rest fixed and evaluated once.
Eigen::Matrix< NumT, Eigen::Dynamic, 1 > Vec
A dynamically-sized column vector of NumT.
Definition eigen_extensions.hpp:296
std::shared_ptr< const System > LoadSystemUnified(std::istream &in)
Load a System from a text archive and unify it with the live intern universe (ADR-0042): deserialize,...
std::vector< std::shared_ptr< node::Variable > > VariableGroup
An ordered group of variables (the unit of homogenization / variable grouping).
Definition node.hpp:69
NodeMatrix SymbolicJacobian(std::vector< std::shared_ptr< node::Node > > const &functions, VariableGroup const &variables)
The symbolic Jacobian of a list of functions w.r.t.
Eigen::Matrix< NumT, Eigen::Dynamic, Eigen::Dynamic > Mat
A dynamically-sized matrix of NumT.
Definition eigen_extensions.hpp:298
void CheckVariableStructuresMatch(System const &a, System const &b, std::string const &operation, std::string const &a_name, std::string const &b_name)
Throw unless two systems describe points the same way, so that combining them is meaningful.
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
void AdoptVariableStructure(System &into, System const &from)
Give a system that declares no variables the variable structure of another.
System MakeHomotopy(System const &target, System const &start, std::string const &path_variable_name="", std::shared_ptr< node::Node > const &gamma=nullptr)
Form the gamma-trick straight-line homotopy H = (1-t)*target + gamma*t*start.
std::shared_ptr< bertini::node::Node > Simplify(std::shared_ptr< bertini::node::Node > const &n)
Functionally simplify a tree: returns a NEW simplified tree, leaving the input untouched (non-mutatin...
std::shared_ptr< const System > InternSystem(std::shared_ptr< System > const &candidate)
Hash-cons a System: return the live sealed representative with equal ContentDigest() if one exists,...
std::string UniquePathVariableName(System const &target, std::string base="t")
Produce a path-variable name guaranteed not to collide with any variable in target.
Provides the bertini::Patch class.
Re-intern deserialized node DAGs into the live hash-consing tables (ADR-0042).
Self-contained SHA-256 (FIPS 180-4) and the Digest256 value type.
Provides the bertini::StraightLineProgram class.
A matrix of expression-tree nodes (the symbolic Jacobian), stored row-major.
Definition system.hpp:84
size_t rows
the number of rows (functions)
Definition system.hpp:86
std::vector< std::shared_ptr< node::Node > > entries
row-major, length rows*cols
Definition system.hpp:85
size_t cols
the number of columns (variables)
Definition system.hpp:87
Numeric traits for a bertini number type: digit counts, conversions, and companion types.
Definition num_traits.hpp:57
A 256-bit content digest – the output of Sha256, used as a persistent identity key.
Definition sha256.hpp:53
Traversal state for one canonical-encoding pass: the back-reference table.
Definition canonical_encoding.hpp:76