Bertini 2 - C++ Core
Software for Numerical Algebraic Geometry
Loading...
Searching...
No Matches
system/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) 2015 - 2021 by 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
22// individual authors of this file include:
23// silviana amethyst, university of wisconsin eau claire
24
30
31#ifndef BERTINI_SYSTEM_HPP
32#define BERTINI_SYSTEM_HPP
33
34#include <assert.h>
35#include <vector>
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/type_index.hpp>
45
49
50
53
55
56#include <boost/archive/binary_oarchive.hpp>
57#include <boost/archive/binary_iarchive.hpp>
58#include <boost/iostreams/stream_buffer.hpp>
59#include <boost/iostreams/stream.hpp>
60#include <boost/iostreams/device/back_inserter.hpp>
61
62namespace bertini {
63
64
65 enum class EvalMethod
66 {
67 FunctionTree, // using virtual methods and recursion
68 SLP // using straight line programs
69 // now! 20230714, Eindhoven, Netherlands
70 };
71
72 enum class DerivMethod
73 {
74 JacobianNode, // using Jacobian nodes, which are either 1 or 0 when evaluated based on the variable of differentiation
75 Derivatives // classic differentiation, using more space in memory but not requiring a variable of differentation when evaluatiing
76 };
77
78
82 EvalMethod DefaultEvalMethod();
83
84 DerivMethod DefaultDerivMethod();
85
86
91
99 class System{
100
101 public:
102 // a few local using statements to reduce typing etc.
103 using Fn = std::shared_ptr<node::Function>;
104 using Var = std::shared_ptr<node::Variable>;
105 using Nd = std::shared_ptr<node::Node>;
106 using Jac = std::shared_ptr<node::Jacobian>;
107
111 System() : is_differentiated_(false), have_path_variable_(false), have_ordering_(false), precision_(DefaultPrecision()), is_patched_(false)
112 {}
113
117 explicit
118 System(std::string const& input);
119
123 System(System const& other);
124
128 System(System && other) : System()
129 {
130 swap(*this, other);
131 }
132
136 System& operator=(const System & other);
137
141 System& operator=(System && other) = default;
142
146 friend void swap(System & a, System & b);
147
153 void precision(unsigned new_precision) const;
154
158 unsigned precision() const
159 {
160 return precision_;
161 }
162
166 void Differentiate() const;
167
168
169
173 void ResetFunctions() const
174 {
175 // TODO: it has the unfortunate side effect of resetting constant functions, too.
176 switch (eval_method_){
177 case EvalMethod::FunctionTree:
178 for (const auto& iter : functions_)
179 iter->Reset();
180 break;
181 case EvalMethod::SLP:
182 // nothing
183 break;
184 }
185
186 }
187
191 void ResetJacobian() const
192 {
193 switch (eval_method_)
194 {
195 case EvalMethod::FunctionTree:{
196
197 switch (deriv_method_){
198 case DerivMethod::JacobianNode:
199 {
200 for (const auto& iter : jacobian_)
201 iter->Reset();
202 break;
203 }
204 case DerivMethod::Derivatives:
205 {
206 for (const auto& iter : space_derivatives_)
207 iter->Reset();
208 break;
209 }
210 }
211
212 break;
213 }
214 case EvalMethod::SLP:
215 {
216 // nothing to do, it's not a resetting kind of thing.
217 break;
218 }
219
220 }
221 }
222
223 void ResetTimeDerivatives() const
224 {
225 switch (eval_method_)
226 {
227 case EvalMethod::FunctionTree:{
228
229 switch (deriv_method_){
230 case DerivMethod::JacobianNode:
231 {
232 for (const auto& iter : jacobian_)
233 iter->Reset();
234 break;
235 }
236 case DerivMethod::Derivatives:
237 {
238 for (const auto& iter : time_derivatives_)
239 iter->Reset();
240 break;
241 }
242 }
243
244 break;
245 }
246 case EvalMethod::SLP:
247 {
248 // nothing to do, it's not a resetting kind of thing.
249 break;
250 }
251
252 }
253 }
254
258 void Reset() const
259 {
262 ResetTimeDerivatives();
263 }
264
271 template<typename T>
272 void EvalInPlace(Vec<T> & function_values) const
273 {
274
275 if (function_values.size() != NumTotalFunctions())
276 {
277 std::stringstream ss;
278 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";
279 throw std::runtime_error(ss.str());
280 }
281
282 switch (eval_method_){
283 case EvalMethod::FunctionTree:
284 {
285 unsigned counter(0);
286 for (auto iter=functions_.begin(); iter!=functions_.end(); iter++, counter++) {
287 (*iter)->EvalInPlace<T>(function_values(counter));
288 }
289 }
290
291 case EvalMethod::SLP:
292 {
293 slp_.GetFuncValsInPlace<T>(function_values);
294 }
295 }
296
297
298 if (IsPatched())
299 patch_.EvalInPlace(function_values,
300 std::get<Vec<T> >(current_variable_values_)); // does a patch not have a caching mechanism?
301 // .segment(NumNaturalFunctions(),NumTotalVariableGroups())
302
303 }
304
305
306
307
308
316 template<typename T>
317 Vec<T> Eval() const
318 {
319 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
320 EvalInPlace(function_values);
321
322 return function_values;
323 }
324
325
326
327
338 template<typename T, typename Derived>
339 void EvalInPlace(Vec<T>& function_values, const Eigen::MatrixBase<Derived>& variable_values) const
340 {
341 static_assert(std::is_same<typename Derived::Scalar,T>::value,"scalar types must match");
342
343 if (variable_values.size()!=NumVariables())
344 {
345 std::stringstream ss;
346 ss << "trying to evaluate system, but number of input variables (" << variable_values.size() << ") doesn't match number of system variables (" << NumVariables() << ").";
347 throw std::runtime_error(ss.str());
348 }
349 if (have_path_variable_)
350 throw std::runtime_error("not using a time value for evaluation of system, but path variable IS defined.");
351
352 SetVariables(variable_values.eval());
354 EvalInPlace(function_values);
355 }
356
357
358
359
370 template<typename Derived>
371 typename Derived::PlainObject Eval(const Eigen::MatrixBase<Derived>& variable_values) const
372 {
373 typedef typename Derived::Scalar T;
374
375 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
376 EvalInPlace(function_values, variable_values);
377 return function_values;
378
379 }
380
381 template<typename T>
382 Vec<T> Eval(const Vec<T> & variable_values) const
383 {
384 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
385 EvalInPlace(function_values, variable_values);
386 return function_values;
387 }
388
389
390
391
392
404 template<typename Derived, typename T>
405 void EvalInPlace(Vec<T> & function_values, const Eigen::MatrixBase<Derived>& variable_values, const T & path_variable_value) const
406 {
407 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
408
409 if (variable_values.size()!=NumVariables())
410 throw std::runtime_error("trying to evaluate system, but number of variables doesn't match.");
411 if (!have_path_variable_)
412 throw std::runtime_error("trying to use a time value for evaluation of system, but no path variable defined.");
413
414 SetVariables(variable_values.eval());//TODO: remove this eval
415 SetPathVariable(path_variable_value);
416
417 ResetFunctions(); // todo, elimiante this. i feel like setting the variables or path variable should be enough to set the flag/ take the action
418
419 EvalInPlace(function_values);
420 }
421
422
423
424
425
426
427
428
429
441 template<typename Derived, typename T>
442 Vec<T> Eval(const Eigen::MatrixBase<Derived>& variable_values, const T & path_variable_value) const
443 {
444 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
445 EvalInPlace(function_values, variable_values, path_variable_value);
446 return function_values;
447 }
448
449
450 template<typename T>
451 Vec<T> Eval(const Vec<T> & variable_values, const T & path_variable_value) const
452 {
453 Vec<T> function_values(NumTotalFunctions()); // create vector with correct number of entries.
454 EvalInPlace(function_values, variable_values, path_variable_value);
455 return function_values;
456 }
457
458
459
469 template <typename T>
470 void JacobianInPlace(Mat<T> & J) const
471 {
472
473
474 if(J.rows() != NumTotalFunctions() || J.cols() != NumVariables())
475 {
476 throw std::runtime_error("trying to evaluate jacobian of system in place, but input J doesn't have right number of columns or rows");
477 }
478
479 const auto& vars = Variables();
480
481 if (!is_differentiated_)
483
484 switch (eval_method_)
485 {
486 case EvalMethod::FunctionTree:
487 {
488 switch (deriv_method_){
489 case DerivMethod::JacobianNode:{
490 for (int ii = 0; ii < NumNaturalFunctions(); ++ii)
491 for (int jj = 0; jj < NumVariables(); ++jj)
492 jacobian_[ii]->EvalJInPlace<T>(J(ii,jj),vars[jj]);
493 break;
494 }
495 case DerivMethod::Derivatives:
496 {
497 for (int jj = 0; jj < NumVariables(); ++jj)
498 for (int ii = 0; ii < NumNaturalFunctions(); ++ii)
499 space_derivatives_[ii+jj*NumNaturalFunctions()]->EvalInPlace<T>(J(ii,jj));
500 break;
501 }
502 }
503 break;
504 } // function tree branch
505
506 case EvalMethod::SLP:
507 {
508 this->slp_.GetJacobianInPlace<T>(J); // the variable values should have been copied into place elsewhere. that's not this function's responsibility.
509 break;
510 }
511 }
512
513 if (IsPatched())
514 patch_.JacobianInPlace(J,std::get<Vec<T> >(current_variable_values_));
515
516 }
517
518
519
520
521
522
523
524
530 template<typename T>
531 Mat<T> Jacobian() const
532 {
533
534 Mat<T> J(NumTotalFunctions(), NumVariables());
536
537 return J;
538 }
539
540
541
542
551 template<typename T>
552 void JacobianInPlace(Mat<T> & J, const Vec<T> & variable_values) const
553 {
554
555 if (variable_values.size()!=NumVariables())
556 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
557
558 if (HavePathVariable())
559 throw std::runtime_error("not using a time value for computation of jacobian, but a path variable is defined.");
560
561 SetAndReset(variable_values);
562
564 }
565
566
567
568
569
570
579 template<typename T>
580 Mat<T> Jacobian(const Vec<T> & variable_values) const
581 {
582 if (variable_values.size()!=NumVariables())
583 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
584
585 if (HavePathVariable())
586 throw std::runtime_error("not using a time value for computation of jacobian, but a path variable is defined.");
587
588 Mat<T> J(NumTotalFunctions(), NumVariables());
589 JacobianInPlace(J,variable_values);
590 return J;
591 }
592
593
594
595
607 template<typename Derived, typename T>
608 void JacobianInPlace(Mat<T> & J, const Eigen::MatrixBase<Derived> & variable_values, const T & path_variable_value) const
609 {
610 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
611
612 if (variable_values.size()!=NumVariables())
613 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
614
615 if (!HavePathVariable())
616 throw std::runtime_error("trying to use a time value for computation of jacobian, but no path variable defined.");
617
618 SetVariables(variable_values.eval()); // TODO: remove this eval
619 SetPathVariable(path_variable_value);
622 }
623
624
625
626
627
639 template<typename Derived, typename T>
640 Mat<T> Jacobian(const Eigen::MatrixBase<Derived> & variable_values, const T & path_variable_value) const
641 {
642 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
643
644 if (variable_values.size()!=NumVariables())
645 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
646
647 if (!HavePathVariable())
648 throw std::runtime_error("trying to use a time value for computation of jacobian, but no path variable defined.");
649
650 Mat<T> J(NumTotalFunctions(), NumVariables());
651 JacobianInPlace(J,variable_values, path_variable_value);
652 return J;
653 }
654
655
656 template<typename T>
657 Mat<T> Jacobian(const Vec<T> & variable_values, const T & path_variable_value) const
658 {
659 if (variable_values.size()!=NumVariables())
660 throw std::runtime_error("trying to evaluate jacobian, but number of variables doesn't match.");
661
662 if (!HavePathVariable())
663 throw std::runtime_error("using a time value for computation of jacobian, but no path variable is defined.");
664
665 Mat<T> J(NumTotalFunctions(), NumVariables());
666 JacobianInPlace(J,variable_values,path_variable_value);
667 return J;
668 }
669
670
679 template<typename Derived, typename T>
680 void TimeDerivativeInPlace(Vec<T> & ds_dt,
681 const Eigen::MatrixBase<Derived> & variable_values,
682 const T & path_variable_value) const
683 {
684 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
685
686 SetVariables(variable_values.eval()); //TODO: remove this eval()
687 SetPathVariable(path_variable_value);
688 ResetTimeDerivatives();
690 }
691
692
693
694
695
696
705 template<typename Derived, typename T>
706 Vec<T> TimeDerivative(const Eigen::MatrixBase<Derived> & variable_values, const T & path_variable_value) const
707 {
708 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
709
710 Vec<T> ds_dt(NumTotalFunctions());
711 TimeDerivativeInPlace(ds_dt, variable_values, path_variable_value);
712 return ds_dt;
713 }
714
715
716
717
718
719
720
721
722 template<typename Derived, typename T>
723 void TimeDerivativeInPlace(Vec<T> & ds_dt,
724 const Eigen::MatrixBase<Derived> & variable_values) const
725 {
726 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
727
728 SetVariables(variable_values.eval()); //TODO: remove this eval()
729 ResetTimeDerivatives();
731 }
732
733
734
735
736
737
746 template<typename Derived, typename T>
747 Vec<T> TimeDerivative(const Eigen::MatrixBase<Derived> & variable_values) const
748 {
749 static_assert(std::is_same<typename Derived::Scalar, T>::value, "scalar types must be the same");
750
751 Vec<T> ds_dt(NumTotalFunctions());
752 TimeDerivativeInPlace(ds_dt, variable_values);
753 return ds_dt;
754 }
755
756
757 template<typename T>
758 void TimeDerivativeInPlace(Vec<T> & ds_dt) const
759 {
760
761 if(ds_dt.size() < NumNaturalFunctions())
762 {
763 std::stringstream ss;
764 ss << "trying to evaluate system in place, but number of input functions (" << ds_dt.size() << ") doesn't match number of system functions (" << NumNaturalFunctions() << ").";
765 throw std::runtime_error(ss.str());
766 }
767
768 if (!HavePathVariable())
769 throw std::runtime_error("computing time derivative of system with no path variable defined");
770
771
772 if (!is_differentiated_)
774
775 switch (eval_method_)
776 {
777 case EvalMethod::FunctionTree:{
778 switch (deriv_method_){
779 case DerivMethod::JacobianNode:
780 {
781 for (int ii = 0; ii < NumNaturalFunctions(); ++ii)
782 jacobian_[ii]->EvalJInPlace<T>(ds_dt(ii), path_variable_);
783 break;
784 }
785 case DerivMethod::Derivatives:
786 {
787 for (int ii = 0; ii < NumNaturalFunctions(); ++ii)
788 time_derivatives_[ii]->EvalInPlace<T>(ds_dt(ii));
789 break;
790 }
791 }
792 break;
793 } // function tree branch
794
795 case EvalMethod::SLP:
796 {
797 this->slp_.GetTimeDerivInPlace(ds_dt); // the variable values should have been copied into place elsewhere. that's not this function's responsibility.
798 break;
799 }
800 }
801
802 // the patch doesn't move with time. derivatives 0.
803 if (IsPatched())
804 for (int ii = 0; ii < NumTotalVariableGroups(); ++ii)
805 ds_dt(ii+NumNaturalFunctions()) = T(0);
806
807 }
808
809
810
811
812
813
822 template<typename T>
823 Vec<T> TimeDerivative() const
824 {
825 if (!HavePathVariable())
826 throw std::runtime_error("computing time derivative of system with no path variable defined");
827
828 Vec<T> ds_dt(NumTotalFunctions());
830 return ds_dt;
831 }
832
839
846 bool IsHomogeneous() const;
847
854 bool IsPolynomial() const;
855
856
858 //
859 // Nummers -- functions which get the numbers of things.
860 //
862
863
867 size_t NumNaturalFunctions() const;
868
872 size_t NumPatches() const
873 {
874 return patch_.NumVariableGroups();
875 }
876
880 size_t NumTotalFunctions() const;
881
885 size_t NumVariables() const;
886
890 size_t NumNaturalVariables() const;
891
895 size_t NumHomVariables() const;
896
901
905 size_t NumVariableGroups() const;
906
907
911 size_t NumUngroupedVariables() const;
912
916 size_t NumHomVariableGroups() const;
917
918
922 size_t NumConstants() const;
923
927 size_t NumParameters() const;
928
929
933 size_t NumImplicitParameters() const;
934
935
936
937
938
940 //
941 // Setters -- templated.
942 //
944
963 template<typename T>
964 void SetVariables(const Vec<T> & new_values) const
965 {
966 if (new_values.size()!= NumVariables())
967 throw std::runtime_error("variable vector of different length from system-owned variables in SetVariables");
968
969 const auto& vars = Variables();
970
971 #ifndef BERTINI_DISABLE_PRECISION_CHECKS
972 if (!std::is_same<T,dbl>::value && (Precision(new_values) != this->precision()))
973 throw std::runtime_error("precision of input point in SetVariables (" + std::to_string(Precision(new_values)) + ") must match the precision of the system (" + std::to_string(this->precision()) + ").");
974
975 if (!std::is_same<T,dbl>::value && (vars[0]->node::NamedSymbol::precision() != this->precision()) )
976 throw std::runtime_error("internally, precision of variables (" + std::to_string(vars[0]->node::NamedSymbol::precision()) + ") in SetVariables must match the precision of the system (" + std::to_string(this->precision()) + ").");
977 #endif
978
979 if (!is_differentiated_)
981
982
983 switch (eval_method_){
984 case EvalMethod::FunctionTree:{
985 auto counter = 0;
986
987 for (auto iter=vars.begin(); iter!=vars.end(); iter++, counter++) {
988 (*iter)->set_current_value(new_values(counter));
989 }
990
991 std::get<Vec<T> >(current_variable_values_) = new_values;
992 break;
993 }
994 case EvalMethod::SLP:{
995 std::get<Vec<T> >(current_variable_values_) = new_values; // if this isn't here, then patch evaluation breaks.
996 slp_.SetVariableValues(new_values);
997 break;
998 }
999 } // switch
1000
1001
1002 }
1003
1004
1005
1014 template<typename T>
1015 void SetPathVariable(T const& new_value) const
1016 {
1017 if (!have_path_variable_)
1018 throw std::runtime_error("trying to set the value of the path variable, but one is not defined for this system");
1019
1020 if (!is_differentiated_)
1021 Differentiate();
1022
1023 switch (eval_method_){
1024 case EvalMethod::FunctionTree:{
1025 path_variable_->set_current_value(new_value);
1026 break;
1027 }
1028 case EvalMethod::SLP:{
1029 path_variable_->set_current_value(new_value);
1030 slp_.SetPathVariable(new_value);
1031 }
1032 }
1033 }
1034
1035
1036 template<typename T>
1037 void SetAndReset(Vec<T> const& new_space, T const& new_time) const
1038 {
1039 SetVariables(new_space);
1040 SetPathVariable(new_time);
1041
1042 Reset();
1043 }
1044
1045 template<typename T>
1046 void SetAndReset(Vec<T> const& new_space) const
1047 {
1048 SetVariables(new_space);
1049
1050 Reset();
1051 }
1052
1058 template<typename T>
1059 void SetImplicitParameters(Vec<T> new_values) const
1060 {
1061 if (new_values.size()!= implicit_parameters_.size())
1062 throw std::runtime_error("trying to set implicit parameter values, but there is a size mismatch");
1063
1064 size_t counter = 0;
1065 for (auto iter=implicit_parameters_.begin(); iter!=implicit_parameters_.end(); iter++, counter++)
1066 (*iter)->set_current_value(new_values(counter));
1067
1068 }
1069
1070
1071
1072
1073
1074
1075
1076
1078 //
1079 // Adders -- functions which add things to the system.
1080 //
1082
1083
1089 void AddVariableGroup(VariableGroup const& v);
1090
1091
1097 void AddHomVariableGroup(VariableGroup const& v);
1098
1099
1100
1106 void AddUngroupedVariable(Var const& v);
1107
1108
1114 void AddUngroupedVariables(VariableGroup const& v);
1115
1116
1122 void AddImplicitParameter(Var const& v);
1123
1124
1130 void AddImplicitParameters(VariableGroup const& v);
1131
1132
1133
1134
1140 void AddParameter(Fn const& F);
1141
1147 void AddParameters(std::vector<Fn> const& F);
1148
1149
1150
1158 void AddSubfunction(Fn const& F);
1159
1167 void AddSubfunctions(std::vector<Fn> const& F);
1168
1169
1170
1176 void AddFunction(Fn const& F);
1177
1184 void AddFunction(Nd const& F, std::string const& name = "unnamed_function");
1185
1186
1192 void AddFunctions(std::vector<Fn> const& F);
1193
1194
1195
1196
1197
1198
1199
1205 void AddConstant(Fn const& C);
1206
1207
1213 void AddConstants(std::vector<Fn> const& C);
1214
1215
1216
1217
1223 void AddPathVariable(Var const& v);
1224
1225
1231 bool HavePathVariable() const;
1232
1233 auto& GetPathVariable() const{
1234 if (this->HavePathVariable())
1235 return this->path_variable_;
1236 else
1237 throw std::runtime_error("trying to get path variable for a system which doesn't have a path variable defined");
1238 }
1239
1251 VariableGroup VariableOrdering() const;
1252
1253
1259 const VariableGroup& Variables() const;
1260
1266 VariableGroup const& AffineVariableGroup(size_t index) const
1267 {
1268 return variable_groups_[index];
1269 }
1270
1273 std::vector<unsigned> VariableGroupSizes() const
1274 {
1275 return VariableGroupSizesFIFO();
1276 }
1277
1285 template<typename T>
1286 Vec<T> DehomogenizePoint(Vec<T> const& x) const
1287 {
1288
1289 if (x.size()!=NumVariables()){
1290 std::stringstream message;
1291 message << "dehomogenizing point with incorrect number of coordinates. input has ";
1292 message << x.size();
1293 message << " but system expects ";
1294 message << NumVariables();
1295 throw std::runtime_error(message.str());
1296 }
1297
1298 if (!have_ordering_)
1299 ConstructOrdering();
1300
1301 return DehomogenizePointFIFO(x);
1302 }
1303
1304
1305
1306
1312 auto Function(unsigned index) const
1313 {
1314 return functions_[index];
1315 }
1316
1317
1322 {
1323 return functions_;
1324 }
1325
1326
1327
1331 auto VariableGroups() const
1332 {
1333 return variable_groups_;
1334 }
1335
1340 {
1341 return hom_variable_groups_;
1342 }
1343
1344
1345 const Var& PathVariable() const
1346 {
1347 return path_variable_;
1348 }
1349
1350
1362 std::vector< Nd > GetSpaceDerivatives() const;
1363
1369 std::vector< Nd > GetTimeDerivatives() const;
1370
1371
1373 //
1374 // Functions involving coefficients of the system
1375 //
1377
1378
1385 template <typename NumT>
1386 typename Eigen::NumTraits<NumT>::Real CoefficientBound(unsigned num_evaluations = 1) const;
1387
1388
1389
1395 int DegreeBound() const;
1396
1402 std::vector<int> Degrees() const;
1403
1410 std::vector<int> Degrees(VariableGroup const& vars) const;
1411
1415 void ReorderFunctionsByDegreeDecreasing();
1416
1417
1421 void ReorderFunctionsByDegreeIncreasing();
1422
1423
1424
1425
1426
1428 //
1429 // Functions regarding patches.
1430 //
1432
1433
1434
1435
1436
1444 void AutoPatch()
1445 {
1446 AutoPatchFIFO();
1447 }
1448
1452 void CopyPatches(System const& other);
1453
1454
1455 Patch GetPatch() const
1456 {
1457 return patch_;
1458 }
1459
1463 bool IsPatched() const
1464 {
1465 return is_patched_;
1466 }
1467
1468
1469 template <typename T>
1470 Vec<T> RescalePointToFitPatch(Vec<T> const& x) const
1471 {
1472 return patch_.RescalePoint(x);
1473 }
1474
1475
1476 template<typename T>
1477 void RescalePointToFitPatchInPlace(Vec<T> & x) const
1478 {
1479 patch_.RescalePointToFitInPlace(x);
1480 }
1484 friend std::ostream& operator <<(std::ostream& out, const System & s);
1485
1486
1490 void ClearVariables();
1491
1492
1502 void CopyVariableStructure(System const& other);
1503
1509 void DontAssumeUniformPrecision()
1510 {
1511 AssumeUniformPrecision(false);
1512 }
1513
1514 void PleaseAssumeUniformPrecision()
1515 {
1516 AssumeUniformPrecision(true);
1517 }
1518
1519 void AssumeUniformPrecision(bool val)
1520 {
1521 assume_uniform_precision_ = false;
1522 }
1523
1527 auto IsAssumingUniformPrecision() const
1528 {
1529 return assume_uniform_precision_;
1530 }
1531
1532 inline
1533 void PleaseAutoSimplify()
1534 {
1535 SetAutoSimplify(true);
1536 }
1537
1538 inline
1539 void DontAutoSimplify()
1540 {
1541 SetAutoSimplify(false);
1542 }
1543
1544 void SetAutoSimplify(bool val)
1545 {
1546 auto_simplify_ = val;
1547 }
1548
1549
1553 auto IsAutoSimplifying() const
1554 {
1555 return auto_simplify_;
1556 }
1557
1563 void SimplifyFunctions();
1564
1570 void SimplifyDerivatives() const;
1571
1577 void Simplify();
1578
1579
1583 void SetEvalMethod(EvalMethod method)
1584 {
1585 eval_method_ = method;
1586 }
1587
1591 EvalMethod GetEvalMethod() const
1592 {
1593 return eval_method_;
1594 }
1595
1596
1597
1598
1602 void SetDerivMethod(DerivMethod method)
1603 {
1604 deriv_method_ = method;
1605 }
1606
1610 DerivMethod GetDerivMethod() const
1611 {
1612 return deriv_method_;
1613 }
1614
1615
1623 System& operator+=(System const& rhs);
1624
1632 friend const System operator+(System lhs, System const& rhs);
1633
1639 System& operator*=(Nd const& N);
1640
1646 friend const System operator*(System s, Nd const& N);
1647
1653 friend const System operator*(Nd const& N, System const& s);
1654 private:
1655
1659 std::vector<unsigned> VariableGroupSizesFIFO() const;
1660
1661
1665 void AutoPatchFIFO();
1666
1667
1668
1676 template<typename T>
1677 Vec<T> DehomogenizePointFIFO(Vec<T> const& x) const
1678 {
1679 #ifndef BERTINI_DISABLE_ASSERTS
1680 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.");
1681 #endif
1682
1683 bool is_homogenized = homogenizing_variables_.size()!=0;
1684 Vec<T> x_dehomogenized(NumNaturalVariables());
1685
1686 unsigned affine_group_counter = 0;
1687 unsigned hom_group_counter = 0;
1688 unsigned ungrouped_variable_counter = 0;
1689
1690 unsigned hom_index = 0; // index into x, the point we are dehomogenizing
1691 unsigned dehom_index = 0; // index into x_dehomogenized, the point we are computing
1692
1693 for (auto& iter : time_order_of_variable_groups_)
1694 {
1695 switch (iter){
1696 case VariableGroupType::Affine:
1697 {
1698 if (is_homogenized)
1699 {
1700 auto h = x(hom_index++);
1701 for (unsigned ii = 0; ii < variable_groups_[affine_group_counter].size(); ++ii)
1702 x_dehomogenized(dehom_index++) = x(hom_index++) / h;
1703 affine_group_counter++;
1704 }
1705 else
1706 {
1707 for (unsigned ii = 0; ii < variable_groups_[affine_group_counter].size(); ++ii)
1708 x_dehomogenized(dehom_index++) = x(hom_index++);
1709 }
1710 break;
1711 }
1712 case VariableGroupType::Homogeneous:
1713 {
1714 for (unsigned ii = 0; ii < hom_variable_groups_[hom_group_counter].size(); ++ii)
1715 x_dehomogenized(dehom_index++) = x(hom_index++);
1716 break;
1717 }
1718 case VariableGroupType::Ungrouped:
1719 {
1720 x_dehomogenized(dehom_index++) = x(hom_index++);
1721 ungrouped_variable_counter++;
1722 break;
1723 }
1724 default:
1725 {
1726 throw std::runtime_error("unacceptable VariableGroupType in FIFOVariableOrdering");
1727 }
1728 }
1729 }
1730
1731 return x_dehomogenized;
1732 }
1733
1734 void DifferentiateUsingDerivatives() const;
1735 void DifferentiateUsingJacobianNode() const;
1736
1740 void ConstructOrdering() const;
1741
1742
1743 VariableGroup ungrouped_variables_;
1744 std::vector< VariableGroup > variable_groups_;
1745 std::vector< VariableGroup > hom_variable_groups_;
1746
1747 VariableGroup homogenizing_variables_;
1748
1749
1750 bool have_path_variable_ = false;
1751 Var path_variable_;
1752
1753 VariableGroup implicit_parameters_;
1754 std::vector< Fn > explicit_parameters_;
1755
1756 std::vector< Fn > constant_subfunctions_;
1757 std::vector< Fn > subfunctions_;
1758 std::vector< Fn > functions_;
1759
1760 class Patch patch_;
1761 bool is_patched_ = false;
1762
1763 mutable std::vector< Jac > jacobian_;
1764
1765 mutable std::vector< Nd > space_derivatives_;
1766
1767 mutable std::vector< Nd > time_derivatives_;
1768
1769 mutable bool is_differentiated_ = false;
1770
1771 mutable StraightLineProgram slp_;
1772
1773 std::vector< VariableGroupType > time_order_of_variable_groups_;
1774
1775 mutable std::tuple< Vec<dbl>, Vec<mpfr_complex> > current_variable_values_;
1776
1777 mutable VariableGroup variable_ordering_;
1778 mutable bool have_ordering_ = false;
1779
1780 mutable unsigned precision_;
1781
1782 bool assume_uniform_precision_ = false;
1783
1784 EvalMethod eval_method_ = DefaultEvalMethod();
1785 DerivMethod deriv_method_ = DefaultDerivMethod();
1786
1787 bool auto_simplify_ = DefaultAutoSimplify();
1788
1789
1790
1791
1792
1793
1794 friend class boost::serialization::access;
1795
1796 /*definition of serialize function*/
1797 template<class Archive>
1798 void serialize(Archive & ar, const unsigned int version){
1799 ar & ungrouped_variables_;
1800 ar & variable_groups_;
1801 ar & hom_variable_groups_;
1802
1803 ar & homogenizing_variables_;
1804
1805 ar & have_path_variable_;
1806 ar & path_variable_;
1807
1808 ar & implicit_parameters_;
1809 ar & explicit_parameters_;
1810
1811 ar & constant_subfunctions_;
1812 ar & subfunctions_;
1813 ar & functions_;
1814
1815
1816 ar & patch_;
1817 ar & is_patched_;
1818
1819
1820 ar & assume_uniform_precision_;
1821
1822 ar & eval_method_;
1823 ar & deriv_method_;
1824
1825 ar & auto_simplify_;
1826
1827 // now for the cached / mutable things
1828 ar & precision_;
1829
1830
1831 // if (Archive::is_loading::value == true){
1832 // is_differentiated_ = false;}
1833 // // else
1834 // // {
1835 ar & is_differentiated_;
1836 ar & jacobian_;
1837 ar & space_derivatives_;
1838 ar & time_derivatives_;
1839 // }
1840
1841
1842 ar & slp_; // does this need to be re-constructed after de-serialization?
1843
1844 ar & time_order_of_variable_groups_;
1845
1846 // if (Archive::is_loading::value == true){
1847 // have_ordering_ = false;}
1848 // else
1849 // {
1850 ar & have_ordering_;
1851 ar & variable_ordering_;
1852 // }
1853
1854
1855 // if (Archive::is_loading::value == true){
1856 // std::get<Vec<dbl>>(current_variable_values_).resize(NumVariables());
1857 // std::get<Vec<mpfr_complex>>(current_variable_values_).resize(NumVariables());
1858 // }
1859 // // next two lines no matter what
1860 // ar & std::get<Vec<dbl>>(current_variable_values_);
1861 // ar & std::get<Vec<mpfr_complex>>(current_variable_values_);
1862
1863 }
1864
1865
1866 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
1867 };
1868
1869
1882 System Concatenate(System sys1, System const& sys2);
1883
1884
1885
1889 System Clone(System const& sys);
1890
1894 void Simplify(System & sys);
1895}
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905#endif // for the ifndef include guards
1906
1907
1908
The fundamental polynomial system class for Bertini2.
Definition system/system.hpp:99
friend void swap(System &a, System &b)
void AddSubfunction(Fn const &F)
auto HomVariableGroups() const
Definition system/system.hpp:1339
void SetPathVariable(T const &new_value) const
Definition system/system.hpp:1015
void AddUngroupedVariable(Var const &v)
void SetImplicitParameters(Vec< T > new_values) const
Definition system/system.hpp:1059
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/system.hpp:680
void EvalInPlace(Vec< T > &function_values) const
Evaluate the system using the previously set variable (and time) values, in place.
Definition system/system.hpp:272
void AddImplicitParameters(VariableGroup const &v)
Vec< T > DehomogenizePoint(Vec< T > const &x) const
Dehomogenize a point, using the variable grouping / structure of the system.
Definition system/system.hpp:1286
void JacobianInPlace(Mat< T > &J, const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Definition system/system.hpp:608
auto Function(unsigned index) const
Get a function by its index.
Definition system/system.hpp:1312
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/system.hpp:1273
void AddFunction(Nd const &F, std::string const &name="unnamed_function")
void AddParameter(Fn const &F)
void AddSubfunctions(std::vector< Fn > const &F)
size_t NumConstants() const
size_t NumImplicitParameters() const
size_t NumNaturalFunctions() const
VariableGroup VariableOrdering() const
void JacobianInPlace(Mat< T > &J, const Vec< T > &variable_values) const
Definition system/system.hpp:552
Mat< T > Jacobian() const
Definition system/system.hpp:531
System()
The default constructor for a system.
Definition system/system.hpp:111
void AddConstant(Fn const &C)
Vec< T > TimeDerivative() const
Compute the time-derivative of a system.
Definition system/system.hpp:823
void AddUngroupedVariables(VariableGroup const &v)
size_t NumVariableGroups() const
bool IsPolynomial() const
Vec< T > Eval(const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Definition system/system.hpp:442
void precision(unsigned new_precision) const
size_t NumTotalVariableGroups() const
size_t NumNaturalVariables() const
System(System const &other)
The copy operator.
void JacobianInPlace(Mat< T > &J) const
Evaluate the Jacobian matrix of the system, using the previous space and time values,...
Definition system/system.hpp:470
VariableGroup const & AffineVariableGroup(size_t index) const
Get an affine variable group the class has defined.
Definition system/system.hpp:1266
void ResetFunctions() const
Force re-evaluation of the system next eval of functions. If something has changed in the system,...
Definition system/system.hpp:173
bool HavePathVariable() const
Mat< T > Jacobian(const Vec< T > &variable_values) const
Definition system/system.hpp:580
unsigned precision() const
Get the current precision of a system.
Definition system/system.hpp:158
Vec< T > TimeDerivative(const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Compute the time-derivative of a system.
Definition system/system.hpp:706
size_t NumPatches() const
Definition system/system.hpp:872
Vec< T > TimeDerivative(const Eigen::MatrixBase< Derived > &variable_values) const
Compute the time-derivative of a system.
Definition system/system.hpp:747
const VariableGroup & Variables() const
size_t NumVariables() const
void SetVariables(const Vec< T > &new_values) const
Definition system/system.hpp:964
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/system.hpp:339
auto VariableGroups() const
Definition system/system.hpp:1331
void AddHomVariableGroup(VariableGroup const &v)
size_t NumUngroupedVariables() const
void ResetJacobian() const
Force re-evaluation of the system next eval of Jacobians. If something has changed in the system,...
Definition system/system.hpp:191
size_t NumHomVariableGroups() const
void EvalInPlace(Vec< T > &function_values, const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Definition system/system.hpp:405
void Reset() const
A complete reset of the system, so that all of functions, space derivatives, and time derivatives wil...
Definition system/system.hpp:258
Vec< T > Eval() const
Evaluate the system using the previously set variable (and time) values, creating vector of function ...
Definition system/system.hpp:317
size_t NumParameters() const
size_t NumTotalFunctions() const
bool IsHomogeneous() const
auto GetNaturalFunctions() const
Get the functions.
Definition system/system.hpp:1321
Mat< T > Jacobian(const Eigen::MatrixBase< Derived > &variable_values, const T &path_variable_value) const
Definition system/system.hpp:640
void AddPathVariable(Var const &v)
void AddFunctions(std::vector< Fn > const &F)
void AddVariableGroup(VariableGroup const &v)
void AddImplicitParameter(Var const &v)
System(System &&other)
The move copy operator.
Definition system/system.hpp:128
size_t NumHomVariables() const
Derived::PlainObject Eval(const Eigen::MatrixBase< Derived > &variable_values) const
Evaluate the system, provided the system has no path variable defined.
Definition system/system.hpp:371
System & operator=(System &&other)=default
The move assignment operator.
void AddConstants(std::vector< Fn > const &C)
void Differentiate() const
Compute and internally store the symbolic Jacobian of the system.
void AddParameters(std::vector< Fn > const &F)
void AddFunction(Fn const &F)
virtual void precision(unsigned int prec) const =0
std::complex< double > operator*(unsigned i, std::complex< double > z)
Overload * for unsigned * complex<double>
Definition double_extensions.hpp:49
Bertini extensions of the Eigen linear algebra library.
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object. If the object is empty, it's the precision of a default-constru...
Definition eigen_extensions.hpp:292
Collects the various header files which define the Bertini2 function tree node types.
The main multiprecision complex number type. This is essentially boost::multiprecision' complex.
Extensions to the Boost.Multiprecision library.
Provides the bertini::Patch class.
Provides the bertini::StraightLineProgram class.
System Concatenate(System sys1, System const &sys2)
Concatenate two compatible systems.
System Clone(System const &sys)
Do a deep clone of the system. This includes the entire structure, variables, etc....
EvalMethod DefaultEvalMethod()
Gets the default evaluation method for Jacobians. One might be faster...
bool DefaultAutoSimplify()
Get the default value for whether a system should autosimplify.