1 #ifndef CPPAD_CG_EVALUATOR_INCLUDED
2 #define CPPAD_CG_EVALUATOR_INCLUDED
23 template<
class ScalarIn,
class ScalarOut,
class ActiveOut,
class FinalEvaluatorType>
26 template<
class ScalarIn,
class ScalarOut,
class ActiveOut,
class Operations>
44 template<
class ScalarIn,
class ScalarOut,
class ActiveOut,
class FinalEvaluatorType>
46 friend FinalEvaluatorType;
51 const ActiveOut* indep_;
53 std::map<size_t, std::vector<ActiveOut>* > evalsArrays_;
54 std::map<size_t, std::vector<ActiveOut>* > evalsSparseArrays_;
95 std::vector<ActiveOut> depNew(depOld.size());
97 evaluate(indepNew.
data(), indepNew.
size(), depNew.data(), depOld.data(), depNew.size());
117 if (depNew.
size() != depOld.size()) {
118 throw CGException(
"Dependent array sizes are different.");
149 throw CGException(
"The same evaluator cannot be used for simultaneous evaluations. "
150 "Either use a new one or wait for this one to finish its current evaluation.");
161 if(path_.capacity() == 0) {
165 FinalEvaluatorType& thisOps =
static_cast<FinalEvaluatorType&
>(*this);
168 thisOps.prepareNewEvaluation();
171 thisOps.analyzeOutIndeps(indep_, indepSize);
173 for (
size_t i = 0; i < depSize; i++) {
174 CPPADCG_ASSERT_UNKNOWN(depth_ == 0);
175 depNew[i] = evalCG(depOld[i]);
190 inline void prepareNewEvaluation() {
200 for (
const auto& p : evalsArrays_) {
203 evalsArrays_.clear();
205 for (
const auto& p : evalsSparseArrays_) {
208 evalsSparseArrays_.clear();
211 inline void analyzeOutIndeps(
const ActiveOut* indep,
216 inline ActiveOut evalCG(
const CG<ScalarIn>& dep) {
217 if (dep.isParameter()) {
219 return ActiveOut(dep.getValue());
221 return evalOperations(*dep.getOperationNode());
225 inline ActiveOut evalArg(
const std::vector<Argument<ScalarIn> >& args,
227 return evalArg(args[pos], pos);
230 inline ActiveOut evalArg(
const Argument<ScalarIn>& arg,
232 if (arg.getOperation() !=
nullptr) {
233 path_.back().argIndex = pos;
234 ActiveOut a = evalOperations(*arg.getOperation());
238 return ActiveOut(*arg.getParameter());
242 inline const ActiveOut& evalOperations(OperationNode<ScalarIn>& node) {
243 CPPADCG_ASSERT_KNOWN(node.getHandlerPosition() < handler_.
getManagedNodesCount(),
"this node is not managed by the code handler")
246 if (evals_[node] !=
nullptr) {
247 return *evals_[node];
251 FinalEvaluatorType& thisOps =
static_cast<FinalEvaluatorType&
>(*this);
253 path_.push_back(OperationPathNode<ScalarIn>(&node, -1));
256 ActiveOut result = thisOps.evalOperation(node);
259 ActiveOut* resultPtr = saveEvaluation(node, ActiveOut(result));
267 inline ActiveOut* saveEvaluation(
const OperationNode<ScalarIn>& node,
268 ActiveOut&& result) {
269 std::unique_ptr<ActiveOut>& resultPtr = evals_[node];
270 CPPADCG_ASSERT_UNKNOWN(resultPtr ==
nullptr);
271 resultPtr.reset(
new ActiveOut(std::move(result)));
273 ActiveOut* resultPtr2 = resultPtr.get();
275 FinalEvaluatorType& thisOps =
static_cast<FinalEvaluatorType&
>(*this);
276 thisOps.processActiveOut(node, *resultPtr2);
281 inline std::vector<ActiveOut>& evalArrayCreationOperation(
const OperationNode<ScalarIn>& node) {
283 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::ArrayCreation,
"Invalid array creation operation");
284 CPPADCG_ASSERT_KNOWN(node.getHandlerPosition() < handler_.
getManagedNodesCount(),
"this node is not managed by the code handler")
287 auto it = evalsArrays_.find(node.getHandlerPosition());
288 if (it != evalsArrays_.end()) {
292 const std::vector<Argument<ScalarIn> >& args = node.getArguments();
293 auto* resultArray =
new std::vector<ActiveOut>(args.size());
296 evalsArrays_[node.getHandlerPosition()] = resultArray;
299 for (
size_t a = 0; a < args.size(); a++) {
300 (*resultArray)[a] = evalArg(args, a);
306 inline std::vector<ActiveOut>& evalSparseArrayCreationOperation(
const OperationNode<ScalarIn>& node) {
308 CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::SparseArrayCreation,
"Invalid array creation operation");
309 CPPADCG_ASSERT_KNOWN(node.getHandlerPosition() < handler_.
getManagedNodesCount(),
"this node is not managed by the code handler")
312 auto it = evalsSparseArrays_.find(node.getHandlerPosition());
313 if (it != evalsSparseArrays_.end()) {
317 const std::vector<Argument<ScalarIn> >& args = node.getArguments();
318 auto* resultArray =
new std::vector<ActiveOut>(args.size());
321 evalsSparseArrays_[node.getHandlerPosition()] = resultArray;
324 for (
size_t a = 0; a < args.size(); a++) {
325 (*resultArray)[a] = evalArg(args, a);
344 template<
class ScalarIn,
class ScalarOut,
class ActiveOut,
class FinalEvaluatorType>
345 class EvaluatorOperations :
public EvaluatorBase<ScalarIn, ScalarOut, ActiveOut, FinalEvaluatorType> {
350 friend class EvaluatorBase<ScalarIn, ScalarOut, ActiveOut, FinalEvaluatorType>;
375 FinalEvaluatorType& thisOps =
static_cast<FinalEvaluatorType&
>(*this);
379 case CGOpCode::Assign:
380 return thisOps.evalAssign(node);
383 return thisOps.evalAbs(node);
386 return thisOps.evalAcos(node);
389 return thisOps.evalAdd(node);
391 case CGOpCode::Alias:
392 return thisOps.evalAlias(node);
395 case CGOpCode::ArrayElement:
396 return thisOps.evalArrayElement(node);
399 return thisOps.evalAsin(node);
402 return thisOps.evalAtan(node);
406 case CGOpCode::ComLt:
407 return thisOps.evalCompareLt(node);
409 case CGOpCode::ComLe:
410 return thisOps.evalCompareLe(node);
412 case CGOpCode::ComEq:
413 return thisOps.evalCompareEq(node);
415 case CGOpCode::ComGe:
416 return thisOps.evalCompareGe(node);
418 case CGOpCode::ComGt:
419 return thisOps.evalCompareGt(node);
421 case CGOpCode::ComNe:
422 return thisOps.evalCompareNe(node);
425 return thisOps.evalCosh(node);
428 return thisOps.evalCos(node);
431 return thisOps.evalDiv(node);
434 return thisOps.evalExp(node);
437 return thisOps.evalIndependent(node);
440 return thisOps.evalLog(node);
443 return thisOps.evalMul(node);
446 return thisOps.evalPow(node);
449 return thisOps.evalPrint(node);
453 return thisOps.evalSign(node);
456 return thisOps.evalSinh(node);
459 return thisOps.evalSin(node);
462 return thisOps.evalSqrt(node);
465 return thisOps.evalSub(node);
468 return thisOps.evalTanh(node);
471 return thisOps.evalTan(node);
473 case CGOpCode::UnMinus:
474 return thisOps.evalMinus(node);
477 return thisOps.evalUnsupportedOperation(node);
481 inline ActiveOut evalAssign(
const NodeIn& node) {
482 const std::vector<ArgIn>& args = node.getArguments();
483 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for assign()")
484 return evalArg(args, 0);
487 inline ActiveOut evalAbs(const NodeIn& node) {
488 const std::vector<ArgIn>& args = node.getArguments();
489 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for abs()")
490 return abs(evalArg(args, 0));
493 inline ActiveOut evalAcos(const NodeIn& node) {
494 const std::vector<ArgIn>& args = node.getArguments();
495 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for acos()")
496 return acos(evalArg(args, 0));
499 inline ActiveOut evalAdd(const NodeIn& node) {
500 const std::vector<ArgIn>& args = node.getArguments();
501 CPPADCG_ASSERT_KNOWN(args.size() == 2,
"Invalid number of arguments for addition")
502 return evalArg(args, 0) + evalArg(args, 1);
505 inline ActiveOut evalAlias(const NodeIn& node) {
506 const std::vector<ArgIn>& args = node.getArguments();
507 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for alias")
508 return evalArg(args, 0);
511 inline ActiveOut evalArrayElement(const NodeIn& node) {
512 const std::vector<ArgIn>& args = node.getArguments();
513 const std::vector<size_t>& info = node.getInfo();
514 CPPADCG_ASSERT_KNOWN(args.size() == 2,
"Invalid number of arguments for array element")
515 CPPADCG_ASSERT_KNOWN(args[0].getOperation() !=
nullptr, "Invalid argument for array element");
516 CPPADCG_ASSERT_KNOWN(args[1].getOperation() !=
nullptr, "Invalid argument for array element");
517 CPPADCG_ASSERT_KNOWN(info.size() == 1, "Invalid number of information data for array element")
518 size_t index = info[0];
519 std::
vector<ActiveOut>& array = this->evalArrayCreationOperation(*args[0].getOperation());
521 FinalEvaluatorType& thisOps = static_cast<FinalEvaluatorType&>(*this);
522 thisOps.evalAtomicOperation(*args[1].getOperation());
527 inline ActiveOut evalAsin(const NodeIn& node) {
528 const std::vector<ArgIn>& args = node.getArguments();
529 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for asin()")
530 return asin(evalArg(args, 0));
533 inline ActiveOut evalAtan(const NodeIn& node) {
534 const std::vector<ArgIn>& args = node.getArguments();
535 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for atan()")
536 return atan(evalArg(args, 0));
539 inline ActiveOut evalCompareLt(const NodeIn& node) {
540 const std::vector<ArgIn>& args = node.getArguments();
541 CPPADCG_ASSERT_KNOWN(args.size() == 4,
"Invalid number of arguments for CondExpOp(CompareLt, )")
542 return CondExpOp(CompareLt, evalArg(args, 0), evalArg(args, 1), evalArg(args, 2), evalArg(args, 3));
545 inline ActiveOut evalCompareLe(const NodeIn& node) {
546 const std::vector<ArgIn>& args = node.getArguments();
547 CPPADCG_ASSERT_KNOWN(args.size() == 4,
"Invalid number of arguments for CondExpOp(CompareLe, )")
548 return CondExpOp(CompareLe, evalArg(args, 0), evalArg(args, 1), evalArg(args, 2), evalArg(args, 3));
551 inline ActiveOut evalCompareEq(const NodeIn& node) {
552 const std::vector<ArgIn>& args = node.getArguments();
553 CPPADCG_ASSERT_KNOWN(args.size() == 4,
"Invalid number of arguments for CondExpOp(CompareEq, )")
554 return CondExpOp(CompareEq, evalArg(args, 0), evalArg(args, 1), evalArg(args, 2), evalArg(args, 3));
557 inline ActiveOut evalCompareGe(const NodeIn& node) {
558 const std::vector<ArgIn>& args = node.getArguments();
559 CPPADCG_ASSERT_KNOWN(args.size() == 4,
"Invalid number of arguments for CondExpOp(CompareGe, )")
560 return CondExpOp(CompareGe, evalArg(args, 0), evalArg(args, 1), evalArg(args, 2), evalArg(args, 3));
563 inline ActiveOut evalCompareGt(const NodeIn& node) {
564 const std::vector<ArgIn>& args = node.getArguments();
565 CPPADCG_ASSERT_KNOWN(args.size() == 4,
"Invalid number of arguments for CondExpOp(CompareGt, )")
566 return CondExpOp(CompareGt, evalArg(args, 0), evalArg(args, 1), evalArg(args, 2), evalArg(args, 3));
569 inline ActiveOut evalCompareNe(const NodeIn& node) {
570 const std::vector<ArgIn>& args = node.getArguments();
571 CPPADCG_ASSERT_KNOWN(args.size() == 4,
"Invalid number of arguments for CondExpOp(CompareNe, )")
572 return CondExpOp(CompareNe, evalArg(args, 0), evalArg(args, 1), evalArg(args, 2), evalArg(args, 3));
575 inline ActiveOut evalCosh(const NodeIn& node) {
576 const std::vector<ArgIn>& args = node.getArguments();
577 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for cosh()")
578 return cosh(evalArg(args, 0));
581 inline ActiveOut evalCos(const NodeIn& node) {
582 const std::vector<ArgIn>& args = node.getArguments();
583 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for cos()")
584 return cos(evalArg(args, 0));
587 inline ActiveOut evalDiv(const NodeIn& node) {
588 const std::vector<ArgIn>& args = node.getArguments();
589 CPPADCG_ASSERT_KNOWN(args.size() == 2,
"Invalid number of arguments for division")
590 return evalArg(args, 0) / evalArg(args, 1);
593 inline ActiveOut evalExp(const NodeIn& node) {
594 const std::vector<ArgIn>& args = node.getArguments();
595 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for exp()")
596 return exp(evalArg(args, 0));
599 inline ActiveOut evalIndependent(const NodeIn& node) {
601 return this->indep_[index];
604 inline ActiveOut evalLog(
const NodeIn& node) {
605 const std::vector<ArgIn>& args = node.getArguments();
606 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for log()")
607 return log(evalArg(args, 0));
610 inline ActiveOut evalMul(const NodeIn& node) {
611 const std::vector<ArgIn>& args = node.getArguments();
612 CPPADCG_ASSERT_KNOWN(args.size() == 2,
"Invalid number of arguments for multiplication")
613 return evalArg(args, 0) * evalArg(args, 1);
616 inline ActiveOut evalPow(const NodeIn& node) {
617 const std::vector<ArgIn>& args = node.getArguments();
618 CPPADCG_ASSERT_KNOWN(args.size() == 2,
"Invalid number of arguments for pow()")
619 return
pow(evalArg(args, 0), evalArg(args, 1));
622 inline ActiveOut evalPrint(const NodeIn& node) {
623 FinalEvaluatorType& thisOps =
static_cast<FinalEvaluatorType&
>(*this);
624 return thisOps.evalUnsupportedOperation(node);
628 inline ActiveOut evalSign(
const NodeIn& node) {
629 const std::vector<ArgIn>& args = node.getArguments();
630 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for sign()")
631 return
sign(evalArg(args, 0));
634 inline ActiveOut evalSinh(const NodeIn& node) {
635 const std::vector<ArgIn>& args = node.getArguments();
636 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for sinh()")
637 return sinh(evalArg(args, 0));
640 inline ActiveOut evalSin(const NodeIn& node) {
641 const std::vector<ArgIn>& args = node.getArguments();
642 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for sin()")
643 return sin(evalArg(args, 0));
646 inline ActiveOut evalSqrt(const NodeIn& node) {
647 const std::vector<ArgIn>& args = node.getArguments();
648 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for sqrt()")
649 return sqrt(evalArg(args, 0));
652 inline ActiveOut evalSub(const NodeIn& node) {
653 const std::vector<ArgIn>& args = node.getArguments();
654 CPPADCG_ASSERT_KNOWN(args.size() == 2,
"Invalid number of arguments for subtraction")
655 return evalArg(args, 0) - evalArg(args, 1);
658 inline ActiveOut evalTanh(const NodeIn& node) {
659 const std::vector<ArgIn>& args = node.getArguments();
660 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for tanh()")
661 return tanh(evalArg(args, 0));
664 inline ActiveOut evalTan(const NodeIn& node) {
665 const std::vector<ArgIn>& args = node.getArguments();
666 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for tan()")
667 return tan(evalArg(args, 0));
670 inline ActiveOut evalMinus(const NodeIn& node) {
671 const std::vector<ArgIn>& args = node.getArguments();
672 CPPADCG_ASSERT_KNOWN(args.size() == 1,
"Invalid number of arguments for unary minus")
673 return -evalArg(args, 0);
676 inline ActiveOut evalUnsupportedOperation(const NodeIn& node) {
677 throw CGException(
"Unknown operation code '", node.getOperationType(),
"'");
680 inline void evalAtomicOperation(
const NodeIn& node) {
681 throw CGException(
"Evaluator is unable to handle atomic functions for these variable types");
684 inline void processActiveOut(
const NodeIn& node,
693 template<
class ScalarIn,
class ScalarOut,
class ActiveOut = CppAD::AD<ScalarOut> >
694 class Evaluator :
public EvaluatorOperations<ScalarIn, ScalarOut, ActiveOut, Evaluator<ScalarIn, ScalarOut, ActiveOut> > {
696 using Base = EvaluatorOperations<ScalarIn, ScalarOut, ActiveOut, Evaluator<ScalarIn, ScalarOut, ActiveOut> >;
699 inline Evaluator(CodeHandler<ScalarIn>& handler) :
703 inline virtual ~Evaluator() =
default;