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