1 #ifndef CPPAD_CG_ABSTRACT_ATOMIC_FUN_INCLUDED 2 #define CPPAD_CG_ABSTRACT_ATOMIC_FUN_INCLUDED 58 bool standAlone =
false) :
61 standAlone_(standAlone) {
62 CPPADCG_ASSERT_KNOWN(!name.empty(),
"The atomic function name cannot be empty")
63 this->option(CppAD::atomic_base<CGB>::set_sparsity_enum);
69 template <
class ADVector>
70 void operator()(
const ADVector& ax,
106 size_t n = vx.size();
108 for (
size_t j = 0; j < n; j++) {
109 x[j] = tx[j * (p + 1)];
112 zeroOrderDependency(vx, vy, x);
118 if (!evalForwardValues(q, p, tx, tyb, ty.size()))
121 CPPADCG_ASSERT_UNKNOWN(tyb.size() == ty.size())
122 for (
size_t i = 0; i < ty.size(); i++) {
128 size_t m = ty.size() / (p + 1);
139 size_t n = tx.size() / (p + 1);
142 for (
size_t j = 0; j < n; j++) {
143 if (!tx[j * (p + 1) + 1].isIdenticalZero())
150 for (
size_t j = 0; j < n; j++) {
151 x[j] = tx[j * (p + 1)];
155 bool good = this->for_sparse_jac(1, r, s, x);
159 vyLocal.resize(ty.size());
160 for (
size_t i = 0; i < vyLocal.size(); i++) {
164 for (
size_t i = 0; i < m; i++) {
165 vyLocal[i * (p + 1) + 1] = !s[i].empty();
170 for (
size_t i = 0; i < vyLocal.size(); i++) {
178 for (
size_t i = 0; i < ty.size(); i++) {
188 if (!evalForwardValues(q, p, tx, tyb, ty.size()))
193 CPPADCG_ASSERT_UNKNOWN(handler !=
nullptr)
197 std::vector<OperationNode<Base>*> txArray(p1), tyArray(p1);
198 for (
size_t k = 0; k < p1; k++) {
206 std::vector<Argument<Base> > args(2 * p1);
207 for (
size_t k = 0; k < p1; k++) {
208 args[0 * p1 + k] = *txArray[k];
209 args[1 * p1 + k] = *tyArray[k];
213 handler->registerAtomicFunction(*
this);
215 for (
size_t k = 0; k < p1; k++) {
216 for (
size_t i = 0; i < m; i++) {
217 size_t pos = i * p1 + k;
218 if (vyLocal.size() == 0 || vyLocal[pos]) {
219 ty[pos] =
CGB(*handler->makeNode(CGOpCode::ArrayElement, {i}, {*tyArray[k], *atomicOp}));
221 ty[pos].setValue(tyb[pos]);
224 CPPADCG_ASSERT_KNOWN(tyb.size() == 0 ||
IdenticalZero(tyb[pos]),
"Invalid value")
251 if (!evalReverseValues(p, tx, ty, pxb, py))
254 CPPADCG_ASSERT_UNKNOWN(pxb.size() == px.size())
256 for (
size_t i = 0; i < px.size(); i++) {
267 for (
size_t j = 0; j < vxLocal.size(); j++) {
273 size_t m = ty.size() / p1;
274 size_t n = tx.size() / p1;
277 for (
size_t i = 0; i < m; i++) {
278 if (!py[i * p1].isIdenticalZero()) {
284 for (
size_t j = 0; j < n; j++) {
289 bool good = this->rev_sparse_jac(1, rt, st, x);
294 for (
size_t j = 0; j < n; j++) {
295 vxLocal[j * p1 + p] = !st[j].empty();
310 for (
size_t j = 0; j < n; j++) {
311 vx[j] = !tx[j * p1].isParameter();
312 if (!tx[j * p1 + 1].isIdenticalZero()) {
316 for (
size_t i = 0; i < m; i++) {
317 s[i] = !py[i * p1 + 1].isIdenticalZero();
320 this->rev_sparse_hes(vx, s, t, 1, r, u, v, x);
322 for (
size_t j = 0; j < n; j++) {
323 vxLocal[j * p1 + p - 1] = !v[j].empty();
328 for (
size_t j = 0; j < vxLocal.size(); j++) {
336 for (
size_t j = 0; j < px.size(); j++) {
352 if (!evalReverseValues(p, tx, ty, pxb, py))
357 if (handler ==
nullptr) {
358 handler = findHandler(ty);
359 if (handler ==
nullptr) {
360 handler = findHandler(py);
363 CPPADCG_ASSERT_UNKNOWN(handler !=
nullptr)
365 std::vector<OperationNode<Base>*> txArray(p1), tyArray(p1), pxArray(p1), pyArray(p1);
366 for (
size_t k = 0; k <= p; k++) {
389 std::vector<Argument<Base> > args(4 * p1);
390 for (
size_t k = 0; k <= p; k++) {
391 args[0 * p1 + k] = *txArray[k];
392 args[1 * p1 + k] = *tyArray[k];
393 args[2 * p1 + k] = *pxArray[k];
394 args[3 * p1 + k] = *pyArray[k];
398 handler->registerAtomicFunction(*
this);
400 for (
size_t k = 0; k < p1; k++) {
401 for (
size_t j = 0; j < n; j++) {
402 size_t pos = j * p1 + k;
404 px[pos] =
CGB(*handler->makeNode(CGOpCode::ArrayElement, {j}, {*pxArray[k], *atomicOp}));
406 px[pos].setValue(pxb[pos]);
424 for (
size_t i = 0; i < n; i++)
428 bool good = this->for_sparse_jac(n, r, s, x);
430 throw CGException(
"Failed to compute jacobian sparsity pattern for atomic function '", this->atomic_name(),
"'");
440 for (
size_t i = 0; i < m; i++)
444 bool good = this->rev_sparse_jac(m, rt, st, x);
446 throw CGException(
"Failed to compute jacobian sparsity pattern for atomic function '", this->atomic_name(),
"'");
456 for (
size_t i = 0; i < m; ++i)
459 return hessianSparsitySet(s, x);
471 for (
size_t j = 0; j < n; j++)
475 for (
size_t i = 0; i < n; ++i)
479 for (
size_t i = 0; i < n; ++i)
485 bool good = this->rev_sparse_hes(vx, s, t, n, r, u, v, x);
487 throw CGException(
"Failed to compute Hessian sparsity pattern for atomic function '", this->atomic_name(),
"'");
496 CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
497 static size_t count = 0;
546 inline bool evalForwardValues(
size_t q,
554 for (
size_t i = 0; i < txb.size(); i++) {
555 txb[i] = tx[i].getValue();
561 inline bool evalReverseValues(
size_t p,
570 pxb.resize(tx.size());
573 for (
size_t i = 0; i < txb.size(); i++) {
574 txb[i] = tx[i].getValue();
576 for (
size_t i = 0; i < tyb.size(); i++) {
577 tyb[i] = ty[i].getValue();
579 for (
size_t i = 0; i < pyb.size(); i++) {
580 pyb[i] = py[i].getValue();
virtual CppAD::vector< std::set< size_t > > hessianSparsitySet(const CppAD::vector< bool > &s, const CppAD::vector< CGB > &x)
bool isStandAlone() const
virtual bool atomicReverse(size_t p, const CppAD::vector< Base > &tx, const CppAD::vector< Base > &ty, CppAD::vector< Base > &px, const CppAD::vector< Base > &py)=0
virtual bool atomicForward(size_t q, size_t p, const CppAD::vector< Base > &tx, CppAD::vector< Base > &ty)=0
bool forward(size_t q, size_t p, const CppAD::vector< bool > &vx, CppAD::vector< bool > &vy, const CppAD::vector< CGB > &tx, CppAD::vector< CGB > &ty) override
bool IdenticalZero(const cg::CG< Base > &x)
bool reverse(size_t p, const CppAD::vector< CGB > &tx, const CppAD::vector< CGB > &ty, CppAD::vector< CGB > &px, const CppAD::vector< CGB > &py) override
CGAbstractAtomicFun(const std::string &name, bool standAlone=false)
static size_t createNewAtomicFunctionID()