1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_JAC_INCLUDED 2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_JAC_INCLUDED 22 void ModelCSourceGen<Base>::generateJacobianSource() {
25 const std::string jobName =
"Jacobian";
27 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
29 CodeHandler<Base> handler;
30 handler.setJobTimer(_jobTimer);
32 vector<CGBase> indVars(_fun.Domain());
33 handler.makeVariables(indVars);
35 for (
size_t i = 0; i < indVars.size(); i++) {
36 indVars[i].setValue(_x[i]);
40 size_t m = _fun.Range();
41 size_t n = _fun.Domain();
43 vector<CGBase> jac(n * m);
44 if (_jacMode == JacobianADMode::Automatic) {
45 jac = _fun.Jacobian(indVars);
46 }
else if (_jacMode == JacobianADMode::Forward) {
47 JacobianFor(_fun, indVars, jac);
49 JacobianRev(_fun, indVars, jac);
54 LanguageC<Base> langC(_baseTypeName);
55 langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
56 langC.setParameterPrecision(_parameterPrecision);
57 langC.setGenerateFunction(_name +
"_" + FUNCTION_JACOBIAN);
59 std::ostringstream code;
60 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"jac"));
62 handler.generateCode(code, langC, jac, *nameGen, _atomicFunctions, jobName);
67 size_t m = _fun.Range();
68 size_t n = _fun.Domain();
73 determineJacobianSparsity();
77 if (_jacMode == JacobianADMode::Automatic) {
78 if (_custom_jac.defined) {
79 forwardMode = estimateBestJacobianADMode(_jacSparsity.rows, _jacSparsity.cols);
84 forwardMode = _jacMode == JacobianADMode::Forward;
90 if (_sparseJacobianReusesOne && _forwardOne && forwardMode) {
91 generateSparseJacobianForRevSource(
true, multiThreadingType);
92 }
else if (_sparseJacobianReusesOne && _reverseOne && !forwardMode) {
93 generateSparseJacobianForRevSource(
false, multiThreadingType);
95 generateSparseJacobianSource(forwardMode);
103 const std::string jobName =
"sparse Jacobian";
106 size_t n = _fun.Domain();
108 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
111 handler.setJobTimer(_jobTimer);
116 for (
size_t i = 0; i < n; i++) {
117 indVars[i].setValue(_x[i]);
122 if (_loopTapes.empty()) {
124 CppAD::sparse_jacobian_work work;
126 _fun.SparseJacobianForward(indVars, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jac, work);
128 _fun.SparseJacobianReverse(indVars, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jac, work);
132 jac = prepareSparseJacobianWithLoops(handler, indVars, forward);
138 langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
140 langC.setGenerateFunction(_name +
"_" + FUNCTION_SPARSE_JACOBIAN);
142 std::ostringstream code;
143 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"jac"));
145 handler.
generateCode(code, langC, jac, *nameGen, _atomicFunctions, jobName);
150 MultiThreadingType multiThreadingType) {
155 std::map<size_t, CompressedVectorInfo> jacInfo;
156 string functionRevFor, revForSuffix;
159 for (
size_t e = 0; e < _jacSparsity.rows.size(); e++) {
160 jacInfo[_jacSparsity.cols[e]].indexes.push_back(_jacSparsity.rows[e]);
162 for (
auto& it : jacInfo) {
163 size_t col = it.first;
164 it.second.locations = determineOrderByCol(col, it.second.indexes, _jacSparsity.rows, _jacSparsity.cols);
167 _cache << _name <<
"_" << FUNCTION_SPARSE_FORWARD_ONE;
168 functionRevFor = _cache.str();
169 revForSuffix =
"indep";
172 for (
size_t e = 0; e < _jacSparsity.rows.size(); e++) {
173 jacInfo[_jacSparsity.rows[e]].indexes.push_back(_jacSparsity.cols[e]);
175 for (
auto& it : jacInfo) {
176 size_t row = it.first;
177 it.second.locations = determineOrderByRow(row, it.second.indexes, _jacSparsity.rows, _jacSparsity.cols);
180 _cache << _name <<
"_" << FUNCTION_SPARSE_REVERSE_ONE;
181 functionRevFor = _cache.str();
182 revForSuffix =
"dep";
190 for (
auto& it : jacInfo) {
191 const std::vector<size_t>& els = it.second.indexes;
192 const std::vector<set<size_t> >& location = it.second.locations;
193 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
194 CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
197 size_t jacArrayStart = *location[0].begin();
198 for (
size_t e = 0; e < els.size(); e++) {
199 if (location[e].size() > 1) {
203 if (*location[e].begin() != jacArrayStart + e) {
208 it.second.ordered = passed;
211 size_t maxCompressedSize = 0;
212 map<size_t, bool>::const_iterator itOrd;
213 map<size_t, std::vector<size_t> >::const_iterator it;
214 for (
const auto& it : jacInfo) {
215 if (it.second.indexes.size() > maxCompressedSize && !it.second.ordered)
216 maxCompressedSize = it.second.indexes.size();
219 if (!_loopTapes.empty()) {
224 generateSparseJacobianWithLoopsSourceFromForRev(jacInfo, maxCompressedSize,
225 FUNCTION_SPARSE_FORWARD_ONE,
"indep",
"jcol",
226 _nonLoopFor1Elements, _loopFor1Groups,
227 generateFunctionNameLoopFor1);
229 generateSparseJacobianWithLoopsSourceFromForRev(jacInfo, maxCompressedSize,
230 FUNCTION_SPARSE_REVERSE_ONE,
"dep",
"jrow",
231 _nonLoopRev1Elements, _loopRev1Groups,
232 generateFunctionNameLoopRev1);
238 _cache << _name <<
"_" << FUNCTION_SPARSE_JACOBIAN;
239 string functionName(_cache.str());
241 if(!_multiThreading || multiThreadingType == MultiThreadingType::NONE) {
242 _sources[functionName +
".c"] = generateSparseJacobianForRevSingleThreadSource(functionName, jacInfo, maxCompressedSize, functionRevFor, revForSuffix, forward);
244 _sources[functionName +
".c"] = generateSparseJacobianForRevMultiThreadSource(functionName, jacInfo, maxCompressedSize, functionRevFor, revForSuffix, forward, multiThreadingType);
252 std::map<size_t, CompressedVectorInfo> jacInfo,
253 size_t maxCompressedSize,
254 const std::string& functionRevFor,
255 const std::string& revForSuffix,
259 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
260 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
263 _cache <<
"#include <stdlib.h>\n" 266 generateFunctionDeclarationSource(_cache, functionRevFor, revForSuffix, jacInfo, argsDcl);
270 " " << _baseTypeName <<
" const * inLocal[2];\n" 271 " " << _baseTypeName <<
" inLocal1 = 1;\n" 272 " " << _baseTypeName <<
" * outLocal[1];\n" 273 " " << _baseTypeName <<
" compressed[" << maxCompressedSize <<
"];\n" 274 " " << _baseTypeName <<
" * jac = out[0];\n" 276 " inLocal[0] = in[0];\n" 277 " inLocal[1] = &inLocal1;\n" 278 " outLocal[0] = compressed;\n";
280 langC.setArgumentIn(
"inLocal");
281 langC.setArgumentOut(
"outLocal");
282 std::string argsLocal = langC.generateDefaultFunctionArguments();
284 bool previousCompressed =
true;
285 for (
const auto& it : jacInfo) {
286 size_t index = it.first;
287 const std::vector<size_t>& els = it.second.indexes;
288 const std::vector<std::set<size_t> >& location = it.second.locations;
289 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
292 bool compressed = !it.second.ordered;
294 _cache <<
" outLocal[0] = &jac[" << *location[0].begin() <<
"];\n";
295 }
else if (!previousCompressed) {
296 _cache <<
" outLocal[0] = compressed;\n";
298 _cache <<
" " << functionRevFor <<
"_" << revForSuffix << index <<
"(" << argsLocal <<
");\n";
300 for (
size_t e = 0; e < els.size(); e++) {
302 for (
size_t itl : location[e]) {
303 _cache <<
"jac[" << (itl) <<
"] = ";
305 _cache <<
"compressed[" << e <<
"];\n";
308 previousCompressed = compressed;
319 std::map<size_t, CompressedVectorInfo> jacInfo,
320 size_t maxCompressedSize,
321 const std::string& functionRevFor,
322 const std::string& revForSuffix,
324 MultiThreadingType multiThreadingType) {
326 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
327 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
330 _cache <<
"#include <stdlib.h>\n" 333 generateFunctionDeclarationSource(_cache, functionRevFor, revForSuffix, jacInfo, argsDcl);
335 langC.setArgumentIn(
"inLocal");
336 langC.setArgumentOut(
"outLocal");
337 std::string argsLocal = langC.generateDefaultFunctionArguments();
342 for (
const auto& it : jacInfo) {
343 size_t index = it.first;
344 const std::vector<size_t>& els = it.second.indexes;
345 const std::vector<std::set<size_t> >& location = it.second.locations;
346 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
348 bool compressed = !it.second.ordered;
353 std::string functionNameWrap = functionRevFor +
"_" + revForSuffix + std::to_string(index) +
"_wrap";
356 " " << _baseTypeName <<
" const * inLocal[2];\n" 357 " " << _baseTypeName <<
" inLocal1 = 1;\n" 358 " " << _baseTypeName <<
" * outLocal[1];\n" 359 " " << _baseTypeName <<
" compressed[" << it.second.indexes.size() <<
"];\n" 360 " " << _baseTypeName <<
" * jac = out[0];\n" 362 " inLocal[0] = in[0];\n" 363 " inLocal[1] = &inLocal1;\n" 364 " outLocal[0] = compressed;\n";
366 _cache <<
" " << functionRevFor <<
"_" << revForSuffix << index <<
"(" << argsLocal <<
");\n";
367 for (
size_t e = 0; e < els.size(); e++) {
369 for (
size_t itl : location[e]) {
370 _cache <<
"jac[" << (itl) <<
"] = ";
372 _cache <<
"compressed[" << e <<
"];\n";
378 "typedef void (*cppadcg_function_type) (" << argsDcl <<
");\n";
383 if(multiThreadingType == MultiThreadingType::OPENMP) {
385 printFileStartOpenMP(_cache);
389 assert(multiThreadingType == MultiThreadingType::PTHREADS);
391 printFileStartPThreads(_cache, _baseTypeName);
398 "void " << functionName <<
"(" << argsDcl <<
") {\n" 399 " static const cppadcg_function_type p[" << jacInfo.size() <<
"] = {";
400 for (
const auto& it : jacInfo) {
401 size_t index = it.first;
402 if (index != jacInfo.begin()->first) _cache <<
", ";
403 if (it.second.ordered) {
404 _cache << functionRevFor <<
"_" << revForSuffix << index;
406 _cache << functionRevFor <<
"_" << revForSuffix << index <<
"_wrap";
410 " static const long offset["<< jacInfo.size() <<
"] = {";
411 for (
const auto& it : jacInfo) {
412 if (it.first != jacInfo.begin()->first) _cache <<
", ";
413 if (it.second.ordered) {
414 _cache << *it.second.locations[0].begin();
420 " " << _baseTypeName <<
" inLocal1 = 1;\n" 421 " " << _baseTypeName <<
" const * inLocal[2] = {in[0], &inLocal1};\n" 422 " " << _baseTypeName <<
" * outLocal[1];\n" 423 " " << _baseTypeName <<
" * jac = out[0];\n" 427 if(multiThreadingType == MultiThreadingType::OPENMP) {
428 printFunctionStartOpenMP(_cache, jacInfo.size());
430 printLoopStartOpenMP(_cache, jacInfo.size());
431 _cache <<
" outLocal[0] = &jac[offset[i]];\n" 432 " (*p[i])(" << argsLocal <<
");\n";
433 printLoopEndOpenMP(_cache, jacInfo.size());
437 assert(multiThreadingType == MultiThreadingType::PTHREADS);
439 printFunctionStartPThreads(_cache, jacInfo.size());
441 " for(i = 0; i < " << jacInfo.size() <<
"; ++i) {\n" 442 " args[i] = (ExecArgStruct*) malloc(sizeof(ExecArgStruct));\n" 443 " args[i]->func = p[i];\n" 444 " args[i]->in = inLocal;\n" 445 " args[i]->out[0] = &jac[offset[i]];\n" 446 " args[i]->atomicFun = " << langC.getArgumentAtomic() <<
";\n" 449 printFunctionEndPThreads(_cache, jacInfo.size());
460 if (_jacSparsity.sparsity.size() > 0) {
467 _jacSparsity.sparsity = jacobianSparsitySet<SparsitySetType, CGBase> (_fun);
469 if (!_custom_jac.defined) {
470 generateSparsityIndexes(_jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols);
473 _jacSparsity.rows = _custom_jac.row;
474 _jacSparsity.cols = _custom_jac.col;
480 determineJacobianSparsity();
482 generateSparsity2DSource(_name +
"_" + FUNCTION_JACOBIAN_SPARSITY, _jacSparsity);
483 _sources[_name +
"_" + FUNCTION_JACOBIAN_SPARSITY +
".c"] = _cache.str();
virtual void generateSparseJacobianSource(MultiThreadingType multiThreadingType)
virtual void determineJacobianSparsity()
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={})
virtual std::string generateSparseJacobianForRevMultiThreadSource(const std::string &functionName, std::map< size_t, CompressedVectorInfo > jacInfo, size_t maxCompressedSize, const std::string &functionRevFor, const std::string &revForSuffix, bool forward, MultiThreadingType multiThreadingType)
void makeVariables(VectorCG &variables)
virtual void setParameterPrecision(size_t p)
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
virtual void generateSparseJacobianForRevSource(bool forward, MultiThreadingType multiThreadingType)