1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_HES_INCLUDED 2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_HES_INCLUDED 22 void ModelCSourceGen<Base>::generateHessianSource() {
25 const std::string jobName =
"Hessian";
27 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
29 CodeHandler<Base> handler;
30 handler.setJobTimer(_jobTimer);
32 size_t m = _fun.Range();
33 size_t n = _fun.Domain();
37 vector<CGBase> indVars(n);
38 handler.makeVariables(indVars);
40 for (
size_t i = 0; i < n; i++) {
41 indVars[i].setValue(_x[i]);
47 handler.makeVariables(w);
49 for (
size_t i = 0; i < m; i++) {
50 w[i].setValue(Base(1.0));
54 vector<CGBase> hess = _fun.Hessian(indVars, w);
57 for (
size_t i = 0; i < n; i++) {
58 for (
size_t j = 0; j < i; j++) {
59 hess[i * n + j] = hess[j * n + i];
65 LanguageC<Base> langC(_baseTypeName);
66 langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
67 langC.setParameterPrecision(_parameterPrecision);
68 langC.setGenerateFunction(_name +
"_" + FUNCTION_HESSIAN);
70 std::ostringstream code;
71 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"hess"));
72 LangCDefaultHessianVarNameGenerator<Base> nameGenHess(nameGen.get(), n);
74 handler.generateCode(code, langC, hess, nameGenHess, _atomicFunctions, jobName);
82 determineHessianSparsity();
84 if (_sparseHessianReusesRev2 && _reverseTwo) {
85 generateSparseHessianSourceFromRev2(multiThreadingType);
87 generateSparseHessianSourceDirectly();
95 const std::string jobName =
"sparse Hessian";
96 size_t m = _fun.Range();
97 size_t n = _fun.Domain();
103 std::vector<size_t> evalRows, evalCols;
104 determineSecondOrderElements4Eval(evalRows, evalCols);
106 std::map<size_t, std::map<size_t, size_t> > locations;
107 for (
size_t e = 0; e < evalRows.size(); e++) {
108 size_t j1 = evalRows[e];
109 size_t j2 = evalCols[e];
110 std::map<size_t, std::map<size_t, size_t> >::iterator itJ1 = locations.find(j1);
111 if (itJ1 == locations.end()) {
112 locations[j1][j2] = e;
114 std::map<size_t, size_t>& j22e = itJ1->second;
115 if (j22e.find(j2) == j22e.end()) {
119 throw CGException(
"Repeated Hessian element requested: ", j1,
" ", j2);
125 std::vector<size_t> lowerHessRows, lowerHessCols, lowerHessOrder;
126 lowerHessRows.reserve(_hessSparsity.rows.size() / 2);
127 lowerHessCols.reserve(lowerHessRows.size());
128 lowerHessOrder.reserve(lowerHessRows.size());
130 std::map<size_t, size_t> duplicates;
131 std::map<size_t, std::map<size_t, size_t> >::const_iterator itJ;
132 std::map<size_t, size_t>::const_iterator itI;
133 for (
size_t e = 0; e < evalRows.size(); e++) {
135 size_t i = evalRows[e];
136 size_t j = evalCols[e];
139 itJ = locations.find(j);
140 if (itJ != locations.end()) {
141 itI = itJ->second.find(i);
142 if (itI != itJ->second.end()) {
143 size_t eSim = itI->second;
144 duplicates[e] = eSim;
151 lowerHessRows.push_back(i);
152 lowerHessCols.push_back(j);
153 lowerHessOrder.push_back(e);
160 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
163 handler.setJobTimer(_jobTimer);
169 for (
size_t i = 0; i < n; i++) {
170 indVars[i].setValue(_x[i]);
178 for (
size_t i = 0; i < m; i++) {
179 w[i].setValue(Base(1.0));
184 if (_loopTapes.empty()) {
185 CppAD::sparse_hessian_work work;
189 work.color_method =
"cppad.general";
191 _fun.SparseHessian(indVars, w, _hessSparsity.sparsity, lowerHessRows, lowerHessCols, lowerHess, work);
193 for (
size_t i = 0; i < lowerHessOrder.size(); i++) {
194 hess[lowerHessOrder[i]] = lowerHess[i];
198 for (
const auto& it2 : duplicates) {
199 hess[it2.first] = hess[it2.second];
205 hess = prepareSparseHessianWithLoops(handler, indVars, w,
206 lowerHessRows, lowerHessCols, lowerHessOrder,
213 langC.setMaxAssigmentsPerFunction(_maxAssignPerFunc, &_sources);
215 langC.setGenerateFunction(_name +
"_" + FUNCTION_SPARSE_HESSIAN);
217 std::ostringstream code;
218 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"hess"));
221 handler.
generateCode(code, langC, hess, nameGenHess, _atomicFunctions, jobName);
232 std::vector<size_t> evalRows, evalCols;
233 determineSecondOrderElements4Eval(evalRows, evalCols);
235 std::map<size_t, CompressedVectorInfo> hessInfo;
238 for (
size_t e = 0; e < evalRows.size(); e++) {
239 hessInfo[evalRows[e]].indexes.push_back(evalCols[e]);
243 for (
auto& it : hessInfo) {
244 it.second.locations = determineOrderByRow(it.first, it.second.indexes, evalRows, evalCols);
251 for (
auto& it : hessInfo) {
252 const std::vector<size_t>& els = it.second.indexes;
253 const std::vector<set<size_t> >& location = it.second.locations;
254 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
255 CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
258 size_t hessRowStart = *location[0].begin();
259 for (
size_t e = 0; e < els.size(); e++) {
260 if (location[e].size() > 1) {
264 if (*location[e].begin() != hessRowStart + e) {
269 it.second.ordered = passed;
275 size_t maxCompressedSize = 0;
277 for (
const auto& it : hessInfo) {
278 if (it.second.indexes.size() > maxCompressedSize && !it.second.ordered)
279 maxCompressedSize = it.second.indexes.size();
282 if (!_loopTapes.empty()) {
286 generateSparseHessianWithLoopsSourceFromRev2(hessInfo, maxCompressedSize);
290 string functionName = _name +
"_" + FUNCTION_SPARSE_HESSIAN;
291 string functionRev2 = _name +
"_" + FUNCTION_SPARSE_REVERSE_TWO;
292 string rev2Suffix =
"indep";
294 if (!_multiThreading || multiThreadingType == MultiThreadingType::NONE) {
295 _sources[functionName +
".c"] = generateSparseHessianRev2SingleThreadSource(functionName, hessInfo, maxCompressedSize, functionRev2, rev2Suffix);
297 _sources[functionName +
".c"] = generateSparseHessianRev2MultiThreadSource(functionName, hessInfo, maxCompressedSize, functionRev2, rev2Suffix, multiThreadingType);
304 std::map<size_t, CompressedVectorInfo> hessInfo,
305 size_t maxCompressedSize,
306 const std::string& functionRev2,
307 const std::string& rev2Suffix) {
309 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
310 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
313 _cache <<
"#include <stdlib.h>\n" 315 generateFunctionDeclarationSource(_cache, functionRev2, rev2Suffix, hessInfo, argsDcl);
319 " " << _baseTypeName <<
" const * inLocal[3];\n" 320 " " << _baseTypeName <<
" inLocal1 = 1;\n" 321 " " << _baseTypeName <<
" * outLocal[1];\n";
322 if (maxCompressedSize > 0) {
323 _cache <<
" " << _baseTypeName <<
" compressed[" << maxCompressedSize <<
"];\n";
325 _cache <<
" " << _baseTypeName <<
" * hess = out[0];\n" 327 " inLocal[0] = in[0];\n" 328 " inLocal[1] = &inLocal1;\n" 329 " inLocal[2] = in[1];\n";
330 if (maxCompressedSize > 0) {
331 _cache <<
" outLocal[0] = compressed;";
334 langC.setArgumentIn(
"inLocal");
335 langC.setArgumentOut(
"outLocal");
336 std::string argsLocal = langC.generateDefaultFunctionArguments();
337 bool previousCompressed =
true;
338 for (
auto& it : hessInfo) {
339 size_t index = it.first;
340 const std::vector<size_t>& els = it.second.indexes;
341 const std::vector<std::set<size_t> >& location = it.second.locations;
342 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
343 CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
346 bool compressed = !it.second.ordered;
348 _cache <<
" outLocal[0] = &hess[" << *location[0].begin() <<
"];\n";
349 }
else if (!previousCompressed) {
350 _cache <<
" outLocal[0] = compressed;\n";
352 _cache <<
" " << functionRev2 <<
"_" << rev2Suffix << index <<
"(" << argsLocal <<
");\n";
354 for (
size_t e = 0; e < els.size(); e++) {
356 for (
size_t itl : location[e]) {
357 _cache <<
"hess[" << itl <<
"] = ";
359 _cache <<
"compressed[" << e <<
"];\n";
362 previousCompressed = compressed;
373 std::map<size_t, CompressedVectorInfo> hessInfo,
374 size_t maxCompressedSize,
375 const std::string& functionRev2,
376 const std::string& rev2Suffix,
377 MultiThreadingType multiThreadingType) {
378 CPPADCG_ASSERT_UNKNOWN(_multiThreading);
379 CPPADCG_ASSERT_UNKNOWN(multiThreadingType != MultiThreadingType::NONE);
382 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
383 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
386 _cache <<
"#include <stdlib.h>\n" 388 generateFunctionDeclarationSource(_cache, functionRev2, rev2Suffix, hessInfo, argsDcl);
391 langC.setArgumentIn(
"inLocal");
392 langC.setArgumentOut(
"outLocal");
393 std::string argsLocal = langC.generateDefaultFunctionArguments();
398 for (
const auto& it : hessInfo) {
399 size_t index = it.first;
400 const std::vector<size_t>& els = it.second.indexes;
401 const std::vector<std::set<size_t> >& location = it.second.locations;
402 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
404 bool compressed = !it.second.ordered;
409 std::string functionNameWrap = functionRev2 +
"_" + rev2Suffix + std::to_string(index) +
"_wrap";
412 " " << _baseTypeName <<
" const * inLocal[3];\n" 413 " " << _baseTypeName <<
" inLocal1 = 1;\n" 414 " " << _baseTypeName <<
" * outLocal[1];\n" 415 " " << _baseTypeName <<
" compressed[" << it.second.indexes.size() <<
"];\n" 416 " " << _baseTypeName <<
" * hess = out[0];\n" 418 " inLocal[0] = in[0];\n" 419 " inLocal[1] = &inLocal1;\n" 420 " inLocal[2] = in[1];\n" 421 " outLocal[0] = compressed;\n";
422 _cache <<
" " << functionRev2 <<
"_" << rev2Suffix << index <<
"(" << argsLocal <<
");\n";
423 for (
size_t e = 0; e < els.size(); e++) {
425 for (
size_t itl : location[e]) {
426 _cache <<
"hess[" << itl <<
"] = ";
428 _cache <<
"compressed[" << e <<
"];\n";
434 "typedef void (*cppadcg_function_type) (" << argsDcl <<
");\n";
437 if (multiThreadingType == MultiThreadingType::OPENMP) {
439 printFileStartOpenMP(_cache);
446 assert(multiThreadingType == MultiThreadingType::PTHREADS);
448 printFileStartPThreads(_cache, _baseTypeName);
455 "void " << functionName <<
"(" << argsDcl <<
") {\n" 456 " static const cppadcg_function_type p[" << hessInfo.size() <<
"] = {";
457 for (
const auto& it : hessInfo) {
458 size_t index = it.first;
459 if (index != hessInfo.begin()->first) _cache <<
", ";
460 if (it.second.ordered) {
461 _cache << functionRev2 <<
"_" << rev2Suffix << index;
463 _cache << functionRev2 <<
"_" << rev2Suffix << index <<
"_wrap";
467 " static const long offset["<< hessInfo.size() <<
"] = {";
468 for (
const auto& it : hessInfo) {
469 if (it.first != hessInfo.begin()->first) _cache <<
", ";
470 if (it.second.ordered) {
471 _cache << *it.second.locations[0].begin();
477 " " << _baseTypeName <<
" inLocal1 = 1;\n" 478 " " << _baseTypeName <<
" const * inLocal[3] = {in[0], &inLocal1, in[1]};\n" 479 " " << _baseTypeName <<
" * outLocal[1];\n";
480 _cache <<
" " << _baseTypeName <<
" * hess = out[0];\n" 484 if(multiThreadingType == MultiThreadingType::OPENMP) {
485 printFunctionStartOpenMP(_cache, hessInfo.size());
487 printLoopStartOpenMP(_cache, hessInfo.size());
488 _cache <<
" outLocal[0] = &hess[offset[i]];\n" 489 " (*p[i])(" << argsLocal <<
");\n";
490 printLoopEndOpenMP(_cache, hessInfo.size());
494 assert(multiThreadingType == MultiThreadingType::PTHREADS);
496 printFunctionStartPThreads(_cache, hessInfo.size());
498 " for(i = 0; i < " << hessInfo.size() <<
"; ++i) {\n" 499 " args[i] = (ExecArgStruct*) malloc(sizeof(ExecArgStruct));\n" 500 " args[i]->func = p[i];\n" 501 " args[i]->in = inLocal;\n" 502 " args[i]->out[0] = &hess[offset[i]];\n" 503 " args[i]->atomicFun = " << langC .getArgumentAtomic() <<
";\n" 506 printFunctionEndPThreads(_cache, hessInfo.size());
516 std::vector<size_t>& evalCols) {
522 evalRows.reserve(_hessSparsity.rows.size());
523 evalCols.reserve(_hessSparsity.cols.size());
525 for (
size_t e = 0; e < _hessSparsity.rows.size(); e++) {
526 size_t i = _hessSparsity.rows[e];
527 size_t j = _hessSparsity.cols[e];
528 if (_hessSparsity.sparsity[i].find(j) == _hessSparsity.sparsity[i].end() &&
529 _hessSparsity.sparsity[j].find(i) != _hessSparsity.sparsity[j].end()) {
532 evalRows.push_back(j);
533 evalCols.push_back(i);
535 evalRows.push_back(i);
536 evalCols.push_back(j);
543 if (_hessSparsity.sparsity.size() > 0) {
547 size_t m = _fun.Range();
548 size_t n = _fun.Domain();
553 SparsitySetType r(n);
554 for (
size_t j = 0; j < n; j++)
556 SparsitySetType jac = _fun.ForSparseJac(n, r);
558 SparsitySetType s(1);
559 for (
size_t i = 0; i < m; i++) {
562 _hessSparsity.sparsity = _fun.RevSparseHes(n, s,
false);
565 if (_hessianByEquation || _reverseTwo) {
570 std::set<size_t> customVarsInHess;
571 if (_custom_hess.defined) {
572 customVarsInHess.insert(_custom_hess.row.begin(), _custom_hess.row.end());
573 customVarsInHess.insert(_custom_hess.col.begin(), _custom_hess.col.end());
575 r = SparsitySetType(n);
576 for (
size_t j : customVarsInHess) {
579 jac = _fun.ForSparseJac(n, r);
585 const std::vector<Color> colors = colorByRow(customVarsInHess, jac);
590 _hessSparsities.resize(m);
591 for (
size_t i = 0; i < m; i++) {
592 _hessSparsities[i].sparsity.resize(n);
595 for (
size_t c = 0; c < colors.size(); c++) {
596 const Color& color = colors[c];
599 r = SparsitySetType(n);
603 _fun.ForSparseJac(n, r);
607 const std::set<size_t>& equations = color.
rows;
608 for (
size_t i : equations) {
612 SparsitySetType sparsityc = _fun.RevSparseHes(n, s,
false);
617 const std::map<size_t, size_t>& var2Eq = color.
column2Row;
619 if (sparsityc[j].size() > 0) {
620 size_t i = var2Eq.at(j);
621 _hessSparsities[i].sparsity[j].insert(sparsityc[j].begin(),
628 for (
size_t i = 0; i < m; i++) {
631 if (!_custom_hess.defined) {
632 generateSparsityIndexes(hessSparsitiesi.
sparsity,
633 hessSparsitiesi.rows, hessSparsitiesi.cols);
636 size_t nnz = _custom_hess.row.size();
637 for (
size_t e = 0; e < nnz; e++) {
638 size_t i1 = _custom_hess.row[e];
639 size_t i2 = _custom_hess.col[e];
640 if (hessSparsitiesi.
sparsity[i1].find(i2) != hessSparsitiesi.
sparsity[i1].end()) {
641 hessSparsitiesi.rows.push_back(i1);
642 hessSparsitiesi.cols.push_back(i2);
650 if (!_custom_hess.defined) {
651 generateSparsityIndexes(_hessSparsity.sparsity,
652 _hessSparsity.rows, _hessSparsity.cols);
655 _hessSparsity.rows = _custom_hess.row;
656 _hessSparsity.cols = _custom_hess.col;
662 determineHessianSparsity();
664 generateSparsity2DSource(_name +
"_" + FUNCTION_HESSIAN_SPARSITY, _hessSparsity);
665 _sources[_name +
"_" + FUNCTION_HESSIAN_SPARSITY +
".c"] = _cache.str();
668 if (_hessianByEquation || _reverseTwo) {
669 generateSparsity2DSource2(_name +
"_" + FUNCTION_HESSIAN_SPARSITY2, _hessSparsities);
670 _sources[_name +
"_" + FUNCTION_HESSIAN_SPARSITY2 +
".c"] = _cache.str();
std::set< size_t > rows
all row with this color
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={})
std::map< size_t, size_t > column2Row
maps column indexes to the corresponding row
virtual void generateSparseHessianSourceDirectly()
virtual std::string generateSparseHessianRev2MultiThreadSource(const std::string &functionName, std::map< size_t, CompressedVectorInfo > hessInfo, size_t maxCompressedSize, const std::string &functionRev2, const std::string &rev2Suffix, MultiThreadingType multiThreadingType)
virtual void generateSparseHessianSourceFromRev2(MultiThreadingType multiThreadingType)
void makeVariables(VectorCG &variables)
virtual void determineSecondOrderElements4Eval(std::vector< size_t > &userRows, std::vector< size_t > &userCols)
virtual void setParameterPrecision(size_t p)
virtual void generateSparseHessianSource(MultiThreadingType multiThreadingType)
std::set< size_t > forbiddenRows
used columns
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
virtual void determineHessianSparsity()