CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
model_c_source_gen_rev1.hpp
1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_REV1_INCLUDED
2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_REV1_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 namespace CppAD {
19 namespace cg {
20 
21 template<class Base>
23 
24  determineJacobianSparsity();
25 
26  // elements[equation]{vars}
27  std::map<size_t, std::vector<size_t> > elements;
28  for (size_t e = 0; e < _jacSparsity.rows.size(); e++) {
29  elements[_jacSparsity.rows[e]].push_back(_jacSparsity.cols[e]);
30  }
31 
32  if (!_loopTapes.empty()) {
36  prepareSparseReverseOneWithLoops(elements);
37  return;
38  }
39 
43  startingJob("'model (reverse one)'", JobTimer::SOURCE_GENERATION);
44 
45  if (isAtomicsUsed()) {
46  generateSparseReverseOneSourcesWithAtomics(elements);
47  } else {
48  generateSparseReverseOneSourcesNoAtomics(elements);
49  }
50 
51  finishedJob();
52 
53  _cache.str("");
54 
55  generateGlobalDirectionalFunctionSource(FUNCTION_SPARSE_REVERSE_ONE,
56  "dep",
57  FUNCTION_REVERSE_ONE_SPARSITY,
58  elements);
59 }
60 
61 template<class Base>
62 void ModelCSourceGen<Base>::generateSparseReverseOneSourcesWithAtomics(const std::map<size_t, std::vector<size_t> >& elements) {
63  using std::vector;
64 
68  size_t m = _fun.Range();
69  size_t n = _fun.Domain();
70 
71  vector<CGBase> w(m);
72 
76  const std::string jobName = "model (reverse one)";
77  startingJob("'" + jobName + "'", JobTimer::SOURCE_GENERATION);
78 
79  for (const auto& it : elements) {
80  size_t i = it.first;
81  const std::vector<size_t>& cols = it.second;
82 
83  _cache.str("");
84  _cache << "model (reverse one, dep " << i << ")";
85  const std::string subJobName = _cache.str();
86 
87  startingJob("'" + subJobName + "'", JobTimer::GRAPH);
88 
89  CodeHandler<Base> handler;
90  handler.setJobTimer(_jobTimer);
91 
92  vector<CGBase> indVars(_fun.Domain());
93  handler.makeVariables(indVars);
94  if (_x.size() > 0) {
95  for (size_t i = 0; i < n; i++) {
96  indVars[i].setValue(_x[i]);
97  }
98  }
99 
100  CGBase py;
101  handler.makeVariable(py);
102  if (_x.size() > 0) {
103  py.setValue(Base(1.0));
104  }
105 
106  // TODO: consider caching the zero order coefficients somehow between calls
107  _fun.Forward(0, indVars);
108 
109  w[i] = py;
110  vector<CGBase> dw = _fun.Reverse(1, w);
111  CPPADCG_ASSERT_UNKNOWN(dw.size() == n);
112  w[i] = Base(0);
113 
114  vector<CGBase> dwCustom;
115  for (size_t it2 : cols) {
116  dwCustom.push_back(dw[it2]);
117  }
118 
119  finishedJob();
120 
121  LanguageC<Base> langC(_baseTypeName);
122  langC.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
123  langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
124  langC.setParameterPrecision(_parameterPrecision);
125  _cache.str("");
126  _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "_dep" << i;
127  langC.setGenerateFunction(_cache.str());
128 
129  std::ostringstream code;
130  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("dw"));
131  LangCDefaultHessianVarNameGenerator<Base> nameGenHess(nameGen.get(), "py", n);
132 
133  handler.generateCode(code, langC, dwCustom, nameGenHess, _atomicFunctions, subJobName);
134  }
135 }
136 
137 template<class Base>
138 void ModelCSourceGen<Base>::generateSparseReverseOneSourcesNoAtomics(const std::map<size_t, std::vector<size_t> >& elements) {
139  using std::vector;
140 
144  size_t m = _fun.Range();
145  size_t n = _fun.Domain();
146 
147  CodeHandler<Base> handler;
148  handler.setJobTimer(_jobTimer);
149 
150  vector<CGBase> x(n);
151  handler.makeVariables(x);
152  if (_x.size() > 0) {
153  for (size_t i = 0; i < n; i++) {
154  x[i].setValue(_x[i]);
155  }
156  }
157 
158  CGBase py;
159  handler.makeVariable(py);
160  if (_x.size() > 0) {
161  py.setValue(Base(1.0));
162  }
163 
164  vector<CGBase> jacFlat(_jacSparsity.rows.size());
165 
166  CppAD::sparse_jacobian_work work; // temporary structure for CPPAD
167  _fun.SparseJacobianReverse(x, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jacFlat, work);
168 
172  std::map<size_t, vector<CGBase> > jac; // by row
173  std::vector<std::map<size_t, size_t> > positions(m); // by row
174 
175  for (const auto& it : elements) {
176  size_t i = it.first;
177  const std::vector<size_t>& row = it.second;
178 
179  jac[i].resize(row.size());
180  std::map<size_t, size_t>& pos = positions[i];
181 
182  for (size_t e = 0; e < row.size(); e++) {
183  size_t j = row[e];
184  pos[j] = e;
185  }
186  }
187 
188  for (size_t el = 0; el < _jacSparsity.rows.size(); el++) {
189  size_t i = _jacSparsity.rows[el];
190  size_t j = _jacSparsity.cols[el];
191  size_t e = positions[i].at(j);
192 
193  vector<CGBase>& row = jac[i];
194  row[e] = jacFlat[el] * py;
195  }
196 
200  typename std::map<size_t, vector<CGBase> >::iterator itI;
201  for (itI = jac.begin(); itI != jac.end(); ++itI) {
202  size_t i = itI->first;
203  vector<CGBase>& dwCustom = itI->second;
204 
205  _cache.str("");
206  _cache << "model (reverse one, dep " << i << ")";
207  const std::string subJobName = _cache.str();
208 
209  LanguageC<Base> langC(_baseTypeName);
210  langC.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
211  langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
212  langC.setParameterPrecision(_parameterPrecision);
213  _cache.str("");
214  _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "_dep" << i;
215  langC.setGenerateFunction(_cache.str());
216 
217  std::ostringstream code;
218  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("dw"));
219  LangCDefaultHessianVarNameGenerator<Base> nameGenHess(nameGen.get(), "py", n);
220 
221  handler.generateCode(code, langC, dwCustom, nameGenHess, _atomicFunctions, subJobName);
222  }
223 }
224 
225 template<class Base>
227  size_t m = _fun.Range();
228  size_t n = _fun.Domain();
229 
230  _cache.str("");
231  _cache << _name << "_" << FUNCTION_REVERSE_ONE;
232  std::string model_function(_cache.str());
233  _cache.str("");
234 
235  LanguageC<Base> langC(_baseTypeName);
236  std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
237  std::string args = langC.generateDefaultFunctionArguments();
238 
239  _cache << "#include <stdlib.h>\n"
241  "\n"
242  "int " << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "(unsigned long pos, " << argsDcl << ");\n"
243  "void " << _name << "_" << FUNCTION_REVERSE_ONE_SPARSITY << "(unsigned long pos, unsigned long const** elements, unsigned long* nnz);\n"
244  "\n";
245  LanguageC<Base>::printFunctionDeclaration(_cache, "int", model_function, {_baseTypeName + " const x[]",
246  _baseTypeName + " const ty[]",
247  _baseTypeName + " px[]",
248  _baseTypeName + " const py[]",
249  langC.generateArgumentAtomicDcl()});
250  _cache << " {\n"
251  " unsigned long ei, ePos, i, j, nnz, nnzMax;\n"
252  " unsigned long const* pos;\n"
253  " unsigned long* pyPos;\n"
254  " unsigned long* pyPosTmp;\n"
255  " unsigned long nnzPy;\n"
256  " " << _baseTypeName << " const * in[2];\n"
257  " " << _baseTypeName << "* out[1];\n"
258  " " << _baseTypeName << "* compressed;\n"
259  " int ret;\n"
260  "\n"
261  " pyPos = 0;\n"
262  " nnzPy = 0;\n"
263  " nnzMax = 0;\n"
264  " for (i = 0; i < " << m << "; i++) {\n"
265  " if (py[i] != 0.0) {\n"
266  " " << _name << "_" << FUNCTION_REVERSE_ONE_SPARSITY << "(i, &pos, &nnz);\n"
267  " if (nnz > nnzMax)\n"
268  " nnzMax = nnz;\n"
269  " else if (nnz == 0)\n"
270  " continue;\n"
271  " nnzPy++;\n"
272  " pyPosTmp = (unsigned long*) realloc(pyPos, nnzPy * sizeof(unsigned long));\n"
273  " if (pyPosTmp != NULL) {\n"
274  " pyPos = pyPosTmp;\n"
275  " } else {\n"
276  " free(pyPos);\n"
277  " return -1; // failure to allocate memory\n"
278  " }\n"
279  " pyPos[nnzPy - 1] = i;\n"
280  " }\n"
281  " }\n"
282  " for (j = 0; j < " << n << "; j++) {\n"
283  " px[j] = 0;\n"
284  " }\n"
285  "\n"
286  " if (nnzPy == 0) {\n"
287  " free(pyPos);\n"
288  " return 0; //nothing to do\n"
289  " }\n"
290  "\n"
291  " compressed = (" << _baseTypeName << "*) malloc(nnzMax * sizeof(" << _baseTypeName << "));\n"
292  "\n"
293  " for (ei = 0; ei < nnzPy; ei++) {\n"
294  " i = pyPos[ei];\n"
295  " " << _name << "_" << FUNCTION_REVERSE_ONE_SPARSITY << "(i, &pos, &nnz);\n"
296  "\n"
297  " in[0] = x;\n"
298  " in[1] = &py[i];\n"
299  " out[0] = compressed;\n";
300  if (!_loopTapes.empty()) {
301  _cache << " for(ePos = 0; ePos < nnz; ePos++)\n"
302  " compressed[ePos] = 0;\n"
303  "\n";
304  }
305  _cache << " ret = " << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "(i, " << args << ");\n"
306  "\n"
307  " if (ret != 0) {\n"
308  " free(compressed);\n"
309  " free(pyPos);\n"
310  " return ret;\n"
311  " }\n"
312  "\n"
313  " for (ePos = 0; ePos < nnz; ePos++) {\n"
314  " px[pos[ePos]] += compressed[ePos];\n"
315  " }\n"
316  "\n"
317  " }\n"
318  " free(compressed);\n"
319  " free(pyPos);\n"
320  " return 0;\n"
321  "}\n";
322  _sources[model_function + ".c"] = _cache.str();
323  _cache.str("");
324 }
325 
326 } // END cg namespace
327 } // END CppAD namespace
328 
329 #endif
void setValue(const Base &val)
Definition: variable.hpp:54
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
Definition: language_c.hpp:273
static void printFunctionDeclaration(std::ostringstream &out, const std::string &returnType, const std::string &functionName, const std::vector< std::string > &arguments, const std::vector< std::string > &arguments2={})
Definition: language_c.hpp:538
void makeVariables(VectorCG &variables)
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
Definition: language_c.hpp:252
void makeVariable(AD< CGB > &variable)
virtual void setParameterPrecision(size_t p)
Definition: language_c.hpp:237
virtual void generateSparseReverseOneSourcesWithAtomics(const std::map< size_t, std::vector< size_t > > &elements)
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
virtual void generateSparseReverseOneSourcesNoAtomics(const std::map< size_t, std::vector< size_t > > &elements)