CppADCodeGen  2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
functor_generic_model.hpp
1 #ifndef CPPAD_CG_FUNCTOR_GENERIC_MODEL_INCLUDED
2 #define CPPAD_CG_FUNCTOR_GENERIC_MODEL_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  * Copyright (C) 2018 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 
19 #include <typeinfo>
20 
21 namespace CppAD {
22 namespace cg {
23 
33 template<class Base>
34 class FunctorGenericModel : public GenericModel<Base> {
35 protected:
36  static constexpr const char* ERROR_LIBRARY_NOT_READY = "The model library is not ready. The model library that"
37  " provided this model might have been closed or deleted.";
38 protected:
39  bool _isLibraryReady;
41  const std::string _name;
42  size_t _m;
43  size_t _n;
44  std::vector<const Base*> _in;
45  std::vector<const Base*> _inHess;
46  std::vector<Base*> _out;
47  LangCAtomicFun _atomicFuncArg;
48  std::vector<std::string> _atomicNames; // names of the atomic/external functions required by this model
49  std::vector<ExternalFunctionWrapper<Base>* > _atomic;
50  size_t _missingAtomicFunctions;
51  CppAD::vector<Base> _tx, _ty, _px, _py;
52  // original model function
53  void (*_zero)(Base const*const*, Base * const*, LangCAtomicFun);
54  // first order forward mode
55  int (*_forwardOne)(Base const tx[], Base ty[], LangCAtomicFun);
56  // first order reverse mode
57  int (*_reverseOne)(Base const tx[], Base const ty[], Base px[], Base const py[], LangCAtomicFun);
58  // second order reverse mode
59  int (*_reverseTwo)(Base const tx[], Base const ty[], Base px[], Base const py[], LangCAtomicFun);
60  // jacobian function in the dynamic library
61  void (*_jacobian)(Base const*const*, Base * const*, LangCAtomicFun);
62  // hessian function in the dynamic library
63  void (*_hessian)(Base const*const*, Base * const*, LangCAtomicFun);
64  //
65  int (*_sparseForwardOne)(unsigned long, Base const *const *, Base * const *, LangCAtomicFun);
66  //
67  int (*_sparseReverseOne)(unsigned long, Base const *const *, Base * const *, LangCAtomicFun);
68  //
69  int (*_sparseReverseTwo)(unsigned long, Base const *const *, Base * const *, LangCAtomicFun);
70  // sparse jacobian function in the dynamic library
71  void (*_sparseJacobian)(Base const*const*, Base * const*, LangCAtomicFun);
72  // sparse hessian function in the dynamic library
73  void (*_sparseHessian)(Base const*const*, Base * const*, LangCAtomicFun);
74  //
75  void (*_forwardOneSparsity)(unsigned long, unsigned long const**, unsigned long*);
76  //
77  void (*_reverseOneSparsity)(unsigned long, unsigned long const**, unsigned long*);
78  //
79  void (*_reverseTwoSparsity)(unsigned long, unsigned long const**, unsigned long*);
80  // jacobian sparsity function in the dynamic library
81  void (*_jacobianSparsity)(unsigned long const** row,
82  unsigned long const** col,
83  unsigned long * nnz);
84  // hessian sparsity function in the dynamic library
85  void (*_hessianSparsity)(unsigned long const** row,
86  unsigned long const** col,
87  unsigned long * nnz);
88  void (*_hessianSparsity2)(unsigned long i,
89  unsigned long const** row,
90  unsigned long const** col,
91  unsigned long * nnz);
92  void (*_atomicFunctions)(const char*** names,
93  unsigned long * n);
94 
95 public:
96 
98  FunctorGenericModel& operator=(const FunctorGenericModel&) = delete;
99 
100  virtual ~FunctorGenericModel() {
101  for (size_t i = 0; i < _atomic.size(); i++) {
102  delete _atomic[i];
103  }
104  }
105 
106  const std::string& getName() const override {
107  return _name;
108  }
109 
110  const std::vector<std::string>& getAtomicFunctionNames() override {
111  return _atomicNames;
112  }
113 
114  bool addAtomicFunction(atomic_base<Base>& atomic) override {
115  return addExternalFunction<atomic_base<Base>, AtomicExternalFunctionWrapper<Base> >
116  (atomic, atomic.atomic_name());
117  }
118 
119  bool addExternalModel(GenericModel<Base>& atomic) override {
120  return addExternalFunction<GenericModel<Base>, GenericModelExternalFunctionWrapper<Base> >
121  (atomic, atomic.getName());
122  }
123 
124  // Jacobian sparsity
125  bool isJacobianSparsityAvailable() override {
126  return _jacobianSparsity != nullptr;
127  }
128 
129  std::vector<bool> JacobianSparsityBool() override {
130  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
131  CPPADCG_ASSERT_KNOWN(_jacobianSparsity != nullptr, "No Jacobian sparsity function defined in the dynamic library")
132 
133  unsigned long const* row, *col;
134  unsigned long nnz;
135  (*_jacobianSparsity)(&row, &col, &nnz);
136 
137  bool set_type = true;
138  std::vector<bool> s;
139 
140  loadSparsity(set_type, s, _m, _n, row, col, nnz);
141 
142  return s;
143  }
144 
145  std::vector<std::set<size_t> > JacobianSparsitySet() override {
146  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
147  CPPADCG_ASSERT_KNOWN(_jacobianSparsity != nullptr, "No Jacobian sparsity function defined in the dynamic library")
148 
149  unsigned long const* row, *col;
150  unsigned long nnz;
151  (*_jacobianSparsity)(&row, &col, &nnz);
152 
153  std::set<size_t> set_type;
154  std::vector<std::set<size_t> > s;
155 
156  loadSparsity(set_type, s, _m, _n, row, col, nnz);
157 
158  return s;
159  }
160 
161  void JacobianSparsity(std::vector<size_t>& equations,
162  std::vector<size_t>& variables) override {
163  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
164  CPPADCG_ASSERT_KNOWN(_jacobianSparsity != nullptr, "No Jacobian sparsity function defined in the dynamic library")
165 
166  unsigned long const* row, *col;
167  unsigned long nnz;
168  (*_jacobianSparsity)(&row, &col, &nnz);
169 
170  equations.resize(nnz);
171  variables.resize(nnz);
172 
173  std::copy(row, row + nnz, equations.begin());
174  std::copy(col, col + nnz, variables.begin());
175  }
176 
177  // Hessian sparsity
178  bool isHessianSparsityAvailable() override {
179  return _hessianSparsity != nullptr;
180  }
181 
182  std::vector<bool> HessianSparsityBool() override {
183  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
184  CPPADCG_ASSERT_KNOWN(_hessianSparsity != nullptr, "No Hessian sparsity function defined in the dynamic library")
185 
186  unsigned long const* row, *col;
187  unsigned long nnz;
188  (*_hessianSparsity)(&row, &col, &nnz);
189 
190  bool set_type = true;
191  std::vector<bool> s;
192 
193  loadSparsity(set_type, s, _n, _n, row, col, nnz);
194 
195  return s;
196  }
197 
198  std::vector<std::set<size_t> > HessianSparsitySet() override {
199  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
200  CPPADCG_ASSERT_KNOWN(_hessianSparsity != nullptr, "No Hessian sparsity function defined in the dynamic library")
201 
202  unsigned long const* row, *col;
203  unsigned long nnz;
204  (*_hessianSparsity)(&row, &col, &nnz);
205 
206  std::set<size_t> set_type;
207  std::vector<std::set<size_t> > s;
208 
209  loadSparsity(set_type, s, _n, _n, row, col, nnz);
210 
211  return s;
212  }
213 
214  void HessianSparsity(std::vector<size_t>& rows,
215  std::vector<size_t>& cols) override {
216  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
217  CPPADCG_ASSERT_KNOWN(_hessianSparsity != nullptr, "No Hessian sparsity function defined in the dynamic library")
218 
219  unsigned long const* row, *col;
220  unsigned long nnz;
221  (*_hessianSparsity)(&row, &col, &nnz);
222 
223  rows.resize(nnz);
224  cols.resize(nnz);
225 
226  std::copy(row, row + nnz, rows.begin());
227  std::copy(col, col + nnz, cols.begin());
228  }
229 
231  return _hessianSparsity2 != nullptr;
232  }
233 
234  std::vector<bool> HessianSparsityBool(size_t i) override {
235  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
236  CPPADCG_ASSERT_KNOWN(_hessianSparsity2 != nullptr, "No Hessian sparsity function defined in the dynamic library")
237 
238  unsigned long const* row, *col;
239  unsigned long nnz;
240  (*_hessianSparsity2)(i, &row, &col, &nnz);
241 
242  bool set_type = true;
243  std::vector<bool> s;
244 
245  loadSparsity(set_type, s, _n, _n, row, col, nnz);
246 
247  return s;
248  }
249 
250  std::vector<std::set<size_t> > HessianSparsitySet(size_t i) override {
251  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
252  CPPADCG_ASSERT_KNOWN(_hessianSparsity2 != nullptr, "No Hessian sparsity function defined in the dynamic library")
253 
254  unsigned long const* row, *col;
255  unsigned long nnz;
256  (*_hessianSparsity2)(i, &row, &col, &nnz);
257 
258  std::set<size_t> set_type;
259  std::vector<std::set<size_t> > s;
260 
261  loadSparsity(set_type, s, _n, _n, row, col, nnz);
262 
263  return s;
264  }
265 
266  void HessianSparsity(size_t i, std::vector<size_t>& rows,
267  std::vector<size_t>& cols) override {
268  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
269  CPPADCG_ASSERT_KNOWN(_hessianSparsity2 != nullptr, "No Hessian sparsity function defined in the dynamic library")
270 
271  unsigned long const* row, *col;
272  unsigned long nnz;
273  (*_hessianSparsity2)(i, &row, &col, &nnz);
274 
275  rows.resize(nnz);
276  cols.resize(nnz);
277 
278  std::copy(row, row + nnz, rows.begin());
279  std::copy(col, col + nnz, cols.begin());
280  }
281 
283 
284  size_t Domain() const override {
285  return _n;
286  }
287 
289 
290  size_t Range() const override {
291  return _m;
292  }
293 
294  bool isForwardZeroAvailable() override {
295  return _zero != nullptr;
296  }
297 
300  ArrayView<Base> dep) override {
301  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
302  CPPADCG_ASSERT_KNOWN(_zero != nullptr, "No zero order forward function defined in the dynamic library")
303  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
304  " please use the variable size methods")
305  CPPADCG_ASSERT_KNOWN(dep.size() == _m, "Invalid dependent array size")
306  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
307  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
308 
309  _in[0] = x.data();
310  _out[0] = dep.data();
311 
312  (*_zero)(&_in[0], &_out[0], _atomicFuncArg);
313  }
314 
315  void ForwardZero(const std::vector<const Base*> &x,
316  ArrayView<Base> dep) override {
317  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
318  CPPADCG_ASSERT_KNOWN(_zero != nullptr, "No zero order forward function defined in the dynamic library")
319  CPPADCG_ASSERT_KNOWN(_in.size() == x.size(), "The number of independent variable arrays is invalid")
320  CPPADCG_ASSERT_KNOWN(dep.size() == _m, "Invalid dependent array size")
321  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
322 
323  _out[0] = dep.data();
324 
325  (*_zero)(&x[0], &_out[0], _atomicFuncArg);
326  }
327 
328  void ForwardZero(const CppAD::vector<bool>& vx,
331  ArrayView<Base> ty) override {
332  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
333  CPPADCG_ASSERT_KNOWN(_zero != nullptr, "No zero order forward function defined in the dynamic library")
334  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
335  " please use the variable size methods")
336  CPPADCG_ASSERT_KNOWN(tx.size() == _n, "Invalid independent array size")
337  CPPADCG_ASSERT_KNOWN(ty.size() == _m, "Invalid dependent array size")
338  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
339 
340  _in[0] = tx.data();
341  _out[0] = ty.data();
342 
343  (*_zero)(&_in[0], &_out[0], _atomicFuncArg);
344 
345  if (vx.size() > 0) {
346  CPPADCG_ASSERT_KNOWN(vx.size() >= _n, "Invalid vx size")
347  CPPADCG_ASSERT_KNOWN(vy.size() >= _m, "Invalid vy size")
348  const std::vector<std::set<size_t> > jacSparsity = JacobianSparsitySet();
349  for (size_t i = 0; i < _m; i++) {
350  for (size_t j : jacSparsity[i]) {
351  if (vx[j]) {
352  vy[i] = true;
353  break;
354  }
355  }
356  }
357  }
358  }
359 
360  bool isJacobianAvailable() override {
361  return _jacobian != nullptr;
362  }
363 
366  ArrayView<Base> jac) override {
367  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
368  CPPADCG_ASSERT_KNOWN(_jacobian != nullptr, "No Jacobian function defined in the dynamic library")
369  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
370  " please use the variable size methods")
371  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
372  CPPADCG_ASSERT_KNOWN(jac.size() == _m * _n, "Invalid Jacobian array size")
373  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
374 
375 
376  _in[0] = x.data();
377  _out[0] = jac.data();
378 
379  (*_jacobian)(&_in[0], &_out[0], _atomicFuncArg);
380  }
381 
382  bool isHessianAvailable() override {
383  return _hessian != nullptr;
384  }
385 
389  ArrayView<Base> hess) override {
390  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
391  CPPADCG_ASSERT_KNOWN(_hessian != nullptr, "No Hessian function defined in the dynamic library")
392  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
393  " please use the variable size methods")
394  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
395  CPPADCG_ASSERT_KNOWN(w.size() == _m, "Invalid multiplier array size")
396  CPPADCG_ASSERT_KNOWN(hess.size() == _n * _n, "Invalid Hessian size")
397  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
398 
399  _inHess[0] = x.data();
400  _inHess[1] = w.data();
401  _out[0] = hess.data();
402 
403  (*_hessian)(&_inHess[0], &_out[0], _atomicFuncArg);
404  }
405 
406  bool isForwardOneAvailable() override {
407  return _forwardOne != nullptr;
408  }
409 
411  ArrayView<Base> ty) override {
412  const size_t k = 1;
413 
414  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
415  CPPADCG_ASSERT_KNOWN(_forwardOne != nullptr, "No forward one function defined in the dynamic library")
416  CPPADCG_ASSERT_KNOWN(tx.size() >= (k + 1) * _n, "Invalid tx size")
417  CPPADCG_ASSERT_KNOWN(ty.size() >= (k + 1) * _m, "Invalid ty size")
418  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
419 
420  int ret = (*_forwardOne)(tx.data(), ty.data(), _atomicFuncArg);
421 
422  CPPADCG_ASSERT_KNOWN(ret == 0, "First-order forward mode failed.") // generic failure
423  }
424 
425  bool isSparseForwardOneAvailable() override {
426  return _forwardOneSparsity != nullptr && _sparseForwardOne != nullptr;
427  }
428 
430  size_t tx1Nnz, const size_t idx[], const Base tx1[],
431  ArrayView<Base> ty1) override {
432  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
433  CPPADCG_ASSERT_KNOWN(_sparseForwardOne != nullptr, "No sparse forward one function defined in the dynamic library")
434  CPPADCG_ASSERT_KNOWN(_forwardOneSparsity != nullptr, "No forward one sparsity function defined in the dynamic library")
435  CPPADCG_ASSERT_KNOWN(x.size() >= _n, "Invalid x size")
436  CPPADCG_ASSERT_KNOWN(ty1.size() >= _m, "Invalid ty1 size")
437  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
438 
439  std::fill(ty1.data(), ty1.data() + _m, Base(0));
440  if (tx1Nnz == 0)
441  return; //nothing to do
442 
443  unsigned long const* pos;
444  size_t nnz = 0;
445 
446  _ty.resize(_m);
447  Base* compressed = &_ty[0];
448 
449  _inHess[0] = x.data();
450  _out[0] = compressed;
451 
452  for (size_t ej = 0; ej < tx1Nnz; ej++) {
453  size_t j = idx[ej];
454  (*_forwardOneSparsity)(j, &pos, &nnz);
455 
456  _inHess[1] = &tx1[ej];
457  int ret = (*_sparseForwardOne)(j, &_inHess[0], &_out[0], _atomicFuncArg);
458 
459  CPPADCG_ASSERT_KNOWN(ret == 0, "First-order forward mode failed.") // generic failure
460 
461  for (size_t ePos = 0; ePos < nnz; ePos++) {
462  ty1[pos[ePos]] += compressed[ePos];
463  }
464  }
465  }
466 
467  bool isReverseOneAvailable() override {
468  return _reverseOne != nullptr;
469  }
470 
473  ArrayView<Base> px,
474  ArrayView<const Base> py) override {
475  const size_t k = 0;
476  const size_t k1 = k + 1;
477 
478  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
479  CPPADCG_ASSERT_KNOWN(_reverseOne != nullptr, "No reverse one function defined in the dynamic library")
480  CPPADCG_ASSERT_KNOWN(tx.size() >= k1 * _n, "Invalid tx size")
481  CPPADCG_ASSERT_KNOWN(ty.size() >= k1 * _m, "Invalid ty size")
482  CPPADCG_ASSERT_KNOWN(px.size() >= k1 * _n, "Invalid px size")
483  CPPADCG_ASSERT_KNOWN(py.size() >= k1 * _m, "Invalid py size")
484  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
485 
486  int ret = (*_reverseOne)(tx.data(), ty.data(), px.data(), py.data(), _atomicFuncArg);
487 
488  CPPADCG_ASSERT_KNOWN(ret == 0, "First-order reverse mode failed.")
489  }
490 
491  bool isSparseReverseOneAvailable() override {
492  return _reverseOneSparsity != nullptr && _sparseReverseOne != nullptr;
493  }
494 
496  ArrayView<Base> px,
497  size_t pyNnz, const size_t idx[], const Base py[]) override {
498  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
499  CPPADCG_ASSERT_KNOWN(_sparseReverseOne != nullptr, "No sparse reverse one function defined in the dynamic library")
500  CPPADCG_ASSERT_KNOWN(_reverseOneSparsity != nullptr, "No reverse one sparsity function defined in the dynamic library")
501  CPPADCG_ASSERT_KNOWN(x.size() >= _n, "Invalid x size")
502  CPPADCG_ASSERT_KNOWN(px.size() >= _n, "Invalid px size")
503  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
504 
505  std::fill(px.data(), px.data() + _n, Base(0));
506  if (pyNnz == 0)
507  return; //nothing to do
508 
509  unsigned long const* pos;
510  size_t nnz = 0;
511 
512  _px.resize(_n);
513  Base* compressed = &_px[0];
514 
515  _inHess[0] = x.data();
516  _out[0] = compressed;
517 
518  for (size_t ei = 0; ei < pyNnz; ei++) {
519  size_t i = idx[ei];
520  (*_reverseOneSparsity)(i, &pos, &nnz);
521 
522  _inHess[1] = &py[ei];
523  int ret = (*_sparseReverseOne)(i, &_inHess[0], &_out[0], _atomicFuncArg);
524 
525  CPPADCG_ASSERT_KNOWN(ret == 0, "First-order reverse mode failed.")
526 
527  for (size_t ePos = 0; ePos < nnz; ePos++) {
528  px[pos[ePos]] += compressed[ePos];
529  }
530  }
531  }
532 
533  bool isReverseTwoAvailable() override {
534  return _reverseTwo != nullptr;
535  }
536 
539  ArrayView<Base> px,
540  ArrayView<const Base> py) override {
541  const size_t k = 1;
542  const size_t k1 = k + 1;
543 
544  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
545  CPPADCG_ASSERT_KNOWN(_reverseTwo != nullptr, "No sparse reverse two function defined in the dynamic library")
546  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1")
547  CPPADCG_ASSERT_KNOWN(tx.size() >= k1 * _n, "Invalid tx size")
548  CPPADCG_ASSERT_KNOWN(ty.size() >= k1 * _m, "Invalid ty size")
549  CPPADCG_ASSERT_KNOWN(px.size() >= k1 * _n, "Invalid px size")
550  CPPADCG_ASSERT_KNOWN(py.size() >= k1 * _m, "Invalid py size")
551  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
552 
553  int ret = (*_reverseTwo)(tx.data(), ty.data(), px.data(), py.data(), _atomicFuncArg);
554 
555  CPPADCG_ASSERT_KNOWN(ret != 1, "Second-order reverse mode failed: py[2*i] (i=0...m) must be zero.")
556  CPPADCG_ASSERT_KNOWN(ret == 0, "Second-order reverse mode failed.")
557  }
558 
559  bool isSparseReverseTwoAvailable() override {
560  return _sparseReverseTwo != nullptr;
561  }
562 
564  size_t tx1Nnz, const size_t idx[], const Base tx1[],
565  ArrayView<Base> px2,
566  ArrayView<const Base> py2) override {
567  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
568  CPPADCG_ASSERT_KNOWN(_sparseReverseTwo != nullptr, "No sparse reverse two function defined in the dynamic library")
569  CPPADCG_ASSERT_KNOWN(_reverseTwoSparsity != nullptr, "No reverse two sparsity function defined in the dynamic library")
570  CPPADCG_ASSERT_KNOWN(x.size() >= _n, "Invalid x size")
571  CPPADCG_ASSERT_KNOWN(px2.size() >= _n, "Invalid px2 size")
572  CPPADCG_ASSERT_KNOWN(py2.size() >= _m, "Invalid py2 size")
573  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
574 
575  std::fill(px2.data(), px2.data() + _n, Base(0));
576  if (tx1Nnz == 0)
577  return; //nothing to do
578 
579  unsigned long const* pos;
580  size_t nnz = 0;
581 
582  _px.resize(_n);
583  Base* compressed = &_px[0];
584 
585  const Base * in[3];
586  in[0] = x.data();
587  in[2] = py2.data();
588  _out[0] = compressed;
589 
590  for (size_t ej = 0; ej < tx1Nnz; ej++) {
591  size_t j = idx[ej];
592  (*_reverseTwoSparsity)(j, &pos, &nnz);
593 
594  in[1] = &tx1[ej];
595  int ret = (*_sparseReverseTwo)(j, &in[0], &_out[0], _atomicFuncArg);
596 
597  CPPADCG_ASSERT_KNOWN(ret == 0, "Second-order reverse mode failed.") // generic failure
598 
599  for (size_t ePos = 0; ePos < nnz; ePos++) {
600  px2[pos[ePos]] += compressed[ePos];
601  }
602  }
603  }
604 
605  bool isSparseJacobianAvailable() override {
606  return _jacobianSparsity != nullptr && _sparseJacobian != nullptr;
607  }
608 
610 
612  ArrayView<Base> jac) override {
613  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
614  CPPADCG_ASSERT_KNOWN(_sparseJacobian != nullptr, "No sparse jacobian function defined in the dynamic library")
615  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
616  " please use the variable size methods")
617  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
618  CPPADCG_ASSERT_KNOWN(jac.size() == _m * _n, "Invalid Jacobian size")
619  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
620 
621  unsigned long const* row;
622  unsigned long const* col;
623  unsigned long nnz;
624  (*_jacobianSparsity)(&row, &col, &nnz);
625 
626  CppAD::vector<Base> compressed(nnz);
627 
628  if (nnz > 0) {
629  _in[0] = x.data();
630  _out[0] = &compressed[0];
631 
632  (*_sparseJacobian)(&_in[0], &_out[0], _atomicFuncArg);
633  }
634 
635  createDenseFromSparse(compressed,
636  _m, _n,
637  row, col,
638  nnz,
639  jac);
640  }
641 
642  void SparseJacobian(const std::vector<Base> &x,
643  std::vector<Base>& jac,
644  std::vector<size_t>& row,
645  std::vector<size_t>& col) override {
646  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
647  CPPADCG_ASSERT_KNOWN(_sparseJacobian != nullptr, "No sparse Jacobian function defined in the dynamic library")
648  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
649  " please use the variable size methods")
650  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
651 
652  unsigned long const* drow;
653  unsigned long const* dcol;
654  unsigned long nnz;
655  (*_jacobianSparsity)(&drow, &dcol, &nnz);
656 
657  jac.resize(nnz);
658  row.resize(nnz);
659  col.resize(nnz);
660 
661  if (nnz > 0) {
662  _in[0] = &x[0];
663  _out[0] = &jac[0];
664 
665  (*_sparseJacobian)(&_in[0], &_out[0], _atomicFuncArg);
666  std::copy(drow, drow + nnz, row.begin());
667  std::copy(dcol, dcol + nnz, col.begin());
668  }
669  }
670 
671  void SparseJacobian(ArrayView<const Base> x,
672  ArrayView<Base> jac,
673  size_t const** row,
674  size_t const** col) override {
675  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
676  CPPADCG_ASSERT_KNOWN(_sparseJacobian != nullptr, "No sparse Jacobian function defined in the dynamic library")
677  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
678  " please use the variable size methods")
679  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
680  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
681 
682  unsigned long const* drow;
683  unsigned long const* dcol;
684  unsigned long nnz;
685  (*_jacobianSparsity)(&drow, &dcol, &nnz);
686  CPPADCG_ASSERT_KNOWN(nnz == jac.size(), "Invalid number of non-zero elements in Jacobian")
687  *row = drow;
688  *col = dcol;
689 
690  if (nnz > 0) {
691  _in[0] = x.data();
692  _out[0] = jac.data();
693 
694  (*_sparseJacobian)(&_in[0], &_out[0], _atomicFuncArg);
695  }
696  }
697 
698  void SparseJacobian(const std::vector<const Base*>& x,
699  ArrayView<Base> jac,
700  size_t const** row,
701  size_t const** col) override {
702  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
703  CPPADCG_ASSERT_KNOWN(_sparseJacobian != nullptr, "No sparse Jacobian function defined in the dynamic library")
704  CPPADCG_ASSERT_KNOWN(_in.size() == x.size(), "The number of independent variable arrays is invalid")
705  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
706 
707  unsigned long const* drow;
708  unsigned long const* dcol;
709  unsigned long nnz;
710  (*_jacobianSparsity)(&drow, &dcol, &nnz);
711  CPPADCG_ASSERT_KNOWN(nnz == jac.size(), "Invalid number of non-zero elements in Jacobian")
712  *row = drow;
713  *col = dcol;
714 
715  if (nnz > 0) {
716  _out[0] = jac.data();
717 
718  (*_sparseJacobian)(&x[0], &_out[0], _atomicFuncArg);
719  }
720  }
721 
722  bool isSparseHessianAvailable() override {
723  return _hessianSparsity != nullptr && _sparseHessian != nullptr;
724  }
725 
727 
730  ArrayView<Base> hess) override {
731  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
732  CPPADCG_ASSERT_KNOWN(_sparseHessian != nullptr, "No sparse Hessian function defined in the dynamic library")
733  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
734  CPPADCG_ASSERT_KNOWN(w.size() == _m, "Invalid multiplier array size")
735  // CPPADCG_ASSERT_KNOWN(hess.size() == _n * _n, "Invalid Hessian size")
736  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
737  " please use the variable size methods")
738  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
739 
740  unsigned long const* row, *col;
741  unsigned long nnz;
742  (*_hessianSparsity)(&row, &col, &nnz);
743 
744  CppAD::vector<Base> compressed(nnz);
745  if (nnz > 0) {
746  _inHess[0] = x.data();
747  _inHess[1] = w.data();
748  _out[0] = &compressed[0];
749 
750  (*_sparseHessian)(&_inHess[0], &_out[0], _atomicFuncArg);
751  }
752 
753  createDenseFromSparse(compressed,
754  _n, _n,
755  row, col,
756  nnz,
757  hess);
758  }
759 
760  void SparseHessian(const std::vector<Base> &x,
761  const std::vector<Base> &w,
762  std::vector<Base>& hess,
763  std::vector<size_t>& row,
764  std::vector<size_t>& col) override {
765  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
766  CPPADCG_ASSERT_KNOWN(_sparseHessian != nullptr, "No sparse Hessian function defined in the dynamic library")
767  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
768  CPPADCG_ASSERT_KNOWN(w.size() == _m, "Invalid multiplier array size")
769  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
770  " please use the variable size methods")
771  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
772 
773  unsigned long const* drow, *dcol;
774  unsigned long nnz;
775  (*_hessianSparsity)(&drow, &dcol, &nnz);
776 
777  hess.resize(nnz);
778  row.resize(nnz);
779  col.resize(nnz);
780 
781  if (nnz > 0) {
782  std::copy(drow, drow + nnz, row.begin());
783  std::copy(dcol, dcol + nnz, col.begin());
784 
785  _inHess[0] = &x[0];
786  _inHess[1] = &w[0];
787  _out[0] = &hess[0];
788 
789  (*_sparseHessian)(&_inHess[0], &_out[0], _atomicFuncArg);
790  }
791  }
792 
793  void SparseHessian(ArrayView<const Base> x,
794  ArrayView<const Base> w,
795  ArrayView<Base> hess,
796  size_t const** row,
797  size_t const** col) override {
798  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
799  CPPADCG_ASSERT_KNOWN(_sparseHessian != nullptr, "No sparse Hessian function defined in the dynamic library")
800  CPPADCG_ASSERT_KNOWN(_in.size() == 1, "The number of independent variable arrays is higher than 1,"
801  " please use the variable size methods")
802  CPPADCG_ASSERT_KNOWN(x.size() == _n, "Invalid independent array size")
803  CPPADCG_ASSERT_KNOWN(w.size() == _m, "Invalid multiplier array size")
804  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
805 
806  unsigned long const* drow, *dcol;
807  unsigned long nnz;
808  (*_hessianSparsity)(&drow, &dcol, &nnz);
809  CPPADCG_ASSERT_KNOWN(nnz == hess.size(), "Invalid number of non-zero elements in Hessian")
810  *row = drow;
811  *col = dcol;
812 
813  if (nnz > 0) {
814  _inHess[0] = x.data();
815  _inHess[1] = w.data();
816  _out[0] = hess.data();
817 
818  (*_sparseHessian)(&_inHess[0], &_out[0], _atomicFuncArg);
819  }
820  }
821 
822  void SparseHessian(const std::vector<const Base*>& x,
824  ArrayView<Base> hess,
825  size_t const** row,
826  size_t const** col) override {
827  CPPADCG_ASSERT_KNOWN(_isLibraryReady, ERROR_LIBRARY_NOT_READY)
828  CPPADCG_ASSERT_KNOWN(_sparseHessian != nullptr, "No sparse Hessian function defined in the dynamic library")
829  CPPADCG_ASSERT_KNOWN(_in.size() == x.size(), "The number of independent variable arrays is invalid")
830  CPPADCG_ASSERT_KNOWN(w.size() == _m, "Invalid multiplier array size")
831  CPPADCG_ASSERT_KNOWN(_missingAtomicFunctions == 0, "Some atomic functions used by the compiled model have not been specified yet")
832 
833  unsigned long const* drow, *dcol;
834  unsigned long nnz;
835  (*_hessianSparsity)(&drow, &dcol, &nnz);
836  CPPADCG_ASSERT_KNOWN(nnz == hess.size(), "Invalid number of non-zero elements in Hessian")
837  *row = drow;
838  *col = dcol;
839 
840  if (nnz > 0) {
841  std::copy(x.begin(), x.end(), _inHess.begin());
842  _inHess.back() = w.data(); // the index might not be 1
843  _out[0] = hess.data();
844 
845  (*_sparseHessian)(&_inHess[0], &_out[0], _atomicFuncArg);
846  }
847  }
848 
849 protected:
850 
856  explicit FunctorGenericModel(std::string name) :
857  _isLibraryReady(false),
858  _name(std::move(name)),
859  _m(0),
860  _n(0),
861  _atomicFuncArg{nullptr}, // not really required
862  _missingAtomicFunctions(0),
863  _zero(nullptr),
864  _forwardOne(nullptr),
865  _reverseOne(nullptr),
866  _reverseTwo(nullptr),
867  _jacobian(nullptr),
868  _hessian(nullptr),
869  _sparseForwardOne(nullptr),
870  _sparseReverseOne(nullptr),
871  _sparseReverseTwo(nullptr),
872  _sparseJacobian(nullptr),
873  _sparseHessian(nullptr),
874  _forwardOneSparsity(nullptr),
875  _reverseOneSparsity(nullptr),
876  _reverseTwoSparsity(nullptr),
877  _jacobianSparsity(nullptr),
878  _hessianSparsity(nullptr),
879  _hessianSparsity2(nullptr),
880  _atomicFunctions(nullptr) {
881 
882  }
883 
884  virtual void init() {
885  // validate the dynamic library
886  validate();
887 
888  // load functions from the dynamic library
889  loadFunctions();
890  }
891 
892  virtual void* loadFunction(const std::string& functionName,
893  bool required = true) = 0;
894 
895  virtual void validate() {
899  void (*infoFunc)(const char** baseName, unsigned long*, unsigned long*, unsigned int*, unsigned int*);
900  infoFunc = reinterpret_cast<decltype(infoFunc)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_INFO));
901 
902  // local
903  const char* localBaseName = typeid (Base).name();
904  std::string local = ModelCSourceGen<Base>::baseTypeName() + " " + localBaseName;
905 
906  // from dynamic library
907  const char* dynamicLibBaseName = nullptr;
908  unsigned int inSize = 0;
909  unsigned int outSize = 0;
910  (*infoFunc)(&dynamicLibBaseName, &_m, &_n, &inSize, &outSize);
911 
912  _in.resize(inSize);
913  _inHess.resize(inSize + 1);
914  _out.resize(outSize);
915 
916  CPPADCG_ASSERT_KNOWN(local == std::string(dynamicLibBaseName),
917  (std::string("Invalid data type in dynamic library. Expected '") + local
918  + "' but the library provided '" + dynamicLibBaseName + "'.").c_str())
919  CPPADCG_ASSERT_KNOWN(inSize > 0,
920  "Invalid dimension received from the dynamic library.")
921  CPPADCG_ASSERT_KNOWN(outSize > 0,
922  "Invalid dimension received from the dynamic library.")
923 
924  _isLibraryReady = true;
925  }
926 
927  virtual void loadFunctions() {
928  _zero = reinterpret_cast<decltype(_zero)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_FORWAD_ZERO, false));
929  _forwardOne = reinterpret_cast<decltype(_forwardOne)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_FORWARD_ONE, false));
930  _reverseOne = reinterpret_cast<decltype(_reverseOne)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_REVERSE_ONE, false));
931  _reverseTwo = reinterpret_cast<decltype(_reverseTwo)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_REVERSE_TWO, false));
932  _jacobian = reinterpret_cast<decltype(_jacobian)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_JACOBIAN, false));
933  _hessian = reinterpret_cast<decltype(_hessian)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_HESSIAN, false));
934  _sparseForwardOne = reinterpret_cast<decltype(_sparseForwardOne)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_SPARSE_FORWARD_ONE, false));
935  _sparseReverseOne = reinterpret_cast<decltype(_sparseReverseOne)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_SPARSE_REVERSE_ONE, false));
936  _sparseReverseTwo = reinterpret_cast<decltype(_sparseReverseTwo)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_SPARSE_REVERSE_TWO, false));
937  _sparseJacobian = reinterpret_cast<decltype(_sparseJacobian)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_SPARSE_JACOBIAN, false));
938  _sparseHessian = reinterpret_cast<decltype(_sparseHessian)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_SPARSE_HESSIAN, false));
939  _forwardOneSparsity = reinterpret_cast<decltype(_forwardOneSparsity)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_FORWARD_ONE_SPARSITY, false));
940  _reverseOneSparsity = reinterpret_cast<decltype(_reverseOneSparsity)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_REVERSE_ONE_SPARSITY, false));
941  _reverseTwoSparsity = reinterpret_cast<decltype(_reverseTwoSparsity)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_REVERSE_TWO_SPARSITY, false));
942  _jacobianSparsity = reinterpret_cast<decltype(_jacobianSparsity)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_JACOBIAN_SPARSITY, false));
943  _hessianSparsity = reinterpret_cast<decltype(_hessianSparsity)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_HESSIAN_SPARSITY, false));
944  _hessianSparsity2 = reinterpret_cast<decltype(_hessianSparsity2)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_HESSIAN_SPARSITY2, false));
945  _atomicFunctions = reinterpret_cast<decltype(_atomicFunctions)>(loadFunction(_name + "_" + ModelCSourceGen<Base>::FUNCTION_ATOMIC_FUNC_NAMES, true));
946 
947  CPPADCG_ASSERT_KNOWN((_sparseForwardOne == nullptr) == (_forwardOneSparsity == nullptr), "Missing functions in the dynamic library")
948  CPPADCG_ASSERT_KNOWN((_sparseForwardOne == nullptr) == (_forwardOne == nullptr), "Missing functions in the dynamic library")
949  CPPADCG_ASSERT_KNOWN((_sparseReverseOne == nullptr) == (_reverseOneSparsity == nullptr), "Missing functions in the dynamic library")
950  CPPADCG_ASSERT_KNOWN((_sparseReverseOne == nullptr) == (_reverseOne == nullptr), "Missing functions in the dynamic library")
951  CPPADCG_ASSERT_KNOWN((_sparseReverseTwo == nullptr) == (_reverseTwoSparsity == nullptr), "Missing functions in the dynamic library")
952  CPPADCG_ASSERT_KNOWN((_sparseReverseTwo == nullptr) == (_reverseTwo == nullptr), "Missing functions in the dynamic library")
953  CPPADCG_ASSERT_KNOWN((_sparseJacobian == nullptr) || (_jacobianSparsity != nullptr), "Missing functions in the dynamic library")
954  CPPADCG_ASSERT_KNOWN((_sparseHessian == nullptr) || (_hessianSparsity != nullptr), "Missing functions in the dynamic library")
955 
956 
959  const char** names;
960  unsigned long n;
961  (*_atomicFunctions)(&names, &n);
962  _atomic.resize(n);
963  _atomicNames.resize(n);
964  for (unsigned long i = 0; i < n; ++i) {
965  _atomicNames[i] = std::string(names[i]);
966  }
967 
968  _atomicFuncArg.libModel = this;
969  _atomicFuncArg.forward = &atomicForward;
970  _atomicFuncArg.reverse = &atomicReverse;
971 
972  _missingAtomicFunctions = n;
973  }
974 
975  template <class VectorSet>
976  inline void loadSparsity(bool set_type,
977  VectorSet& s,
978  unsigned long nrows, unsigned long ncols,
979  unsigned long const* rows, unsigned long const* cols,
980  unsigned long nnz) {
981  s.resize(nrows * ncols, false);
982 
983  for (unsigned long i = 0; i < nnz; i++) {
984  s[rows[i] * ncols + cols[i]] = true;
985  }
986  }
987 
988  template <class VectorSet>
989  inline void loadSparsity(const std::set<size_t>& set_type,
990  VectorSet& s,
991  unsigned long nrows, unsigned long ncols,
992  unsigned long const* rows, unsigned long const* cols,
993  unsigned long nnz) {
994 
995  // dimension size of result vector
996  s.resize(nrows);
997 
998  for (unsigned long i = 0; i < nnz; i++) {
999  s[rows[i]].insert(cols[i]);
1000  }
1001  }
1002 
1003  inline void createDenseFromSparse(const CppAD::vector<Base>& compressed,
1004  unsigned long nrows, unsigned long ncols,
1005  unsigned long const* rows, unsigned long const* cols,
1006  unsigned long nnz,
1007  ArrayView<Base> mat) const {
1008  CPPADCG_ASSERT_KNOWN(mat.size() == nrows * ncols, "Invalid matrix size")
1009  mat.fill(Base(0));
1010 
1011  for (size_t i = 0; i < nnz; i++) {
1012  mat[rows[i] * ncols + cols[i]] = compressed[i];
1013  }
1014  }
1015 
1016  virtual void modelLibraryClosed() {
1017  _isLibraryReady = false;
1018  _zero = nullptr;
1019  _forwardOne = nullptr;
1020  _reverseOne = nullptr;
1021  _reverseTwo = nullptr;
1022  _jacobian = nullptr;
1023  _hessian = nullptr;
1024  _sparseForwardOne = nullptr;
1025  _sparseReverseOne = nullptr;
1026  _sparseReverseTwo = nullptr;
1027  _sparseJacobian = nullptr;
1028  _sparseHessian = nullptr;
1029  _forwardOneSparsity = nullptr;
1030  _reverseOneSparsity = nullptr;
1031  _reverseTwoSparsity = nullptr;
1032  _jacobianSparsity = nullptr;
1033  _hessianSparsity = nullptr;
1034  _hessianSparsity2 = nullptr;
1035  }
1036 
1037 private:
1038 
1039  template<class ExtFunc, class Wrapper>
1040  inline bool addExternalFunction(ExtFunc& atomic,
1041  const std::string& name) {
1042  size_t n = _atomicNames.size();
1043  for (size_t i = 0; i < n; i++) {
1044  if (name == _atomicNames[i]) {
1045  if (_atomic[i] == nullptr) {
1046  _missingAtomicFunctions--;
1047  } else {
1048  delete _atomic[i];
1049  }
1050  _atomic[i] = new Wrapper(atomic);
1051  return true;
1052  }
1053  }
1054  return false;
1055  }
1056 
1057  static int atomicForward(void* libModelIn,
1058  int atomicIndex,
1059  int q,
1060  int p,
1061  const Array tx[],
1062  Array* ty) {
1063  auto* libModel = static_cast<FunctorGenericModel<Base>*> (libModelIn);
1064  ExternalFunctionWrapper<Base>* externalFunc = libModel->_atomic[atomicIndex];
1065 
1066  return externalFunc->forward(*libModel, q, p, tx, *ty);
1067  }
1068 
1069  static int atomicReverse(void* libModelIn,
1070  int atomicIndex,
1071  int p,
1072  const Array tx[],
1073  Array* px,
1074  const Array py[]) {
1075  auto* libModel = static_cast<FunctorGenericModel<Base>*> (libModelIn);
1076  ExternalFunctionWrapper<Base>* externalFunc = libModel->_atomic[atomicIndex];
1077 
1078  return externalFunc->reverse(*libModel, p, tx, *px, py);
1079  }
1080 #ifdef CPPAD_CG_SYSTEM_LINUX
1081  friend class LinuxDynamicLib<Base>;
1082 #endif
1083  friend class AtomicExternalFunctionWrapper<Base>;
1084 };
1085 
1086 } // END cg namespace
1087 } // END CppAD namespace
1088 
1089 #endif
size_t size() const noexcept
Definition: array_view.hpp:202
pointer data() noexcept
Definition: array_view.hpp:220
void ReverseOne(ArrayView< const Base > x, ArrayView< Base > px, size_t pyNnz, const size_t idx[], const Base py[]) override
size_t Domain() const override
number of independent variables
void ForwardOne(ArrayView< const Base > x, size_t tx1Nnz, const size_t idx[], const Base tx1[], ArrayView< Base > ty1) override
void SparseJacobian(const std::vector< const Base * > &x, ArrayView< Base > jac, size_t const **row, size_t const **col) override
const std::vector< std::string > & getAtomicFunctionNames() override
void ReverseTwo(ArrayView< const Base > x, size_t tx1Nnz, const size_t idx[], const Base tx1[], ArrayView< Base > px2, ArrayView< const Base > py2) override
const std::string _name
the model name
void Hessian(ArrayView< const Base > x, ArrayView< const Base > w, ArrayView< Base > hess) override
calculate Hessian for one component of f
void ForwardZero(ArrayView< const Base > x, ArrayView< Base > dep) override
calculate the dependent values (zero order)
void SparseHessian(const std::vector< const Base * > &x, ArrayView< const Base > w, ArrayView< Base > hess, size_t const **row, size_t const **col) override
void ReverseTwo(ArrayView< const Base > tx, ArrayView< const Base > ty, ArrayView< Base > px, ArrayView< const Base > py) override
void SparseJacobian(ArrayView< const Base > x, ArrayView< Base > jac) override
calculate sparse Jacobians
void ForwardZero(const std::vector< const Base * > &x, ArrayView< Base > dep) override
void Jacobian(ArrayView< const Base > x, ArrayView< Base > jac) override
calculate entire Jacobian
bool addExternalModel(GenericModel< Base > &atomic) override
void SparseHessian(ArrayView< const Base > x, ArrayView< const Base > w, ArrayView< Base > hess) override
calculate sparse Hessians
void ReverseOne(ArrayView< const Base > tx, ArrayView< const Base > ty, ArrayView< Base > px, ArrayView< const Base > py) override
const std::string & getName() const override
std::vector< std::set< size_t > > HessianSparsitySet() override
void ForwardOne(ArrayView< const Base > tx, ArrayView< Base > ty) override
size_t Range() const override
number of dependent variables
bool addAtomicFunction(atomic_base< Base > &atomic) override
virtual const std::string & getName() const =0