CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
model_c_source_gen_rev2.hpp
1#ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_REV2_INCLUDED
2#define CPPAD_CG_MODEL_C_SOURCE_GEN_REV2_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 determineHessianSparsity();
25
30 std::vector<size_t> evalRows, evalCols;
31 determineSecondOrderElements4Eval(evalRows, evalCols);
32
33 // elements[var]{vars}
34 std::map<size_t, std::vector<size_t> > elements;
35 for (size_t e = 0; e < evalCols.size(); e++) {
36 elements[evalRows[e]].push_back(evalCols[e]);
37 }
38
39 if (!_loopTapes.empty()) {
43 prepareSparseReverseTwoWithLoops(elements);
44 return;
45 }
46
47 if (!evalRows.empty()) {
48
49 startingJob("'model (reverse two)'", JobTimer::SOURCE_GENERATION);
50
51 if (isAtomicsUsed()) {
52 generateSparseReverseTwoSourcesWithAtomics(elements);
53 } else {
54 generateSparseReverseTwoSourcesNoAtomics(elements, evalRows, evalCols);
55 }
56
57 finishedJob();
58
59 _cache.str("");
60 }
61
62 generateGlobalDirectionalFunctionSource(FUNCTION_SPARSE_REVERSE_TWO,
63 "indep",
64 FUNCTION_REVERSE_TWO_SPARSITY,
65 elements);
66}
67
68template<class Base>
69void ModelCSourceGen<Base>::generateSparseReverseTwoSourcesWithAtomics(const std::map<size_t, std::vector<size_t> >& elements) {
70 using std::vector;
71
72 const size_t m = _fun.Range();
73 const size_t n = _fun.Domain();
74 //const size_t k = 1;
75 const size_t p = 2;
76
77 vector<CGBase> tx1v(n);
78
79 for (const auto& it : elements) {
80 size_t j = it.first;
81 const std::vector<size_t>& cols = it.second;
82
83 _cache.str("");
84 _cache << "model (reverse two, indep " << j << ")";
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> tx0(n);
93 handler.makeVariables(tx0);
94 if (_x.size() > 0) {
95 for (size_t i = 0; i < n; i++) {
96 tx0[i].setValue(_x[i]);
97 }
98 }
99
100 CGBase tx1;
101 handler.makeVariable(tx1);
102 if (_x.size() > 0) {
103 tx1.setValue(Base(1.0));
104 }
105
106 vector<CGBase> py(m); // (k+1)*m is not used because we are not interested in all values
107 handler.makeVariables(py);
108 if (_x.size() > 0) {
109 for (size_t i = 0; i < m; i++) {
110 py[i].setValue(Base(1.0));
111 }
112 }
113
114 _fun.Forward(0, tx0);
115
116 tx1v[j] = tx1;
117 _fun.Forward(1, tx1v);
118 tx1v[j] = Base(0);
119 vector<CGBase> px = _fun.Reverse(2, py);
120 CPPADCG_ASSERT_UNKNOWN(px.size() == 2 * n);
121
122 vector<CGBase> pxCustom;
123 for (size_t jj : cols) {
124 pxCustom.push_back(px[jj * p + 1]); // not interested in all values
125 }
126
127 finishedJob();
128
129 LanguageC<Base> langC(_baseTypeName);
130 langC.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
131 langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
132 langC.setParameterPrecision(_parameterPrecision);
133 _cache.str("");
134 _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_TWO << "_indep" << j;
135 langC.setGenerateFunction(_cache.str());
136
137 std::ostringstream code;
138 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("px"));
139 LangCDefaultReverse2VarNameGenerator<Base> nameGenRev2(nameGen.get(), n, 1);
140
141 handler.generateCode(code, langC, pxCustom, nameGenRev2, _atomicFunctions, subJobName);
142 }
143}
144
145template<class Base>
146void ModelCSourceGen<Base>::generateSparseReverseTwoSourcesNoAtomics(const std::map<size_t, std::vector<size_t> >& elements,
147 const std::vector<size_t>& evalRows,
148 const std::vector<size_t>& evalCols) {
149 using std::vector;
150
151 const size_t m = _fun.Range();
152 const size_t n = _fun.Domain();
153
154 // save compressed positions
155 std::map<size_t, std::map<size_t, size_t> > positions;
156 for (const auto& itJ1 : elements) {
157 size_t j1 = itJ1.first;
158 const std::vector<size_t>& row = itJ1.second;
159 std::map<size_t, size_t>& pos = positions[j1];
160
161 for (size_t e = 0; e < row.size(); e++) {
162 size_t j2 = row[e];
163 pos[j2] = e;
164 }
165 }
166
167 // we can use a new handler to reduce memory usage
168 CodeHandler<Base> handler;
169 handler.setJobTimer(_jobTimer);
170
171 vector<CGBase> tx0(n);
172 handler.makeVariables(tx0);
173 if (_x.size() > 0) {
174 for (size_t i = 0; i < n; i++) {
175 tx0[i].setValue(_x[i]);
176 }
177 }
178
179 CGBase tx1;
180 handler.makeVariable(tx1);
181 if (_x.size() > 0) {
182 tx1.setValue(Base(1.0));
183 }
184
185 vector<CGBase> py(m); // (k+1)*m is not used because we are not interested in all values
186 handler.makeVariables(py);
187 if (_x.size() > 0) {
188 for (size_t i = 0; i < m; i++) {
189 py[i].setValue(Base(1.0));
190 }
191 }
192
193 vector<CGBase> hessFlat(evalRows.size());
194
195 CppAD::sparse_hessian_work work; // temporary structure for CPPAD
196 // "cppad.symmetric" may have missing values for functions using atomic
197 // functions which only provide half of the elements, but there is none here
198 work.color_method = "cppad.symmetric";
199 _fun.SparseHessian(tx0, py, _hessSparsity.sparsity, evalRows, evalCols, hessFlat, work);
200
201 std::map<size_t, vector<CGBase> > hess;
202 for (const auto& itJ1 : elements) {
203 size_t j1 = itJ1.first;
204 hess[j1].resize(itJ1.second.size());
205 }
206
207 // organize hessian elements
208 for (size_t el = 0; el < evalRows.size(); el++) {
209 size_t j1 = evalRows[el];
210 size_t j2 = evalCols[el];
211 size_t e = positions[j1][j2];
212
213 hess[j1][e] = hessFlat[el];
214 }
215
219 for (const auto& it : hess) {
220 size_t j = it.first;
221 const vector<CGBase>& row = it.second;
222
223 _cache.str("");
224 _cache << "model (reverse two, indep " << j << ")";
225 const std::string subJobName = _cache.str();
226
227 vector<CGBase> pxCustom(row.size());
228 for (size_t e = 0; e < row.size(); e++) {
229 pxCustom[e] = row[e] * tx1;
230 }
231
232 LanguageC<Base> langC(_baseTypeName);
233 langC.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
234 langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
235 langC.setParameterPrecision(_parameterPrecision);
236 _cache.str("");
237 _cache << _name << "_" << FUNCTION_SPARSE_REVERSE_TWO << "_indep" << j;
238 langC.setGenerateFunction(_cache.str());
239
240 std::ostringstream code;
241 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator("px"));
242 LangCDefaultReverse2VarNameGenerator<Base> nameGenRev2(nameGen.get(), n, 1);
243
244 handler.generateCode(code, langC, pxCustom, nameGenRev2, _atomicFunctions, subJobName);
245 }
246}
247
248template<class Base>
250 size_t m = _fun.Range();
251 size_t n = _fun.Domain();
252
253 _cache.str("");
254 _cache << _name << "_" << FUNCTION_REVERSE_TWO;
255 std::string model_function(_cache.str());
256 _cache.str("");
257
258 LanguageC<Base> langC(_baseTypeName);
259 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
260 std::string args = langC.generateDefaultFunctionArguments();
261
262 _cache << "#include <stdlib.h>\n"
264 "\n"
265 "int " << _name << "_" << FUNCTION_SPARSE_REVERSE_TWO << "(unsigned long pos, " << argsDcl << ");\n"
266 "void " << _name << "_" << FUNCTION_REVERSE_TWO_SPARSITY << "(unsigned long pos, unsigned long const** elements, unsigned long* nnz);\n"
267 "\n";
268 LanguageC<Base>::printFunctionDeclaration(_cache, "int", model_function, {_baseTypeName + " const tx[]",
269 _baseTypeName + " const ty[]",
270 _baseTypeName + " px[]",
271 _baseTypeName + " const py[]",
272 langC.generateArgumentAtomicDcl()});
273 _cache << " {\n"
274 " unsigned long ej, ePos, i, j, nnz, nnzMax;\n"
275 " unsigned long const* pos;\n"
276 " unsigned long* txPos;\n"
277 " unsigned long* txPosTmp;\n"
278 " unsigned long nnzTx;\n"
279 " " << _baseTypeName << " const * in[3];\n"
280 " " << _baseTypeName << "* out[1];\n"
281 " " << _baseTypeName << " x[" << n << "];\n"
282 " " << _baseTypeName << " w[" << m << "];\n"
283 " " << _baseTypeName << "* compressed;\n"
284 " int nonZeroW;\n"
285 " int ret;\n"
286 "\n"
287 " nonZeroW = 0;\n"
288 " for (i = 0; i < " << m << "; i++) {\n"
289 " if (py[i * 2] != 0.0) {\n"
290 " return 1; // error\n"
291 " }\n"
292 " w[i] = py[i * 2 + 1];\n"
293 " if(w[i] != 0.0) nonZeroW++;\n"
294 " }\n"
295 "\n"
296 " for (j = 0; j < " << n << "; j++) {\n"
297 " px[j * 2] = 0;\n"
298 " }\n"
299 "\n"
300 " if (nonZeroW == 0)\n"
301 " return 0; //nothing to do\n"
302 "\n"
303 " txPos = 0;\n"
304 " nnzTx = 0;\n"
305 " nnzMax = 0;\n"
306 " for (j = 0; j < " << n << "; j++) {\n"
307 " if (tx[j * 2 + 1] != 0.0) {\n"
308 " " << _name << "_" << FUNCTION_REVERSE_TWO_SPARSITY << "(j, &pos, &nnz);\n"
309 " if (nnz > nnzMax)\n"
310 " nnzMax = nnz;\n"
311 " else if (nnz == 0)\n"
312 " continue;\n"
313 " nnzTx++;\n"
314 " txPosTmp = (unsigned long*) realloc(txPos, nnzTx * sizeof(unsigned long));\n"
315 " if (txPosTmp != NULL) {\n"
316 " txPos = txPosTmp;\n"
317 " } else {\n"
318 " free(txPos);\n"
319 " return -1; // failure to allocate memory\n"
320 " }\n"
321 " txPos[nnzTx - 1] = j;\n"
322 " }\n"
323 " }\n"
324 "\n"
325 " if (nnzTx == 0) {\n"
326 " free(txPos);\n"
327 " return 0; // nothing to do\n"
328 " }\n"
329 "\n"
330 " for (j = 0; j < " << n << "; j++)\n"
331 " x[j] = tx[j * 2];\n"
332 "\n"
333 " compressed = (" << _baseTypeName << "*) malloc(nnzMax * sizeof(" << _baseTypeName << "));\n"
334 "\n"
335 " for (ej = 0; ej < nnzTx; ej++) {\n"
336 " j = txPos[ej];\n"
337 " " << _name << "_" << FUNCTION_REVERSE_TWO_SPARSITY << "(j, &pos, &nnz);\n"
338 "\n"
339 " in[0] = x;\n"
340 " in[1] = &tx[j * 2 + 1];\n"
341 " in[2] = w;\n"
342 " out[0] = compressed;\n";
343 if (!_loopTapes.empty()) {
344 _cache << " for (ePos = 0; ePos < nnz; ePos++)\n"
345 " compressed[ePos] = 0;\n"
346 "\n";
347 }
348 _cache << " ret = " << _name << "_" << FUNCTION_SPARSE_REVERSE_TWO << "(j, " << args << ");\n"
349 "\n"
350 " if (ret != 0) {\n"
351 " free(compressed);\n"
352 " free(txPos);\n"
353 " return ret;\n"
354 " }\n"
355 "\n"
356 " for (ePos = 0; ePos < nnz; ePos++) {\n"
357 " px[pos[ePos] * 2] += compressed[ePos];\n"
358 " }\n"
359 "\n"
360 " }\n"
361 " free(compressed);\n"
362 " free(txPos);\n"
363 " return 0;\n"
364 "};\n";
365
366 _sources[model_function + ".c"] = _cache.str();
367 _cache.str("");
368}
369
370} // END cg namespace
371} // END CppAD namespace
372
373#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 generateSparseReverseTwoSourcesNoAtomics(const std::map< size_t, std::vector< size_t > > &elements, const std::vector< size_t > &evalRows, const std::vector< size_t > &evalCols)