CppADCodeGen  2.3.0
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() {
611  }
612 
613  /***************************************************************************
614  * STATIC
615  **************************************************************************/
616  static inline void printIndexCondExpr(std::ostringstream& out,
617  const std::vector<size_t>& info,
618  const std::string& index) {
619  CPPADCG_ASSERT_KNOWN(info.size() > 1 && info.size() % 2 == 0, "Invalid number of information elements for an index condition expression operation");
620 
621  size_t infoSize = info.size();
622  for (size_t e = 0; e < infoSize; e += 2) {
623  if (e > 0) {
624  out << " \\vee "; // or
625  }
626  size_t min = info[e];
627  size_t max = info[e + 1];
628  if (min == max) {
629  out << index << " == " << min;
630  } else if (min == 0) {
631  out << index << " \\le " << max;
632  } else if (max == std::numeric_limits<size_t>::max()) {
633  out << min << " \\le " << index;
634  } else {
635  if (infoSize != 2)
636  out << "(";
637 
638  if (max - min == 1)
639  out << min << " == " << index << " \\vee " << index << " == " << max;
640  else
641  out << min << " \\le " << index << " \\wedge" << index << " \\le " << max;
642 
643  if (infoSize != 2)
644  out << ")";
645  }
646  }
647  }
648 
649  /***************************************************************************
650  *
651  **************************************************************************/
652 
653  inline void printStaticIndexArray(std::ostringstream& os,
654  const std::string& name,
655  const std::vector<size_t>& values);
656 
657  inline void printStaticIndexMatrix(std::ostringstream& os,
658  const std::string& name,
659  const std::map<size_t, std::map<size_t, size_t> >& values);
660 
661  /***************************************************************************
662  * index patterns
663  **************************************************************************/
664  static inline void generateNames4RandomIndexPatterns(const std::set<RandomIndexPattern*>& randomPatterns);
665 
666  inline void printRandomIndexPatternDeclaration(std::ostringstream& os,
667  const std::string& identation,
668  const std::set<RandomIndexPattern*>& randomPatterns);
669 
670  static inline std::string indexPattern2String(const IndexPattern& ip,
671  const Node& index);
672 
673  static inline std::string indexPattern2String(const IndexPattern& ip,
674  const std::vector<const Node*>& indexes);
675 
676  static inline std::string linearIndexPattern2String(const LinearIndexPattern& lip,
677  const Node& index);
678 
679  /***************************************************************************
680  * protected
681  **************************************************************************/
682 protected:
683 
684  void generateSourceCode(std::ostream& out,
685  const std::unique_ptr<LanguageGenerationData<Base> >& info) override {
686 
687  const bool multiFile = _maxAssignmentsPerFile > 0 && _sources != nullptr;
688 
689  // clean up
690  _code.str("");
691  _ss.str("");
692  _indentationLevel = 0;
693  _temporary.clear();
694  _inEquationEnv = false;
695  auxArrayName_ = "";
696  _currentLoops.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.size() > 0 && depArg.size() > 0,
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  std::map<size_t, size_t>::const_iterator 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  const std::vector<FuncArgument>& depArg = _nameGen->getDependent();
813  if (!depArg.empty())
814  checkEquationEnvStart();
815  for (size_t i = 0; i < depArg.size(); i++) {
816  _code << _startAlgLine << _startEq;
817  const FuncArgument& a = depArg[i];
818  if (a.array) {
819  _code << a.name;
820  } else {
821  _code << _startDepVar << _nameGen->generateDependent(i) << _endDepVar;
822  }
823  _code << _assignStr;
824  printParameter(Base(0.0));
825  _code << _endEq << _endAlgLine << _endline;
826  }
827  }
828 
829  size_t assignCount = 0;
830  for (Node* it : variableOrder) {
831  // check if a new function should start
832  if (assignCount >= _maxAssignmentsPerFile && multiFile && _currentLoops.empty()) {
833  assignCount = 0;
834  saveLocalFunction(inputLatexFiles, inputLatexFiles.empty() && info->zeroDependents);
835  }
836 
837  Node& node = *it;
838 
839  // a dependent variable assigned by a loop does require any source code (its done inside the loop)
840  if (node.getOperationType() == CGOpCode::DependentRefRhs) {
841  continue; // nothing to do (this operation is right hand side only)
842  } else if (node.getOperationType() == CGOpCode::TmpDcl) { // temporary variable declaration does not need any source code here
843  continue; // nothing to do (bogus operation)
844  }
845 
846  assignCount += printAssignment(node);
847  }
848 
849  if (inputLatexFiles.size() > 0 && assignCount > 0) {
850  assignCount = 0;
851  saveLocalFunction(inputLatexFiles, false);
852  }
853  }
854 
855  if (!inputLatexFiles.empty()) {
859  CPPADCG_ASSERT_KNOWN(tmpArg[0].array,
860  "The temporary variables must be saved in an array in order to generate multiple functions");
861  printAlgorithmFileStart(_code);
862  for (size_t i = 0; i < inputLatexFiles.size(); i++) {
863  _code << "\\input{" << inputLatexFiles[i] << "}" << _endline;
864  }
865  printAlgorithmFileEnd(_code);
866  }
867 
868  // dependent duplicates
869  if (dependentDuplicates.size() > 0) {
870  _code << "% variable duplicates: " << dependentDuplicates.size() << _endline;
871 
872  checkEquationEnvStart();
873  for (size_t index : dependentDuplicates) {
874  const CG<Base>& dep = (*_dependent)[index];
875  std::string varName = _nameGen->generateDependent(index);
876  const std::string& origVarName = *dep.getOperationNode()->getName();
877 
878  _code << _startAlgLine << _startEq
879  << _startDepVar << varName << _endDepVar
880  << _assignStr
881  << _startDepVar << origVarName << _endDepVar;
882  printAssignmentEnd();
883  }
884  }
885 
886  // constant dependent variables
887  bool commentWritten = false;
888  for (size_t i = 0; i < dependent.size(); i++) {
889  if (dependent[i].isParameter()) {
890  if (!_ignoreZeroDepAssign || !dependent[i].isIdenticalZero()) {
891  if (!commentWritten) {
892  _code << "% dependent variables without operations" << _endline;
893  commentWritten = true;
894  }
895  checkEquationEnvStart();
896 
897  std::string varName = _nameGen->generateDependent(i);
898  _code << _startAlgLine << _startEq
899  << _startDepVar << varName << _endDepVar << _assignStr;
900  printParameter(dependent[i].getValue());
901  printAssignmentEnd();
902  }
903  } else if (dependent[i].getOperationNode()->getOperationType() == CGOpCode::Inv) {
904  if (!commentWritten) {
905  _code << "% dependent variables without operations" << _endline;
906  commentWritten = true;
907  }
908  checkEquationEnvStart();
909 
910  std::string varName = _nameGen->generateDependent(i);
911  const std::string& indepName = *dependent[i].getOperationNode()->getName();
912  _code << _startAlgLine << _startEq
913  << _startDepVar << varName << _endDepVar
914  << _assignStr
915  << _startIndepVar << indepName << _endIndepVar;
916  printAssignmentEnd(*dependent[i].getOperationNode());
917  }
918  }
919 
920  checkEquationEnvEnd();
921 
925  if (inputLatexFiles.empty()) {
926  // a single source file
927  printAlgorithmFileStart(_ss);
928  _ss << _code.str();
929  printAlgorithmFileEnd(_ss);
930 
931  out << _ss.str();
932 
933  if (_sources != nullptr) {
934  (*_sources)[_filename + ".tex"] = _ss.str();
935  }
936  } else {
937  // there are multiple source files (this last one is the master)
938  (*_sources)[_filename + ".tex"] = _code.str();
939  }
940 
941  }
942 
943  inline size_t getVariableID(const Node& node) const {
944  return _info->varId[node];
945  }
946 
947  inline virtual void printAlgorithmFileStart(std::ostream& out) {
948  out << "% Latex source file for '" << _filename << "' (automatically generated by CppADCodeGen)" << _endline;
949  out << _algFileStart << _endline;
950  }
951 
952  inline virtual void printAlgorithmFileEnd(std::ostream& out) {
953  out << _algFileEnd;
954  }
955 
956  inline virtual void checkEquationEnvStart() {
957  if (!_inEquationEnv) {
958  _code << _startEqBlock << _endline;
959  _inEquationEnv = true;
960  }
961  }
962 
963  inline virtual void checkEquationEnvEnd() {
964  if (_inEquationEnv) {
965  _code << _endEqBlock << _endline;
966  _inEquationEnv = false;
967  }
968  }
969 
970  inline unsigned printAssignment(Node& node) {
971  return printAssignment(node, node);
972  }
973 
974  inline unsigned printAssignment(Node& nodeName,
975  const Arg& nodeRhs) {
976  if (nodeRhs.getOperation() != nullptr) {
977  return printAssignment(nodeName, *nodeRhs.getOperation());
978  } else {
979  printAssignmentStart(nodeName);
980  printParameter(*nodeRhs.getParameter());
981  printAssignmentEnd(nodeName);
982  return 1;
983  }
984  }
985 
986  inline unsigned printAssignment(Node& nodeName,
987  Node& nodeRhs) {
988  bool createsVar = directlyAssignsVariable(nodeRhs); // do we need to do the assignment here?
989  if (!createsVar) {
990  printAssignmentStart(nodeName);
991  }
992  unsigned lines = printExpressionNoVarCheck(nodeRhs);
993  if (!createsVar) {
994  printAssignmentEnd(nodeRhs);
995  }
996 
997  if (nodeRhs.getOperationType() == CGOpCode::ArrayElement) {
998  Node* array = nodeRhs.getArguments()[0].getOperation();
999  size_t arrayId = getVariableID(*array);
1000  size_t pos = nodeRhs.getInfo()[0];
1001  if (array->getOperationType() == CGOpCode::ArrayCreation)
1002  _tmpArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
1003  else
1004  _tmpSparseArrayValues[arrayId - 1 + pos] = nullptr; // this could probably be removed!
1005  }
1006 
1007  return lines;
1008  }
1009 
1010  inline virtual void printAssignmentStart(Node& op) {
1011  printAssignmentStart(op, createVariableName(op), isDependent(op));
1012  }
1013 
1014  inline virtual void printAssignmentStart(Node& node, const std::string& varName, bool isDep) {
1015  if (!isDep) {
1016  _temporary[getVariableID(node)] = &node;
1017  }
1018 
1019  checkEquationEnvStart();
1020 
1021  _code << _startAlgLine << _startEq;
1022  if (isDep)
1023  _code << _startDepVar << varName << _endDepVar;
1024  else
1025  _code << _startVar << varName << _endVar;
1026 
1027  CGOpCode op = node.getOperationType();
1028  if (op == CGOpCode::DependentMultiAssign || (op == CGOpCode::LoopIndexedDep && node.getInfo()[1] == 1)) {
1029  _code << " += ";
1030  } else {
1031  _code << _assignStr;
1032  }
1033  }
1034 
1035  inline virtual void printAssignmentEnd() {
1036  _code << _endEq << _endAlgLine << _endline;
1037  }
1038 
1039  inline virtual void printAssignmentEnd(Node& op) {
1040  printAssignmentEnd();
1041  }
1042 
1043  virtual void saveLocalFunction(std::vector<std::string>& localFuncNames,
1044  bool zeroDependentArray) {
1045  _ss << _filename << "__part_" << (localFuncNames.size() + 1);
1046  std::string funcName = _ss.str();
1047  _ss.str("");
1048 
1049  // loop indexes
1050  _nameGen->prepareCustomFunctionVariables(_ss);
1051  _ss << _code.str();
1052  _nameGen->finalizeCustomFunctionVariables(_ss);
1053 
1054  (*_sources)[funcName + ".tex"] = _ss.str();
1055  localFuncNames.push_back(funcName);
1056 
1057  _code.str("");
1058  _ss.str("");
1059  }
1060 
1061  bool createsNewVariable(const Node& var,
1062  size_t totalUseCount) 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  std::map<size_t, size_t>::const_iterator 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  printUnaryFunction(node);
1266  break;
1267  case CGOpCode::AtomicForward: // atomicFunction.forward(q, p, vx, vy, tx, ty)
1268  printAtomicForwardOp(node);
1269  break;
1270  case CGOpCode::AtomicReverse: // atomicFunction.reverse(p, tx, ty, px, py)
1271  printAtomicReverseOp(node);
1272  break;
1273  case CGOpCode::Add:
1274  printOperationAdd(node);
1275  break;
1276  case CGOpCode::Alias:
1277  return printOperationAlias(node);
1278 
1279  case CGOpCode::ComLt:
1280  case CGOpCode::ComLe:
1281  case CGOpCode::ComEq:
1282  case CGOpCode::ComGe:
1283  case CGOpCode::ComGt:
1284  case CGOpCode::ComNe:
1285  printConditionalAssignment(node);
1286  break;
1287  case CGOpCode::Div:
1288  printOperationDiv(node);
1289  break;
1290  case CGOpCode::Inv:
1291  printIndependentVariableName(node);
1292  break;
1293  case CGOpCode::Mul:
1294  printOperationMul(node);
1295  break;
1296  case CGOpCode::Pow:
1297  printPowFunction(node);
1298  break;
1299  case CGOpCode::Pri:
1300  // do nothing
1301  break;
1302  case CGOpCode::Sub:
1303  printOperationMinus(node);
1304  break;
1305 
1306  case CGOpCode::UnMinus:
1307  printOperationUnaryMinus(node);
1308  break;
1309 
1310  case CGOpCode::DependentMultiAssign:
1311  return printDependentMultiAssign(node);
1312 
1313  case CGOpCode::Index:
1314  return 0; // nothing to do
1315  case CGOpCode::IndexAssign:
1316  printIndexAssign(node);
1317  break;
1318  case CGOpCode::IndexDeclaration:
1319  return 0; // already done
1320 
1321  case CGOpCode::LoopStart:
1322  printLoopStart(node);
1323  break;
1324  case CGOpCode::LoopIndexedIndep:
1325  printLoopIndexedIndep(node);
1326  break;
1327  case CGOpCode::LoopIndexedDep:
1328  printLoopIndexedDep(node);
1329  break;
1330  case CGOpCode::LoopIndexedTmp:
1331  printLoopIndexedTmp(node);
1332  break;
1333  case CGOpCode::TmpDcl:
1334  // nothing to do
1335  return 0;
1336  case CGOpCode::Tmp:
1337  printTmpVar(node);
1338  break;
1339  case CGOpCode::LoopEnd:
1340  printLoopEnd(node);
1341  break;
1342  case CGOpCode::IndexCondExpr:
1343  printIndexCondExprOp(node);
1344  break;
1345  case CGOpCode::StartIf:
1346  printStartIf(node);
1347  break;
1348  case CGOpCode::ElseIf:
1349  printElseIf(node);
1350  break;
1351  case CGOpCode::Else:
1352  printElse(node);
1353  break;
1354  case CGOpCode::EndIf:
1355  printEndIf(node);
1356  break;
1357  case CGOpCode::CondResult:
1358  printCondResult(node);
1359  break;
1360  case CGOpCode::UserCustom:
1361  printUserCustom(node);
1362  break;
1363  default:
1364  throw CGException("Unknown operation code '", op, "'.");
1365  }
1366  return 1;
1367  }
1368 
1369  virtual unsigned printAssignOp(Node& node) {
1370  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for assign operation");
1371 
1372  return print(node.getArguments()[0]);
1373  }
1374 
1375  virtual void printUnaryFunction(Node& op) {
1376  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary function");
1377 
1378  switch (op.getOperationType()) {
1379  case CGOpCode::Abs:
1380  _code << "\\abs{";
1381  print(op.getArguments()[0]);
1382  _code << "}";
1383  return;
1384  case CGOpCode::Acos:
1385  _code << "\\arccos";
1386  break;
1387  case CGOpCode::Asin:
1388  _code << "\\arcsin";
1389  break;
1390  case CGOpCode::Atan:
1391  _code << "\\arctan";
1392  break;
1393  case CGOpCode::Cosh:
1394  _code << "\\cosh";
1395  break;
1396  case CGOpCode::Cos:
1397  _code << "\\cos";
1398  break;
1399  case CGOpCode::Exp:
1400  _code << "\\exp";
1401  break;
1402  case CGOpCode::Log:
1403  _code << "\\ln";
1404  break;
1405  case CGOpCode::Sinh:
1406  _code << "\\sinh";
1407  break;
1408  case CGOpCode::Sign:
1409  _code << "\\operatorname{sgn}";
1410  break;
1411  case CGOpCode::Sin:
1412  _code << "\\sin";
1413  break;
1414  case CGOpCode::Sqrt:
1415  _code << "\\sqrt{";
1416  print(op.getArguments()[0]);
1417  _code << "}";
1418  return;
1419  case CGOpCode::Tanh:
1420  _code << "\\tanh";
1421  break;
1422  case CGOpCode::Tan:
1423  _code << "\\tan";
1424  break;
1425  default:
1426  throw CGException("Unknown function name for operation code '", op.getOperationType(), "'.");
1427  }
1428 
1429  _code << "\\mathopen{}\\left(";
1430  print(op.getArguments()[0]);
1431  _code << "\\right)\\mathclose{}";
1432  }
1433 
1434  virtual void printPowFunction(Node& op) {
1435  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for pow() function");
1436 
1437  auto encloseInParentheses = [this](const Node* node) {
1438  while (node != nullptr) {
1439  if (getVariableID(*node) != 0)
1440  return false;
1441  if (node->getOperationType() == CGOpCode::Alias)
1442  node = node->getArguments()[0].getOperation();
1443  else
1444  break;
1445  }
1446  return node != nullptr &&
1447  getVariableID(*node) == 0 &&
1448  !isFunction(node->getOperationType());
1449  };
1450 
1451  bool encloseBase = _powBaseEnclose || encloseInParentheses(op.getArguments()[0].getOperation());
1452  bool encloseExpo = encloseInParentheses(op.getArguments()[1].getOperation());
1453 
1454  _code << "{";
1455  if (encloseBase)
1456  _code << "\\left(";
1457  print(op.getArguments()[0]);
1458  if (encloseBase)
1459  _code << "\\right)";
1460  _code << "}^{";
1461  if (encloseExpo)
1462  _code << "\\left(";
1463  print(op.getArguments()[1]);
1464  if (encloseExpo)
1465  _code << "\\right)";
1466  _code << "}";
1467  }
1468 
1469  virtual unsigned printOperationAlias(Node& op) {
1470  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for alias");
1471  return print(op.getArguments()[0]);
1472  }
1473 
1474  virtual void printOperationAdd(Node& op) {
1475  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for addition");
1476 
1477  const Arg& left = op.getArguments()[0];
1478  const Arg& right = op.getArguments()[1];
1479 
1480  if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1481  print(left);
1482  _code << " + ";
1483  print(right);
1484  } else {
1485  // right has a negative parameter so we would get v0 + -v1
1486  print(left);
1487  _code << " - ";
1488  printParameter(-*right.getParameter()); // make it positive
1489  }
1490  }
1491 
1492  virtual void printOperationMinus(Node& op) {
1493  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for subtraction");
1494 
1495  const Arg& left = op.getArguments()[0];
1496  const Arg& right = op.getArguments()[1];
1497 
1498  if(right.getParameter() == nullptr || (*right.getParameter() >= 0)) {
1499  bool encloseRight = encloseInParenthesesMul(right);
1500 
1501  print(left);
1502  _code << " - ";
1503  if (encloseRight) {
1504  _code << "\\left(";
1505  }
1506  print(right);
1507  if (encloseRight) {
1508  _code << "\\right)";
1509  }
1510  } else {
1511  // right has a negative parameter so we would get v0 - -v1
1512  print(left);
1513  _code << " + ";
1514  printParameter(-*right.getParameter()); // make it positive
1515  }
1516  }
1517 
1518  virtual void printOperationDiv(Node& op) {
1519  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for division");
1520 
1521  const Arg& left = op.getArguments()[0];
1522  const Arg& right = op.getArguments()[1];
1523 
1524 
1525  _code << "\\frac{";
1526  print(left);
1527  _code << "}{";
1528  print(right);
1529  _code << "}";
1530 
1531  }
1532 
1533  inline bool encloseInParenthesesMul(const Arg& arg) const {
1534  if (arg.getParameter() != nullptr) {
1535  return ((*arg.getParameter()) < 0);
1536  } else {
1537  return encloseInParenthesesMul(arg.getOperation());
1538  }
1539  }
1540 
1541  inline bool encloseInParenthesesMul(const Node* node) const {
1542  while (node != nullptr) {
1543  if (getVariableID(*node) != 0) {
1544  return false;
1545  } else if (node->getOperationType() == CGOpCode::Alias) {
1546  node = node->getArguments()[0].getOperation();
1547  } else {
1548  break;
1549  }
1550  }
1551  return node != nullptr &&
1552  getVariableID(*node) == 0 &&
1553  node->getOperationType() != CGOpCode::Div &&
1554  node->getOperationType() != CGOpCode::Mul &&
1555  !isFunction(node->getOperationType());
1556  }
1557 
1558  virtual void printOperationMul(Node& op) {
1559  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 2, "Invalid number of arguments for multiplication");
1560 
1561  const Arg& left = op.getArguments()[0];
1562  const Arg& right = op.getArguments()[1];
1563 
1564  bool encloseLeft = encloseInParenthesesMul(left);
1565  bool encloseRight = encloseInParenthesesMul(right);
1566 
1567  auto isNumber = [this](const Node* node, int pos) -> bool {
1568  while (node != nullptr) {
1569  if(getVariableID(*node) != 0) {
1570  return false;
1571  }
1572  CGOpCode op = node->getOperationType();
1573  if (op == CGOpCode::Alias) {
1574  node = node->getArguments()[0].getOperation();
1575  continue;
1576  } else if (op == CGOpCode::Mul) {
1577  node = node->getArguments()[pos].getOperation();
1578  } else if (pos == 0 && op == CGOpCode::Pow) {
1579  node = node->getArguments()[0].getOperation();
1580  } else {
1581  return false;
1582  }
1583  }
1584  return true; // a constant number
1585  };
1586 
1587  if (encloseLeft) {
1588  _code << "\\left(";
1589  }
1590  print(left);
1591  if (encloseLeft) {
1592  _code << "\\right)";
1593  }
1594 
1595  if (isNumber(left.getOperation(), 1) && isNumber(right.getOperation(), 0))
1596  _code << _multValOpStr; // numbers too close together are difficult to distinguish
1597  else
1598  _code << _multOpStr; // e.g. invisible times
1599 
1600  if (encloseRight) {
1601  _code << "\\left(";
1602  }
1603  print(right);
1604  if (encloseRight) {
1605  _code << "\\right)";
1606  }
1607  }
1608 
1609  virtual void printOperationUnaryMinus(Node& op) {
1610  CPPADCG_ASSERT_KNOWN(op.getArguments().size() == 1, "Invalid number of arguments for unary minus");
1611 
1612  const Arg& arg = op.getArguments()[0];
1613 
1614  bool enclose = encloseInParenthesesMul(arg);
1615 
1616  _code << "-";
1617  if (enclose) {
1618  _code << "\\left(";
1619  }
1620  print(arg);
1621  if (enclose) {
1622  _code << "\\right)";
1623  }
1624  }
1625 
1626  virtual void printConditionalAssignment(Node& node) {
1627  CPPADCG_ASSERT_UNKNOWN(getVariableID(node) > 0);
1628 
1629  const std::vector<Arg>& args = node.getArguments();
1630  const Arg &left = args[0];
1631  const Arg &right = args[1];
1632  const Arg &trueCase = args[2];
1633  const Arg &falseCase = args[3];
1634 
1635  bool isDep = isDependent(node);
1636  const std::string& varName = createVariableName(node);
1637 
1638  if ((trueCase.getParameter() != nullptr && falseCase.getParameter() != nullptr && *trueCase.getParameter() == *falseCase.getParameter()) ||
1639  (trueCase.getOperation() != nullptr && falseCase.getOperation() != nullptr && trueCase.getOperation() == falseCase.getOperation())) {
1640  // true and false cases are the same
1641  printAssignmentStart(node, varName, isDep);
1642  print(trueCase);
1643  printAssignmentEnd(node);
1644  } else {
1645  checkEquationEnvEnd();
1646 
1647  _code << _ifStart;
1648  _code << _conditionStart;
1649  print(left);
1650  _code << " " << getComparison(node.getOperationType()) << " ";
1651  print(right);
1652  _code << _conditionEnd;
1653  _code << _endline;
1654  //checkEquationEnvStart(); // no need
1655  printAssignmentStart(node, varName, isDep);
1656  print(trueCase);
1657  printAssignmentEnd(node);
1658  checkEquationEnvEnd();
1659  _code << _ifEnd << _endline;
1660  _code << _elseStart << _endline; // else
1661  //checkEquationEnvStart(); // no need
1662  printAssignmentStart(node, varName, isDep);
1663  print(falseCase);
1664  printAssignmentEnd(node);
1665  checkEquationEnvEnd();
1666  _code << _elseEnd << _endline; // end if
1667  }
1668  }
1669 
1670  inline bool isSameArgument(const Arg& newArg,
1671  const Arg* oldArg) {
1672  if (oldArg != nullptr) {
1673  if (oldArg->getParameter() != nullptr) {
1674  if (newArg.getParameter() != nullptr) {
1675  return (*newArg.getParameter() == *oldArg->getParameter());
1676  }
1677  } else {
1678  return (newArg.getOperation() == oldArg->getOperation());
1679  }
1680  }
1681  return false;
1682  }
1683 
1684  virtual void printArrayCreationOp(Node& op);
1685 
1686  virtual void printSparseArrayCreationOp(Node& op);
1687 
1688  inline void printArrayStructInit(const std::string& dataArrayName,
1689  size_t pos,
1690  const std::vector<Node*>& arrays,
1691  size_t k);
1692 
1693  inline void printArrayStructInit(const std::string& dataArrayName,
1694  Node& array);
1695 
1696  inline void markArrayChanged(Node& ty);
1697 
1698  inline size_t printArrayCreationUsingLoop(size_t startPos,
1699  Node& array,
1700  size_t startj,
1701  std::vector<const Arg*>& tmpArrayValues);
1702 
1703  inline std::string getTempArrayName(const Node& op);
1704 
1705  virtual void printArrayElementOp(Node& op);
1706 
1707  virtual void printAtomicForwardOp(Node& atomicFor) {
1708  CPPADCG_ASSERT_KNOWN(atomicFor.getInfo().size() == 3, "Invalid number of information elements for atomic forward operation");
1709  int q = atomicFor.getInfo()[1];
1710  int p = atomicFor.getInfo()[2];
1711  size_t p1 = p + 1;
1712  const std::vector<Arg>& opArgs = atomicFor.getArguments();
1713  CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 2, "Invalid number of arguments for atomic forward operation");
1714 
1715  size_t id = atomicFor.getInfo()[0];
1716  std::vector<Node*> tx(p1), ty(p1);
1717  for (size_t k = 0; k < p1; k++) {
1718  tx[k] = opArgs[0 * p1 + k].getOperation();
1719  ty[k] = opArgs[1 * p1 + k].getOperation();
1720  }
1721 
1722  CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1723  CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1724  CPPADCG_ASSERT_KNOWN(ty[p]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1725 
1726  // tx
1727  for (size_t k = 0; k < p1; k++) {
1728  printArrayStructInit(_ATOMIC_TX, k, tx, k);
1729  }
1730  // ty
1731  printArrayStructInit(_ATOMIC_TY, *ty[p]);
1732  _ss.str("");
1733 
1734  _code << _startAlgLine << _startEq
1735  << _info->atomicFunctionId2Name.at(id) << ".forward("
1736  << q << ", " << p << ", "
1737  << _ATOMIC_TX << ", &" << _ATOMIC_TY << ")"
1738  << _endEq << _endAlgLine << _endline;
1739 
1743  markArrayChanged(*ty[p]);
1744  }
1745 
1746  virtual void printAtomicReverseOp(Node& atomicRev) {
1747  CPPADCG_ASSERT_KNOWN(atomicRev.getInfo().size() == 2, "Invalid number of information elements for atomic reverse operation");
1748  int p = atomicRev.getInfo()[1];
1749  size_t p1 = p + 1;
1750  const std::vector<Arg>& opArgs = atomicRev.getArguments();
1751  CPPADCG_ASSERT_KNOWN(opArgs.size() == p1 * 4, "Invalid number of arguments for atomic reverse operation");
1752 
1753  size_t id = atomicRev.getInfo()[0];
1754  std::vector<Node*> tx(p1), px(p1), py(p1);
1755  for (size_t k = 0; k < p1; k++) {
1756  tx[k] = opArgs[0 * p1 + k].getOperation();
1757  px[k] = opArgs[2 * p1 + k].getOperation();
1758  py[k] = opArgs[3 * p1 + k].getOperation();
1759  }
1760 
1761  CPPADCG_ASSERT_KNOWN(tx[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1762  CPPADCG_ASSERT_KNOWN(p == 0 || tx[1]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1763 
1764  CPPADCG_ASSERT_KNOWN(px[0]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1765 
1766  CPPADCG_ASSERT_KNOWN(py[0]->getOperationType() == CGOpCode::SparseArrayCreation, "Invalid array type");
1767  CPPADCG_ASSERT_KNOWN(p == 0 || py[1]->getOperationType() == CGOpCode::ArrayCreation, "Invalid array type");
1768 
1769  // tx
1770  for (size_t k = 0; k < p1; k++) {
1771  printArrayStructInit(_ATOMIC_TX, k, tx, k);
1772  }
1773  // py
1774  for (size_t k = 0; k < p1; k++) {
1775  printArrayStructInit(_ATOMIC_PY, k, py, k);
1776  }
1777  // px
1778  printArrayStructInit(_ATOMIC_PX, *px[0]);
1779  _ss.str("");
1780 
1781  _code << _startAlgLine << _startEq
1782  << _info->atomicFunctionId2Name.at(id) << ".reverse("
1783  << p << ", "
1784  << _ATOMIC_TX << ", &" << _ATOMIC_PX << ", " << _ATOMIC_PY << ")"
1785  << _endEq << _endAlgLine << _endline;
1786 
1790  markArrayChanged(*px[0]);
1791  }
1792 
1793  virtual unsigned printDependentMultiAssign(Node& node) {
1794  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::DependentMultiAssign, "Invalid node type");
1795  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments");
1796 
1797  const std::vector<Arg>& args = node.getArguments();
1798  for (size_t a = 0; a < args.size(); a++) {
1799  bool useArg = false;
1800  const Arg& arg = args[a];
1801  if (arg.getParameter() != nullptr) {
1802  useArg = true;
1803  } else {
1804  CGOpCode op = arg.getOperation()->getOperationType();
1805  useArg = op != CGOpCode::DependentRefRhs && op != CGOpCode::LoopEnd && op != CGOpCode::EndIf;
1806  }
1807 
1808  if (useArg) {
1809  printAssignment(node, arg); // ignore other arguments!
1810  return 1;
1811  }
1812  }
1813  return 0;
1814  }
1815 
1816  virtual void printLoopStart(Node& node) {
1817  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopStart, "Invalid node type");
1818 
1819  LoopStartOperationNode<Base>& lnode = static_cast<LoopStartOperationNode<Base>&> (node);
1820  _currentLoops.push_back(&lnode);
1821 
1822  const std::string& jj = *lnode.getIndex().getName();
1823  std::string lastIt;
1824  if (lnode.getIterationCountNode() != nullptr) {
1825  lastIt = *lnode.getIterationCountNode()->getIndex().getName() + " - 1";
1826  } else {
1827  lastIt = std::to_string(lnode.getIterationCount() - 1);
1828  }
1829 
1830  checkEquationEnvEnd();
1831 
1832  _code << _forStart << "{$" << jj << "\\in \\left[0, " << lastIt << "\\right]$}" << _endline;
1833  _indentationLevel++;
1834  }
1835 
1836  virtual void printLoopEnd(Node& node) {
1837  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopEnd, "Invalid node type");
1838 
1839  checkEquationEnvEnd();
1840 
1841  _indentationLevel--;
1842 
1843  _code << _forEnd << _endline;
1844 
1845  _currentLoops.pop_back();
1846  }
1847 
1848  virtual void printLoopIndexedDep(Node& node) {
1849  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for loop indexed dependent operation");
1850 
1851  // LoopIndexedDep
1852  print(node.getArguments()[0]);
1853  }
1854 
1855  virtual void printLoopIndexedIndep(Node& node) {
1856  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedIndep, "Invalid node type");
1857  CPPADCG_ASSERT_KNOWN(node.getInfo().size() == 1, "Invalid number of information elements for loop indexed independent operation");
1858 
1859  // CGLoopIndexedIndepOp
1860  size_t pos = node.getInfo()[1];
1861  const IndexPattern* ip = _info->loopIndependentIndexPatterns[pos];
1862  _code << _nameGen->generateIndexedIndependent(node, getVariableID(node), *ip);
1863  }
1864 
1865  virtual void printLoopIndexedTmp(Node& node) {
1866  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::LoopIndexedTmp, "Invalid node type");
1867  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for loop indexed temporary operation");
1868  Node* tmpVar = node.getArguments()[0].getOperation();
1869  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1870 
1871  print(node.getArguments()[1]);
1872  }
1873 
1874  virtual void printTmpVar(Node& node) {
1875  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Tmp, "Invalid node type");
1876  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for temporary variable usage operation");
1877  Node* tmpVar = node.getArguments()[0].getOperation();
1878  CPPADCG_ASSERT_KNOWN(tmpVar != nullptr && tmpVar->getOperationType() == CGOpCode::TmpDcl, "Invalid arguments for loop indexed temporary operation");
1879 
1880  _code << _startVar << *tmpVar->getName() << _endVar;
1881  }
1882 
1883  virtual void printIndexAssign(Node& node) {
1884  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign, "Invalid node type");
1885  CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for an index assignment operation");
1886 
1887  IndexAssignOperationNode<Base>& inode = static_cast<IndexAssignOperationNode<Base>&> (node);
1888 
1889  checkEquationEnvStart();
1890 
1891  const IndexPattern& ip = inode.getIndexPattern();
1892  _code << _startAlgLine << _startEq
1893  << (*inode.getIndex().getName())
1894  << _assignStr << indexPattern2String(ip, inode.getIndexPatternIndexes())
1895  << _endEq << _endAlgLine << _endline;
1896  }
1897 
1898  virtual void printIndexCondExprOp(Node& node) {
1899  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexCondExpr, "Invalid node type");
1900  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 1, "Invalid number of arguments for an index condition expression operation");
1901  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an index condition expression operation");
1902  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation()->getOperationType() == CGOpCode::Index, "Invalid argument for an index condition expression operation");
1903 
1904  const std::vector<size_t>& info = node.getInfo();
1905 
1906  IndexOperationNode<Base>& iterationIndexOp = static_cast<IndexOperationNode<Base>&> (*node.getArguments()[0].getOperation());
1907  const std::string& index = *iterationIndexOp.getIndex().getName();
1908 
1909  checkEquationEnvStart();
1910 
1911  printIndexCondExpr(_code, info, index);
1912  }
1913 
1914  virtual void printStartIf(Node& node) {
1919  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::StartIf, "Invalid node type");
1920  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'if start' operation");
1921  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'if start' operation");
1922 
1923  checkEquationEnvEnd();
1924 
1925  _code << _ifStart;
1926  //checkEquationEnvStart(); // no need
1927  _code << _conditionStart;
1928  printIndexCondExprOp(*node.getArguments()[0].getOperation());
1929  checkEquationEnvEnd();
1930  _code << _conditionEnd;
1931  _code << _endline;
1932 
1933  _indentationLevel++;
1934  }
1935 
1936  virtual void printElseIf(Node& node) {
1942  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ElseIf, "Invalid node type");
1943  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 2, "Invalid number of arguments for an 'else if' operation");
1944  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an 'else if' operation");
1945  CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an 'else if' operation");
1946 
1947  checkEquationEnvEnd();
1948  _indentationLevel--;
1949 
1950  // close previous environment
1951  CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
1952  if (nType == CGOpCode::StartIf) {
1953  _code << _ifEnd << _endline;
1954  } else if (nType == CGOpCode::ElseIf) {
1955  _code << _elseIfEnd << _endline;
1956  }
1957 
1958  // start new else if
1959  _code << _elseIfStart;
1960  _code << _conditionStart;
1961  //checkEquationEnvStart(); // no need
1962  printIndexCondExprOp(*node.getArguments()[1].getOperation());
1963  checkEquationEnvEnd();
1964  _code << _conditionEnd;
1965  _code << _endline;
1966 
1967  _indentationLevel++;
1968  }
1969 
1970  virtual void printElse(Node& node) {
1975  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::Else, "Invalid node type");
1976  CPPADCG_ASSERT_KNOWN(node.getArguments().size() >= 1, "Invalid number of arguments for an 'else' operation");
1977 
1978  checkEquationEnvEnd();
1979  _indentationLevel--;
1980 
1981  // close previous environment
1982  CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
1983  if (nType == CGOpCode::StartIf) {
1984  _code << _ifEnd << _endline;
1985  } else if (nType == CGOpCode::ElseIf) {
1986  _code << _elseIfEnd << _endline;
1987  }
1988 
1989  // start else
1990  _code << _elseStart << _endline;
1991 
1992  _indentationLevel++;
1993  }
1994 
1995  virtual void printEndIf(Node& node) {
1996  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::EndIf, "Invalid node type for an 'end if' operation");
1997 
1998  _indentationLevel--;
1999 
2000  // close previous environment
2001  CGOpCode nType = node.getArguments()[0].getOperation()->getOperationType();
2002  if (nType == CGOpCode::StartIf) {
2003  _code << _ifEnd << _endline;
2004  } else if (nType == CGOpCode::ElseIf) {
2005  _code << _elseIfEnd << _endline;
2006  } else {
2007  assert(nType == CGOpCode::Else);
2008  _code << _elseEnd << _endline;
2009  }
2010  }
2011 
2012  virtual void printCondResult(Node& node) {
2013  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::CondResult, "Invalid node type");
2014  CPPADCG_ASSERT_KNOWN(node.getArguments().size() == 2, "Invalid number of arguments for an assignment inside an if/else operation");
2015  CPPADCG_ASSERT_KNOWN(node.getArguments()[0].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation");
2016  CPPADCG_ASSERT_KNOWN(node.getArguments()[1].getOperation() != nullptr, "Invalid argument for an an assignment inside an if/else operation");
2017 
2018  // just follow the argument
2019  Node& nodeArg = *node.getArguments()[1].getOperation();
2020  printAssignment(nodeArg);
2021  }
2022 
2023  virtual void printUserCustom(Node& node) {
2024  CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::UserCustom, "Invalid node type");
2025 
2026  throw CGException("Unable to generate Latex for user custom operation nodes.");
2027  }
2028 
2029  inline bool isDependent(const Node& arg) const {
2030  if (arg.getOperationType() == CGOpCode::LoopIndexedDep) {
2031  return true;
2032  }
2033  size_t id = getVariableID(arg);
2034  return id > _independentSize && id < _minTemporaryVarID;
2035  }
2036 
2037  virtual void printParameter(const Base& value) {
2038  // make sure all digits of floating point values are printed
2039  std::ostringstream os;
2040  os << std::setprecision(_parameterPrecision) << value;
2041 
2042  std::string number = os.str();
2043  size_t pos = number.find('e');
2044  if (pos != std::string::npos) {
2045  std::string n = " \\times 10^{";
2046  number.replace(pos, 1, n);
2047  pos += n.size();
2048  if (number[pos] == '-' || number[pos] == '+')
2049  pos++;
2050  while (number[pos] == '0')
2051  number.replace(pos, 1, ""); // remove zeros
2052 
2053  number += "}";
2054  }
2055  _code << number;
2056 
2057  }
2058 
2059  virtual const std::string& getComparison(enum CGOpCode op) const {
2060  switch (op) {
2061  case CGOpCode::ComLt:
2062  return _COMP_OP_LT;
2063 
2064  case CGOpCode::ComLe:
2065  return _COMP_OP_LE;
2066 
2067  case CGOpCode::ComEq:
2068  return _COMP_OP_EQ;
2069 
2070  case CGOpCode::ComGe:
2071  return _COMP_OP_GE;
2072 
2073  case CGOpCode::ComGt:
2074  return _COMP_OP_GT;
2075 
2076  case CGOpCode::ComNe:
2077  return _COMP_OP_NE;
2078 
2079  default:
2080  CPPAD_ASSERT_UNKNOWN(0);
2081  }
2082  throw CGException("Invalid comparison operator code"); // should never get here
2083  }
2084 
2085  inline const std::string& getPrintfBaseFormat() {
2086  static const std::string format; // empty string
2087  return format;
2088  }
2089 
2090  static bool isFunction(enum CGOpCode op) {
2091  return isUnaryFunction(op) || op == CGOpCode::Pow;
2092  }
2093 
2094  static bool isUnaryFunction(enum CGOpCode op) {
2095  switch (op) {
2096  case CGOpCode::Abs:
2097  case CGOpCode::Acos:
2098  case CGOpCode::Asin:
2099  case CGOpCode::Atan:
2100  case CGOpCode::Cosh:
2101  case CGOpCode::Cos:
2102  case CGOpCode::Exp:
2103  case CGOpCode::Log:
2104  case CGOpCode::Sign:
2105  case CGOpCode::Sinh:
2106  case CGOpCode::Sin:
2107  case CGOpCode::Sqrt:
2108  case CGOpCode::Tanh:
2109  case CGOpCode::Tan:
2110  return true;
2111  default:
2112  return false;
2113  }
2114  }
2115 
2116  static bool isCondAssign(enum CGOpCode op) {
2117  switch (op) {
2118  case CGOpCode::ComLt:
2119  case CGOpCode::ComLe:
2120  case CGOpCode::ComEq:
2121  case CGOpCode::ComGe:
2122  case CGOpCode::ComGt:
2123  case CGOpCode::ComNe:
2124  return true;
2125  default:
2126  return false;
2127  }
2128  }
2129 };
2130 
2131 template<class Base>
2132 const std::string LanguageLatex<Base>::_COMP_OP_LT = "<";
2133 template<class Base>
2134 const std::string LanguageLatex<Base>::_COMP_OP_LE = "\\le";
2135 template<class Base>
2136 const std::string LanguageLatex<Base>::_COMP_OP_EQ = "==";
2137 template<class Base>
2138 const std::string LanguageLatex<Base>::_COMP_OP_GE = "\\ge";
2139 template<class Base>
2140 const std::string LanguageLatex<Base>::_COMP_OP_GT = ">";
2141 template<class Base>
2142 const std::string LanguageLatex<Base>::_COMP_OP_NE = "\\ne";
2143 
2144 template<class Base>
2145 const std::string LanguageLatex<Base>::_C_STATIC_INDEX_ARRAY = "index";
2146 
2147 template<class Base>
2148 const std::string LanguageLatex<Base>::_C_SPARSE_INDEX_ARRAY = "idx";
2149 
2150 template<class Base>
2151 const std::string LanguageLatex<Base>::_ATOMIC_TX = "atx";
2152 
2153 template<class Base>
2154 const std::string LanguageLatex<Base>::_ATOMIC_TY = "aty";
2155 
2156 template<class Base>
2157 const std::string LanguageLatex<Base>::_ATOMIC_PX = "apx";
2158 
2159 template<class Base>
2160 const std::string LanguageLatex<Base>::_ATOMIC_PY = "apy";
2161 
2162 } // END cg namespace
2163 } // END CppAD namespace
2164 
2165 #endif
virtual size_t getParameterPrecision() const
virtual void printStartIf(Node &node)
const std::map< size_t, std::string > & atomicFunctionId2Name
Definition: language.hpp:68
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:48
virtual void setIndependentVarEnvironment(const std::string &begin, const std::string &end)
bool createsNewVariable(const Node &var, size_t totalUseCount) 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:94
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)
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)
void generateSourceCode(std::ostream &out, const std::unique_ptr< LanguageGenerationData< Base > > &info) override
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)