CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
18namespace CppAD {
19namespace cg {
20
21template<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
61template<class Base>
62void 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
137template<class Base>
138void 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
225template<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 makeVariables(VectorCG &variables)
void makeVariable(AD< CGB > &variable)
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
virtual void setParameterPrecision(size_t p)
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={})
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
virtual void generateSparseReverseOneSourcesWithAtomics(const std::map< size_t, std::vector< size_t > > &elements)
virtual void generateSparseReverseOneSourcesNoAtomics(const std::map< size_t, std::vector< size_t > > &elements)