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