CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
19namespace CppAD {
20namespace cg {
21
30template <class Base>
32public:
34 using ADCGD = CppAD::AD<CGB>;
35protected:
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_;
41public:
42
55 CGAtomicFunBridge(const std::string& name,
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) {
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
274protected:
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
321private:
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,
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 atomicReverse(size_t p, const CppAD::vector< Base > &tx, const CppAD::vector< Base > &ty, CppAD::vector< Base > &px, const CppAD::vector< Base > &py) 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 atomicForward(size_t q, size_t p, const CppAD::vector< Base > &tx, CppAD::vector< Base > &ty) override