CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
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 
19 namespace CppAD {
20 namespace cg {
21 
29 template<class Base>
30 class LanguageLatex : public Language<Base> {
31 public:
32  using Node = OperationNode<Base>;
33  using Arg = Argument<Base>;
34 protected:
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;
47 protected:
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;
132 private:
133  std::string auxArrayName_;
134 
135 public:
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  **************************************************************************/
681 protected:
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)
1277  printAtomicForwardOp(node);
1278  break;
1279  case CGOpCode::AtomicReverse: // atomicFunction.reverse(p, tx, ty, px, py)
1280  printAtomicReverseOp(node);
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 
2173 template<class Base>
2174 const std::string LanguageLatex<Base>::_COMP_OP_LT = "<"; // NOLINT(cert-err58-cpp)
2175 template<class Base>
2176 const std::string LanguageLatex<Base>::_COMP_OP_LE = "\\le"; // NOLINT(cert-err58-cpp)
2177 template<class Base>
2178 const std::string LanguageLatex<Base>::_COMP_OP_EQ = "=="; // NOLINT(cert-err58-cpp)
2179 template<class Base>
2180 const std::string LanguageLatex<Base>::_COMP_OP_GE = "\\ge"; // NOLINT(cert-err58-cpp)
2181 template<class Base>
2182 const std::string LanguageLatex<Base>::_COMP_OP_GT = ">"; // NOLINT(cert-err58-cpp)
2183 template<class Base>
2184 const std::string LanguageLatex<Base>::_COMP_OP_NE = "\\ne"; // NOLINT(cert-err58-cpp)
2185 
2186 template<class Base>
2187 const std::string LanguageLatex<Base>::_C_STATIC_INDEX_ARRAY = "index"; // NOLINT(cert-err58-cpp)
2188 
2189 template<class Base>
2190 const std::string LanguageLatex<Base>::_C_SPARSE_INDEX_ARRAY = "idx"; // NOLINT(cert-err58-cpp)
2191 
2192 template<class Base>
2193 const std::string LanguageLatex<Base>::_ATOMIC_TX = "atx"; // NOLINT(cert-err58-cpp)
2194 
2195 template<class Base>
2196 const std::string LanguageLatex<Base>::_ATOMIC_TY = "aty"; // NOLINT(cert-err58-cpp)
2197 
2198 template<class Base>
2199 const std::string LanguageLatex<Base>::_ATOMIC_PX = "apx"; // NOLINT(cert-err58-cpp)
2200 
2201 template<class Base>
2202 const std::string LanguageLatex<Base>::_ATOMIC_PY = "apy"; // NOLINT(cert-err58-cpp)
2203 
2204 } // END cg namespace
2205 } // END CppAD namespace
2206 
2207 #endif
virtual size_t getParameterPrecision() const
virtual void printStartIf(Node &node)
const std::map< size_t, std::string > & atomicFunctionId2Name
Definition: language.hpp:69
virtual std::string generateTemporary(const OperationNode< Base > &variable, size_t id)=0
virtual const std::string & getDependentVarEnvironmentEnd() const
virtual std::string generateIndexedDependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual const std::string & getForEnvironmentEnd() const
virtual size_t getMaxTemporaryArrayVariableID() const =0
virtual void setIfEnvironment(const std::string &begin, const std::string &end)
virtual std::string generateIndexedIndependent(const OperationNode< Base > &var, size_t id, const IndexPattern &ip)=0
virtual void setEquationEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getElseEnvironmentStart() const
const std::string * getName() const
virtual const std::string & getAlgorithmLineEnvironmentStart() const
virtual const std::string & getIfEnvironmentEnd() const
const std::vector< Argument< Base > > & getArguments() const
virtual const std::vector< FuncArgument > & getTemporary() const
virtual const std::string & getElseIfEnvironmentStart() const
STL namespace.
virtual const std::string & getIndependentVarEnvironmentEnd() const
virtual void printElse(Node &node)
virtual const std::string & getConditionEnvironmentStart() const
virtual bool isAlwaysEnclosePowBase() const
virtual const std::string & getElseIfEnvironmentEnd() const
virtual const std::string & getEquationEnvironmentStart() const
const CodeHandlerVector< Base, size_t > & varId
Definition: language.hpp:49
virtual void setIndependentVarEnvironment(const std::string &begin, const std::string &end)
bool createsNewVariable(const Node &var, size_t totalUseCount, size_t opCount) const override
virtual void printAtomicForwardOp(Node &atomicFor)
const std::string & getMultiplicationConstParOperator() const
virtual void setElseEnvironment(const std::string &begin, const std::string &end)
virtual std::string generateDependent(size_t index)=0
virtual const std::string & getVariableEnvironmentStart() const
virtual const std::string & getElseEnvironmentEnd() const
const CodeHandlerVector< Base, size_t > & totalUseCount
Definition: language.hpp:95
CGOpCode getOperationType() const
virtual const std::string & getForEnvironmentStart() const
virtual const std::string & getIndependentVarEnvironmentStart() const
virtual const std::string & getAgorithmFileEnvironmentStart() const
virtual void setAlwaysEnclosePowBase(bool enclose)
virtual const std::string & getIfEnvironmentStart() const
bool requiresVariableDependencies() const override
virtual const std::string & getDependentVarEnvironmentStart() const
virtual void setConditionEnvironment(const std::string &begin, const std::string &end)
virtual std::string generateTemporaryArray(const OperationNode< Base > &variable, size_t id)=0
virtual void setElseIfEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getEquationEnvironmentEnd() const
virtual size_t getMaxTemporarySparseArrayVariableID() const =0
void setMultiplicationOperator(const std::string &multOpStr)
void generateSourceCode(std::ostream &out, std::unique_ptr< LanguageGenerationData< Base > > info) override
virtual const std::vector< FuncArgument > & getDependent() const
virtual std::string generateTemporarySparseArray(const OperationNode< Base > &variable, size_t id)=0
size_t printArrayCreationUsingLoop(size_t startPos, Node &array, size_t startj, std::vector< const Arg *> &tmpArrayValues)
const std::string & getMultiplicationOperator() const
virtual const std::string & getEquationBlockEnvironmentEnd() const
virtual const std::vector< FuncArgument > & getIndependent() const
virtual void setParameterPrecision(size_t p)
virtual const std::string & getConditionEnvironmentEnd() const
virtual void setDependentVarEnvironment(const std::string &begin, const std::string &end)
virtual void printElseIf(Node &node)
virtual std::string generateIndependent(const OperationNode< Base > &variable, size_t id)=0
void setName(const std::string &name)
void setMultiplicationConstParOperator(const std::string &multValOpStr)
virtual const std::string & getVariableEnvironmentEnd() const
virtual const std::string & getAlgorithmLineEnvironmentEnd() const
virtual bool directlyAssignsVariable(const Node &var) const
virtual void setForEnvironment(const std::string &begin, const std::string &end)
size_t size() const noexcept
Definition: array_view.hpp:202
virtual void setVariableEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getAgorithmFileEnvironmentEnd() const
void printRandomIndexPatternDeclaration(std::ostringstream &os, const std::string &identation, const std::set< RandomIndexPattern *> &randomPatterns)
virtual void printAtomicReverseOp(Node &atomicRev)
virtual void setEquationBlockEnvironment(const std::string &begin, const std::string &end)
virtual const std::string & getEquationBlockEnvironmentStart() const
virtual void setAlgorithmLineEnvironment(const std::string &begin, const std::string &end)
const std::vector< size_t > & getInfo() const
virtual void setAgorithmFileEnvironment(const std::string &begin, const std::string &end)