CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
evaluator_cg.hpp
1#ifndef CPPAD_CG_EVALUATOR_CG_INCLUDED
2#define CPPAD_CG_EVALUATOR_CG_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2016 Ciengis
6 * Copyright (C) 2020 Joao Leal
7 *
8 * CppADCodeGen is distributed under multiple licenses:
9 *
10 * - Eclipse Public License Version 1.0 (EPL1), and
11 * - GNU General Public License Version 3 (GPL3).
12 *
13 * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14 * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15 * ----------------------------------------------------------------------------
16 * Author: Joao Leal
17 */
18
19namespace CppAD {
20namespace cg {
21
26template<class ScalarIn, class ScalarOut, class FinalEvaluatorType>
27class EvaluatorCG : public EvaluatorOperations<ScalarIn, ScalarOut, CG<ScalarOut>, FinalEvaluatorType> {
32 friend EvaluatorBase<ScalarIn, ScalarOut, CG<ScalarOut>, FinalEvaluatorType>;
34public:
35 using ActiveIn = CG<ScalarIn>;
41protected:
43protected:
51 std::map<const NodeIn*, std::vector<ScalarOut*>> atomicEvalResults_;
57 using EvaluatorBase<ScalarIn, ScalarOut, CG<ScalarOut>, FinalEvaluatorType>::evals_;
58public:
59
60 inline EvaluatorCG(CodeHandler<ScalarIn>& handler) :
61 Super(handler),
62 outHandler_(nullptr),
64 }
65
70 inline void setPrintOutPrintOperations(bool print) {
72 }
73
78 inline bool isPrintOutPrintOperations() const {
80 }
81
82protected:
83
88 inline void analyzeOutIndeps(const ActiveOut* indep,
89 size_t n) {
90 CPPAD_ASSERT_KNOWN(indep != nullptr || n == 0, "null array with a non-zero size");
91 outHandler_ = findHandler(ArrayView<const ActiveOut>(indep, n));
92 }
93
98 inline void clear() {
100
101 for (const auto& it : atomicEvalResults_) {
102 for (const ScalarOut* e : it.second) {
103 delete e;
104 }
105 }
106 atomicEvalResults_.clear();
107 }
108
109
114 void processActiveOut(const NodeIn& node,
115 ActiveOut& a) {
116 if (node.getName() != nullptr) {
117 if (a.getOperationNode() != nullptr) {
118 a.getOperationNode()->setName(*node.getName());
119 }
120 }
121 }
122
127 inline ActiveOut evalPrint(const NodeIn& node) {
128 const std::vector<ArgIn>& args = node.getArguments();
129 CPPADCG_ASSERT_KNOWN(args.size() == 1, "Invalid number of arguments for print()")
130 ActiveOut out(this->evalArg(args, 0));
131
133 const auto& nodePri = static_cast<const PrintOperationNode<ScalarIn>&>(node);
134 std::cout << nodePri.getBeforeString() << out << nodePri.getAfterString();
135 }
136
137 if (out.getOperationNode() != nullptr) {
138 const auto& nodePri = static_cast<const PrintOperationNode<ScalarIn>&>(node);
139 ActiveOut out2(*outHandler_->makePrintNode(nodePri.getBeforeString(), *out.getOperationNode(), nodePri.getAfterString()));
140 if (out.isValueDefined())
141 out2.setValue(out.getValue());
142 return out2;
143 }
144
145 return out;
146 }
147
152 void evalAtomicOperation(const NodeIn& node) {
153 CGOpCode op = node.getOperationType();
154 CPPADCG_ASSERT_KNOWN(op == CGOpCode::AtomicForward || op == CGOpCode::AtomicReverse,
155 "Invalid operation type")
156
157 // check if this node was previously determined
158 if (evals_[node] != nullptr) {
159 return; // *evals_[node];
160 }
161
162 const std::vector<size_t>& info = node.getInfo();
163 const std::vector<Argument<ScalarIn> >& inArgs = node.getArguments();
164
165 CPPADCG_ASSERT_KNOWN(info.size() == 3, "Invalid number of information data for atomic operation")
166 size_t p = info[2];
167 size_t p1 = p + 1;
168
169 CPPADCG_ASSERT_KNOWN(inArgs.size() == 2 * p1, "Invalid number of information data for atomic operation")
170
171 if (outHandler_ == nullptr) {
172 throw CGException("Evaluator is unable to determine the new CodeHandler for an atomic operation");
173 }
174
175 std::vector<Argument<ScalarOut> > outArgs(inArgs.size());
176
177 std::vector<std::vector<ScalarOut>> outVals(inArgs.size());
178 bool valuesDefined = true;
179 bool allParameters = true;
180
181 for (size_t i = 0; i < inArgs.size(); i++) {
182 auto* a = inArgs[i].getOperation();
183 CPPADCG_ASSERT_KNOWN(a != nullptr, "Invalid argument for atomic operation")
184
185 outArgs[i] = asArgument(makeArray(*a, outVals[i], valuesDefined, allParameters));
186 }
187
188 this->saveEvaluation(node, ActiveOut(*outHandler_->makeNode(op, info, outArgs)));
189
190 if (valuesDefined) {
191 const std::map<size_t, CGAbstractAtomicFun<ScalarIn>*>& afun = this->handler_.getAtomicFunctions();
192 size_t id = info[0];
193 size_t q = info[1];
194 if (op == CGOpCode::AtomicForward) {
195 auto itAFun = afun.find(id);
196 if (itAFun == afun.end()) {
197 if (allParameters)
198 throw CGException("Atomic function for ID ", id, " is not defined in evaluator");
199 else
200 return; // the atomic function is not available but it is not essential
201 }
202 auto& atomic = *itAFun->second;
203
204 CppAD::vector<bool> vx, vy;
205 CppAD::vector<ActiveOut> tx(outVals[0].size()), ty(outVals[1].size());
206 for (size_t i = 0; i < tx.size(); ++i)
207 tx[i] = ActiveIn(outVals[0][i]);
208 for (size_t i = 0; i < ty.size(); ++i)
209 ty[i] = ActiveIn(outVals[1][i]);
210
211 atomic.forward(q, p, vx, vy, tx, ty);
212
213 std::vector<ScalarOut*>& yOut = atomicEvalResults_[&node];
214 assert(yOut.empty());
215 yOut.resize(ty.size());
216 for (size_t i = 0; i < ty.size(); ++i) {
217 if (ty[i].isValueDefined())
218 yOut[i] = new ScalarOut(ty[i].getValue());
219 }
220 }
221 }
222
223 }
224
229 inline ActiveOut evalArrayElement(const NodeIn& node) {
230 // check if this node was previously determined
231 if (evals_[node] != nullptr) {
232 return *evals_[node];
233 }
234
235 const std::vector<ArgIn>& args = node.getArguments();
236 const std::vector<size_t>& info = node.getInfo();
237 CPPADCG_ASSERT_KNOWN(args.size() == 2, "Invalid number of arguments for array element")
238 CPPADCG_ASSERT_KNOWN(args[0].getOperation() != nullptr, "Invalid argument for array element")
239 CPPADCG_ASSERT_KNOWN(args[1].getOperation() != nullptr, "Invalid argument for array element")
240 CPPADCG_ASSERT_KNOWN(info.size() == 1, "Invalid number of information data for array element")
241 size_t index = info[0];
242
243 ArgOut arrayArg = asArgument(makeArray(*args[0].getOperation()));
244
245 auto& thisOps = static_cast<FinalEvaluatorType&>(*this);
246 const NodeIn& atomicNode = *args[1].getOperation();
247 thisOps.evalAtomicOperation(atomicNode); // atomic operation
248 ArgOut atomicArg = *evals_[atomicNode]->getOperationNode();
249
250 ActiveOut out(*outHandler_->makeNode(CGOpCode::ArrayElement, {index}, {arrayArg, atomicArg}));
251
252 auto it = atomicEvalResults_.find(&atomicNode);
253 if (it != atomicEvalResults_.end()) {
254 const std::vector<ScalarOut*>& yOut = it->second;
255 if (index < yOut.size() && yOut[index] != nullptr)
256 out.setValue(*yOut[index]);
257 }
258
259 return out;
260 }
261
262 inline ActiveOut makeArray(const NodeIn& node) {
263 if (node.getOperationType() == CGOpCode::ArrayCreation) {
264 return makeDenseArray(node);
265 } else {
266 return makeSparseArray(node);
267 }
268 }
269
270 inline ActiveOut makeArray(const NodeIn& node,
271 std::vector<ScalarOut>& values,
272 bool& valuesDefined,
273 bool& allParameters) {
274 const std::vector<ActiveOut>* arrayActiveOut;
275 ActiveOut result;
276
277 if (node.getOperationType() == CGOpCode::ArrayCreation) {
278 result = makeDenseArray(node);
279 arrayActiveOut = this->evalsArrays_[node.getHandlerPosition()];
280 } else {
281 result = makeSparseArray(node);
282 arrayActiveOut = this->evalsSparseArrays_[node.getHandlerPosition()];
283 }
284
285 processArray(*arrayActiveOut, values, valuesDefined, allParameters);
286
287 return result;
288 }
289
290 inline ActiveOut makeDenseArray(const NodeIn& node) {
291 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ArrayCreation, "Invalid array creation operation")
292 CPPADCG_ASSERT_KNOWN(node.getHandlerPosition() < this->handler_.getManagedNodesCount(), "this node is not managed by the code handler")
293
294 // check if this node was previously determined
295 if (evals_[node] != nullptr) {
296 return *evals_[node];
297 }
298
299 if (outHandler_ == nullptr) {
300 throw CGException("Evaluator is unable to determine the new CodeHandler for an array creation operation");
301 }
302
303 // values
304 const std::vector<ActiveOut>& array = this->evalArrayCreationOperation(node);
305
306 // makeDenseArray() never called directly by EvaluatorOperations
307 return *this->saveEvaluation(node, ActiveOut(*outHandler_->makeNode(CGOpCode::ArrayCreation, {}, asArguments(array))));
308 }
309
310 inline ActiveOut makeSparseArray(const NodeIn& node) {
311 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::SparseArrayCreation, "Invalid sparse array creation operation")
312 CPPADCG_ASSERT_KNOWN(node.getHandlerPosition() < this->handler_.getManagedNodesCount(), "this node is not managed by the code handler")
313
314 // check if this node was previously determined
315 if (evals_[node] != nullptr) {
316 return *evals_[node];
317 }
318
319 if (outHandler_ == nullptr) {
320 throw CGException("Evaluator is unable to determine the new CodeHandler for a sparse array creation operation");
321 }
322
323 // values
324 const std::vector<ActiveOut>& array = this->evalSparseArrayCreationOperation(node);
325
326 // makeSparseArray() never called directly by EvaluatorOperations
327 return *this->saveEvaluation(node, ActiveOut(*outHandler_->makeNode(CGOpCode::SparseArrayCreation, node.getInfo(), asArguments(array))));
328 }
329
330 static inline void processArray(const std::vector<ActiveOut>& array,
331 std::vector<ScalarOut>& values,
332 bool& valuesDefined,
333 bool& allParameters) {
334 values.resize(array.size());
335 for (size_t i = 0; i < array.size(); i++) {
336 if (!array[i].isValueDefined()) {
337 valuesDefined = false;
338 allParameters = false;
339 break;
340 } else {
341 values[i] = array[i].getValue();
342 if (!array[i].isParameter())
343 allParameters = false;
344 }
345 }
346 }
347
348 static inline bool isParameters(const CppAD::vector<ActiveOut>& tx) {
349 for (size_t i = 0; i < tx.size(); i++) {
350 if (!tx[i].isParameter()) {
351 return false;
352 }
353 }
354 return true;
355 }
356
357 static inline bool isValuesDefined(const std::vector<ArgOut>& tx) {
358 for (size_t i = 0; i < tx.size(); i++) {
359 if (tx[i].getOperationNode() != nullptr) {
360 return false;
361 }
362 }
363 return true;
364 }
365
366};
367
371template<class ScalarIn, class ScalarOut>
372class Evaluator<ScalarIn, ScalarOut, CG<ScalarOut> > : public EvaluatorCG<ScalarIn, ScalarOut, Evaluator<ScalarIn, ScalarOut, CG<ScalarOut> > > {
373protected:
375public:
376
377 inline Evaluator(CodeHandler<ScalarIn>& handler) :
378 Super(handler) {
379 }
380};
381
382} // END cg namespace
383} // END CppAD namespace
384
385#endif
void setValue(const Base &val)
Definition variable.hpp:54
const Base & getValue() const
Definition variable.hpp:45
bool isValueDefined() const
Definition variable.hpp:40
const std::map< size_t, CGAbstractAtomicFun< Base > * > & getAtomicFunctions() const
void evalAtomicOperation(const NodeIn &node)
void processActiveOut(const NodeIn &node, ActiveOut &a)
ActiveOut evalArrayElement(const NodeIn &node)
ActiveOut evalPrint(const NodeIn &node)
CodeHandler< ScalarOut > * outHandler_
bool isPrintOutPrintOperations() const
void analyzeOutIndeps(const ActiveOut *indep, size_t n)
std::map< const NodeIn *, std::vector< ScalarOut * > > atomicEvalResults_
void setPrintOutPrintOperations(bool print)
void setName(const std::string &name)
const std::vector< size_t > & getInfo() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const
const std::string * getName() const