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.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
56 langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
57 langC.setParameterPrecision(_parameterPrecision);
58 langC.setGenerateFunction(_name +
"_" + FUNCTION_JACOBIAN);
60 std::ostringstream code;
61 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"jac"));
63 handler.generateCode(code, langC, jac, *nameGen, _atomicFunctions, jobName);
68 size_t m = _fun.Range();
69 size_t n = _fun.Domain();
74 determineJacobianSparsity();
78 if (_jacMode == JacobianADMode::Automatic) {
79 if (_custom_jac.defined) {
80 forwardMode = estimateBestJacobianADMode(_jacSparsity.rows, _jacSparsity.cols);
85 forwardMode = _jacMode == JacobianADMode::Forward;
91 if (_sparseJacobianReusesOne && _forwardOne && forwardMode) {
92 generateSparseJacobianForRevSource(
true, multiThreadingType);
93 }
else if (_sparseJacobianReusesOne && _reverseOne && !forwardMode) {
94 generateSparseJacobianForRevSource(
false, multiThreadingType);
96 generateSparseJacobianSource(forwardMode);
104 const std::string jobName =
"sparse Jacobian";
107 size_t n = _fun.Domain();
109 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
112 handler.setJobTimer(_jobTimer);
117 for (
size_t i = 0; i < n; i++) {
118 indVars[i].setValue(_x[i]);
123 if (_loopTapes.empty()) {
125 CppAD::sparse_jacobian_work work;
127 _fun.SparseJacobianForward(indVars, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jac, work);
129 _fun.SparseJacobianReverse(indVars, _jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols, jac, work);
133 jac = prepareSparseJacobianWithLoops(handler, indVars, forward);
142 langC.setGenerateFunction(_name +
"_" + FUNCTION_SPARSE_JACOBIAN);
144 std::ostringstream code;
145 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"jac"));
147 handler.
generateCode(code, langC, jac, *nameGen, _atomicFunctions, jobName);
152 MultiThreadingType multiThreadingType) {
157 std::map<size_t, CompressedVectorInfo> jacInfo;
158 string functionRevFor, revForSuffix;
161 for (
size_t e = 0; e < _jacSparsity.rows.size(); e++) {
162 jacInfo[_jacSparsity.cols[e]].indexes.push_back(_jacSparsity.rows[e]);
164 for (
auto& it : jacInfo) {
165 size_t col = it.first;
166 it.second.locations = determineOrderByCol(col, it.second.indexes, _jacSparsity.rows, _jacSparsity.cols);
169 _cache << _name <<
"_" << FUNCTION_SPARSE_FORWARD_ONE;
170 functionRevFor = _cache.str();
171 revForSuffix =
"indep";
174 for (
size_t e = 0; e < _jacSparsity.rows.size(); e++) {
175 jacInfo[_jacSparsity.rows[e]].indexes.push_back(_jacSparsity.cols[e]);
177 for (
auto& it : jacInfo) {
178 size_t row = it.first;
179 it.second.locations = determineOrderByRow(row, it.second.indexes, _jacSparsity.rows, _jacSparsity.cols);
182 _cache << _name <<
"_" << FUNCTION_SPARSE_REVERSE_ONE;
183 functionRevFor = _cache.str();
184 revForSuffix =
"dep";
192 for (
auto& it : jacInfo) {
193 const std::vector<size_t>& els = it.second.indexes;
194 const std::vector<set<size_t> >& location = it.second.locations;
195 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
196 CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
199 size_t jacArrayStart = *location[0].begin();
200 for (
size_t e = 0; e < els.size(); e++) {
201 if (location[e].size() > 1) {
205 if (*location[e].begin() != jacArrayStart + e) {
210 it.second.ordered = passed;
213 size_t maxCompressedSize = 0;
214 map<size_t, bool>::const_iterator itOrd;
215 map<size_t, std::vector<size_t> >::const_iterator it;
216 for (
const auto& it : jacInfo) {
217 if (it.second.indexes.size() > maxCompressedSize && !it.second.ordered)
218 maxCompressedSize = it.second.indexes.size();
221 if (!_loopTapes.empty()) {
226 generateSparseJacobianWithLoopsSourceFromForRev(jacInfo, maxCompressedSize,
227 FUNCTION_SPARSE_FORWARD_ONE,
"indep",
"jcol",
228 _nonLoopFor1Elements, _loopFor1Groups,
229 generateFunctionNameLoopFor1);
231 generateSparseJacobianWithLoopsSourceFromForRev(jacInfo, maxCompressedSize,
232 FUNCTION_SPARSE_REVERSE_ONE,
"dep",
"jrow",
233 _nonLoopRev1Elements, _loopRev1Groups,
234 generateFunctionNameLoopRev1);
240 _cache << _name <<
"_" << FUNCTION_SPARSE_JACOBIAN;
241 string functionName(_cache.str());
243 if(!_multiThreading || multiThreadingType == MultiThreadingType::NONE) {
244 _sources[functionName +
".c"] = generateSparseJacobianForRevSingleThreadSource(functionName, jacInfo, maxCompressedSize, functionRevFor, revForSuffix, forward);
246 _sources[functionName +
".c"] = generateSparseJacobianForRevMultiThreadSource(functionName, jacInfo, maxCompressedSize, functionRevFor, revForSuffix, forward, multiThreadingType);
254 std::map<size_t, CompressedVectorInfo> jacInfo,
255 size_t maxCompressedSize,
256 const std::string& functionRevFor,
257 const std::string& revForSuffix,
261 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
262 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
265 _cache <<
"#include <stdlib.h>\n" 268 generateFunctionDeclarationSource(_cache, functionRevFor, revForSuffix, jacInfo, argsDcl);
272 " " << _baseTypeName <<
" const * inLocal[2];\n" 273 " " << _baseTypeName <<
" inLocal1 = 1;\n" 274 " " << _baseTypeName <<
" * outLocal[1];\n" 275 " " << _baseTypeName <<
" compressed[" << maxCompressedSize <<
"];\n" 276 " " << _baseTypeName <<
" * jac = out[0];\n" 278 " inLocal[0] = in[0];\n" 279 " inLocal[1] = &inLocal1;\n" 280 " outLocal[0] = compressed;\n";
282 langC.setArgumentIn(
"inLocal");
283 langC.setArgumentOut(
"outLocal");
284 std::string argsLocal = langC.generateDefaultFunctionArguments();
286 bool previousCompressed =
true;
287 for (
const auto& it : jacInfo) {
288 size_t index = it.first;
289 const std::vector<size_t>& els = it.second.indexes;
290 const std::vector<std::set<size_t> >& location = it.second.locations;
291 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
294 bool compressed = !it.second.ordered;
296 _cache <<
" outLocal[0] = &jac[" << *location[0].begin() <<
"];\n";
297 }
else if (!previousCompressed) {
298 _cache <<
" outLocal[0] = compressed;\n";
300 _cache <<
" " << functionRevFor <<
"_" << revForSuffix << index <<
"(" << argsLocal <<
");\n";
302 for (
size_t e = 0; e < els.size(); e++) {
304 for (
size_t itl : location[e]) {
305 _cache <<
"jac[" << (itl) <<
"] = ";
307 _cache <<
"compressed[" << e <<
"];\n";
310 previousCompressed = compressed;
321 std::map<size_t, CompressedVectorInfo> jacInfo,
322 size_t maxCompressedSize,
323 const std::string& functionRevFor,
324 const std::string& revForSuffix,
326 MultiThreadingType multiThreadingType) {
328 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
329 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
332 _cache <<
"#include <stdlib.h>\n" 335 generateFunctionDeclarationSource(_cache, functionRevFor, revForSuffix, jacInfo, argsDcl);
337 langC.setArgumentIn(
"inLocal");
338 langC.setArgumentOut(
"outLocal");
339 std::string argsLocal = langC.generateDefaultFunctionArguments();
344 for (
const auto& it : jacInfo) {
345 size_t index = it.first;
346 const std::vector<size_t>& els = it.second.indexes;
347 const std::vector<std::set<size_t> >& location = it.second.locations;
348 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
350 bool compressed = !it.second.ordered;
355 std::string functionNameWrap = functionRevFor +
"_" + revForSuffix + std::to_string(index) +
"_wrap";
358 " " << _baseTypeName <<
" const * inLocal[2];\n" 359 " " << _baseTypeName <<
" inLocal1 = 1;\n" 360 " " << _baseTypeName <<
" * outLocal[1];\n" 361 " " << _baseTypeName <<
" compressed[" << it.second.indexes.size() <<
"];\n" 362 " " << _baseTypeName <<
" * jac = out[0];\n" 364 " inLocal[0] = in[0];\n" 365 " inLocal[1] = &inLocal1;\n" 366 " outLocal[0] = compressed;\n";
368 _cache <<
" " << functionRevFor <<
"_" << revForSuffix << index <<
"(" << argsLocal <<
");\n";
369 for (
size_t e = 0; e < els.size(); e++) {
371 for (
size_t itl : location[e]) {
372 _cache <<
"jac[" << (itl) <<
"] = ";
374 _cache <<
"compressed[" << e <<
"];\n";
380 "typedef void (*cppadcg_function_type) (" << argsDcl <<
");\n";
385 if(multiThreadingType == MultiThreadingType::OPENMP) {
387 printFileStartOpenMP(_cache);
391 assert(multiThreadingType == MultiThreadingType::PTHREADS);
393 printFileStartPThreads(_cache, _baseTypeName);
400 "void " << functionName <<
"(" << argsDcl <<
") {\n" 401 " static const cppadcg_function_type p[" << jacInfo.size() <<
"] = {";
402 for (
const auto& it : jacInfo) {
403 size_t index = it.first;
404 if (index != jacInfo.begin()->first) _cache <<
", ";
405 if (it.second.ordered) {
406 _cache << functionRevFor <<
"_" << revForSuffix << index;
408 _cache << functionRevFor <<
"_" << revForSuffix << index <<
"_wrap";
412 " static const long offset["<< jacInfo.size() <<
"] = {";
413 for (
const auto& it : jacInfo) {
414 if (it.first != jacInfo.begin()->first) _cache <<
", ";
415 if (it.second.ordered) {
416 _cache << *it.second.locations[0].begin();
422 " " << _baseTypeName <<
" inLocal1 = 1;\n" 423 " " << _baseTypeName <<
" const * inLocal[2] = {in[0], &inLocal1};\n" 424 " " << _baseTypeName <<
" * outLocal[1];\n" 425 " " << _baseTypeName <<
" * jac = out[0];\n" 429 if(multiThreadingType == MultiThreadingType::OPENMP) {
430 printFunctionStartOpenMP(_cache, jacInfo.size());
432 printLoopStartOpenMP(_cache, jacInfo.size());
433 _cache <<
" outLocal[0] = &jac[offset[i]];\n" 434 " (*p[i])(" << argsLocal <<
");\n";
435 printLoopEndOpenMP(_cache, jacInfo.size());
439 assert(multiThreadingType == MultiThreadingType::PTHREADS);
441 printFunctionStartPThreads(_cache, jacInfo.size());
443 " for(i = 0; i < " << jacInfo.size() <<
"; ++i) {\n" 444 " args[i] = (ExecArgStruct*) malloc(sizeof(ExecArgStruct));\n" 445 " args[i]->func = p[i];\n" 446 " args[i]->in = inLocal;\n" 447 " args[i]->out[0] = &jac[offset[i]];\n" 448 " args[i]->atomicFun = " << langC.getArgumentAtomic() <<
";\n" 451 printFunctionEndPThreads(_cache, jacInfo.size());
462 if (_jacSparsity.sparsity.size() > 0) {
469 _jacSparsity.sparsity = jacobianSparsitySet<SparsitySetType, CGBase> (_fun);
471 if (!_custom_jac.defined) {
472 generateSparsityIndexes(_jacSparsity.sparsity, _jacSparsity.rows, _jacSparsity.cols);
475 _jacSparsity.rows = _custom_jac.row;
476 _jacSparsity.cols = _custom_jac.col;
482 determineJacobianSparsity();
484 generateSparsity2DSource(_name +
"_" + FUNCTION_JACOBIAN_SPARSITY, _jacSparsity);
485 _sources[_name +
"_" + FUNCTION_JACOBIAN_SPARSITY +
".c"] = _cache.str();
virtual void generateSparseJacobianSource(MultiThreadingType multiThreadingType)
virtual void determineJacobianSparsity()
void setMaxOperationsPerAssignment(size_t maxOperationsPerAssignment)
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 setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
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)