CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
atomic_fun_bridge.hpp
1 #ifndef CPPAD_CG_ATOMIC_FUN_BRIDGE_INCLUDED
2 #define CPPAD_CG_ATOMIC_FUN_BRIDGE_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2013 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 namespace CppAD {
20 namespace cg {
21 
30 template <class Base>
31 class CGAtomicFunBridge : public CGAbstractAtomicFun<Base> {
32 public:
33  using CGB = CppAD::cg::CG<Base>;
34  using ADCGD = CppAD::AD<CGB>;
35 protected:
36  ADFun<CGB>& fun_;
37  bool cacheSparsities_;
38  CustomPosition custom_jac_;
39  CustomPosition custom_hess_;
40  std::map<size_t, CppAD::vector<std::set<size_t> > > hess_;
41 public:
42 
55  CGAtomicFunBridge(const std::string& name,
56  CppAD::ADFun<CGB>& fun,
57  bool standAlone = false,
58  bool cacheSparsities = true) :
59  CGAbstractAtomicFun<Base>(name, standAlone),
60  fun_(fun),
61  cacheSparsities_(cacheSparsities) {
62  this->option(CppAD::atomic_base<CGB>::set_sparsity_enum);
63  }
64 
65  CGAtomicFunBridge(const CGAtomicFunBridge& orig) = delete;
66  CGAtomicFunBridge& operator=(const CGAtomicFunBridge& rhs) = delete;
67 
68  virtual ~CGAtomicFunBridge() = default;
69 
70  template <class ADVector>
71  void operator()(const ADVector& ax, ADVector& ay, size_t id = 0) {
72  this->CGAbstractAtomicFun<Base>::operator()(ax, ay, id);
73  }
74 
75  template<class VectorSize>
76  inline void setCustomSparseJacobianElements(const VectorSize& row,
77  const VectorSize& col) {
78  custom_jac_ = CustomPosition(fun_.Range(), fun_.Domain(), row, col);
79  }
80 
81  template<class VectorSet>
82  inline void setCustomSparseJacobianElements(const VectorSet& elements) {
83  custom_jac_ = CustomPosition(fun_.Range(), fun_.Domain(), elements);
84  }
85 
86  template<class VectorSize>
87  inline void setCustomSparseHessianElements(const VectorSize& row,
88  const VectorSize& col) {
89  size_t n = fun_.Domain();
90  custom_hess_ = CustomPosition(n, n, row, col);
91  }
92 
93  template<class VectorSet>
94  inline void setCustomSparseHessianElements(const VectorSet& elements) {
95  size_t n = fun_.Domain();
96  custom_hess_ = CustomPosition(n, n, elements);
97  }
98 
99  bool for_sparse_jac(size_t q,
100  const CppAD::vector<std::set<size_t> >& r,
101  CppAD::vector<std::set<size_t> >& s,
102  const CppAD::vector<CGB>& x) override {
103  return for_sparse_jac(q, r, s);
104  }
105 
106  bool for_sparse_jac(size_t q,
107  const CppAD::vector<std::set<size_t> >& r,
108  CppAD::vector<std::set<size_t> >& s) override {
109  using CppAD::vector;
110 
111  if (cacheSparsities_ || custom_jac_.isFilterDefined()) {
112  size_t n = fun_.Domain();
113  size_t m = fun_.Range();
114  if (!custom_jac_.isFullDefined()) {
115  custom_jac_.setFullElements(jacobianForwardSparsitySet<std::vector<std::set<size_t> > >(fun_));
116  fun_.size_forward_set(0);
117  }
118 
119  for (size_t i = 0; i < s.size(); i++) {
120  s[i].clear();
121  }
122  CppAD::cg::multMatrixMatrixSparsity(custom_jac_.getFullElements(), r, s, m, n, q);
123  } else {
124  s = fun_.ForSparseJac(q, r);
125  fun_.size_forward_set(0);
126  }
127 
128  return true;
129  }
130 
131  bool rev_sparse_jac(size_t q,
132  const CppAD::vector<std::set<size_t> >& rt,
133  CppAD::vector<std::set<size_t> >& st,
134  const CppAD::vector<CGB>& x) override {
135  return rev_sparse_jac(q, rt, st);
136  }
137 
138  bool rev_sparse_jac(size_t q,
139  const CppAD::vector<std::set<size_t> >& rt,
140  CppAD::vector<std::set<size_t> >& st) override {
141  using CppAD::vector;
142 
143  if (cacheSparsities_ || custom_jac_.isFilterDefined()) {
144  size_t n = fun_.Domain();
145  size_t m = fun_.Range();
146  if (!custom_jac_.isFullDefined()) {
147  custom_jac_.setFullElements(jacobianReverseSparsitySet<std::vector<std::set<size_t> > >(fun_));
148  }
149 
150  for (size_t i = 0; i < st.size(); i++) {
151  st[i].clear();
152  }
153  CppAD::cg::multMatrixMatrixSparsityTrans(rt, custom_jac_.getFullElements(), st, m, n, q);
154  } else {
155  st = fun_.RevSparseJac(q, rt, true);
156  }
157 
158  return true;
159  }
160 
161  bool rev_sparse_hes(const CppAD::vector<bool>& vx,
162  const CppAD::vector<bool>& s,
164  size_t q,
165  const CppAD::vector<std::set<size_t> >& r,
166  const CppAD::vector<std::set<size_t> >& u,
167  CppAD::vector<std::set<size_t> >& v,
168  const CppAD::vector<CGB>& x) override {
169  return rev_sparse_hes(vx, s, t, q, r, u, v);
170  }
171 
173  const CppAD::vector<bool>& s,
175  size_t q,
176  const CppAD::vector<std::set<size_t> >& r,
177  const CppAD::vector<std::set<size_t> >& u,
178  CppAD::vector<std::set<size_t> >& v) override {
179  using CppAD::vector;
180 
181  if (cacheSparsities_ || custom_jac_.isFilterDefined() || custom_hess_.isFilterDefined()) {
182  size_t n = fun_.Domain();
183  size_t m = fun_.Range();
184 
185  for (size_t i = 0; i < n; i++) {
186  v[i].clear();
187  }
188 
189  if (!custom_jac_.isFullDefined()) {
190  custom_jac_.setFullElements(jacobianSparsitySet<std::vector<std::set<size_t> > >(fun_));
191  }
192  const std::vector<std::set<size_t> >& jacSparsity = custom_jac_.getFullElements();
193 
197  // f'^T(x) U(x)
198  CppAD::cg::multMatrixTransMatrixSparsity(jacSparsity, u, v, m, n, q);
199 
200  // Sum( s(x)i f''(x) R(x) )
201  bool allSelected = true;
202  for (size_t i = 0; i < m; i++) {
203  if (!s[i]) {
204  allSelected = false;
205  break;
206  }
207  }
208 
209  if (allSelected) {
210  if (!custom_hess_.isFullDefined()) {
211  custom_hess_.setFullElements(hessianSparsitySet<std::vector<std::set<size_t> > >(fun_)); // f''(x)
212  }
213  const std::vector<std::set<size_t> >& sF2 = custom_hess_.getFullElements();
214  CppAD::cg::multMatrixTransMatrixSparsity(sF2, r, v, n, n, q); // f''^T * R
215  } else {
216  vector<std::set<size_t> > sparsitySF2R(n);
217  for (size_t i = 0; i < m; i++) {
218  if (s[i]) {
219  const auto itH = hess_.find(i);
220  const vector<std::set<size_t> >* spari;
221  if (itH == hess_.end()) {
222  vector<std::set<size_t> >& hi = hess_[i] = hessianSparsitySet<vector<std::set<size_t> > >(fun_, i); // f''_i(x)
223  spari = &hi;
224  custom_hess_.filter(hi);
225  } else {
226  spari = &itH->second;
227  }
228  CppAD::cg::addMatrixSparsity(*spari, sparsitySF2R);
229  }
230  }
231  CppAD::cg::multMatrixTransMatrixSparsity(sparsitySF2R, r, v, n, n, q); // f''^T * R
232  }
233 
237  for (size_t i = 0; i < m; i++) {
238  if (s[i]) {
239  for (size_t j : jacSparsity[i]) {
240  t[j] = true;
241  }
242  }
243  }
244  } else {
245  size_t m = fun_.Range();
246  size_t n = fun_.Domain();
247 
248  t = fun_.RevSparseJac(1, s);
249  vector<std::set<size_t> > a = fun_.RevSparseJac(q, u, true);
250 
251  // set version of s
252  vector<std::set<size_t> > set_s(1);
253  for (size_t i = 0; i < m; i++) {
254  if (s[i])
255  set_s[0].insert(i);
256  }
257 
258  fun_.ForSparseJac(q, r);
259  v = fun_.RevSparseHes(q, set_s, true);
260 
261  for (size_t i = 0; i < n; i++) {
262  for (size_t j : a[i]) {
263  CPPAD_ASSERT_UNKNOWN(j < q)
264  v[i].insert(j);
265  }
266  }
267 
268  fun_.size_forward_set(0);
269  }
270 
271  return true;
272  }
273 
274 protected:
275 
276  void zeroOrderDependency(const CppAD::vector<bool>& vx,
278  const CppAD::vector<CGB>& x) override {
279  CppAD::cg::zeroOrderDependency(fun_, vx, vy);
280  }
281 
282  bool atomicForward(size_t q,
283  size_t p,
284  const CppAD::vector<Base>& tx,
285  CppAD::vector<Base>& ty) override {
286  using CppAD::vector;
287 
288  vector<CGB> txcg(tx.size());
289  toCG(tx, txcg);
290 
291  vector<CGB> tycg = fun_.Forward(p, txcg);
292  fromCG(tycg, ty);
293 
294  fun_.capacity_order(0);
295 
296  return true;
297  }
298 
299  bool atomicReverse(size_t p,
300  const CppAD::vector<Base>& tx,
301  const CppAD::vector<Base>& ty,
303  const CppAD::vector<Base>& py) override {
304  using CppAD::vector;
305 
306  vector<CGB> txcg(tx.size());
307  vector<CGB> pycg(py.size());
308 
309  toCG(tx, txcg);
310  toCG(py, pycg);
311 
312  fun_.Forward(p, txcg);
313 
314  vector<CGB> pxcg = fun_.Reverse(p + 1, pycg);
315  fromCG(pxcg, px);
316 
317  fun_.capacity_order(0);
318  return true;
319  }
320 
321 private:
322 
323  static void toCG(const CppAD::vector<Base>& from,
324  CppAD::vector<CGB>& to) {
325  CPPAD_ASSERT_UNKNOWN(from.size() == to.size())
326 
327  for (size_t i = 0; i < from.size(); i++) {
328  to[i] = from[i];
329  }
330  }
331 
332  static void fromCG(const CppAD::vector<CGB>& from,
333  CppAD::vector<Base>& to) {
334  CPPAD_ASSERT_UNKNOWN(from.size() == to.size())
335 
336  for (size_t i = 0; i < from.size(); i++) {
337  CPPADCG_ASSERT_KNOWN(from[i].isValueDefined(), "No value defined")
338  to[i] = from[i].getValue();
339  }
340  }
341 
342 };
343 
344 } // END cg namespace
345 } // END CppAD namespace
346 
347 #endif
bool atomicForward(size_t q, size_t p, const CppAD::vector< Base > &tx, CppAD::vector< Base > &ty) override
CGAtomicFunBridge(const std::string &name, CppAD::ADFun< CGB > &fun, bool standAlone=false, bool cacheSparsities=true)
bool rev_sparse_hes(const CppAD::vector< bool > &vx, const CppAD::vector< bool > &s, CppAD::vector< bool > &t, size_t q, const CppAD::vector< std::set< size_t > > &r, const CppAD::vector< std::set< size_t > > &u, CppAD::vector< std::set< size_t > > &v) override
bool atomicReverse(size_t p, const CppAD::vector< Base > &tx, const CppAD::vector< Base > &ty, CppAD::vector< Base > &px, const CppAD::vector< Base > &py) override