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.setMaxAssignmentsPerFunction(_maxAssignPerFunc, &_sources);
67 langC.setMaxOperationsPerAssignment(_maxOperationsPerAssignment);
68 langC.setParameterPrecision(_parameterPrecision);
69 langC.setGenerateFunction(_name +
"_" + FUNCTION_HESSIAN);
71 std::ostringstream code;
72 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"hess"));
73 LangCDefaultHessianVarNameGenerator<Base> nameGenHess(nameGen.get(), n);
75 handler.generateCode(code, langC, hess, nameGenHess, _atomicFunctions, jobName);
83 determineHessianSparsity();
85 if (_sparseHessianReusesRev2 && _reverseTwo) {
86 generateSparseHessianSourceFromRev2(multiThreadingType);
88 generateSparseHessianSourceDirectly();
96 const std::string jobName =
"sparse Hessian";
97 size_t m = _fun.Range();
98 size_t n = _fun.Domain();
104 std::vector<size_t> evalRows, evalCols;
105 determineSecondOrderElements4Eval(evalRows, evalCols);
107 std::map<size_t, std::map<size_t, size_t> > locations;
108 for (
size_t e = 0; e < evalRows.size(); e++) {
109 size_t j1 = evalRows[e];
110 size_t j2 = evalCols[e];
111 std::map<size_t, std::map<size_t, size_t> >::iterator itJ1 = locations.find(j1);
112 if (itJ1 == locations.end()) {
113 locations[j1][j2] = e;
115 std::map<size_t, size_t>& j22e = itJ1->second;
116 if (j22e.find(j2) == j22e.end()) {
120 throw CGException(
"Repeated Hessian element requested: ", j1,
" ", j2);
126 std::vector<size_t> lowerHessRows, lowerHessCols, lowerHessOrder;
127 lowerHessRows.reserve(_hessSparsity.rows.size() / 2);
128 lowerHessCols.reserve(lowerHessRows.size());
129 lowerHessOrder.reserve(lowerHessRows.size());
131 std::map<size_t, size_t> duplicates;
132 std::map<size_t, std::map<size_t, size_t> >::const_iterator itJ;
133 std::map<size_t, size_t>::const_iterator itI;
134 for (
size_t e = 0; e < evalRows.size(); e++) {
136 size_t i = evalRows[e];
137 size_t j = evalCols[e];
140 itJ = locations.find(j);
141 if (itJ != locations.end()) {
142 itI = itJ->second.find(i);
143 if (itI != itJ->second.end()) {
144 size_t eSim = itI->second;
145 duplicates[e] = eSim;
152 lowerHessRows.push_back(i);
153 lowerHessCols.push_back(j);
154 lowerHessOrder.push_back(e);
161 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
164 handler.setJobTimer(_jobTimer);
170 for (
size_t i = 0; i < n; i++) {
171 indVars[i].setValue(_x[i]);
179 for (
size_t i = 0; i < m; i++) {
180 w[i].setValue(Base(1.0));
185 if (_loopTapes.empty()) {
186 CppAD::sparse_hessian_work work;
190 work.color_method =
"cppad.general";
192 _fun.SparseHessian(indVars, w, _hessSparsity.sparsity, lowerHessRows, lowerHessCols, lowerHess, work);
194 for (
size_t i = 0; i < lowerHessOrder.size(); i++) {
195 hess[lowerHessOrder[i]] = lowerHess[i];
199 for (
const auto& it2 : duplicates) {
200 hess[it2.first] = hess[it2.second];
206 hess = prepareSparseHessianWithLoops(handler, indVars, w,
207 lowerHessRows, lowerHessCols, lowerHessOrder,
217 langC.setGenerateFunction(_name +
"_" + FUNCTION_SPARSE_HESSIAN);
219 std::ostringstream code;
220 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"hess"));
223 handler.
generateCode(code, langC, hess, nameGenHess, _atomicFunctions, jobName);
234 std::vector<size_t> evalRows, evalCols;
235 determineSecondOrderElements4Eval(evalRows, evalCols);
237 std::map<size_t, CompressedVectorInfo> hessInfo;
240 for (
size_t e = 0; e < evalRows.size(); e++) {
241 hessInfo[evalRows[e]].indexes.push_back(evalCols[e]);
245 for (
auto& it : hessInfo) {
246 it.second.locations = determineOrderByRow(it.first, it.second.indexes, evalRows, evalCols);
253 for (
auto& it : hessInfo) {
254 const std::vector<size_t>& els = it.second.indexes;
255 const std::vector<set<size_t> >& location = it.second.locations;
256 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
257 CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
260 size_t hessRowStart = *location[0].begin();
261 for (
size_t e = 0; e < els.size(); e++) {
262 if (location[e].size() > 1) {
266 if (*location[e].begin() != hessRowStart + e) {
271 it.second.ordered = passed;
277 size_t maxCompressedSize = 0;
279 for (
const auto& it : hessInfo) {
280 if (it.second.indexes.size() > maxCompressedSize && !it.second.ordered)
281 maxCompressedSize = it.second.indexes.size();
284 if (!_loopTapes.empty()) {
288 generateSparseHessianWithLoopsSourceFromRev2(hessInfo, maxCompressedSize);
292 string functionName = _name +
"_" + FUNCTION_SPARSE_HESSIAN;
293 string functionRev2 = _name +
"_" + FUNCTION_SPARSE_REVERSE_TWO;
294 string rev2Suffix =
"indep";
296 if (!_multiThreading || multiThreadingType == MultiThreadingType::NONE) {
297 _sources[functionName +
".c"] = generateSparseHessianRev2SingleThreadSource(functionName, hessInfo, maxCompressedSize, functionRev2, rev2Suffix);
299 _sources[functionName +
".c"] = generateSparseHessianRev2MultiThreadSource(functionName, hessInfo, maxCompressedSize, functionRev2, rev2Suffix, multiThreadingType);
306 std::map<size_t, CompressedVectorInfo> hessInfo,
307 size_t maxCompressedSize,
308 const std::string& functionRev2,
309 const std::string& rev2Suffix) {
311 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
312 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
315 _cache <<
"#include <stdlib.h>\n" 317 generateFunctionDeclarationSource(_cache, functionRev2, rev2Suffix, hessInfo, argsDcl);
321 " " << _baseTypeName <<
" const * inLocal[3];\n" 322 " " << _baseTypeName <<
" inLocal1 = 1;\n" 323 " " << _baseTypeName <<
" * outLocal[1];\n";
324 if (maxCompressedSize > 0) {
325 _cache <<
" " << _baseTypeName <<
" compressed[" << maxCompressedSize <<
"];\n";
327 _cache <<
" " << _baseTypeName <<
" * hess = out[0];\n" 329 " inLocal[0] = in[0];\n" 330 " inLocal[1] = &inLocal1;\n" 331 " inLocal[2] = in[1];\n";
332 if (maxCompressedSize > 0) {
333 _cache <<
" outLocal[0] = compressed;";
336 langC.setArgumentIn(
"inLocal");
337 langC.setArgumentOut(
"outLocal");
338 std::string argsLocal = langC.generateDefaultFunctionArguments();
339 bool previousCompressed =
true;
340 for (
auto& it : hessInfo) {
341 size_t index = it.first;
342 const std::vector<size_t>& els = it.second.indexes;
343 const std::vector<std::set<size_t> >& location = it.second.locations;
344 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
345 CPPADCG_ASSERT_UNKNOWN(els.size() > 0);
348 bool compressed = !it.second.ordered;
350 _cache <<
" outLocal[0] = &hess[" << *location[0].begin() <<
"];\n";
351 }
else if (!previousCompressed) {
352 _cache <<
" outLocal[0] = compressed;\n";
354 _cache <<
" " << functionRev2 <<
"_" << rev2Suffix << index <<
"(" << argsLocal <<
");\n";
356 for (
size_t e = 0; e < els.size(); e++) {
358 for (
size_t itl : location[e]) {
359 _cache <<
"hess[" << itl <<
"] = ";
361 _cache <<
"compressed[" << e <<
"];\n";
364 previousCompressed = compressed;
375 std::map<size_t, CompressedVectorInfo> hessInfo,
376 size_t maxCompressedSize,
377 const std::string& functionRev2,
378 const std::string& rev2Suffix,
379 MultiThreadingType multiThreadingType) {
380 CPPADCG_ASSERT_UNKNOWN(_multiThreading);
381 CPPADCG_ASSERT_UNKNOWN(multiThreadingType != MultiThreadingType::NONE);
384 std::string argsDcl = langC.generateDefaultFunctionArgumentsDcl();
385 std::vector<std::string> argsDcl2 = langC.generateDefaultFunctionArgumentsDcl2();
388 _cache <<
"#include <stdlib.h>\n" 390 generateFunctionDeclarationSource(_cache, functionRev2, rev2Suffix, hessInfo, argsDcl);
393 langC.setArgumentIn(
"inLocal");
394 langC.setArgumentOut(
"outLocal");
395 std::string argsLocal = langC.generateDefaultFunctionArguments();
400 for (
const auto& it : hessInfo) {
401 size_t index = it.first;
402 const std::vector<size_t>& els = it.second.indexes;
403 const std::vector<std::set<size_t> >& location = it.second.locations;
404 CPPADCG_ASSERT_UNKNOWN(els.size() == location.size());
406 bool compressed = !it.second.ordered;
411 std::string functionNameWrap = functionRev2 +
"_" + rev2Suffix + std::to_string(index) +
"_wrap";
414 " " << _baseTypeName <<
" const * inLocal[3];\n" 415 " " << _baseTypeName <<
" inLocal1 = 1;\n" 416 " " << _baseTypeName <<
" * outLocal[1];\n" 417 " " << _baseTypeName <<
" compressed[" << it.second.indexes.size() <<
"];\n" 418 " " << _baseTypeName <<
" * hess = out[0];\n" 420 " inLocal[0] = in[0];\n" 421 " inLocal[1] = &inLocal1;\n" 422 " inLocal[2] = in[1];\n" 423 " outLocal[0] = compressed;\n";
424 _cache <<
" " << functionRev2 <<
"_" << rev2Suffix << index <<
"(" << argsLocal <<
");\n";
425 for (
size_t e = 0; e < els.size(); e++) {
427 for (
size_t itl : location[e]) {
428 _cache <<
"hess[" << itl <<
"] = ";
430 _cache <<
"compressed[" << e <<
"];\n";
436 "typedef void (*cppadcg_function_type) (" << argsDcl <<
");\n";
439 if (multiThreadingType == MultiThreadingType::OPENMP) {
441 printFileStartOpenMP(_cache);
448 assert(multiThreadingType == MultiThreadingType::PTHREADS);
450 printFileStartPThreads(_cache, _baseTypeName);
457 "void " << functionName <<
"(" << argsDcl <<
") {\n" 458 " static const cppadcg_function_type p[" << hessInfo.size() <<
"] = {";
459 for (
const auto& it : hessInfo) {
460 size_t index = it.first;
461 if (index != hessInfo.begin()->first) _cache <<
", ";
462 if (it.second.ordered) {
463 _cache << functionRev2 <<
"_" << rev2Suffix << index;
465 _cache << functionRev2 <<
"_" << rev2Suffix << index <<
"_wrap";
469 " static const long offset["<< hessInfo.size() <<
"] = {";
470 for (
const auto& it : hessInfo) {
471 if (it.first != hessInfo.begin()->first) _cache <<
", ";
472 if (it.second.ordered) {
473 _cache << *it.second.locations[0].begin();
479 " " << _baseTypeName <<
" inLocal1 = 1;\n" 480 " " << _baseTypeName <<
" const * inLocal[3] = {in[0], &inLocal1, in[1]};\n" 481 " " << _baseTypeName <<
" * outLocal[1];\n";
482 _cache <<
" " << _baseTypeName <<
" * hess = out[0];\n" 486 if(multiThreadingType == MultiThreadingType::OPENMP) {
487 printFunctionStartOpenMP(_cache, hessInfo.size());
489 printLoopStartOpenMP(_cache, hessInfo.size());
490 _cache <<
" outLocal[0] = &hess[offset[i]];\n" 491 " (*p[i])(" << argsLocal <<
");\n";
492 printLoopEndOpenMP(_cache, hessInfo.size());
496 assert(multiThreadingType == MultiThreadingType::PTHREADS);
498 printFunctionStartPThreads(_cache, hessInfo.size());
500 " for(i = 0; i < " << hessInfo.size() <<
"; ++i) {\n" 501 " args[i] = (ExecArgStruct*) malloc(sizeof(ExecArgStruct));\n" 502 " args[i]->func = p[i];\n" 503 " args[i]->in = inLocal;\n" 504 " args[i]->out[0] = &hess[offset[i]];\n" 505 " args[i]->atomicFun = " << langC .getArgumentAtomic() <<
";\n" 508 printFunctionEndPThreads(_cache, hessInfo.size());
518 std::vector<size_t>& evalCols) {
524 evalRows.reserve(_hessSparsity.rows.size());
525 evalCols.reserve(_hessSparsity.cols.size());
527 for (
size_t e = 0; e < _hessSparsity.rows.size(); e++) {
528 size_t i = _hessSparsity.rows[e];
529 size_t j = _hessSparsity.cols[e];
530 if (_hessSparsity.sparsity[i].find(j) == _hessSparsity.sparsity[i].end() &&
531 _hessSparsity.sparsity[j].find(i) != _hessSparsity.sparsity[j].end()) {
534 evalRows.push_back(j);
535 evalCols.push_back(i);
537 evalRows.push_back(i);
538 evalCols.push_back(j);
545 if (_hessSparsity.sparsity.size() > 0) {
549 size_t m = _fun.Range();
550 size_t n = _fun.Domain();
555 SparsitySetType r(n);
556 for (
size_t j = 0; j < n; j++)
558 SparsitySetType jac = _fun.ForSparseJac(n, r);
560 SparsitySetType s(1);
561 for (
size_t i = 0; i < m; i++) {
564 _hessSparsity.sparsity = _fun.RevSparseHes(n, s,
false);
567 if (_hessianByEquation || _reverseTwo) {
572 std::set<size_t> customVarsInHess;
573 if (_custom_hess.defined) {
574 customVarsInHess.insert(_custom_hess.row.begin(), _custom_hess.row.end());
575 customVarsInHess.insert(_custom_hess.col.begin(), _custom_hess.col.end());
577 r = SparsitySetType(n);
578 for (
size_t j : customVarsInHess) {
581 jac = _fun.ForSparseJac(n, r);
587 const std::vector<Color> colors = colorByRow(customVarsInHess, jac);
592 _hessSparsities.resize(m);
593 for (
size_t i = 0; i < m; i++) {
594 _hessSparsities[i].sparsity.resize(n);
597 for (
size_t c = 0; c < colors.size(); c++) {
598 const Color& color = colors[c];
601 r = SparsitySetType(n);
605 _fun.ForSparseJac(n, r);
609 const std::set<size_t>& equations = color.
rows;
610 for (
size_t i : equations) {
614 SparsitySetType sparsityc = _fun.RevSparseHes(n, s,
false);
619 const std::map<size_t, size_t>& var2Eq = color.
column2Row;
621 if (sparsityc[j].size() > 0) {
622 size_t i = var2Eq.at(j);
623 _hessSparsities[i].sparsity[j].insert(sparsityc[j].begin(),
630 for (
size_t i = 0; i < m; i++) {
633 if (!_custom_hess.defined) {
634 generateSparsityIndexes(hessSparsitiesi.
sparsity,
635 hessSparsitiesi.rows, hessSparsitiesi.cols);
638 size_t nnz = _custom_hess.row.size();
639 for (
size_t e = 0; e < nnz; e++) {
640 size_t i1 = _custom_hess.row[e];
641 size_t i2 = _custom_hess.col[e];
642 if (hessSparsitiesi.
sparsity[i1].find(i2) != hessSparsitiesi.
sparsity[i1].end()) {
643 hessSparsitiesi.rows.push_back(i1);
644 hessSparsitiesi.cols.push_back(i2);
652 if (!_custom_hess.defined) {
653 generateSparsityIndexes(_hessSparsity.sparsity,
654 _hessSparsity.rows, _hessSparsity.cols);
657 _hessSparsity.rows = _custom_hess.row;
658 _hessSparsity.cols = _custom_hess.col;
664 determineHessianSparsity();
666 generateSparsity2DSource(_name +
"_" + FUNCTION_HESSIAN_SPARSITY, _hessSparsity);
667 _sources[_name +
"_" + FUNCTION_HESSIAN_SPARSITY +
".c"] = _cache.str();
670 if (_hessianByEquation || _reverseTwo) {
671 generateSparsity2DSource2(_name +
"_" + FUNCTION_HESSIAN_SPARSITY2, _hessSparsities);
672 _sources[_name +
"_" + FUNCTION_HESSIAN_SPARSITY2 +
".c"] = _cache.str();
std::set< size_t > rows
all row with this color
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={})
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 setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
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()