CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
language_latex.hpp
1#ifndef CPPAD_CG_LANGUAGE_LATEX_INCLUDED
2#define CPPAD_CG_LANGUAGE_LATEX_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2014 Ciengis
6 * Copyright (C) 2018 Joao Leal
7 *
8 * CppADCodeGen is distributed under multiple licenses:
9 *
10 * - Eclipse Public License Version 1.0 (EPL1), and
11 * - GNU General Public License Version 3 (GPL3).
12 *
13 * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14 * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15 * ----------------------------------------------------------------------------
16 * Author: Joao Leal
17 */
18
19namespace CppAD {
20namespace cg {
21
29template<class Base>
30class LanguageLatex : public Language<Base> {
31public:
33 using Arg = Argument<Base>;
34protected:
35 static const std::string _C_STATIC_INDEX_ARRAY;
36 static const std::string _C_SPARSE_INDEX_ARRAY;
37 static const std::string _COMP_OP_LT;
38 static const std::string _COMP_OP_LE;
39 static const std::string _COMP_OP_EQ;
40 static const std::string _COMP_OP_GE;
41 static const std::string _COMP_OP_GT;
42 static const std::string _COMP_OP_NE;
43 static const std::string _ATOMIC_TX;
44 static const std::string _ATOMIC_TY;
45 static const std::string _ATOMIC_PX;
46 static const std::string _ATOMIC_PY;
47protected:
48 // information from the code handler (not owned)
50 // current indentation
51 size_t _indentationLevel;
52 // text before a variable name
53 std::string _startVar;
54 // text after a variable name
55 std::string _endVar;
56 // text before a dependent variable name
57 std::string _startDepVar;
58 // text after a dependent variable name
59 std::string _endDepVar;
60 // text before an independent variable name
61 std::string _startIndepVar;
62 // text after an independent variable name
63 std::string _endIndepVar;
64 // text before an individual equation
65 std::string _startEq;
66 // text after an individual equation
67 std::string _endEq;
68 // text before a line in the algorithm
69 std::string _startAlgLine;
70 // text after a line in the algorithm
71 std::string _endAlgLine;
72 // text before an equation block with multiple lines with the same indentation
73 std::string _startEqBlock;
74 // text after an equation block with multiple lines with the same indentation
75 std::string _endEqBlock;
76 std::string _algFileStart;
77 std::string _algFileEnd;
78 std::string _forStart;
79 std::string _forEnd;
80 std::string _conditionStart;
81 std::string _conditionEnd;
82 std::string _ifStart;
83 std::string _ifEnd;
84 std::string _elseIfStart;
85 std::string _elseIfEnd;
86 std::string _elseStart;
87 std::string _elseEnd;
88 std::string _assignStr;
89 // markup for multiplications
90 std::string _multOpStr;
91 // markup for multiplications with parameters
92 std::string _multValOpStr;
93 // new line characters
94 std::string _endline;
95 // output stream for the generated source code
96 std::ostringstream _code;
97 // creates the variable names
99 // auxiliary string stream
100 std::ostringstream _ss;
101 //
102 size_t _independentSize;
103 //
104 size_t _minTemporaryVarID;
105 // maps the variable IDs to the their position in the dependent vector
106 // (some IDs may be the same as the independent variables when dep = indep)
107 std::map<size_t, size_t> _dependentIDs;
108 // the dependent variable vector
109 const ArrayView<CG<Base> >* _dependent;
110 // the temporary variables that may require a declaration
111 std::map<size_t, Node*> _temporary;
112 // whether or not to ignore assignment of constant zero values to dependent variables
113 bool _ignoreZeroDepAssign;
114 // the name of the file to be created without the extension
115 std::string _filename;
116 // the maximum number of assignment (~lines) per local file
117 size_t _maxAssignmentsPerFile;
118 //
119 std::map<std::string, std::string>* _sources;
120 // the values in the temporary array
121 std::vector<const Arg*> _tmpArrayValues;
122 // the values in the temporary sparse array
123 std::vector<const Arg*> _tmpSparseArrayValues;
124 //
125 std::vector<const LoopStartOperationNode<Base>*> _currentLoops;
126 // the maximum precision used to print values
127 size_t _parameterPrecision;
128 // whether or not we are in an equation/align block
129 bool _inEquationEnv;
130 // whether or not to always enclose the base of a power within parenthesis
131 bool _powBaseEnclose;
132private:
133 std::string auxArrayName_;
134
135public:
136
141 _info(nullptr),
142 _indentationLevel(0),
143 _startVar("\\begin{CGVar}"),
144 _endVar("\\end{CGVar}"),
145 _startDepVar("\\begin{CGDepVar}"),
146 _endDepVar("\\end{CGDepVar}"),
147 _startIndepVar("\\begin{CGIndVar}"),
148 _endIndepVar("\\end{CGIndVar}"),
149 _startEq("\\begin{CGEq}"),
150 _endEq("\\end{CGEq}"),
151 _startAlgLine("\\begin{CGLine}"),
152 _endAlgLine("\\end{CGLine}"),
153 _startEqBlock("\\begin{CGEqBlock}"),
154 _endEqBlock("\\end{CGEqBlock}"),
155 _algFileStart("\\begin{CGAlgFile}"),
156 _algFileEnd("\\end{CGAlgFile}"),
157 _forStart("\\begin{CGFor}"),
158 _forEnd("\\end{CGFor}"),
159 _conditionStart("\\begin{CGCond}"),
160 _conditionEnd("\\end{CGCond}"),
161 _ifStart("\\begin{CGIf}"),
162 _ifEnd("\\end{CGIf}"),
163 _elseIfStart("\\begin{CGElseIf}"),
164 _elseIfEnd("\\end{CGElseIf}"),
165 _elseStart("\\begin{CGElse}"),
166 _elseEnd("\\end{CGElse}"),
167 _assignStr(" = "),
168 _multOpStr(" "),
169 _multValOpStr("\\times"),
170 _endline("\n"),
171 _nameGen(nullptr),
172 _independentSize(0), // not really required (but it avoids warnings)
173 _minTemporaryVarID(0), // not really required (but it avoids warnings)
174 _dependent(nullptr),
175 _ignoreZeroDepAssign(false),
176 _filename("algorithm"),
177 _maxAssignmentsPerFile(0),
178 _sources(nullptr),
179 _parameterPrecision(std::numeric_limits<Base>::digits10),
180 _inEquationEnv(false),
181 _powBaseEnclose(false) {
182 }
183
184 inline const std::string& getAssignString() const {
185 return _assignStr;
186 }
187
188 inline void setAssignString(const std::string& assign) {
189 _assignStr = assign;
190 }
191
192 inline bool isIgnoreZeroDepAssign() const {
193 return _ignoreZeroDepAssign;
194 }
195
196 inline void setIgnoreZeroDepAssign(bool ignore) {
197 _ignoreZeroDepAssign = ignore;
198 }
199
200 virtual void setFilename(const std::string& name) {
201 _filename = name;
202 }
203
210 virtual void setVariableEnvironment(const std::string& begin,
211 const std::string& end) {
212 _startVar = begin;
213 _endVar = end;
214 }
215
219 virtual const std::string& getVariableEnvironmentStart() const {
220 return _startVar;
221 }
222
226 virtual const std::string& getVariableEnvironmentEnd() const {
227 return _endVar;
228 }
229
236 virtual void setDependentVarEnvironment(const std::string& begin,
237 const std::string& end) {
238 _startDepVar = begin;
239 _endDepVar = end;
240 }
241
245 virtual const std::string& getDependentVarEnvironmentStart() const {
246 return _startDepVar;
247 }
248
252 virtual const std::string& getDependentVarEnvironmentEnd() const {
253 return _endDepVar;
254 }
255
262 virtual void setIndependentVarEnvironment(const std::string& begin,
263 const std::string& end) {
264 _startIndepVar = begin;
265 _endIndepVar = end;
266 }
267
271 virtual const std::string& getIndependentVarEnvironmentStart() const {
272 return _startIndepVar;
273 }
274
278 virtual const std::string& getIndependentVarEnvironmentEnd() const {
279 return _endIndepVar;
280 }
281
288 virtual void setEquationEnvironment(const std::string& begin,
289 const std::string& end) {
290 _startEq = begin;
291 _endEq = end;
292 }
293
297 virtual const std::string& getEquationEnvironmentStart() const {
298 return _startEq;
299 }
300
304 virtual const std::string& getEquationEnvironmentEnd() const {
305 return _endEq;
306 }
307
314 virtual void setAlgorithmLineEnvironment(const std::string& begin,
315 const std::string& end) {
316 _startAlgLine = begin;
317 _endAlgLine = end;
318 }
319
323 virtual const std::string& getAlgorithmLineEnvironmentStart() const {
324 return _startAlgLine;
325 }
326
330 virtual const std::string& getAlgorithmLineEnvironmentEnd() const {
331 return _endAlgLine;
332 }
333
341 virtual void setEquationBlockEnvironment(const std::string& begin,
342 const std::string& end) {
343 _startEqBlock = begin;
344 _endEqBlock = end;
345 }
346
351 virtual const std::string& getEquationBlockEnvironmentStart() const {
352 return _startEqBlock;
353 }
354
359 virtual const std::string& getEquationBlockEnvironmentEnd() const {
360 return _endEqBlock;
361 }
362
369 virtual void setAgorithmFileEnvironment(const std::string& begin,
370 const std::string& end) {
371 _algFileStart = begin;
372 _algFileEnd = end;
373 }
374
378 virtual const std::string& getAgorithmFileEnvironmentStart() const {
379 return _algFileStart;
380 }
381
385 virtual const std::string& getAgorithmFileEnvironmentEnd() const {
386 return _algFileEnd;
387 }
388
395 virtual void setForEnvironment(const std::string& begin,
396 const std::string& end) {
397 _forStart = begin;
398 _forEnd = end;
399 }
400
404 virtual const std::string& getForEnvironmentStart() const {
405 return _forStart;
406 }
407
411 virtual const std::string& getForEnvironmentEnd() const {
412 return _forEnd;
413 }
414
421 virtual void setConditionEnvironment(const std::string& begin,
422 const std::string& end) {
423 _conditionStart = begin;
424 _conditionEnd = end;
425 }
426
430 virtual const std::string& getConditionEnvironmentStart() const {
431 return _conditionStart;
432 }
433
437 virtual const std::string& getConditionEnvironmentEnd() const {
438 return _conditionEnd;
439 }
440
447 virtual void setIfEnvironment(const std::string& begin,
448 const std::string& end) {
449 _ifStart = begin;
450 _ifEnd = end;
451 }
452
456 virtual const std::string& getIfEnvironmentStart() const {
457 return _ifStart;
458 }
459
463 virtual const std::string& getIfEnvironmentEnd() const {
464 return _ifEnd;
465 }
466
473 virtual void setElseIfEnvironment(const std::string& begin,
474 const std::string& end) {
475 _elseIfStart = begin;
476 _elseIfEnd = end;
477 }
478
482 virtual const std::string& getElseIfEnvironmentStart() const {
483 return _elseIfStart;
484 }
485
489 virtual const std::string& getElseIfEnvironmentEnd() const {
490 return _elseIfEnd;
491 }
492
499 virtual void setElseEnvironment(const std::string& begin,
500 const std::string& end) {
501 _elseStart = begin;
502 _elseEnd = end;
503 }
504
508 virtual const std::string& getElseEnvironmentStart() const {
509 return _elseStart;
510 }
511
515 virtual const std::string& getElseEnvironmentEnd() const {
516 return _elseEnd;
517 }
518
525 virtual size_t getParameterPrecision() const {
526 return _parameterPrecision;
527 }
528
535 virtual void setParameterPrecision(size_t p) {
536 _parameterPrecision = p;
537 }
538
547 virtual void setAlwaysEnclosePowBase(bool enclose) {
548 _powBaseEnclose = enclose;
549 }
550
557 virtual bool isAlwaysEnclosePowBase() const {
558 return _powBaseEnclose;
559 }
560
561
569 inline const std::string& getMultiplicationOperator() const {
570 return _multOpStr;
571 }
572
581 inline void setMultiplicationOperator(const std::string& multOpStr) {
582 _multOpStr = multOpStr;
583 }
584
589 inline const std::string& getMultiplicationConstParOperator() const {
590 return _multValOpStr;
591 }
592
600 inline void setMultiplicationConstParOperator(const std::string& multValOpStr) {
601 _multValOpStr = multValOpStr;
602 }
603
604 virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction,
605 std::map<std::string, std::string>* sources) {
606 _maxAssignmentsPerFile = maxAssignmentsPerFunction;
607 _sources = sources;
608 }
609
610 inline virtual ~LanguageLatex() = default;
611
612 /***************************************************************************
613 * STATIC
614 **************************************************************************/
615 static inline void printIndexCondExpr(std::ostringstream& out,
616 const std::vector<size_t>& info,
617 const std::string& index) {
618 CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0, "Invalid number of information elements for an index condition expression operation")
619
620 size_t infoSize = info.size();
621 for (size_t e = 0; e < infoSize; e += 2) {
622 if (e > 0) {
623 out << " \\vee "; // or
624 }
625 size_t min = info[e];
626 size_t max = info[e + 1];
627 if (min == max) {
628 out << index << " == " << min;
629 } else if (min == 0) {
630 out << index << " \\le " << max;
631 } else if (max == (std::numeric_limits<size_t>::max)()) {
632 out << min << " \\le " << index;
633 } else {
634 if (infoSize != 2)
635 out << "(";
636
637 if (max - min == 1)
638 out << min << " == " << index << " \\vee " << index << " == " << max;
639 else
640 out << min << " \\le " << index << " \\wedge" << index << " \\le " << max;
641
642 if (infoSize != 2)
643 out << ")";
644 }
645 }
646 }
647
648 /***************************************************************************
649 *
650 **************************************************************************/
651
652 inline void printStaticIndexArray(std::ostringstream& os,
653 const std::string& name,
654 const std::vector<size_t>& values);
655
656 inline void printStaticIndexMatrix(std::ostringstream& os,
657 const std::string& name,
658 const std::map<size_t, std::map<size_t, size_t> >& values);
659
660 /***************************************************************************
661 * index patterns
662 **************************************************************************/
663 static inline void generateNames4RandomIndexPatterns(const std::set<RandomIndexPattern*>& randomPatterns);
664
665 inline void printRandomIndexPatternDeclaration(std::ostringstream& os,
666 const std::string& identation,
667 const std::set<RandomIndexPattern*>& randomPatterns);
668
669 static inline std::string indexPattern2String(const IndexPattern& ip,
670 const Node& index);
671
672 static inline std::string indexPattern2String(const IndexPattern& ip,
673 const std::vector<const Node*>& indexes);
674
675 static inline std::string linearIndexPattern2String(const LinearIndexPattern& lip,
676 const Node& index);
677
678 /***************************************************************************
679 * protected
680 **************************************************************************/
681protected:
682
683 void generateSourceCode(std::ostream& out,
684 std::unique_ptr<LanguageGenerationData<Base> > info) override {
685
686 const bool multiFile = _maxAssignmentsPerFile > 0 && _sources != nullptr;
687
688 // clean up
689 _code.str("");
690 _ss.str("");
691 _indentationLevel = 0;
692 _temporary.clear();
693 _inEquationEnv = false;
694 auxArrayName_ = "";
695 _currentLoops.clear();
696 _dependentIDs.clear();
697
698
699 // save some info
700 _info = info.get();
701 _independentSize = info->independent.size();
702 _dependent = &info->dependent;
703 _nameGen = &info->nameGen;
704 _minTemporaryVarID = info->minTemporaryVarID;
705 const ArrayView<CG<Base> >& dependent = info->dependent;
706 const std::vector<Node*>& variableOrder = info->variableOrder;
707
708 _tmpArrayValues.resize(_nameGen->getMaxTemporaryArrayVariableID());
709 std::fill(_tmpArrayValues.begin(), _tmpArrayValues.end(), nullptr);
710 _tmpSparseArrayValues.resize(_nameGen->getMaxTemporarySparseArrayVariableID());
711 std::fill(_tmpSparseArrayValues.begin(), _tmpSparseArrayValues.end(), nullptr);
712
716 generateNames4RandomIndexPatterns(info->indexRandomPatterns);
717
721 //generate names for the independent variables
722 for (size_t j = 0; j < _independentSize; j++) {
723 Node& op = *info->independent[j];
724 if (op.getName() == nullptr) {
725 op.setName(_nameGen->generateIndependent(op, getVariableID(op)));
726 }
727 }
728
729 // generate names for the dependent variables (must be after naming independents)
730 for (size_t i = 0; i < dependent.size(); i++) {
731 Node* node = dependent[i].getOperationNode();
732 if (node != nullptr && node->getOperationType() != CGOpCode::LoopEnd && node->getName() == nullptr) {
733 if (node->getOperationType() == CGOpCode::LoopIndexedDep) {
734 size_t pos = node->getInfo()[0];
735 const IndexPattern* ip = info->loopDependentIndexPatterns[pos];
736 node->setName(_nameGen->generateIndexedDependent(*node, getVariableID(*node), *ip));
737
738 } else {
739 node->setName(_nameGen->generateDependent(i));
740 }
741 }
742 }
743
747 const std::vector<FuncArgument>& indArg = _nameGen->getIndependent();
748 const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
749 const std::vector<FuncArgument>& tmpArg = _nameGen->getTemporary();
750 CPPADCG_ASSERT_KNOWN(!indArg.empty() && !depArg.empty(),
751 "There must be at least one dependent and one independent argument")
752 CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
753 "There must be three temporary variables")
754
755 auxArrayName_ = tmpArg[1].name + "p";
756
760 // dependent variables indexes that are copies of other dependent variables
761 std::set<size_t> dependentDuplicates;
762
763 for (size_t i = 0; i < dependent.size(); i++) {
764 Node* node = dependent[i].getOperationNode();
765 if (node != nullptr) {
766 CGOpCode type = node->getOperationType();
767 if (type != CGOpCode::Inv && type != CGOpCode::LoopEnd) {
768 size_t varID = getVariableID(*node);
769 if (varID > 0) {
770 auto it2 = _dependentIDs.find(varID);
771 if (it2 == _dependentIDs.end()) {
772 _dependentIDs[getVariableID(*node)] = i;
773 } else {
774 // there can be several dependent variables with the same ID
775 dependentDuplicates.insert(i);
776 }
777 }
778 }
779 }
780 }
781
782 // the names of local functions
783 std::vector<std::string> inputLatexFiles;
784 if (multiFile) {
785 inputLatexFiles.reserve(variableOrder.size() / _maxAssignmentsPerFile);
786 }
787
791 if (variableOrder.size() > 0) {
792 // generate names for temporary variables
793 for (Node* node : variableOrder) {
794 CGOpCode op = node->getOperationType();
795 if (!isDependent(*node) && op != CGOpCode::IndexDeclaration) {
796 // variable names for temporaries must always be created since they might have been used before with a different name/id
797 if (requiresVariableName(*node) && op != CGOpCode::ArrayCreation && op != CGOpCode::SparseArrayCreation) {
798 node->setName(_nameGen->generateTemporary(*node, getVariableID(*node)));
799 } else if (op == CGOpCode::ArrayCreation) {
800 node->setName(_nameGen->generateTemporaryArray(*node, getVariableID(*node)));
801 } else if (op == CGOpCode::SparseArrayCreation) {
802 node->setName(_nameGen->generateTemporarySparseArray(*node, getVariableID(*node)));
803 }
804 }
805 }
806
810 if (info->zeroDependents) {
811 // zero initial values
812 if (!depArg.empty())
813 checkEquationEnvStart();
814 for (size_t i = 0; i < depArg.size(); i++) {
815 _code << _startAlgLine << _startEq;
816 const FuncArgument& a = depArg[i];
817 if (a.array) {
818 _code << a.name;
819 } else {
820 _code << _startDepVar << _nameGen->generateDependent(i) << _endDepVar;
821 }
822 _code << _assignStr;
823 printParameter(Base(0.0));
824 _code << _endEq << _endAlgLine << _endline;
825 }
826 }
827
828 size_t assignCount = 0;
829 for (Node* it : variableOrder) {
830 // check if a new function should start
831 if (assignCount >= _maxAssignmentsPerFile && multiFile && _currentLoops.empty()) {
832 assignCount = 0;
833 saveLocalFunction(inputLatexFiles, inputLatexFiles.empty() && info->zeroDependents);
834 }
835
836 Node& node = *it;
837
838 // a dependent variable assigned by a loop does require any source code (its done inside the loop)
839 if (node.getOperationType() == CGOpCode::DependentRefRhs) {
840 continue; // nothing to do (this operation is right hand side only)
841 } else if (node.getOperationType() == CGOpCode::TmpDcl) { // temporary variable declaration does not need any source code here
842 continue; // nothing to do (bogus operation)
843 }
844
845 assignCount += printAssignment(node);
846 }
847
848 if (!inputLatexFiles.empty() && assignCount > 0) {
849 assignCount = 0;
850 saveLocalFunction(inputLatexFiles, false);
851 }
852 }
853
854 if (!inputLatexFiles.empty()) {
858 CPPADCG_ASSERT_KNOWN(tmpArg[0].array,
859 "The temporary variables must be saved in an array in order to generate multiple functions")
860 printAlgorithmFileStart(_code);
861 for (auto & inputLatexFile : inputLatexFiles) {
862 _code << "\\input{" << inputLatexFile << "}" << _endline;
863 }
864 printAlgorithmFileEnd(_code);
865 }
866
867 // dependent duplicates
868 if (!dependentDuplicates.empty()) {
869 _code << "% variable duplicates: " << dependentDuplicates.size() << _endline;
870
871 checkEquationEnvStart();
872 for (size_t index : dependentDuplicates) {
873 const CG<Base>& dep = (*_dependent)[index];
874 std::string varName = _nameGen->generateDependent(index);
875 const std::string& origVarName = *dep.getOperationNode()->getName();
876
877 _code << _startAlgLine << _startEq
878 << _startDepVar << varName << _endDepVar
879 << _assignStr
880 << _startDepVar << origVarName << _endDepVar;
881 printAssignmentEnd();
882 }
883 }
884
885 // constant dependent variables
886 bool commentWritten = false;
887 for (size_t i = 0; i < dependent.size(); i++) {
888 if (dependent[i].isParameter()) {
889 if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
890 if (!commentWritten) {
891 _code << "% dependent variables without operations" << _endline;
892 commentWritten = true;
893 }
894 checkEquationEnvStart();
895
896 std::string varName = _nameGen->generateDependent(i);
897 _code << _startAlgLine << _startEq
898 << _startDepVar << varName << _endDepVar << _assignStr;
899 printParameter(dependent[i].getValue());
900 printAssignmentEnd();
901 }
902 } else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
903 if (!commentWritten) {
904 _code << "% dependent variables without operations" << _endline;
905 commentWritten = true;
906 }
907 checkEquationEnvStart();
908
909 std::string varName = _nameGen->generateDependent(i);
910 const std::string& indepName = *dependent[i].getOperationNode()->getName();
911 _code << _startAlgLine << _startEq
912 << _startDepVar << varName << _endDepVar
913 << _assignStr
914 << _startIndepVar << indepName << _endIndepVar;
915 printAssignmentEnd(*dependent[i].getOperationNode());
916 }
917 }
918
919 checkEquationEnvEnd();
920
924 if (inputLatexFiles.empty()) {
925 // a single source file
926 printAlgorithmFileStart(_ss);
927 _ss << _code.str();
928 printAlgorithmFileEnd(_ss);
929
930 out << _ss.str();
931
932 if (_sources != nullptr) {
933 (*_sources)[_filename + ".tex"] = _ss.str();
934 }
935 } else {
936 // there are multiple source files (this last one is the master)
937 (*_sources)[_filename + ".tex"] = _code.str();
938 }
939
940 }
941
942 inline size_t getVariableID(const Node& node) const {
943 return _info->varId[node];
944 }
945
946 inline virtual void printAlgorithmFileStart(std::ostream& out) {
947 out << "% Latex source file for '" << _filename << "' (automatically generated by CppADCodeGen)" << _endline;
948 out << _algFileStart << _endline;
949 }
950
951 inline virtual void printAlgorithmFileEnd(std::ostream& out) {
952 out << _algFileEnd;
953 }
954
955 inline virtual void checkEquationEnvStart() {
956 if (!_inEquationEnv) {
957 _code << _startEqBlock << _endline;
958 _inEquationEnv = true;
959 }
960 }
961
962 inline virtual void checkEquationEnvEnd() {
963 if (_inEquationEnv) {
964 _code << _endEqBlock << _endline;
965 _inEquationEnv = false;
966 }
967 }
968
969 inline unsigned printAssignment(Node& node) {
970 return printAssignment(node, node);
971 }
972
973 inline unsigned printAssignment(Node& nodeName,
974 const Arg& nodeRhs) {
975 if (nodeRhs.getOperation() != nullptr) {
976 return printAssignment(nodeName, *nodeRhs.getOperation());
977 } else {
978 printAssignmentStart(nodeName);
979 printParameter(*nodeRhs.getParameter());
980 printAssignmentEnd(nodeName);
981 return 1;
982 }
983 }
984
985 inline unsigned printAssignment(Node& nodeName,
986 Node& nodeRhs) {
987 bool createsVar = directlyAssignsVariable(nodeRhs); // do we need to do the assignment here?
988 if (!createsVar) {
989 printAssignmentStart(nodeName);
990 }
991 unsigned lines = printExpressionNoVarCheck(nodeRhs);
992 if (!createsVar) {
993 printAssignmentEnd(nodeRhs);
994 }
995
996 if (nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
997 Node* array = nodeRhs.getArguments()[0].getOperation();
998 size_t arrayId = getVariableID(*array);
999 size_t pos = nodeRhs.getInfo()[0];
1000 if (array->getOperationType() == CGOpCode::ArrayCreation)
1001 _tmpArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
1002 else
1003 _tmpSparseArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
1004 }
1005
1006 return lines;
1007 }
1008
1009 inline virtual void printAssignmentStart(Node& op) {
1010 printAssignmentStart(op, createVariableName(op), isDependent(op));
1011 }
1012
1013 inline virtual void printAssignmentStart(Node& node, const std::string& varName, bool isDep) {
1014 if (!isDep) {
1015 _temporary[getVariableID(node)] = &node;
1016 }
1017
1018 checkEquationEnvStart();
1019
1020 _code << _startAlgLine << _startEq;
1021 if (isDep)
1022 _code << _startDepVar << varName << _endDepVar;
1023 else
1024 _code << _startVar << varName << _endVar;
1025
1026 CGOpCode op = node.getOperationType();
1027 if (op == CGOpCode::DependentMultiAssign || (op == CGOpCode::LoopIndexedDep && node.getInfo()[1] == 1)) {
1028 _code << " += ";
1029 } else {
1030 _code << _assignStr;
1031 }
1032 }
1033
1034 inline virtual void printAssignmentEnd() {
1035 _code << _endEq << _endAlgLine << _endline;
1036 }
1037
1038 inline virtual void printAssignmentEnd(Node& op) {
1039 printAssignmentEnd();
1040 }
1041
1042 virtual void saveLocalFunction(std::vector<std::string>& localFuncNames,
1043 bool zeroDependentArray) {
1044 _ss << _filename << "__part_" << (localFuncNames.size() + 1);
1045 std::string funcName = _ss.str();
1046 _ss.str("");
1047
1048 // loop indexes
1049 _nameGen->prepareCustomFunctionVariables(_ss);
1050 _ss << _code.str();
1051 _nameGen->finalizeCustomFunctionVariables(_ss);
1052
1053 (*_sources)[funcName + ".tex"] = _ss.str();
1054 localFuncNames.push_back(funcName);
1055
1056 _code.str("");
1057 _ss.str("");
1058 }
1059
1060 bool createsNewVariable(const Node& var,
1061 size_t totalUseCount,
1062 size_t opCount) const override {
1063 CGOpCode op = var.getOperationType();
1064 if (totalUseCount > 1) {
1065 return op != CGOpCode::ArrayElement && op != CGOpCode::Index && op != CGOpCode::IndexDeclaration && op != CGOpCode::Tmp;
1066 } else {
1067 return ( op == CGOpCode::ArrayCreation ||
1068 op == CGOpCode::SparseArrayCreation ||
1069 op == CGOpCode::AtomicForward ||
1070 op == CGOpCode::AtomicReverse ||
1071 op == CGOpCode::ComLt ||
1072 op == CGOpCode::ComLe ||
1073 op == CGOpCode::ComEq ||
1074 op == CGOpCode::ComGe ||
1075 op == CGOpCode::ComGt ||
1076 op == CGOpCode::ComNe ||
1077 op == CGOpCode::LoopIndexedDep ||
1078 op == CGOpCode::LoopIndexedTmp ||
1079 op == CGOpCode::IndexAssign ||
1080 op == CGOpCode::Assign) &&
1081 op != CGOpCode::CondResult;
1082 }
1083 }
1084
1085 virtual bool requiresVariableName(const Node& var) const {
1086 CGOpCode op = var.getOperationType();
1087 return (_info->totalUseCount.get(var) > 1 &&
1088 op != CGOpCode::AtomicForward &&
1089 op != CGOpCode::AtomicReverse &&
1090 op != CGOpCode::LoopStart &&
1091 op != CGOpCode::LoopEnd &&
1092 op != CGOpCode::Index &&
1093 op != CGOpCode::IndexAssign &&
1094 op != CGOpCode::StartIf &&
1095 op != CGOpCode::ElseIf &&
1096 op != CGOpCode::Else &&
1097 op != CGOpCode::EndIf &&
1098 op != CGOpCode::CondResult &&
1099 op != CGOpCode::LoopIndexedTmp &&
1100 op != CGOpCode::Tmp);
1101 }
1102
1110 virtual bool directlyAssignsVariable(const Node& var) const {
1111 CGOpCode op = var.getOperationType();
1112 return isCondAssign(op) ||
1113 op == CGOpCode::ArrayCreation ||
1114 op == CGOpCode::SparseArrayCreation ||
1115 op == CGOpCode::AtomicForward ||
1116 op == CGOpCode::AtomicReverse ||
1117 op == CGOpCode::DependentMultiAssign ||
1118 op == CGOpCode::LoopStart ||
1119 op == CGOpCode::LoopEnd ||
1120 op == CGOpCode::IndexAssign ||
1121 op == CGOpCode::StartIf ||
1122 op == CGOpCode::ElseIf ||
1123 op == CGOpCode::Else ||
1124 op == CGOpCode::EndIf ||
1125 op == CGOpCode::CondResult ||
1126 op == CGOpCode::IndexDeclaration;
1127 }
1128
1129 bool requiresVariableArgument(enum CGOpCode op, size_t argIndex) const override {
1130 return op == CGOpCode::CondResult;
1131 }
1132
1133 inline const std::string& createVariableName(Node& var) {
1134 CGOpCode op = var.getOperationType();
1135 CPPADCG_ASSERT_UNKNOWN(getVariableID(var) > 0)
1136 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicForward)
1137 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::AtomicReverse)
1138 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopStart)
1139 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::LoopEnd)
1140 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::Index)
1141 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexAssign)
1142 CPPADCG_ASSERT_UNKNOWN(op != CGOpCode::IndexDeclaration)
1143
1144 if (var.getName() == nullptr) {
1145 if (op == CGOpCode::ArrayCreation) {
1146 var.setName(_nameGen->generateTemporaryArray(var, getVariableID(var)));
1147
1148 } else if (op == CGOpCode::SparseArrayCreation) {
1149 var.setName(_nameGen->generateTemporarySparseArray(var, getVariableID(var)));
1150
1151 } else if (op == CGOpCode::LoopIndexedDep) {
1152 size_t pos = var.getInfo()[0];
1153 const IndexPattern* ip = _info->loopDependentIndexPatterns[pos];
1154 var.setName(_nameGen->generateIndexedDependent(var, getVariableID(var), *ip));
1155
1156 } else if (op == CGOpCode::LoopIndexedIndep) {
1157 size_t pos = var.getInfo()[1];
1158 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1159 var.setName(_nameGen->generateIndexedIndependent(var, getVariableID(var), *ip));
1160
1161 } else if (getVariableID(var) <= _independentSize) {
1162 // independent variable
1163 var.setName(_nameGen->generateIndependent(var, getVariableID(var)));
1164
1165 } else if (getVariableID(var) < _minTemporaryVarID) {
1166 // dependent variable
1167 auto it = _dependentIDs.find(getVariableID(var));
1168 CPPADCG_ASSERT_UNKNOWN(it != _dependentIDs.end())
1169
1170 size_t index = it->second;
1171 var.setName(_nameGen->generateDependent(index));
1172
1173 } else if (op == CGOpCode::LoopIndexedTmp || op == CGOpCode::Tmp) {
1174 CPPADCG_ASSERT_KNOWN(var.getArguments().size() >= 1, "Invalid number of arguments for loop indexed temporary operation")
1175 Node* tmpVar = var.getArguments()[0].getOperation();
1176 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1177 return createVariableName(*tmpVar);
1178
1179 } else {
1180 // temporary variable
1181 var.setName(_nameGen->generateTemporary(var, getVariableID(var)));
1182 }
1183 }
1184
1185
1186 return *var.getName();
1187 }
1188
1189 bool requiresVariableDependencies() const override {
1190 return false;
1191 }
1192
1193 virtual void printIndependentVariableName(Node& op) {
1194 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 0, "Invalid number of arguments for independent variable")
1195
1196 _code << _startIndepVar << _nameGen->generateIndependent(op, getVariableID(op)) << _endIndepVar;
1197 }
1198
1199 virtual unsigned print(const Arg& arg) {
1200 if (arg.getOperation() != nullptr) {
1201 // expression
1202 return printExpression(*arg.getOperation());
1203 } else {
1204 // parameter
1205 printParameter(*arg.getParameter());
1206 return 1;
1207 }
1208 }
1209
1210 virtual unsigned printExpression(Node& node) {
1211 if (getVariableID(node) > 0) {
1212 const std::string& name = createVariableName(node); // use variable name
1213
1214 CGOpCode op = node.getOperationType();
1215 if (getVariableID(node) >= _minTemporaryVarID || op == CGOpCode::ArrayCreation || op == CGOpCode::SparseArrayCreation || op == CGOpCode::LoopIndexedDep || op == CGOpCode::LoopIndexedIndep) {
1216
1217 _code << _startVar << name << _endVar;
1218
1219 } else if (getVariableID(node) <= _independentSize) {
1220 // independent variable
1221 _code << _startIndepVar << name << _endIndepVar;
1222
1223 } else {
1224 // dependent variable
1225 _code << _startDepVar << name << _endDepVar;
1226
1227 }
1228
1229 return 1;
1230 } else {
1231 // print expression code
1232 return printExpressionNoVarCheck(node);
1233 }
1234 }
1235
1236 virtual unsigned printExpressionNoVarCheck(Node& node) {
1237 CGOpCode op = node.getOperationType();
1238 switch (op) {
1239 case CGOpCode::ArrayCreation:
1240 printArrayCreationOp(node);
1241 break;
1242 case CGOpCode::SparseArrayCreation:
1243 printSparseArrayCreationOp(node);
1244 break;
1245 case CGOpCode::ArrayElement:
1246 printArrayElementOp(node);
1247 break;
1248 case CGOpCode::Assign:
1249 return printAssignOp(node);
1250
1251 case CGOpCode::Abs:
1252 case CGOpCode::Acos:
1253 case CGOpCode::Asin:
1254 case CGOpCode::Atan:
1255 case CGOpCode::Cosh:
1256 case CGOpCode::Cos:
1257 case CGOpCode::Exp:
1258 case CGOpCode::Log:
1259 case CGOpCode::Sign:
1260 case CGOpCode::Sinh:
1261 case CGOpCode::Sin:
1262 case CGOpCode::Sqrt:
1263 case CGOpCode::Tanh:
1264 case CGOpCode::Tan:
1265#if CPPAD_USE_CPLUSPLUS_2011
1266 case CGOpCode::Erf:
1267 case CGOpCode::Erfc:
1268 case CGOpCode::Asinh:
1269 case CGOpCode::Acosh:
1270 case CGOpCode::Atanh:
1271 case CGOpCode::Expm1:
1272 case CGOpCode::Log1p:
1273#endif
1274 printUnaryFunction(node);
1275 break;
1276 case CGOpCode::AtomicForward: // atomicFunction.forward(q, p, vx, vy, tx, ty)
1278 break;
1279 case CGOpCode::AtomicReverse: // atomicFunction.reverse(p, tx, ty, px, py)
1281 break;
1282 case CGOpCode::Add:
1283 printOperationAdd(node);
1284 break;
1285 case CGOpCode::Alias:
1286 return printOperationAlias(node);
1287
1288 case CGOpCode::ComLt:
1289 case CGOpCode::ComLe:
1290 case CGOpCode::ComEq:
1291 case CGOpCode::ComGe:
1292 case CGOpCode::ComGt:
1293 case CGOpCode::ComNe:
1294 printConditionalAssignment(node);
1295 break;
1296 case CGOpCode::Div:
1297 printOperationDiv(node);
1298 break;
1299 case CGOpCode::Inv:
1300 printIndependentVariableName(node);
1301 break;
1302 case CGOpCode::Mul:
1303 printOperationMul(node);
1304 break;
1305 case CGOpCode::Pow:
1306 printPowFunction(node);
1307 break;
1308 case CGOpCode::Pri:
1309 // do nothing
1310 break;
1311 case CGOpCode::Sub:
1312 printOperationMinus(node);
1313 break;
1314
1315 case CGOpCode::UnMinus:
1316 printOperationUnaryMinus(node);
1317 break;
1318
1319 case CGOpCode::DependentMultiAssign:
1320 return printDependentMultiAssign(node);
1321
1322 case CGOpCode::Index:
1323 return 0; // nothing to do
1324 case CGOpCode::IndexAssign:
1325 printIndexAssign(node);
1326 break;
1327 case CGOpCode::IndexDeclaration:
1328 return 0; // already done
1329
1330 case CGOpCode::LoopStart:
1331 printLoopStart(node);
1332 break;
1333 case CGOpCode::LoopIndexedIndep:
1334 printLoopIndexedIndep(node);
1335 break;
1336 case CGOpCode::LoopIndexedDep:
1337 printLoopIndexedDep(node);
1338 break;
1339 case CGOpCode::LoopIndexedTmp:
1340 printLoopIndexedTmp(node);
1341 break;
1342 case CGOpCode::TmpDcl:
1343 // nothing to do
1344 return 0;
1345 case CGOpCode::Tmp:
1346 printTmpVar(node);
1347 break;
1348 case CGOpCode::LoopEnd:
1349 printLoopEnd(node);
1350 break;
1351 case CGOpCode::IndexCondExpr:
1352 printIndexCondExprOp(node);
1353 break;
1354 case CGOpCode::StartIf:
1355 printStartIf(node);
1356 break;
1357 case CGOpCode::ElseIf:
1358 printElseIf(node);
1359 break;
1360 case CGOpCode::Else:
1361 printElse(node);
1362 break;
1363 case CGOpCode::EndIf:
1364 printEndIf(node);
1365 break;
1366 case CGOpCode::CondResult:
1367 printCondResult(node);
1368 break;
1369 case CGOpCode::UserCustom:
1370 printUserCustom(node);
1371 break;
1372 default:
1373 throw CGException("Unknown operation code '", op, "'.");
1374 }
1375 return 1;
1376 }
1377
1378 virtual unsigned printAssignOp(Node& node) {
1379 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for assign operation")
1380
1381 return print(node.getArguments()[0]);
1382 }
1383
1384 virtual void printUnaryFunction(Node& op) {
1385 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary function")
1386
1387 switch (op.getOperationType()) {
1388 case CGOpCode::Abs:
1389 _code << "\\abs{";
1390 print(op.getArguments()[0]);
1391 _code << "}";
1392 return;
1393 case CGOpCode::Acos:
1394 _code << "\\arccos";
1395 break;
1396 case CGOpCode::Asin:
1397 _code << "\\arcsin";
1398 break;
1399 case CGOpCode::Atan:
1400 _code << "\\arctan";
1401 break;
1402 case CGOpCode::Cosh:
1403 _code << "\\cosh";
1404 break;
1405 case CGOpCode::Cos:
1406 _code << "\\cos";
1407 break;
1408 case CGOpCode::Exp:
1409 _code << "\\exp";
1410 break;
1411 case CGOpCode::Log:
1412 _code << "\\ln";
1413 break;
1414 case CGOpCode::Sinh:
1415 _code << "\\sinh";
1416 break;
1417 case CGOpCode::Sign:
1418 _code << "\\operatorname{sgn}";
1419 break;
1420 case CGOpCode::Sin:
1421 _code << "\\sin";
1422 break;
1423 case CGOpCode::Sqrt:
1424 _code << "\\sqrt{";
1425 print(op.getArguments()[0]);
1426 _code << "}";
1427 return;
1428 case CGOpCode::Tanh:
1429 _code << "\\tanh";
1430 break;
1431 case CGOpCode::Tan:
1432 _code << "\\tan";
1433 break;
1434#if CPPAD_USE_CPLUSPLUS_2011
1435 case CGOpCode::Erf:
1436 _code << "\\operatorname{erf}";
1437 break;
1438 case CGOpCode::Erfc:
1439 _code << "\\operatorname{erfc}";
1440 break;
1441 case CGOpCode::Asinh:
1442 _code << "\\operatorname{arcsinh}";
1443 break;
1444 case CGOpCode::Acosh:
1445 _code << "\\operatorname{arccosh}";
1446 break;
1447 case CGOpCode::Atanh:
1448 _code << "\\operatorname{arctanh}";
1449 break;
1450 case CGOpCode::Expm1:
1451 _code << "\\operatorname{expm1}";
1452 break;
1453 case CGOpCode::Log1p:
1454 _code << "\\operatorname{log1p}";
1455 break;
1456#endif
1457 default:
1458 throw CGException("Unknown function name for operation code '", op.getOperationType(), "'.");
1459 }
1460
1461 _code << "\\mathopen{}\\left(";
1462 print(op.getArguments()[0]);
1463 _code << "\\right)\\mathclose{}";
1464 }
1465
1466 virtual void printPowFunction(Node& op) {
1467 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for pow() function")
1468
1469 auto encloseInParentheses = [this](const Node* node) {
1470 while (node != nullptr) {
1471 if (getVariableID(*node) != 0)
1472 return false;
1473 if (node->getOperationType() == CGOpCode::Alias)
1474 node = node->getArguments()[0].getOperation();
1475 else
1476 break;
1477 }
1478 return node != nullptr &&
1479 getVariableID(*node) == 0 &&
1480 !isFunction(node->getOperationType());
1481 };
1482
1483 bool encloseBase = _powBaseEnclose || encloseInParentheses(op.getArguments()[0].getOperation());
1484 bool encloseExpo = encloseInParentheses(op.getArguments()[1].getOperation());
1485
1486 _code << "{";
1487 if (encloseBase)
1488 _code << "\\left(";
1489 print(op.getArguments()[0]);
1490 if (encloseBase)
1491 _code << "\\right)";
1492 _code << "}^{";
1493 if (encloseExpo)
1494 _code << "\\left(";
1495 print(op.getArguments()[1]);
1496 if (encloseExpo)
1497 _code << "\\right)";
1498 _code << "}";
1499 }
1500
1501 virtual unsigned printOperationAlias(Node& op) {
1502 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for alias")
1503 return print(op.getArguments()[0]);
1504 }
1505
1506 virtual void printOperationAdd(Node& op) {
1507 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for addition")
1508
1509 const Arg& left = op.getArguments()[0];
1510 const Arg& right = op.getArguments()[1];
1511
1512 if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1513 print(left);
1514 _code << " + ";
1515 print(right);
1516 } else {
1517 // right has a negative parameter so we would get v0 + -v1
1518 print(left);
1519 _code << " - ";
1520 printParameter(-*right.getParameter()); // make it positive
1521 }
1522 }
1523
1524 virtual void printOperationMinus(Node& op) {
1525 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for subtraction")
1526
1527 const Arg& left = op.getArguments()[0];
1528 const Arg& right = op.getArguments()[1];
1529
1530 if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1531 bool encloseRight = encloseInParenthesesMul(right);
1532
1533 print(left);
1534 _code << " - ";
1535 if (encloseRight) {
1536 _code << "\\left(";
1537 }
1538 print(right);
1539 if (encloseRight) {
1540 _code << "\\right)";
1541 }
1542 } else {
1543 // right has a negative parameter so we would get v0 - -v1
1544 print(left);
1545 _code << " + ";
1546 printParameter(-*right.getParameter()); // make it positive
1547 }
1548 }
1549
1550 virtual void printOperationDiv(Node& op) {
1551 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for division")
1552
1553 const Arg& left = op.getArguments()[0];
1554 const Arg& right = op.getArguments()[1];
1555
1556
1557 _code << "\\frac{";
1558 print(left);
1559 _code << "}{";
1560 print(right);
1561 _code << "}";
1562
1563 }
1564
1565 inline bool encloseInParenthesesMul(const Arg& arg) const {
1566 if (arg.getParameter() != nullptr) {
1567 return ((*arg.getParameter()) < 0);
1568 } else {
1569 return encloseInParenthesesMul(arg.getOperation());
1570 }
1571 }
1572
1573 inline bool encloseInParenthesesMul(const Node* node) const {
1574 while (node != nullptr) {
1575 if (getVariableID(*node) != 0) {
1576 return false;
1577 } else if (node->getOperationType() == CGOpCode::Alias) {
1578 node = node->getArguments()[0].getOperation();
1579 } else {
1580 break;
1581 }
1582 }
1583 return node != nullptr &&
1584 getVariableID(*node) == 0 &&
1585 node->getOperationType() != CGOpCode::Div &&
1586 node->getOperationType() != CGOpCode::Mul &&
1587 !isFunction(node->getOperationType());
1588 }
1589
1590 virtual void printOperationMul(Node& op) {
1591 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for multiplication")
1592
1593 const Arg& left = op.getArguments()[0];
1594 const Arg& right = op.getArguments()[1];
1595
1596 bool encloseLeft = encloseInParenthesesMul(left);
1597 bool encloseRight = encloseInParenthesesMul(right);
1598
1599 auto isNumber = [this](const Node* node, int pos) -> bool {
1600 while (node != nullptr) {
1601 if(getVariableID(*node) != 0) {
1602 return false;
1603 }
1604 CGOpCode op = node->getOperationType();
1605 if (op == CGOpCode::Alias) {
1606 node = node->getArguments()[0].getOperation();
1607 continue;
1608 } else if (op == CGOpCode::Mul) {
1609 node = node->getArguments()[pos].getOperation();
1610 } else if (pos == 0 && op == CGOpCode::Pow) {
1611 node = node->getArguments()[0].getOperation();
1612 } else {
1613 return false;
1614 }
1615 }
1616 return true; // a constant number
1617 };
1618
1619 if (encloseLeft) {
1620 _code << "\\left(";
1621 }
1622 print(left);
1623 if (encloseLeft) {
1624 _code << "\\right)";
1625 }
1626
1627 if (isNumber(left.getOperation(), 1) && isNumber(right.getOperation(), 0))
1628 _code << _multValOpStr; // numbers too close together are difficult to distinguish
1629 else
1630 _code << _multOpStr; // e.g. invisible times
1631
1632 if (encloseRight) {
1633 _code << "\\left(";
1634 }
1635 print(right);
1636 if (encloseRight) {
1637 _code << "\\right)";
1638 }
1639 }
1640
1641 virtual void printOperationUnaryMinus(Node& op) {
1642 CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary minus")
1643
1644 const Arg& arg = op.getArguments()[0];
1645
1646 bool enclose = encloseInParenthesesMul(arg);
1647
1648 _code << "-";
1649 if (enclose) {
1650 _code << "\\left(";
1651 }
1652 print(arg);
1653 if (enclose) {
1654 _code << "\\right)";
1655 }
1656 }
1657
1658 virtual void printConditionalAssignment(Node& node) {
1659 CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0)
1660
1661 const std::vector<Arg>& args = node.getArguments();
1662 const Arg &left = args[0];
1663 const Arg &right = args[1];
1664 const Arg &trueCase = args[2];
1665 const Arg &falseCase = args[3];
1666
1667 bool isDep = isDependent(node);
1668 const std::string& varName = createVariableName(node);
1669
1670 if ((trueCase.getParameter() != nullptr && falseCase.getParameter() != nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1671 (trueCase.getOperation() != nullptr && falseCase.getOperation() != nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1672 // true and false cases are the same
1673 printAssignmentStart(node, varName, isDep);
1674 print(trueCase);
1675 printAssignmentEnd(node);
1676 } else {
1677 checkEquationEnvEnd();
1678
1679 _code << _ifStart;
1680 _code << _conditionStart;
1681 print(left);
1682 _code << " " << getComparison(node.getOperationType()) << " ";
1683 print(right);
1684 _code << _conditionEnd;
1685 _code << _endline;
1686 //checkEquationEnvStart(); // no need
1687 printAssignmentStart(node, varName, isDep);
1688 print(trueCase);
1689 printAssignmentEnd(node);
1690 checkEquationEnvEnd();
1691 _code << _ifEnd << _endline;
1692 _code << _elseStart << _endline; // else
1693 //checkEquationEnvStart(); // no need
1694 printAssignmentStart(node, varName, isDep);
1695 print(falseCase);
1696 printAssignmentEnd(node);
1697 checkEquationEnvEnd();
1698 _code << _elseEnd << _endline; // end if
1699 }
1700 }
1701
1702 inline bool isSameArgument(const Arg& newArg,
1703 const Arg* oldArg) {
1704 if (oldArg != nullptr) {
1705 if (oldArg->getParameter() != nullptr) {
1706 if (newArg.getParameter() != nullptr) {
1707 return (*newArg.getParameter() == *oldArg->getParameter());
1708 }
1709 } else {
1710 return (newArg.getOperation() == oldArg->getOperation());
1711 }
1712 }
1713 return false;
1714 }
1715
1716 virtual void printArrayCreationOp(Node& op);
1717
1718 virtual void printSparseArrayCreationOp(Node& op);
1719
1720 inline void printArrayStructInit(const std::string& dataArrayName,
1721 size_t pos,
1722 const std::vector<Node*>& arrays,
1723 size_t k);
1724
1725 inline void printArrayStructInit(const std::string& dataArrayName,
1726 Node& array);
1727
1728 inline void markArrayChanged(Node& ty);
1729
1730 inline size_t printArrayCreationUsingLoop(size_t startPos,
1731 Node& array,
1732 size_t startj,
1733 std::vector<const Arg*>& tmpArrayValues);
1734
1735 inline std::string getTempArrayName(const Node& op);
1736
1737 virtual void printArrayElementOp(Node& op);
1738
1739 virtual void printAtomicForwardOp(Node& atomicFor) {
1740 CPPADCG_ASSERT_KNOWN(atomicFor.getInfo().size() == 3, "Invalid number of information elements for atomic forward operation")
1741 int q = atomicFor.getInfo()[1];
1742 int p = atomicFor.getInfo()[2];
1743 size_t p1 = p + 1;
1744 const std::vector<Arg>& opArgs = atomicFor.getArguments();
1745 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2, "Invalid number of arguments for atomic forward operation")
1746
1747 size_t id = atomicFor.getInfo()[0];
1748 std::vector<Node*> tx(p1), ty(p1);
1749 for (size_t k = 0; k < p1; k++) {
1750 tx[k] = opArgs[0 * p1 + k].getOperation();
1751 ty[k] = opArgs[1 * p1 + k].getOperation();
1752 }
1753
1754 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1755 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type")
1756 CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1757
1758 // tx
1759 for (size_t k = 0; k < p1; k++) {
1760 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1761 }
1762 // ty
1763 printArrayStructInit(_ATOMIC_TY, *ty[p]);
1764 _ss.str("");
1765
1766 _code << _startAlgLine << _startEq
1767 << _info->atomicFunctionId2Name.at(id) << ".forward("
1768 << q << ", " << p << ", "
1769 << _ATOMIC_TX << ", &" << _ATOMIC_TY << ")"
1770 << _endEq << _endAlgLine << _endline;
1771
1775 markArrayChanged(*ty[p]);
1776 }
1777
1778 virtual void printAtomicReverseOp(Node& atomicRev) {
1779 CPPADCG_ASSERT_KNOWN(atomicRev.getInfo().size() == 2, "Invalid number of information elements for atomic reverse operation")
1780 int p = atomicRev.getInfo()[1];
1781 size_t p1 = p + 1;
1782 const std::vector<Arg>& opArgs = atomicRev.getArguments();
1783 CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4, "Invalid number of arguments for atomic reverse operation")
1784
1785 size_t id = atomicRev.getInfo()[0];
1786 std::vector<Node*> tx(p1), px(p1), py(p1);
1787 for (size_t k = 0; k < p1; k++) {
1788 tx[k] = opArgs[0 * p1 + k].getOperation();
1789 px[k] = opArgs[2 * p1 + k].getOperation();
1790 py[k] = opArgs[3 * p1 + k].getOperation();
1791 }
1792
1793 CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1794 CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type")
1795
1796 CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1797
1798 CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type")
1799 CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type")
1800
1801 // tx
1802 for (size_t k = 0; k < p1; k++) {
1803 printArrayStructInit(_ATOMIC_TX, k, tx, k);
1804 }
1805 // py
1806 for (size_t k = 0; k < p1; k++) {
1807 printArrayStructInit(_ATOMIC_PY, k, py, k);
1808 }
1809 // px
1810 printArrayStructInit(_ATOMIC_PX, *px[0]);
1811 _ss.str("");
1812
1813 _code << _startAlgLine << _startEq
1814 << _info->atomicFunctionId2Name.at(id) << ".reverse("
1815 << p << ", "
1816 << _ATOMIC_TX << ", &" << _ATOMIC_PX << ", " << _ATOMIC_PY << ")"
1817 << _endEq << _endAlgLine << _endline;
1818
1822 markArrayChanged(*px[0]);
1823 }
1824
1825 virtual unsigned printDependentMultiAssign(Node& node) {
1826 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::DependentMultiAssign, "Invalid node type")
1827 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments")
1828
1829 const std::vector<Arg>& args = node.getArguments();
1830 for (size_t a = 0; a < args.size(); a++) {
1831 bool useArg = false;
1832 const Arg& arg = args[a];
1833 if (arg.getParameter() != nullptr) {
1834 useArg = true;
1835 } else {
1836 CGOpCode op = arg.getOperation()->getOperationType();
1837 useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1838 }
1839
1840 if (useArg) {
1841 printAssignment(node, arg); // ignore other arguments!
1842 return 1;
1843 }
1844 }
1845 return 0;
1846 }
1847
1848 virtual void printLoopStart(Node& node) {
1849 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart, "Invalid node type")
1850
1851 auto& lnode = static_cast<LoopStartOperationNode<Base>&> (node);
1852 _currentLoops.push_back(&lnode);
1853
1854 const std::string& jj = *lnode.getIndex().getName();
1855 std::string lastIt;
1856 if (lnode.getIterationCountNode() != nullptr) {
1857 lastIt = *lnode.getIterationCountNode()->getIndex().getName() + " - 1";
1858 } else {
1859 lastIt = std::to_string(lnode.getIterationCount() - 1);
1860 }
1861
1862 checkEquationEnvEnd();
1863
1864 _code << _forStart << "{$" << jj << "\\in \\left[0, " << lastIt << "\\right]$}" << _endline;
1865 _indentationLevel++;
1866 }
1867
1868 virtual void printLoopEnd(Node& node) {
1869 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd, "Invalid node type")
1870
1871 checkEquationEnvEnd();
1872
1873 _indentationLevel--;
1874
1875 _code << _forEnd << _endline;
1876
1877 _currentLoops.pop_back();
1878 }
1879
1880 virtual void printLoopIndexedDep(Node& node) {
1881 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for loop indexed dependent operation")
1882
1883 // LoopIndexedDep
1884 print(node.getArguments()[0]);
1885 }
1886
1887 virtual void printLoopIndexedIndep(Node& node) {
1888 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type")
1889 CPPADCG_ASSERT_KNOWN(node.getInfo().size() == 1, "Invalid number of information elements for loop indexed independent operation")
1890
1891 // CGLoopIndexedIndepOp
1892 size_t pos = node.getInfo()[1];
1893 const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1894 _code << _nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1895 }
1896
1897 virtual void printLoopIndexedTmp(Node& node) {
1898 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp, "Invalid node type")
1899 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for loop indexed temporary operation")
1900 Node* tmpVar = node.getArguments()[0].getOperation();
1901 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1902
1903 print(node.getArguments()[1]);
1904 }
1905
1906 virtual void printTmpVar(Node& node) {
1907 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp, "Invalid node type")
1908 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for temporary variable usage operation")
1909 Node* tmpVar = node.getArguments()[0].getOperation();
1910 CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation")
1911
1912 _code << _startVar << *tmpVar->getName() << _endVar;
1913 }
1914
1915 virtual void printIndexAssign(Node& node) {
1916 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign, "Invalid node type")
1917 CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for an index assignment operation")
1918
1919 auto& inode = static_cast<IndexAssignOperationNode<Base>&> (node);
1920
1921 checkEquationEnvStart();
1922
1923 const IndexPattern& ip = inode.getIndexPattern();
1924 _code << _startAlgLine << _startEq
1925 << (*inode.getIndex().getName())
1926 << _assignStr << indexPattern2String(ip, inode.getIndexPatternIndexes())
1927 << _endEq << _endAlgLine << _endline;
1928 }
1929
1930 virtual void printIndexCondExprOp(Node& node) {
1931 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexCondExpr, "Invalid node type")
1932 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for an index condition expression operation")
1933 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an index condition expression operation")
1934 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument for an index condition expression operation")
1935
1936 const std::vector<size_t>& info = node.getInfo();
1937
1938 auto& iterationIndexOp = static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1939 const std::string& index = *iterationIndexOp.getIndex().getName();
1940
1941 checkEquationEnvStart();
1942
1943 printIndexCondExpr(_code, info, index);
1944 }
1945
1946 virtual void printStartIf(Node& node) {
1951 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::StartIf, "Invalid node type")
1952 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'if start' operation")
1953 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'if start' operation")
1954
1955 checkEquationEnvEnd();
1956
1957 _code << _ifStart;
1958 //checkEquationEnvStart(); // no need
1959 _code << _conditionStart;
1960 printIndexCondExprOp(*node.getArguments()[0].getOperation());
1961 checkEquationEnvEnd();
1962 _code << _conditionEnd;
1963 _code << _endline;
1964
1965 _indentationLevel++;
1966 }
1967
1968 virtual void printElseIf(Node& node) {
1974 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ElseIf, "Invalid node type")
1975 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 2, "Invalid number of arguments for an 'else if' operation")
1976 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'else if' operation")
1977 CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an 'else if' operation")
1978
1979 checkEquationEnvEnd();
1980 _indentationLevel--;
1981
1982 // close previous environment
1983 CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
1984 if (nType == CGOpCode::StartIf) {
1985 _code << _ifEnd << _endline;
1986 } else if (nType == CGOpCode::ElseIf) {
1987 _code << _elseIfEnd << _endline;
1988 }
1989
1990 // start new else if
1991 _code << _elseIfStart;
1992 _code << _conditionStart;
1993 //checkEquationEnvStart(); // no need
1994 printIndexCondExprOp(*node.getArguments()[1].getOperation());
1995 checkEquationEnvEnd();
1996 _code << _conditionEnd;
1997 _code << _endline;
1998
1999 _indentationLevel++;
2000 }
2001
2002 virtual void printElse(Node& node) {
2007 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Else, "Invalid node type")
2008 CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'else' operation")
2009
2010 checkEquationEnvEnd();
2011 _indentationLevel--;
2012
2013 // close previous environment
2014 CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
2015 if (nType == CGOpCode::StartIf) {
2016 _code << _ifEnd << _endline;
2017 } else if (nType == CGOpCode::ElseIf) {
2018 _code << _elseIfEnd << _endline;
2019 }
2020
2021 // start else
2022 _code << _elseStart << _endline;
2023
2024 _indentationLevel++;
2025 }
2026
2027 virtual void printEndIf(Node& node) {
2028 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf, "Invalid node type for an 'end if' operation")
2029
2030 _indentationLevel--;
2031
2032 // close previous environment
2033 CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
2034 if (nType == CGOpCode::StartIf) {
2035 _code << _ifEnd << _endline;
2036 } else if (nType == CGOpCode::ElseIf) {
2037 _code << _elseIfEnd << _endline;
2038 } else {
2039 assert(nType == CGOpCode::Else);
2040 _code << _elseEnd << _endline;
2041 }
2042 }
2043
2044 virtual void printCondResult(Node& node) {
2045 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::CondResult, "Invalid node type")
2046 CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for an assignment inside an if/else operation")
2047 CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation")
2048 CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation")
2049
2050 // just follow the argument
2051 Node& nodeArg = *node.getArguments()[1].getOperation();
2052 printAssignment(nodeArg);
2053 }
2054
2055 virtual void printUserCustom(Node& node) {
2056 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::UserCustom, "Invalid node type")
2057
2058 throw CGException("Unable to generate Latex for user custom operation nodes.");
2059 }
2060
2061 inline bool isDependent(const Node& arg) const {
2062 if (arg.getOperationType() == CGOpCode::LoopIndexedDep) {
2063 return true;
2064 }
2065 size_t id = getVariableID(arg);
2066 return id > _independentSize && id < _minTemporaryVarID;
2067 }
2068
2069 virtual void printParameter(const Base& value) {
2070 // make sure all digits of floating point values are printed
2071 std::ostringstream os;
2072 os << std::setprecision(_parameterPrecision) << value;
2073
2074 std::string number = os.str();
2075 size_t pos = number.find('e');
2076 if (pos != std::string::npos) {
2077 std::string n = " \\times 10^{";
2078 number.replace(pos, 1, n);
2079 pos += n.size();
2080 if (number[pos] == '-' || number[pos] == '+')
2081 pos++;
2082 while (number[pos] == '0')
2083 number.replace(pos, 1, ""); // remove zeros
2084
2085 number += "}";
2086 }
2087 _code << number;
2088
2089 }
2090
2091 virtual const std::string& getComparison(enum CGOpCode op) const {
2092 switch (op) {
2093 case CGOpCode::ComLt:
2094 return _COMP_OP_LT;
2095
2096 case CGOpCode::ComLe:
2097 return _COMP_OP_LE;
2098
2099 case CGOpCode::ComEq:
2100 return _COMP_OP_EQ;
2101
2102 case CGOpCode::ComGe:
2103 return _COMP_OP_GE;
2104
2105 case CGOpCode::ComGt:
2106 return _COMP_OP_GT;
2107
2108 case CGOpCode::ComNe:
2109 return _COMP_OP_NE;
2110
2111 default:
2112 CPPAD_ASSERT_UNKNOWN(0)
2113 break;
2114 }
2115 throw CGException("Invalid comparison operator code"); // should never get here
2116 }
2117
2118 inline const std::string& getPrintfBaseFormat() {
2119 static const std::string format; // empty string
2120 return format;
2121 }
2122
2123 static bool isFunction(enum CGOpCode op) {
2124 return isUnaryFunction(op) || op == CGOpCode::Pow;
2125 }
2126
2127 static bool isUnaryFunction(enum CGOpCode op) {
2128 switch (op) {
2129 case CGOpCode::Abs:
2130 case CGOpCode::Acos:
2131 case CGOpCode::Asin:
2132 case CGOpCode::Atan:
2133 case CGOpCode::Cosh:
2134 case CGOpCode::Cos:
2135 case CGOpCode::Exp:
2136 case CGOpCode::Log:
2137 case CGOpCode::Sign:
2138 case CGOpCode::Sinh:
2139 case CGOpCode::Sin:
2140#if CPPAD_USE_CPLUSPLUS_2011
2141 case CGOpCode::Erf:
2142 case CGOpCode::Erfc:
2143 case CGOpCode::Asinh:
2144 case CGOpCode::Acosh:
2145 case CGOpCode::Atanh:
2146 case CGOpCode::Expm1:
2147 case CGOpCode::Log1p:
2148#endif
2149 case CGOpCode::Sqrt:
2150 case CGOpCode::Tanh:
2151 case CGOpCode::Tan:
2152 return true;
2153 default:
2154 return false;
2155 }
2156 }
2157
2158 static bool isCondAssign(enum CGOpCode op) {
2159 switch (op) {
2160 case CGOpCode::ComLt:
2161 case CGOpCode::ComLe:
2162 case CGOpCode::ComEq:
2163 case CGOpCode::ComGe:
2164 case CGOpCode::ComGt:
2165 case CGOpCode::ComNe:
2166 return true;
2167 default:
2168 return false;
2169 }
2170 }
2171};
2172
2173template<class Base>
2174const std::string LanguageLatex<Base>::_COMP_OP_LT = "<"; // NOLINT(cert-err58-cpp)
2175template<class Base>
2176const std::string LanguageLatex<Base>::_COMP_OP_LE = "\\le"; // NOLINT(cert-err58-cpp)
2177template<class Base>
2178const std::string LanguageLatex<Base>::_COMP_OP_EQ = "=="; // NOLINT(cert-err58-cpp)
2179template<class Base>
2180const std::string LanguageLatex<Base>::_COMP_OP_GE = "\\ge"; // NOLINT(cert-err58-cpp)
2181template<class Base>
2182const std::string LanguageLatex<Base>::_COMP_OP_GT = ">"; // NOLINT(cert-err58-cpp)
2183template<class Base>
2184const std::string LanguageLatex<Base>::_COMP_OP_NE = "\\ne"; // NOLINT(cert-err58-cpp)
2185
2186template<class Base>
2187const std::string LanguageLatex<Base>::_C_STATIC_INDEX_ARRAY = "index"; // NOLINT(cert-err58-cpp)
2188
2189template<class Base>
2190const std::string LanguageLatex<Base>::_C_SPARSE_INDEX_ARRAY = "idx"; // NOLINT(cert-err58-cpp)
2191
2192template<class Base>
2193const std::string LanguageLatex<Base>::_ATOMIC_TX = "atx"; // NOLINT(cert-err58-cpp)
2194
2195template<class Base>
2196const std::string LanguageLatex<Base>::_ATOMIC_TY = "aty"; // NOLINT(cert-err58-cpp)
2197
2198template<class Base>
2199const std::string LanguageLatex<Base>::_ATOMIC_PX = "apx"; // NOLINT(cert-err58-cpp)
2200
2201template<class Base>
2202const std::string LanguageLatex<Base>::_ATOMIC_PY = "apy"; // NOLINT(cert-err58-cpp)
2203
2204} // END cg namespace
2205} // END CppAD namespace
2206
2207#endif
size_t size() const noexcept
const CodeHandlerVector< Base, size_t > & totalUseCount
Definition language.hpp:95
const CodeHandlerVector< Base, size_t > & varId
Definition language.hpp:49
const std::vector< Node * > & independent
Definition language.hpp:36
virtual const std::string & getIfEnvironmentStart() const
virtual void printStartIf(Node &node)
virtual const std::string & getAgorithmFileEnvironmentEnd() const
virtual const std::string & getAlgorithmLineEnvironmentEnd() const
virtual void setAgorithmFileEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getDependentVarEnvironmentStart() const
virtual void setEquationBlockEnvironment(const std::string &begin, const std::string &end)
virtual bool isAlwaysEnclosePowBase() const
virtual void printElseIf(Node &node)
virtual const std::string & getIndependentVarEnvironmentEnd() const
virtual bool directlyAssignsVariable(const Node &var) const
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
virtual void setForEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getAgorithmFileEnvironmentStart() const
virtual void printAtomicForwardOp(Node &atomicFor)
virtual const std::string & getForEnvironmentEnd() const
virtual void setAlgorithmLineEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getForEnvironmentStart() const
const std::string & getMultiplicationConstParOperator() const
virtual void setVariableEnvironment(const std::string &begin, const std::string &end)
virtual void setIndependentVarEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getVariableEnvironmentStart() const
virtual void setAlwaysEnclosePowBase(bool enclose)
virtual const std::string & getEquationBlockEnvironmentEnd() const
virtual void setElseIfEnvironment(const std::string &begin, const std::string &end)
virtual void setElseEnvironment(const std::string &begin, const std::string &end)
void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern * > &randomPatterns)
virtual const std::string & getEquationEnvironmentEnd() const
virtual const std::string & getIfEnvironmentEnd() const
virtual void setIfEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getEquationEnvironmentStart() const
virtual const std::string & getElseEnvironmentEnd() const
bool createsNewVariable(const Node &var, size_t totalUseCount, size_t opCount) const override
void setMultiplicationOperator(const std::string &multOpStr)
virtual void setEquationEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getVariableEnvironmentEnd() const
bool requiresVariableDependencies() const override
virtual void printElse(Node &node)
virtual const std::string & getConditionEnvironmentEnd() const
virtual const std::string & getEquationBlockEnvironmentStart() const
virtual void setDependentVarEnvironment(const std::string &begin, const std::string &end)
virtual void setConditionEnvironment(const std::string &begin, const std::string &end)
const std::string & getMultiplicationOperator() const
virtual const std::string & getElseIfEnvironmentEnd() const
void setMultiplicationConstParOperator(const std::string &multValOpStr)
virtual const std::string & getDependentVarEnvironmentEnd() const
virtual const std::string & getElseEnvironmentStart() const
virtual const std::string & getAlgorithmLineEnvironmentStart() const
virtual void setParameterPrecision(size_t p)
virtual size_t getParameterPrecision() const
virtual void printAtomicReverseOp(Node &atomicRev)
virtual const std::string & getIndependentVarEnvironmentStart() const
virtual const std::string & getElseIfEnvironmentStart() const
virtual const std::string & getConditionEnvironmentStart() const
void setName(const std::string &name)
const std::vector< size_t > & getInfo() const
CGOpCode getOperationType() const
const std::string * getName() const
virtual std::string generateTemporary(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getDependent() const
virtual size_t getMaxTemporarySparseArrayVariableID() const =0
virtual std::string generateIndexedIndependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual std::string generateTemporaryArray(const OperationNode< Base > &variable, size_t id)=0
virtual const std::vector< FuncArgument > & getIndependent() const
virtual const std::vector< FuncArgument > & getTemporary() const
virtual std::string generateTemporarySparseArray(const OperationNode< Base > &variable, size_t id)=0
virtual std::string generateIndependent(const OperationNode< Base > &variable, size_t id)=0
virtual std::string generateIndexedDependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual size_t getMaxTemporaryArrayVariableID() const =0
virtual std::string generateDependent(size_t index)=0