Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
straight_line_program.hpp
Go to the documentation of this file.
1
2//This file is part of Bertini 2.
3//
4//straight_line_program.hpp is free software: you can redistribute it and/or modify
5//it under the terms of the GNU General Public License as published by
6//the Free Software Foundation, either version 3 of the License, or
7//(at your option) any later version.
8//
9//straight_line_program.hpp is distributed in the hope that it will be useful,
10//but WITHOUT ANY WARRANTY; without even the implied warranty of
11//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12//GNU General Public License for more details.
13//
14//You should have received a copy of the GNU General Public License
15//along with straight_line_program.hpp. If not, see <http://www.gnu.org/licenses/>.
16//
17// Copyright(C) Bertini2 Development Team
18//
19// See <http://www.gnu.org/licenses/> for a copy of the license,
20// as well as COPYING. Bertini2 is provided with permitted
21// additional terms in the b2/licenses/ directory.
22
39
40#ifndef BERTINI_SLP_HPP
41#define BERTINI_SLP_HPP
42
43#pragma once
44
45#include <assert.h>
46#include <vector>
47#include <map>
48#include <memory>
49#include <tuple>
50
56
57#include <boost/serialization/utility.hpp>
58#include <boost/serialization/split_member.hpp>
59
60// code copied from Bertini1's file include/bertini.h
61
62
63/*
64
65typedef struct
66{
67 int num_funcs;
68 int num_hom_var_gp;
69 int num_var_gp;
70 int *type; // 0 - hom_var_gp, 1 - var_gp
71 int *size; // size of the group of the user listed variables (total size = size + type)
72} preproc_data;
73
74
75typedef struct
76{
77 point_d funcVals;
78 point_d parVals;
79 vec_d parDer;
80 mat_d Jv;
81 mat_d Jp;
82} eval_struct_d;
83
84typedef struct
85{
86 point_mp funcVals;
87 point_mp parVals;
88 vec_mp parDer;
89 mat_mp Jv;
90 mat_mp Jp;
91} eval_struct_mp;
92
93
94The straight-line program structure. This is the way that polynomials are stored internally.
95typedef struct {
96 int *prog; // The program instructions. (a big integer array)
97 int size; // size of the instruction program.
98 int memSize; // Amount of memory it needs in workspace (for temp and final results).
99 num_t *nums; // The array of real numbers.
100 int precision; // The precision at which evaluation should occur
101
102 // INFO NEEDED FOR M-HOM:
103 int num_var_gps; // The total number of variable groups (i.e., m from m-hom).
104 int *var_gp_sizes; // The size of each of the groups.
105 int index_of_first_number_for_proj_trans; // The address of the first number used in the projective transformation polynomials.
106
107 // STOP LOCATIONS:
108 int numInstAtEndUpdate; // instruction number at end of update. i.e. i = 0; while (i < numInstAtEndUpdate) ..
109 int numInstAtEndParams; // instruction number at end of params. i.e. i = numInstAtEndUpdate; while (i < numInstAtEndParams) ..
110 int numInstAtEndFnEval; // instruction number at end of function eval. i.e. i = numInstAtEndParams; while (i < numInstAtEndFnEval) ..
111 int numInstAtEndPDeriv; // instruction number at end of param diff. i.e. i = numInstAtEndFnEval; while (i < numInstAtEndPDeriv) ..
112 int numInstAtEndJvEval; // instruction number at end of Jv eval. i.e. i = numInstAtEndPDeriv; while (i < numInstAtEndJvEval) ..
113 // for Jp eval: i = numInstAtEndJvEval; while (i < size) ..
114
115 // INPUT AMOUNTS:
116 int numVars; // Number of variables in the function being computed.
117 int numPathVars; // Number of path variables. Ought to be 1 usually.
118 int numNums; // Number of real numbers used in evaluation.
119 int numConsts; // Number of constants.
120
121 // OUTPUT AMOUNTS:
122 int numPars; // Number of parameters
123 int numFuncs; // Number of coordinate functions in the homotopy.
124 int numSubfuncs; // Number of subfunctions.
125
126 // INPUT LOCATIONS:
127 int inpVars; // Where the input variable values are stored.
128 int inpPathVars; // Where the values of the path variables are stored.
129 int IAddr; // Where the constant I is stored.
130 int numAddr; // Where the first num_t is stored.
131 int constAddr; // Where the first constant is stored.
132
133 // OUTPUT LOCATIONS:
134 int evalPars; // Where U(t), for given t, is stored.
135 int evalDPars; // Where the derivatives of the parameters are stored.
136 int evalFuncs; // Where H(x,t) is stored.
137 int evalJVars; // Where the Jacobian w.r.t. vars is stored.
138 int evalJPars; // Where the Jacobian w.r.t. pars is stored.
139 int evalSubs; // Where the subfunctions are stored
140 int evalJSubsV; // Where the derivatives of the subfunctions w.r.t. vars are stored.
141 int evalJSubsP; // Where the derivatives of the subfunctions w.r.t. pars are stored.
142} prog_t;
143*/
144
145
146
147namespace bertini {
148
149 class SLPCompiler;
150 class System; // a forward declaration, solving the circular inclusion problem
152
153
165 enum class NumType : uint8_t { Real = 0, Complex = 1 }; // Integer added in a later stage
166
167
169 enum Operation { // we'll start with the binary ones
170 Add= 1 << 0,
171 Subtract= 1 << 1,
172 Multiply= 1 << 2,
173 Divide= 1 << 3,
174 Power= 1 << 4,
175 Exp= 1 << 5,
176 Log= 1 << 6,
177 Negate= 1 << 7,
178 Sqrt= 1 << 8,
179 Sin= 1 << 9,
180 Cos= 1 << 10,
181 Tan= 1 << 11,
182 Asin= 1 << 12,
183 Acos= 1 << 13,
184 Atan= 1 << 14,
185 Assign= 1 << 15,
186 IntPower= 1 << 16,
187 };
188
192
194 constexpr bool IsUnary(Operation op)
195 {
196 return op & UnaryOperations;
197 }
198
200 constexpr bool IsBinary(Operation op)
201 {
202 return op & BinaryOperations;
203 }
204
206 std::string OpcodeToString(Operation op);
207
215 void SetSLPValueNumbering(bool on);
216
217 // Compile-time bank selectors (ADR-0034). After NumType inference, each instruction's opcode word
218 // gets these high bits set to record which bank (real or complex) each operand and the result live
219 // in, so the hot eval loop reads the banks inline from the instruction it has already loaded instead
220 // of looking up slot_numtype_[slot] per operand. The base Operation occupies bits 0..16, so these
221 // sit well clear of it; masking with kOpcodeMask recovers the base op for the switch and for IsUnary.
222 constexpr size_t kOpcodeMask = (static_cast<size_t>(1) << 17) - 1;
223 constexpr size_t kArg0Real = static_cast<size_t>(1) << 20;
224 constexpr size_t kArg1Real = static_cast<size_t>(1) << 21;
225 constexpr size_t kOutReal = static_cast<size_t>(1) << 22;
226
227
234 size_t Functions{0};
235 size_t Jacobian{0};
236 size_t TimeDeriv{0};
237
239
241 template <typename Archive>
242 void serialize(Archive& ar, const unsigned /*version*/) {
243 ar & Functions;
244 ar & Jacobian;
245 ar & TimeDeriv;
246 }
248 };
249
256 size_t Variables{0};
257 size_t Time{0};
258
260
262 template <typename Archive>
263 void serialize(Archive& ar, const unsigned /*version*/) {
264 ar & Variables;
265 ar & Time;
266 }
268 };
269
276 size_t Functions{0};
277 size_t Variables{0};
278 size_t Jacobian{0};
279 size_t TimeDeriv{0};
280
282
284 template <typename Archive>
285 void serialize(Archive& ar, const unsigned /*version*/) {
286 ar & Functions;
287 ar & Variables;
288 ar & Jacobian;
289 ar & TimeDeriv;
290 }
292 };
293
294
295
308 enum class Kind : int { Integer, Rational, Complex, Pi, E };
309
315 size_t slot = 0;
316
319 template<typename NumT> NumT Produce() const;
320
322 template<typename RealT> RealT ProduceReal() const;
323
326 bool IsReal() const {
327 switch (kind) {
328 case Kind::Integer: case Kind::Pi: case Kind::E: return true;
329 case Kind::Rational: return rat_imag == 0;
330 case Kind::Complex: return float_value.imag() == 0;
331 }
332 return false;
333 }
334
337 template <typename Archive>
338 void serialize(Archive& ar, const unsigned /*version*/) {
339 int k = static_cast<int>(kind);
340 ar & k;
341 kind = static_cast<Kind>(k);
342 ar & int_value;
343 ar & rat_real;
344 ar & rat_imag;
345 ar & float_value;
346 ar & slot;
347 }
349 };
350
351
352
361 public:
363 template<typename NumT>
364 std::vector<NumT>& Get() { return std::get<std::vector<NumT>>(registers_); }
365
367 template<typename NumT>
368 std::vector<NumT> const& Get() const { return std::get<std::vector<NumT>>(registers_); }
369
373 mutable std::tuple< std::vector<real_dbl>, std::vector<complex_dbl>,
374 std::vector<real_mp>, std::vector<complex_mp> > registers_;
375
376 mutable unsigned precision_ = 16;
377 mutable bool is_evaluated_ = false;
378
379 // Whether the frozen prologue's results in memory are valid. Tracked per number type: the
380 // double constants never change once computed; the mpfr constants are valid only while the
381 // working precision is unchanged. Transient (recomputed on first eval; not serialized).
382 mutable bool frozen_valid_dbl_ = false;
383 mutable unsigned frozen_valid_mp_precision_ = 0;
384
386
388 template <typename Archive>
389 void serialize(Archive& ar, const unsigned /*version*/) {
390 ar & std::get<std::vector<real_dbl>>(registers_);
391 ar & std::get<std::vector<complex_dbl>>(registers_);
392 ar & std::get<std::vector<real_mp>>(registers_);
393 ar & std::get<std::vector<complex_mp>>(registers_);
394 ar & precision_;
395 ar & is_evaluated_;
396 // frozen_valid_* are transient (recomputed on first eval); not serialized.
397 }
399 };
400
401
402
412 friend SLPCompiler;
414 friend std::ostream& operator <<(std::ostream& out, const StraightLineProgram & s);
415
416 private:
417 using Nd = std::shared_ptr<const node::Node>;
418
419 public:
420 using IntT = int;
421
422 SLPProgram() = default;
423
426 static bool tiers_enabled_;
427
429 bool HavePathVariable() const { return has_path_variable_; }
431 inline unsigned NumFunctions() const{ return static_cast<unsigned>(number_of_.Functions);}
433 inline unsigned NumVariables() const{ return static_cast<unsigned>(number_of_.Variables);}
435 inline size_t NumSlots() const { return num_slots_; }
437 inline size_t FirstLiveInstructionOffset() const { return first_live_instruction_; }
438
443 std::size_t ContentHash() const;
444
447 bool SameContent(SLPProgram const& other) const;
448
459 template<typename NumT>
460 void Eval(SLPMemory& memory) const; // this definition is in cpp, along with the lines that instantiate the needed versions.
461
462 private:
471 void AddInstruction(Operation binary_op, size_t in_loc1, size_t in_loc2, size_t out_loc);
472
480 void AddInstruction(Operation unary_op, size_t in_loc, size_t out_loc);
481
485 void AddConstant(ConstantRecipe recipe);
486
487 // Reorder `instructions_` into [frozen | live] and set `first_live_instruction_`. Called once
488 // at the end of compilation, after `num_slots_` is set.
489 void PartitionInstructions();
490
491 // Fill slot_numtype_ by a forward pass over the (dependency-ordered) tape (ADR-0034): seed
492 // constant slots from ConstantRecipe::IsReal() and input slots as Complex, then propagate the
493 // NumType join through each instruction. Called at the end of compilation.
494 void ComputeSlotNumTypes();
495
496 // Pack each instruction's operand/result banks (from slot_numtype_) into its opcode word's high
497 // bits (kArg0Real/kArg1Real/kOutReal), so eval dispatches banks without per-slot lookups. Runs
498 // after ComputeSlotNumTypes and PartitionInstructions (it only sets bits; order vs. partition
499 // doesn't matter as it rewrites instructions in place).
500 void SpecializeInstructions();
501
502
503 bool has_path_variable_ = false;
504
505 SLPNumberOf number_of_;
506 SLPOutputLocations output_locations_;
507 SLPInputLocations input_locations_;
508
509 std::vector<IntT> integers_;
510
511 std::vector<size_t> instructions_;
512 std::vector<ConstantRecipe> constant_recipes_;
513
514 // Freeze-set tape partition (ADR-0027). After compilation the instructions are stably
515 // reordered so every "frozen" instruction (one whose result depends only on frozen input
516 // slots --- the literal numbers, Pi/E; i.e. the freeze set is currently the constants)
517 // precedes every "live" instruction. `first_live_instruction_` is the word offset where the
518 // live segment begins. The frozen prologue depends only on precision, so a point-only change
519 // re-runs from `first_live_instruction_` and reuses the frozen slots already in memory; the
520 // whole tape runs only when the frozen values are not yet valid for the working precision.
521 size_t first_live_instruction_ = 0;
522
523 size_t num_slots_ = 0;
524
525 // The NumType of each slot (ADR-0034), indexed by global slot number; sized to num_slots_.
526 // Selects which register bank a slot lives in. Default Complex (filled by the compiler);
527 // an all-Complex table reproduces the pre-tier behavior exactly.
528 std::vector<NumType> slot_numtype_;
529
530
532
534 template <typename Archive>
535 void serialize(Archive& ar, const unsigned /*version*/) {
536 ar & has_path_variable_;
537 ar & number_of_;
538 ar & output_locations_;
539 ar & input_locations_;
540 ar & integers_;
541 ar & instructions_;
542 ar & constant_recipes_;
543 ar & first_live_instruction_;
544 ar & num_slots_;
545 ar & slot_numtype_;
546 }
548 };
549
550
551
563 std::shared_ptr<const SLPProgram> InternProgram(std::shared_ptr<const SLPProgram> const& candidate);
564
565
588 friend SLPCompiler;
589 friend std::ostream& operator <<(std::ostream& out, const StraightLineProgram & s);
590
591 private:
592 using Nd = std::shared_ptr<const node::Node>;
593
594 public:
595
600
601 StraightLineProgram() : program_(std::make_shared<const SLPProgram>()) {}
602
606 template<typename Derived>
607 void Eval(Eigen::MatrixBase<Derived> const& variable_values) const
608 {
609 using NumT = typename Derived::Scalar;
610 SetVariableValues(variable_values);
611 program_->Eval<NumT>(memory_);
612 }
613
626 template<typename Derived, typename ComplexT>
627 void Eval(Eigen::MatrixBase<Derived> const& variable_values, ComplexT const& time) const
628 {
629 using NumT = typename Derived::Scalar;
630 static_assert(std::is_same<NumT, ComplexT>::value, "scalar types must be the same");
631
632 // 1. copy variable values into memory locations they're supposed to go in
633 SetVariableValues(variable_values);
634 SetPathVariable(time);
635 program_->Eval<NumT>(memory_);
636 }
637
638
639
640 // a placeholder function that needs to be written. now just calls eval, since the eval functionality is both functions and jacobian wrapped together -- we don't keep arrays of their locations separately yet, so that would be the starting point.
642 template <typename T>
643 void EvalFunctions() const{
644 program_->Eval<T>(memory_);
645 }
646
647
648
649 // a placeholder function that needs to be written. now just calls eval, since the eval functionality is both functions and jacobian wrapped together -- we don't keep arrays of their locations separately yet, so that would be the starting point.
651 template <typename T>
652 void EvalJacobian() const{
653 program_->Eval<T>(memory_);
654 }
655
656
657 // a placeholder function that needs to be written. now just calls eval, since the eval functionality is both functions and jacobian wrapped together -- we don't keep arrays of their locations separately yet, so that would be the starting point.
659 template <typename T>
660 void EvalTimeDeriv() const{
661 program_->Eval<T>(memory_);
662 }
663
664
668 std::shared_ptr<const SLPProgram> Program() const { return program_; }
669
673 size_t NumRealSlots() const {
674 size_t n = 0;
675 for (auto t : program_->slot_numtype_) if (t == NumType::Real) ++n;
676 return n;
677 }
678
679 // Read a slot's value as NumT (complex), pulling from the real or complex bank per its NumType
680 // (ADR-0034). Used to copy outputs out, since a function/derivative slot could be Real-typed.
682 template<typename NumT>
683 NumT ReadSlotAsComplex(size_t slot) const {
684 using RealT = typename NumTraits<NumT>::Real;
685 if (program_->slot_numtype_[slot] == NumType::Real)
686 return NumT(memory_.template Get<RealT>()[slot]);
687 return memory_.template Get<NumT>()[slot];
688 }
689
693 template<typename NumT>
694 void GetFuncValsInPlace(Eigen::Ref<Vec<NumT>> result) const{
695 if (!memory_.is_evaluated_)
696 program_->Eval<NumT>(memory_);
697
698 // copy content (an output slot may be Real-typed; read from the bank its NumType selects)
699 for (size_t ii = 0; ii < program_->number_of_.Functions; ++ii) {
700 result(static_cast<Eigen::Index>(ii)) = ReadSlotAsComplex<NumT>(ii + program_->output_locations_.Functions);
701 }
702 }
703
714
715 template<typename NumT>
716 void GetJacobianInPlace(Eigen::Ref<Mat<NumT>> result) const{
717 if (!memory_.is_evaluated_)
718 program_->Eval<NumT>(memory_);
719
720 // copy content (a derivative slot may be Real-typed; read from the bank its NumType selects)
721 for (size_t jj =0; jj < program_->number_of_.Variables; ++jj) {
722 for (size_t ii = 0; ii < program_->number_of_.Functions; ++ii) {
723 result(static_cast<Eigen::Index>(ii), static_cast<Eigen::Index>(jj)) = ReadSlotAsComplex<NumT>(ii+jj*program_->number_of_.Functions + program_->output_locations_.Jacobian);
724 }
725 }
726 }
727
738
739 template<typename NumT>
740 void GetTimeDerivInPlace(Eigen::Ref<Vec<NumT>> result) const{
741 if (!memory_.is_evaluated_)
742 program_->Eval<NumT>(memory_);
743
744 // copy content (a time-derivative slot may be Real-typed; read from the right bank)
745 for (size_t ii = 0; ii < program_->number_of_.Functions; ++ii) {
746 result(static_cast<Eigen::Index>(ii)) = ReadSlotAsComplex<NumT>(ii + program_->output_locations_.TimeDeriv);
747 }
748 }
749
756 template<typename NumT>
758 Vec<NumT> return_me(this->NumFunctions());
759 GetFuncValsInPlace<NumT>(return_me);
760 return return_me;
761 }
762
768 template<typename NumT>
770 Mat<NumT> return_me(this->NumFunctions(), this->NumVariables());
771 GetJacobianInPlace<NumT>(return_me);
772 return return_me;
773 }
774
780 template<typename NumT>
782 Vec<NumT> return_me(this->NumFunctions());
783 GetTimeDerivInPlace<NumT>(return_me);
784 return return_me;
785 }
786
787
789 inline unsigned NumFunctions() const{ return program_->NumFunctions();}
790
792 inline unsigned NumVariables() const{ return program_->NumVariables();}
793
797 inline size_t NumMemorySlots() const{ return program_->NumSlots(); }
798
802 inline size_t FirstLiveInstructionOffset() const { return program_->FirstLiveInstructionOffset(); }
803
804
810 inline
811 unsigned precision() const
812 {
813 return memory_.precision_;
814 }
815
823 void precision(unsigned new_precision) const;
824
833 template<typename Derived>
834 void SyncPrecision(Eigen::MatrixBase<Derived> const& variable_values) const
835 {
836 using NumT = typename Derived::Scalar;
837 if constexpr (!std::is_same<NumT,complex_dbl>::value)
838 {
839 if (variable_values.size() > 0 && Precision(variable_values)!=memory_.precision_)
840 this->precision(Precision(variable_values));
841 }
842 }
843
849 bool HavePathVariable() const {
850 return program_->has_path_variable_;
851 }
852
856 friend std::ostream& operator <<(std::ostream& out, const StraightLineProgram & s);
857
858
859
860
866 template<typename Derived>
867 void SetVariableValues(Eigen::MatrixBase<Derived> const& variable_values) const{
868 using NumT = typename Derived::Scalar;
869
870 // The Memory's precision is an ARTIFACT OF THE CURRENT EVALUATION, never an
871 // invariant to defend. The compiled Program is a precision-independent tape of
872 // operations; only the Memory holding values carries digits. So evaluating at
873 // whatever precision the caller brings is always meaningful, and the right
874 // response to a mismatch is to RE-TAG THE MEMORY, not to refuse.
875 //
876 // Refusing was a genuine trap, not merely unergonomic. A Memory takes its
877 // precision from the ambient DefaultPrecision() when the program is lazily
878 // compiled, while the owning System keeps whatever it was told, so the two
879 // diverge the moment anything moves the ambient default -- which an AMP tracker
880 // or endgame does as a matter of course. The System was then WEDGED with no way
881 // out: evaluating at its own reported precision raised here, and
882 // System::precision(n) could not repair it, because both setters short-circuit
883 // when the value they are handed already equals the one they hold. See #377.
884 //
885 // An empty variable vector (a constant program with no variables) has no
886 // precision to read. Re-tagging refills the constants from their exact recipes
887 // at the new precision, so accuracy is rebuilt rather than padded with zeros.
888 SyncPrecision(variable_values);
889
890 auto& memory = memory_.Get<NumT>(); // unpack for local reference
891
892 for (size_t ii = 0; ii < program_->number_of_.Variables; ++ii) {
893 //assign to memory
894 memory[ii + program_->input_locations_.Variables] = variable_values(static_cast<Eigen::Index>(ii));
895 }
896 memory_.is_evaluated_ = false;
897 }
898
907 template<typename ComplexT>
908 void SetPathVariable(ComplexT const& time) const{
909
910 // Same doctrine as SetVariableValues, but this one only ever raises: the
911 // variables have already been written into memory by the time the path variable
912 // arrives, so re-tagging DOWNWARD here would truncate them. Memory therefore
913 // ends an evaluation at the max of its arguments' precisions.
914 if constexpr (!std::is_same<ComplexT,complex_dbl>::value)
915 {
916 if (Precision(time) > memory_.precision_)
917 this->precision(Precision(time));
918 }
919
920 if (!this->HavePathVariable())
921 throw std::runtime_error("calling Eval with path variable, but this StraightLineProgram doesn't have one.");
922 // then actually copy the path variable into where it goes in memory
923
924 auto& memory = memory_.Get<ComplexT>(); // unpack for local reference
925
926 memory[program_->input_locations_.Time] = time;
927 // assigning an mp value adopts the SOURCE's precision, so a lower-precision time
928 // would otherwise leave one slot out of step with the rest of memory
929 if constexpr (!std::is_same<ComplexT,complex_dbl>::value)
930 Precision(memory[program_->input_locations_.Time], memory_.precision_);
931 memory_.is_evaluated_ = false;
932 }
933
934
935
936
937
938
939 using IntT = int;
940
941 private:
942
943 // Size the register file to the program's slot count and copy the constant values in. Called
944 // by the compiler once the program is built and memory_.precision_ is set.
945 void SetupMemory();
946
948 template<typename NumT>
949 void CopyNumbersIntoMemory() const;
950
951
952 std::shared_ptr<const SLPProgram> program_;
953 mutable SLPMemory memory_;
954
955
956
958
960
961 // The program is serialized by value through the (owning, this-stage) shared_ptr, sidestepping
962 // boost's shared_ptr<const T> handling. Clone (system.cpp) recompiles the SLP after a round
963 // trip anyway; node_serialization round-trips it faithfully.
964 template <typename Archive>
965 void save(Archive& ar, const unsigned /*version*/) const {
966 SLPProgram const& prog = *program_;
967 ar & prog;
968 ar & memory_;
969 }
970
971 template <typename Archive>
972 void load(Archive& ar, const unsigned /*version*/) {
973 auto prog = std::make_shared<SLPProgram>();
974 ar & *prog;
975 // Re-intern on load (ADR-0042): a deserialized program unifies with a content-equal
976 // live one instead of forking the intern universe.
977 program_ = InternProgram(std::shared_ptr<const SLPProgram>(std::move(prog)));
978 ar & memory_;
979 }
980
981 BOOST_SERIALIZATION_SPLIT_MEMBER()
983
984 };
985
986
989 class SLPCompiler : public VisitorBase,
990
991 // IF YOU ADD A THING HERE, YOU MUST ADD IT ABOVE AND IN THE CPP SOURCE
992
993
994 // symbols and roots
995 public Visitor<node::Variable>,
996 public Visitor<node::Integer>,
997 public Visitor<node::Complex>,
998 public Visitor<node::Rational>,
999 public Visitor<node::NamedExpression>,
1000 public Visitor<node::Differential>,
1001
1002 // arithmetic
1003 public Visitor<node::SumOperator>,
1004 public Visitor<node::MultOperator>,
1005 public Visitor<node::IntegerPowerOperator>,
1006 public Visitor<node::PowerOperator>,
1007 public Visitor<node::ExpOperator>,
1008 public Visitor<node::LogOperator>,
1009 public Visitor<node::NegateOperator>,
1010 public Visitor<node::SqrtOperator>,
1011
1012 // the trig operators
1013 public Visitor<node::SinOperator>,
1014 public Visitor<node::ArcSinOperator>,
1015 public Visitor<node::CosOperator>,
1016 public Visitor<node::ArcCosOperator>,
1017 public Visitor<node::TanOperator>,
1018 public Visitor<node::ArcTanOperator>,
1019
1020 public Visitor<node::special_number::Pi>,
1021 public Visitor<node::special_number::E>
1022
1023 // also missing -- linears and difflinears.
1024
1025 // these abstract base types left out,
1026
1027 // but commented here to explain why
1028 // public Visitor<node::Operator>,// abstract
1029 // public Visitor<node::UnaryOperator>,// abstract
1030 // public Visitor<node::NaryOperator>,// abstract
1031 // public Visitor<node::TrigOperator>,// abstract
1032 {
1033 private:
1034 using Nd = std::shared_ptr<const node::Node>;
1035 using SLP = StraightLineProgram;
1036
1037 public:
1038
1039 // Compile from any source exposing the variable-ordering / functions / derivatives /
1040 // path-variable accessors -- both System and blocks::PolynomialBlock qualify.
1041 // Definition + explicit instantiations live in straight_line_program.cpp.
1046 template <typename SourceT>
1047 SLP Compile(SourceT const& source);
1048
1049
1050 // IF YOU ADD A THING HERE, YOU MUST ADD IT ABOVE AND IN THE CPP SOURCE
1051
1053 // symbols and roots
1054 virtual void Visit(node::Variable const& n);
1055 virtual void Visit(node::Integer const& n);
1056 virtual void Visit(node::Complex const& n);
1057 virtual void Visit(node::Rational const& n);
1058 virtual void Visit(node::NamedExpression const& n);
1059 virtual void Visit(node::Differential const& n);
1060
1061 // arithmetic
1062 virtual void Visit(node::SumOperator const& n);
1063 virtual void Visit(node::MultOperator const& n);
1064 virtual void Visit(node::IntegerPowerOperator const& n);
1065 virtual void Visit(node::PowerOperator const& n);
1066 virtual void Visit(node::ExpOperator const& n);
1067 virtual void Visit(node::LogOperator const& n);
1068 virtual void Visit(node::NegateOperator const& n);
1069 virtual void Visit(node::SqrtOperator const& n);
1070
1071
1072 // the trig operators
1073 virtual void Visit(node::SinOperator const& n);
1074 virtual void Visit(node::ArcSinOperator const& n);
1075 virtual void Visit(node::CosOperator const& n);
1076 virtual void Visit(node::ArcCosOperator const& n);
1077 virtual void Visit(node::TanOperator const& n);
1078 virtual void Visit(node::ArcTanOperator const& n);
1079
1080 virtual void Visit(node::special_number::Pi const& n);
1081 virtual void Visit(node::special_number::E const& n);
1082 // missing -- linear and difflinear
1084 private:
1085
1086
1093 void RegisterConstant(Nd const& nd, ConstantRecipe recipe);
1094
1102 size_t EmitBinary(Operation op, size_t a, size_t b);
1104 size_t EmitUnary(Operation op, size_t a);
1105
1109 void Clear();
1110
1111 size_t next_available_complex_ = 0;
1112 size_t next_available_int_ = 0;
1113
1114 using IntT = int;
1115
1116 std::map<Nd, size_t> locations_encountered_nodes_;
1117 std::map<IntT, size_t> locations_integers_;
1118
1119 // Value-numbering tables (instruction-level CSE): map an emitted computation to the slot
1120 // holding its result, so an identical later computation reuses it. Keyed by (op, operand
1121 // slots); commutative ops canonicalize operand order before keying. Reset per Compile.
1122 std::map<std::tuple<Operation,size_t,size_t>, size_t> vn_binary_;
1123 std::map<std::pair<Operation,size_t>, size_t> vn_unary_;
1124
1125 SLPProgram program_under_construction_;
1126 };
1127
1128
1129
1130} // namespace bertini
1131
1132
1133
1134
1135#endif // for the ifndef include guards
Compiles a System (or polynomial block) into a StraightLineProgram by visiting its function-tree node...
Definition straight_line_program.hpp:1032
SLP Compile(SourceT const &source)
Compile a source (a System or polynomial block) into a StraightLineProgram.
The per-thread mutable working state of a straight-line program evaluation: the register file (one ba...
Definition straight_line_program.hpp:360
std::vector< NumT > const & Get() const
Get a const reference to the register bank for number type NumT.
Definition straight_line_program.hpp:368
unsigned precision_
The current working number of digits.
Definition straight_line_program.hpp:376
std::vector< NumT > & Get()
Get a mutable reference to the register bank for number type NumT.
Definition straight_line_program.hpp:364
unsigned frozen_valid_mp_precision_
Precision at which the frozen prologue's mp results are valid (0 = none).
Definition straight_line_program.hpp:383
bool frozen_valid_dbl_
Whether the frozen prologue's double results in memory are valid.
Definition straight_line_program.hpp:382
bool is_evaluated_
Whether the program has been evaluated against this memory.
Definition straight_line_program.hpp:377
std::tuple< std::vector< real_dbl >, std::vector< complex_dbl >, std::vector< real_mp >, std::vector< complex_mp > > registers_
The register file (ADR-0034): one bank per (precision, NumType).
Definition straight_line_program.hpp:374
friend class boost::serialization::access
Definition straight_line_program.hpp:385
The immutable compiled straight-line program (ADR-0027): the instruction tape, the constant recipe (t...
Definition straight_line_program.hpp:411
unsigned NumFunctions() const
Get the number of functions in the program.
Definition straight_line_program.hpp:431
friend std::ostream & operator<<(std::ostream &out, const StraightLineProgram &s)
size_t FirstLiveInstructionOffset() const
Get the word offset into the tape where the live (post-frozen-prologue) segment begins.
Definition straight_line_program.hpp:437
void Eval(SLPMemory &memory) const
loops through the instructions in the tape and evaluates each operation against the given memory.
unsigned NumVariables() const
Get the number of variables in the program.
Definition straight_line_program.hpp:433
bool SameContent(SLPProgram const &other) const
Exact content equality over every field ContentHash folds; disambiguates hash collisions in the progr...
std::size_t ContentHash() const
In-process structural hash of the full immutable program content: the (specialized) instruction tape,...
friend class boost::serialization::access
Definition straight_line_program.hpp:531
int IntT
The integer type used for the program's integer bank.
Definition straight_line_program.hpp:420
friend class StraightLineProgram
Definition straight_line_program.hpp:413
size_t NumSlots() const
Get the total number of memory slots (per register bank) the program needs.
Definition straight_line_program.hpp:435
bool HavePathVariable() const
Query whether the program has a path variable.
Definition straight_line_program.hpp:429
static bool tiers_enabled_
ADR-0034 A/B switch: when false, leave every slot Complex (pre-tier all-complex eval).
Definition straight_line_program.hpp:426
An implementation of straight-line programs, implemented with strong inspiration from Bertini1's impl...
Definition straight_line_program.hpp:587
StraightLineProgram(System const &sys)
The constructor – how to make a SLP from a System.
int IntT
The integer type used for the program's integer bank.
Definition straight_line_program.hpp:939
void EvalFunctions() const
Evaluate the program's functions (currently a synonym for the full Eval).
Definition straight_line_program.hpp:643
unsigned NumFunctions() const
Get the number of functions in the program.
Definition straight_line_program.hpp:789
size_t FirstLiveInstructionOffset() const
Word offset into the instruction tape where the live segment begins (== total word length of the froz...
Definition straight_line_program.hpp:802
friend std::ostream & operator<<(std::ostream &out, const StraightLineProgram &s)
void GetJacobianInPlace(Eigen::Ref< Mat< NumT > > result) const
retrieves the computed values of jacobians
Definition straight_line_program.hpp:716
void GetTimeDerivInPlace(Eigen::Ref< Vec< NumT > > result) const
copies the values of the time derivatives into your given vector
Definition straight_line_program.hpp:740
Vec< NumT > GetTimeDeriv() const
creates the Vec<NumT> to be used in the overloaded function
Definition straight_line_program.hpp:781
void EvalJacobian() const
Evaluate the program's Jacobian (currently a synonym for the full Eval).
Definition straight_line_program.hpp:652
NumT ReadSlotAsComplex(size_t slot) const
Read a slot's value as a complex NumT, pulling from its real or complex bank per its NumType.
Definition straight_line_program.hpp:683
void SetVariableValues(Eigen::MatrixBase< Derived > const &variable_values) const
Copy the values of the variables from the passed in vector to memory.
Definition straight_line_program.hpp:867
size_t NumMemorySlots() const
Number of memory slots: one per distinct value the program holds (inputs, constants,...
Definition straight_line_program.hpp:797
unsigned precision() const
Get the current precision of the SLP.
Definition straight_line_program.hpp:811
void Eval(Eigen::MatrixBase< Derived > const &variable_values) const
Evaluate the program at the given variable values (no path variable).
Definition straight_line_program.hpp:607
bool HavePathVariable() const
Does this SLP have a path variable?
Definition straight_line_program.hpp:849
unsigned NumVariables() const
Get the number of variables in the program.
Definition straight_line_program.hpp:792
void precision(unsigned new_precision) const
change the precision of the SLP.
void SetPathVariable(ComplexT const &time) const
Copy the current time value to memory.
Definition straight_line_program.hpp:908
Mat< NumT > GetJacobian() const
creates the Vec<NumT> to be used in the overloaded function
Definition straight_line_program.hpp:769
void GetFuncValsInPlace(Eigen::Ref< Vec< NumT > > result) const
Copy the computed function values into the provided vector (does not resize it).
Definition straight_line_program.hpp:694
void Eval(Eigen::MatrixBase< Derived > const &variable_values, ComplexT const &time) const
copies the variable values into the Matrix base and the path variables into the complex type time
Definition straight_line_program.hpp:627
friend class boost::serialization::access
Definition straight_line_program.hpp:957
Vec< NumT > GetFuncVals() const
creates the Vec<NumT> to be used in the overloaded function
Definition straight_line_program.hpp:757
void SyncPrecision(Eigen::MatrixBase< Derived > const &variable_values) const
Materialize this program's memory at the precision of the point being evaluated.
Definition straight_line_program.hpp:834
std::shared_ptr< const SLPProgram > Program() const
The immutable compiled program this facade runs.
Definition straight_line_program.hpp:668
size_t NumRealSlots() const
Number of slots the compiler inferred as NumType::Real (ADR-0034).
Definition straight_line_program.hpp:673
void EvalTimeDeriv() const
Evaluate the program's time derivative (currently a synonym for the full Eval).
Definition straight_line_program.hpp:660
StraightLineProgram()
Definition straight_line_program.hpp:601
The fundamental polynomial system class for Bertini2.
Definition system.hpp:106
A strawman class for implementing the visitor pattern.
Definition visitor.hpp:42
The first non-trivial visitor class.
Definition visitor.hpp:58
virtual ReturnType Visit(node::Variable const &)=0
Provides the arc cosine Operator.
Definition trig.hpp:264
Provides the inverse sine Operator.
Definition trig.hpp:139
Provides the inverse tangent Operator.
Definition trig.hpp:391
A complex-number literal node in an expression tree.
Definition number.hpp:254
Provides the cosine Operator.
Definition trig.hpp:202
Provides the differential type for differentiation of expression trees.
Definition differential.hpp:52
represents the exponential function
Definition arithmetic.hpp:914
This class represents the exponentiation Operator.
Definition arithmetic.hpp:709
Signed real Integer storage in an expression tree.
Definition number.hpp:143
represents the natural logarithm function
Definition arithmetic.hpp:971
Multiplication and division Operator.
Definition arithmetic.hpp:379
A user-named expression — the surviving, immutable entry point into a subtree.
Definition named_expression.hpp:50
The negation Operator.
Definition arithmetic.hpp:271
Operator for power functions with arbitrary expressions in the exponent and base.
Definition arithmetic.hpp:559
The Rational number type for Bertini2 expression trees.
Definition number.hpp:379
Provides the sine Operator.
Definition trig.hpp:80
Represents the square root Operator.
Definition arithmetic.hpp:847
Represents summation and difference Operator.
Definition arithmetic.hpp:70
Provides the tangent Operator.
Definition trig.hpp:332
Represents variable leaves in the function tree.
Definition variable.hpp:48
The number .
Definition special_number.hpp:115
The number .
Definition special_number.hpp:55
Bertini extensions of the Eigen linear algebra library.
Forward declarations for types in the node:: namespace.
The main multiprecision complex number type.
Extensions to the Boost.Multiprecision library.
Definition algorithm_builder.hpp:36
std::string OpcodeToString(Operation op)
Get a human-readable name for an opcode.
constexpr bool IsBinary(Operation op)
Query whether an operation takes two operands.
Definition straight_line_program.hpp:200
Eigen::Matrix< NumT, Eigen::Dynamic, 1 > Vec
A dynamically-sized column vector of NumT.
Definition eigen_extensions.hpp:296
bool SLPValueNumbering()
Whether the SLP compiler value-numbers (instruction-level CSE) while emitting the tape: an identical ...
constexpr size_t kOutReal
High bit: result slot is NumType::Real.
Definition straight_line_program.hpp:225
boost::multiprecision::number< boost::multiprecision::backends::gmp_int, boost::multiprecision::et_on > mpz_int
The arbitrary-precision integer type.
Definition mpfr_extensions.hpp:54
constexpr size_t kArg0Real
High bit: first operand slot is NumType::Real.
Definition straight_line_program.hpp:223
constexpr bool IsUnary(Operation op)
Query whether an operation takes a single operand.
Definition straight_line_program.hpp:194
Eigen::Matrix< NumT, Eigen::Dynamic, Eigen::Dynamic > Mat
A dynamically-sized matrix of NumT.
Definition eigen_extensions.hpp:298
void SetSLPValueNumbering(bool on)
Set whether the SLP compiler value-numbers while emitting the tape.
constexpr size_t kOpcodeMask
Mask recovering the base opcode from an instruction word.
Definition straight_line_program.hpp:222
bmp::number< mpc_complex_backend< 0 >, bmp::et_on > complex_mp
The arbitrary-precision complex number type.
Definition mpfr_complex.hpp:58
constexpr size_t kArg1Real
High bit: second operand slot is Real (binary, not IntPower).
Definition straight_line_program.hpp:224
std::shared_ptr< const SLPProgram > InternProgram(std::shared_ptr< const SLPProgram > const &candidate)
Hash-cons a freshly-compiled program: return an existing content-equal SLPProgram if one is live,...
const int UnaryOperations
Bit-mask of the one-operand operations.
Definition straight_line_program.hpp:191
boost::multiprecision::number< boost::multiprecision::backends::gmp_rational, boost::multiprecision::et_on > mpq_rational
The exact rational number type.
Definition mpfr_extensions.hpp:55
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object.
Definition eigen_extensions.hpp:339
NumType
The numeric type a memory slot holds, orthogonal to working precision (ADR-0034).
Definition straight_line_program.hpp:165
@ Complex
Definition straight_line_program.hpp:165
@ Real
Definition straight_line_program.hpp:165
Operation
The opcodes for the operations a straight-line program instruction can perform.
Definition straight_line_program.hpp:169
@ Acos
Definition straight_line_program.hpp:183
@ Asin
Definition straight_line_program.hpp:182
@ Atan
Definition straight_line_program.hpp:184
@ Exp
Definition straight_line_program.hpp:175
@ Multiply
Definition straight_line_program.hpp:172
@ Cos
Definition straight_line_program.hpp:180
@ IntPower
Definition straight_line_program.hpp:186
@ Subtract
Definition straight_line_program.hpp:171
@ Power
Definition straight_line_program.hpp:174
@ Sqrt
Definition straight_line_program.hpp:178
@ Assign
Definition straight_line_program.hpp:185
@ Log
Definition straight_line_program.hpp:176
@ Add
Definition straight_line_program.hpp:170
@ Tan
Definition straight_line_program.hpp:181
@ Negate
Definition straight_line_program.hpp:177
@ Divide
Definition straight_line_program.hpp:173
@ Sin
Definition straight_line_program.hpp:179
const int TrigOperations
Bit-mask of the trigonometric operations.
Definition straight_line_program.hpp:190
const int BinaryOperations
Bit-mask of the two-operand operations.
Definition straight_line_program.hpp:189
An exact, node-independent description of a constant baked into the program: enough to (re)produce th...
Definition straight_line_program.hpp:306
mpq_rational rat_real
Kind::Rational real part (exact).
Definition straight_line_program.hpp:312
bool IsReal() const
Whether this constant is real-valued: Integer/Pi/E always; a Rational/Complex literal iff its imagina...
Definition straight_line_program.hpp:326
size_t slot
where this constant lives in the register file
Definition straight_line_program.hpp:315
mpz_int int_value
Kind::Integer (exact).
Definition straight_line_program.hpp:311
Kind
Which kind of constant this recipe produces.
Definition straight_line_program.hpp:308
@ Complex
Definition straight_line_program.hpp:308
@ Pi
Definition straight_line_program.hpp:308
@ Rational
Definition straight_line_program.hpp:308
@ E
Definition straight_line_program.hpp:308
@ Integer
Definition straight_line_program.hpp:308
mpq_rational rat_imag
Kind::Rational imaginary part (exact).
Definition straight_line_program.hpp:313
Kind kind
Which kind of constant this is.
Definition straight_line_program.hpp:310
RealT ProduceReal() const
Produce just the REAL value (for a slot inferred NumType::Real). Only valid when IsReal().
friend class boost::serialization::access
Definition straight_line_program.hpp:335
NumT Produce() const
Produce the constant's value at the ambient working precision (ThreadPrecision), matching the corresp...
complex_mp float_value
Kind::Complex (authored-precision literal; also a fixed variable's value).
Definition straight_line_program.hpp:314
Numeric traits for a bertini number type: digit counts, conversions, and companion types.
Definition num_traits.hpp:57
A struct encapsulating the starting locations of inputs in the SLP's memory layout.
Definition straight_line_program.hpp:255
size_t Variables
Memory offset of the variable inputs.
Definition straight_line_program.hpp:256
size_t Time
Memory offset of the path-variable (time) input.
Definition straight_line_program.hpp:257
friend class boost::serialization::access
Definition straight_line_program.hpp:259
A struct encapsulating the numbers of things appearing in the SLP.
Definition straight_line_program.hpp:275
size_t Functions
The number of functions in the system.
Definition straight_line_program.hpp:276
size_t Jacobian
The number of Jacobian entries.
Definition straight_line_program.hpp:278
friend class boost::serialization::access
Definition straight_line_program.hpp:281
size_t Variables
The number of variables in the system.
Definition straight_line_program.hpp:277
size_t TimeDeriv
The number of time-derivative entries.
Definition straight_line_program.hpp:279
A struct encapsulating the starting locations of outputs in the SLP's memory layout.
Definition straight_line_program.hpp:233
size_t Functions
Memory offset of the function-value outputs.
Definition straight_line_program.hpp:234
size_t TimeDeriv
Memory offset of the time-derivative outputs.
Definition straight_line_program.hpp:236
size_t Jacobian
Memory offset of the Jacobian outputs.
Definition straight_line_program.hpp:235
friend class boost::serialization::access
Definition straight_line_program.hpp:238
Contains the visitor base types.