27#include <ql/errors.hpp>
29#include <ql/shared_ptr.hpp>
35 const std::vector<std::function<std::vector<T>(
const std::vector<const T*>&,
const T*)>>& grad,
36 std::function<
void(T&)> deleter = {},
const std::vector<bool>& keepNodes = {},
37 const std::vector<std::function<T(
const std::vector<const T*>&)>>& fwdOps = {},
38 const std::vector<std::function<std::pair<std::vector<bool>,
bool>(
const std::size_t)>>&
39 fwdOpRequiresNodesForDerivatives = {},
40 const std::vector<bool>& fwdKeepNodes = {},
const std::size_t conditionalExpectationOpId = 0,
46 std::size_t redBlockId = 0;
50 for (std::size_t node = g.
size() - 1; node > 0; --node) {
56 if (deleter && redBlockId > 0) {
59 "backwardDerivatives(): red block " << redBlockId <<
" was not closed.");
60 for (std::size_t n = range.first; n < range.second; ++n) {
61 if (g.
redBlockId(n) == redBlockId && !fwdKeepNodes[n])
71 "backwardDerivatives(): red block " << g.
redBlockId(node) <<
" was not closed.");
72 forwardEvaluation(g, values, fwdOps, deleter,
true, fwdOpRequiresNodesForDerivatives, fwdKeepNodes,
73 range.first, range.second,
true);
86 for (std::size_t arg = 0; arg < g.
predecessors(node).size(); ++arg) {
90 QL_REQUIRE(derivatives[node].initialised(),
91 "backwardDerivatives(): derivative at active node " << node <<
" is not initialized.");
96 args[0] = &derivatives[node];
101 auto gr = grad[g.
opId(node)](args, &values[node]);
103 for (std::size_t p = 0; p < g.
predecessors(node).size(); ++p) {
104 QL_REQUIRE(derivatives[g.
predecessors(node)[p]].initialised(),
105 "backwardDerivatives: derivative at node "
106 << g.
predecessors(node)[p] <<
" not initialized, which is an active predecessor of "
108 QL_REQUIRE(gr[p].initialised(),
109 "backwardDerivatives: gradient at node "
110 << node <<
" (opId " << g.
opId(node) <<
") not initialized at component " << p
111 <<
" but required to push to predecessor " << g.
predecessors(node)[p]);
112 derivatives[g.
predecessors(node)[p]] += derivatives[node] * gr[p];
123 if (!keepNodes.empty() && keepNodes[node])
128 deleter(derivatives[node]);
const std::vector< std::size_t > & predecessors(const std::size_t node) const
std::size_t redBlockId(const std::size_t node) const
const std::vector< std::pair< std::size_t, std::size_t > > & redBlockRanges() const
std::size_t opId(const std::size_t node) const
bool isDeterministicAndZero(const ExternalRandomVariable &x)
RandomVariable conditionalExpectation(const std::vector< const RandomVariable * > ®ressor, const std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > &basisFn, const Array &coefficients)
void backwardDerivatives(const ComputationGraph &g, std::vector< T > &values, std::vector< T > &derivatives, const std::vector< std::function< std::vector< T >(const std::vector< const T * > &, const T *)> > &grad, std::function< void(T &)> deleter={}, const std::vector< bool > &keepNodes={}, const std::vector< std::function< T(const std::vector< const T * > &)> > &fwdOps={}, const std::vector< std::function< std::pair< std::vector< bool >, bool >(const std::size_t)> > &fwdOpRequiresNodesForDerivatives={}, const std::vector< bool > &fwdKeepNodes={}, const std::size_t conditionalExpectationOpId=0, const std::function< T(const std::vector< const T * > &)> &conditionalExpectation={})
void forwardEvaluation(const ComputationGraph &g, std::vector< T > &values, const std::vector< std::function< T(const std::vector< const T * > &)> > &ops, std::function< void(T &)> deleter={}, bool keepValuesForDerivatives=true, const std::vector< std::function< std::pair< std::vector< bool >, bool >(const std::size_t)> > &opRequiresNodesForDerivatives={}, const std::vector< bool > &keepNodes={}, const std::size_t startNode=0, const std::size_t endNode=ComputationGraph::nan, const bool redBlockReconstruction=false)