CppADCodeGen  2.3.0
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.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
123  langC.setParameterPrecision(_parameterPrecision);
124  _cache.str("");
125  _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "_dep" << i;
126  langC.setGenerateFunction(_cache.str());
127 
128  std::ostringstream code;
129  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("dw"));
130  LangCDefaultHessianVarNameGenerator<Base> nameGenHess(nameGen.get(), "py", n);
131 
132  handler.generateCode(code, langC, dwCustom, nameGenHess, _atomicFunctions, subJobName);
133  }
134 }
135 
136 template<class Base>
137 void ModelCSourceGen<Base>::generateSparseReverseOneSourcesNoAtomics(const std::map<size_t, std::vector<size_t> >& elements) {
138  using std::vector;
139 
143  size_t m = _fun.Range();
144  size_t n = _fun.Domain();
145 
146  CodeHandler<Base> handler;
147  handler.setJobTimer(_jobTimer);
148 
149  vector<CGBase> x(n);
150  handler.makeVariables(x);
151  if (_x.size() > 0) {
152  for (size_t i = 0; i < n; i++) {
153  x[i].setValue(_x[i]);
154  }
155  }
156 
157  CGBase py;
158  handler.makeVariable(py);
159  if (_x.size() > 0) {
160  py.setValue(Base(1.0));
161  }
162 
163  vector<CGBase> jacFlat(_jacSparsity.rows.size());
164 
165  CppAD::sparse_jacobian_work work; // temporary structure for CPPAD
166  _fun.SparseJacobianReverse(x, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jacFlat, work);
167 
171  std::map<size_t, vector<CGBase> > jac; // by row
172  std::vector<std::map<size_t, size_t> > positions(m); // by row
173 
174  for (const auto& it : elements) {
175  size_t i = it.first;
176  const std::vector<size_t>& row = it.second;
177 
178  jac[i].resize(row.size());
179  std::map<size_t, size_t>& pos = positions[i];
180 
181  for (size_t e = 0; e < row.size(); e++) {
182  size_t j = row[e];
183  pos[j] = e;
184  }
185  }
186 
187  for (size_t el = 0; el < _jacSparsity.rows.size(); el++) {
188  size_t i = _jacSparsity.rows[el];
189  size_t j = _jacSparsity.cols[el];
190  size_t e = positions[i].at(j);
191 
192  vector<CGBase>& row = jac[i];
193  row[e] = jacFlat[el] * py;
194  }
195 
199  typename std::map<size_t, vector<CGBase> >::iterator itI;
200  for (itI = jac.begin(); itI != jac.end(); ++itI) {
201  size_t i = itI->first;
202  vector<CGBase>& dwCustom = itI->second;
203 
204  _cache.str("");
205  _cache << "model (reverse one, dep " << i << ")";
206  const std::string subJobName = _cache.str();
207 
208  LanguageC<Base> langC(_baseTypeName);
209  langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
210  langC.setParameterPrecision(_parameterPrecision);
211  _cache.str("");
212  _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "_dep" << i;
213  langC.setGenerateFunction(_cache.str());
214 
215  std::ostringstream code;
216  std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("dw"));
217  LangCDefaultHessianVarNameGenerator<Base> nameGenHess(nameGen.get(), "py", n);
218 
219  handler.generateCode(code, langC, dwCustom, nameGenHess, _atomicFunctions, subJobName);
220  }
221 }
222 
223 template<class Base>
225  size_t m = _fun.Range();
226  size_t n = _fun.Domain();
227 
228  _cache.str("");
229  _cache << _name << "_" << FUNCTION_REVERSE_ONE;
230  std::string model_function(_cache.str());
231  _cache.str("");
232 
233  LanguageC<Base> langC(_baseTypeName);
234  std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
235  std::string args = langC.generateDefaultFunctionArguments();
236 
237  _cache << "#include <stdlib.h>\n"
239  "\n"
240  "int " << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "(unsigned long pos, " << argsDcl << ");\n"
241  "void " << _name << "_" << FUNCTION_REVERSE_ONE_SPARSITY << "(unsigned long pos, unsigned long const** elements, unsigned long* nnz);\n"
242  "\n";
243  LanguageC<Base>::printFunctionDeclaration(_cache, "int", model_function, {_baseTypeName + " const x[]",
244  _baseTypeName + " const ty[]",
245  _baseTypeName + " px[]",
246  _baseTypeName + " const py[]",
247  langC.generateArgumentAtomicDcl()});
248  _cache << " {\n"
249  " unsigned long ei, ePos, i, j, nnz, nnzMax;\n"
250  " unsigned long const* pos;\n"
251  " unsigned long* pyPos;\n"
252  " unsigned long* pyPosTmp;\n"
253  " unsigned long nnzPy;\n"
254  " " << _baseTypeName << " const * in[2];\n"
255  " " << _baseTypeName << "* out[1];\n"
256  " " << _baseTypeName << "* compressed;\n"
257  " int ret;\n"
258  "\n"
259  " pyPos = 0;\n"
260  " nnzPy = 0;\n"
261  " nnzMax = 0;\n"
262  " for (i = 0; i < " << m << "; i++) {\n"
263  " if (py[i] != 0.0) {\n"
264  " " << _name << "_" << FUNCTION_REVERSE_ONE_SPARSITY << "(i, &pos, &nnz);\n"
265  " if (nnz > nnzMax)\n"
266  " nnzMax = nnz;\n"
267  " else if (nnz == 0)\n"
268  " continue;\n"
269  " nnzPy++;\n"
270  " pyPosTmp = (unsigned long*) realloc(pyPos, nnzPy * sizeof(unsigned long));\n"
271  " if (pyPosTmp != NULL) {\n"
272  " pyPos = pyPosTmp;\n"
273  " } else {\n"
274  " free(pyPos);\n"
275  " return -1; // failure to allocate memory\n"
276  " }\n"
277  " pyPos[nnzPy - 1] = i;\n"
278  " }\n"
279  " }\n"
280  " for (j = 0; j < " << n << "; j++) {\n"
281  " px[j] = 0;\n"
282  " }\n"
283  "\n"
284  " if (nnzPy == 0) {\n"
285  " free(pyPos);\n"
286  " return 0; //nothing to do\n"
287  " }\n"
288  "\n"
289  " compressed = (" << _baseTypeName << "*) malloc(nnzMax * sizeof(" << _baseTypeName << "));\n"
290  "\n"
291  " for (ei = 0; ei < nnzPy; ei++) {\n"
292  " i = pyPos[ei];\n"
293  " " << _name << "_" << FUNCTION_REVERSE_ONE_SPARSITY << "(i, &pos, &nnz);\n"
294  "\n"
295  " in[0] = x;\n"
296  " in[1] = &py[i];\n"
297  " out[0] = compressed;\n";
298  if (!_loopTapes.empty()) {
299  _cache << " for(ePos = 0; ePos < nnz; ePos++)\n"
300  " compressed[ePos] = 0;\n"
301  "\n";
302  }
303  _cache << " ret = " << _name << "_" << FUNCTION_SPARSE_REVERSE_ONE << "(i, " << args << ");\n"
304  "\n"
305  " if (ret != 0) {\n"
306  " free(compressed);\n"
307  " free(pyPos);\n"
308  " return ret;\n"
309  " }\n"
310  "\n"
311  " for (ePos = 0; ePos < nnz; ePos++) {\n"
312  " px[pos[ePos]] += compressed[ePos];\n"
313  " }\n"
314  "\n"
315  " }\n"
316  " free(compressed);\n"
317  " free(pyPos);\n"
318  " return 0;\n"
319  "}\n";
320  _sources[model_function + ".c"] = _cache.str();
321  _cache.str("");
322 }
323 
324 } // END cg namespace
325 } // END CppAD namespace
326 
327 #endif
void setValue(const Base &val)
Definition: variable.hpp:54
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:489
void makeVariables(VectorCG &variables)
void makeVariable(AD< CGB > &variable)
virtual void setParameterPrecision(size_t p)
Definition: language_c.hpp:219
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)