1 #ifndef CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_REV1_INCLUDED 2 #define CPPAD_CG_MODEL_C_SOURCE_GEN_LOOPS_REV1_INCLUDED 37 size_t n = _fun.Domain();
40 handler.setJobTimer(_jobTimer);
43 auto& indexJrowDcl = *handler.makeIndexDclrNode(
"jrow");
45 auto& iterationIndexOp = *handler.makeIndexNode(indexIterationDcl);
46 auto& jrowIndexOp = *handler.makeIndexNode(indexJrowDcl);
48 std::vector<OperationNode<Base>*> localNodes(4);
49 localNodes[0] = &indexJrowDcl;
50 localNodes[1] = &indexIterationDcl;
51 localNodes[2] = &iterationIndexOp;
52 localNodes[3] = &jrowIndexOp;
54 size_t nonIndexdedEqSize = _funNoLoops !=
nullptr ? _funNoLoops->getOrigDependentIndexes().size() : 0;
56 std::vector<set<size_t> > noLoopEvalSparsity;
57 std::vector<map<size_t, set<size_t> > > noLoopEvalLocations;
58 map<LoopModel<Base>*, std::vector<set<size_t> > > loopsEvalSparsities;
59 map<LoopModel<Base>*, std::vector<JacobianWithLoopsRowInfo> > loopEqInfo;
61 size_t nnz = _jacSparsity.rows.size();
62 std::vector<size_t> rows(nnz);
63 std::vector<size_t> cols(nnz);
64 std::vector<size_t> locations(nnz);
67 for (
const auto& itI : elements) {
69 const std::vector<size_t>& r = itI.second;
71 for (
size_t e = 0; e < r.size(); e++) {
78 CPPADCG_ASSERT_UNKNOWN(p == nnz);
80 analyseSparseJacobianWithLoops(rows, cols, locations,
81 noLoopEvalSparsity, noLoopEvalLocations, loopsEvalSparsities, loopEqInfo);
83 std::vector<CGBase> x(n);
86 for (
size_t i = 0; i < n; i++) {
105 std::vector<CGBase> tmps;
108 std::vector<map<size_t, CGBase> > dzDx(_funNoLoops !=
nullptr ? _funNoLoops->getTemporaryDependentCount() : 0);
113 if (_funNoLoops !=
nullptr) {
119 std::vector<CGBase> depNL = _funNoLoops->getTape().Forward(0, x);
121 tmps.resize(depNL.size() - nonIndexdedEqSize);
122 for (
size_t i = 0; i < tmps.size(); i++)
123 tmps[i] = depNL[nonIndexdedEqSize + i];
128 bool hasAtomics = isAtomicsUsed();
129 std::vector<map<size_t, CGBase> > dydx = generateLoopRev1Jac(fun, _funNoLoops->getJacobianSparsity(), noLoopEvalSparsity, x, hasAtomics);
131 const std::vector<size_t>& dependentIndexes = _funNoLoops->getOrigDependentIndexes();
132 map<size_t, std::vector<CGBase> > jacNl;
134 for (
size_t inl = 0; inl < nonIndexdedEqSize; inl++) {
135 size_t i = dependentIndexes[inl];
138 std::vector<CGBase>& row = jacNl[i];
139 row.resize(dydx[inl].size());
141 for (
const auto& itjv : dydx[inl]) {
142 size_t j = itjv.first;
144 const set<size_t>& locations = noLoopEvalLocations[inl][j];
146 CPPADCG_ASSERT_UNKNOWN(locations.size() == 1);
147 size_t e = *locations.begin();
149 row[e] = itjv.second * py;
151 _nonLoopRev1Elements[i].insert(e);
156 for (
size_t inl = nonIndexdedEqSize; inl < dydx.size(); inl++) {
157 size_t k = inl - nonIndexdedEqSize;
159 for (
const auto& itjv : dydx[inl]) {
160 size_t j = itjv.first;
161 dzDx[k][j] = itjv.second;
168 typename map<size_t, std::vector<CGBase> >::iterator itJ;
169 for (itJ = jacNl.begin(); itJ != jacNl.end(); ++itJ) {
170 createReverseOneWithLoopsNL(handler, itJ->first, itJ->second);
177 typename map<LoopModel<Base>*, std::vector<JacobianWithLoopsRowInfo> >::iterator itl2Eq;
178 for (itl2Eq = loopEqInfo.begin(); itl2Eq != loopEqInfo.end(); ++itl2Eq) {
180 const std::vector<JacobianWithLoopsRowInfo>& info = itl2Eq->second;
182 const std::vector<std::vector<LoopPosition> >& dependentIndexes = lModel.
getDependentIndexes();
186 _cache <<
"model (reverse one, loop " << lModel.
getLoopId() <<
")";
187 std::string jobName = _cache.str();
192 startingJob(
"'" + jobName +
"'", JobTimer::GRAPH);
194 std::vector<CGBase> indexedIndeps = createIndexedIndependents(handler, lModel, iterationIndexOp);
195 std::vector<CGBase> xl = createLoopIndependentVector(handler, lModel, indexedIndeps, x, tmps);
197 bool hasAtomics = isAtomicsUsed();
198 std::vector<map<size_t, CGBase> > dyiDxtape = generateLoopRev1Jac(fun, lModel.getJacobianSparsity(), loopsEvalSparsities[&lModel], xl, hasAtomics);
205 std::vector<std::pair<CGBase, IndexPattern*> > indexedLoopResults;
206 for (
size_t tapeI = 0; tapeI < info.size(); tapeI++) {
209 size_t maxRowEls = rowInfo.indexedPositions.size() + rowInfo.nonIndexedPositions.size();
216 map<size_t, size_t> irow2It;
217 for (
size_t it = 0; it < nIterations; it++) {
218 size_t i = dependentIndexes[tapeI][it].original;
219 if (i < _fun.Range())
224 auto* iterationIndexPatternOp = handler.makeIndexAssignNode(indexIterationDcl, *itPattern.get(), jrowIndexOp);
225 iterationIndexOp.makeAssigmentDependent(*iterationIndexPatternOp);
230 std::set<size_t> allLocations;
231 indexedLoopResults.resize(maxRowEls);
234 std::vector<IfElseInfo<Base> > ifElses;
236 prepareSparseJacobianRowWithLoops(handler, lModel,
240 iterationIndexOp, ifElses,
241 jacLE, indexedLoopResults, allLocations);
242 indexedLoopResults.resize(jacLE);
244 std::vector<CGBase> pxCustom(indexedLoopResults.size());
246 for (
size_t i = 0; i < indexedLoopResults.size(); i++) {
247 const CGBase& val = indexedLoopResults[i].first;
250 pxCustom[i] = createLoopDependentFunctionResult(handler, i, val, ip, iterationIndexOp);
256 std::map<size_t, std::set<size_t> >& row2position = _loopRev1Groups[&lModel][tapeI];
258 for (
size_t it = 0; it < nIterations; it++) {
259 size_t i = dependentIndexes[tapeI][it].original;
260 if (i < _fun.Range()) {
261 std::set<size_t> positions;
263 for (
const auto& itc : rowInfo.indexedPositions) {
264 const std::vector<size_t>& positionsC = itc.second;
265 if (positionsC[it] != (std::numeric_limits<size_t>::max)())
266 positions.insert(positionsC[it]);
268 for (
const auto& itc : rowInfo.nonIndexedPositions) {
269 const std::vector<size_t>& positionsC = itc.second;
270 if (positionsC[it] != (std::numeric_limits<size_t>::max)())
271 positions.insert(positionsC[it]);
274 if (!positions.empty())
275 row2position[i].swap(positions);
283 langC.setFunctionIndexArgument(indexJrowDcl);
287 std::ostringstream code;
288 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"dw"));
295 _cache <<
"model (reverse one, loop " << lModel.
getLoopId() <<
", group " << tapeI <<
")";
296 string jobName = _cache.str();
297 handler.
generateCode(code, langC, pxCustom, nameGenHess, _atomicFunctions, jobName);
300 generateFunctionNameLoopRev1(_cache, lModel, tapeI);
301 std::string functionName = _cache.str();
303 std::string argsDcl = langC.generateFunctionArgumentsDcl();
306 _cache <<
"#include <stdlib.h>\n" 307 "#include <math.h>\n" 311 "void " << functionName <<
"(" << argsDcl <<
") {\n";
312 nameGenHess.customFunctionVariableDeclarations(_cache);
313 _cache << langC.generateIndependentVariableDeclaration() <<
"\n";
314 _cache << langC.generateDependentVariableDeclaration() <<
"\n";
315 _cache << langC.generateTemporaryVariableDeclaration(
false,
false,
318 nameGenHess.prepareCustomFunctionVariables(_cache);
321 _cache << code.str();
323 nameGenHess.finalizeCustomFunctionVariables(_cache);
326 _sources[functionName +
".c"] = _cache.str();
332 if (tapeI + 1 < info.size() || &lModel != loopEqInfo.rbegin()->first) {
342 string functionRev1 = _name +
"_" + FUNCTION_SPARSE_REVERSE_ONE;
343 _sources[functionRev1 +
".c"] = generateGlobalForRevWithLoopsFunctionSource(elements,
344 _loopRev1Groups, _nonLoopRev1Elements,
345 functionRev1, _name, _baseTypeName,
"dep",
346 generateFunctionNameLoopRev1);
351 generateSparsity1DSource2(_name +
"_" + FUNCTION_REVERSE_ONE_SPARSITY, elements);
352 _sources[_name +
"_" + FUNCTION_REVERSE_ONE_SPARSITY +
".c"] = _cache.str();
360 size_t n = _fun.Domain();
363 _cache <<
"model (forward one, dep " << i <<
") no loop";
364 const std::string jobName = _cache.str();
370 _cache << _name <<
"_" << FUNCTION_SPARSE_REVERSE_ONE <<
"_noloop_dep" << i;
371 langC.setGenerateFunction(_cache.str());
373 std::ostringstream code;
374 std::unique_ptr<VariableNameGenerator<Base> > nameGen(createVariableNameGenerator(
"dw"));
377 handler.
generateCode(code, langC, jacRow, nameGenHess, _atomicFunctions, jobName);
384 const SparsitySetType& sparsity,
385 const SparsitySetType& evalSparsity,
386 const std::vector<CGBase>& x,
387 bool constainsAtomics) {
390 size_t m = fun.Range();
392 std::vector<map<size_t, CGBase> > dyDx(m);
394 if (!constainsAtomics) {
395 std::vector<size_t> row, col;
396 generateSparsityIndexes(evalSparsity, row, col);
401 std::vector<CGBase> jacLoop(row.size());
403 CppAD::sparse_jacobian_work work;
404 fun.SparseJacobianReverse(x, sparsity, row, col, jacLoop, work);
407 for (
size_t el = 0; el < jacLoop.size(); el++) {
410 dyDx[i][j] = jacLoop[el];
415 std::vector<CGBase> w(m);
417 for (
size_t i = 0; i < m; i++) {
418 const set<size_t>& row = evalSparsity[i];
426 std::vector<CGBase> dw = fun.Reverse(1, w);
427 CPPADCG_ASSERT_UNKNOWN(dw.size() == fun.Domain());
430 map<size_t, CGBase>& dyIDx = dyDx[i];
432 for (
size_t j : row) {
446 generateFunctionNameLoopRev1(cache, _name, loop, tapeI);
451 const std::string& modelName,
454 cache << modelName <<
"_" << FUNCTION_SPARSE_REVERSE_ONE <<
455 "_loop" << loop.
getLoopId() <<
"_g" << tapeI;
void setValue(const Base &val)
ADFun< CGB > & getTape() const
const std::vector< int > & getExternalFuncMaxForwardOrder() const
static IndexPattern * detect(const VectorSizeT &x2y)
void makeVariables(VectorCG &variables)
virtual void setMaxAssignmentsPerFunction(size_t maxAssignmentsPerFunction, std::map< std::string, std::string > *sources)
void makeVariable(AD< CGB > &variable)
virtual void setParameterPrecision(size_t p)
const size_t getIterationCount() const
void setZeroDependents(bool zeroDependents)
const std::vector< std::vector< LoopPosition > > & getDependentIndexes() const
const std::vector< int > & getExternalFuncMaxReverseOrder() const
virtual void prepareSparseReverseOneWithLoops(const std::map< size_t, std::vector< size_t > > &elements)
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")