TMB Documentation  v1.9.11
tmbad_atomic_macro.hpp
1 
2 
3 #define TMB_ATOMIC_VECTOR_FUNCTION_DEFINE( \
4  ATOMIC_NAME, OUTPUT_DIM, \
5  ATOMIC_DOUBLE, \
6  ATOMIC_REVERSE \
7 ) \
8 template<class dummy> \
9 CppAD::vector<TMBad::ad_aug> \
10 ATOMIC_NAME (const CppAD::vector<TMBad::ad_aug> &x); \
11 template<class dummy> \
12 CppAD::vector<double> \
13 ATOMIC_NAME (const CppAD::vector<double> &tx) CSKIP_ATOMIC({ \
14  CppAD::vector<double> ty(OUTPUT_DIM); \
15  ATOMIC_DOUBLE; \
16  return ty; \
17 }) \
18 template<class dummy=void> \
19 struct ATOMIC_NAME ## Op : TMBad::global::DynamicInputOutputOperator { \
20  typedef TMBad::global::DynamicInputOutputOperator Base; \
21  ATOMIC_NAME ## Op (TMBad::Index n, TMBad::Index m) : Base(n, m) {} \
22  const char* op_name() { return #ATOMIC_NAME; } \
23  static const bool add_static_identifier = true; \
24  void forward(TMBad::ForwardArgs<TMBad::Scalar> _args_) { \
25  CppAD::vector<TMBad::Scalar> tx(this->input_size()); \
26  CppAD::vector<TMBad::Scalar> ty(this->output_size()); \
27  for (size_t i=0; i<tx.size(); i++) tx[i] = _args_.x(i); \
28  ATOMIC_DOUBLE; \
29  for (size_t i=0; i<ty.size(); i++) _args_.y(i) = ty[i]; \
30  } \
31  void forward(TMBad::ForwardArgs<TMBad::Replay> _args_) { \
32  CppAD::vector<TMBad::Replay> tx(this->input_size()); \
33  for (size_t i=0; i<tx.size(); i++) tx[i] = _args_.x(i); \
34  CppAD::vector<TMBad::Replay> ty = ATOMIC_NAME(tx); \
35  for (size_t i=0; i<ty.size(); i++) _args_.y(i) = ty[i]; \
36  } \
37  template<class Type> void reverse(TMBad::ReverseArgs<Type> _args_) { \
38  if (isDouble<Type>::value && \
39  this->output_size() == 1 && \
40  _args_.dy(0) == Type(0)) { \
41  return; \
42  } \
43  CppAD::vector<Type> tx(this->input_size()); \
44  CppAD::vector<Type> ty(this->output_size()); \
45  CppAD::vector<Type> px(this->input_size()); \
46  CppAD::vector<Type> py(this->output_size()); \
47  for (size_t i=0; i<tx.size(); i++) tx[i] = _args_.x(i); \
48  for (size_t i=0; i<ty.size(); i++) ty[i] = _args_.y(i); \
49  for (size_t i=0; i<py.size(); i++) py[i] = _args_.dy(i); \
50  ATOMIC_REVERSE; \
51  for (size_t i=0; i<px.size(); i++) _args_.dx(i) += px[i]; \
52  } \
53  void forward \
54  (TMBad::ForwardArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); } \
55  void reverse \
56  (TMBad::ReverseArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); } \
57 }; \
58 template<class dummy> \
59 CppAD::vector<TMBad::ad_aug> \
60 ATOMIC_NAME (const CppAD::vector<TMBad::ad_aug> &tx) CSKIP_ATOMIC({ \
61  TMBad::Index n = tx.size(); \
62  TMBad::Index m = OUTPUT_DIM; \
63  typedef ATOMIC_NAME ## Op <> OP; \
64  bool all_constant = true; \
65  for (size_t i = 0; i<tx.size(); i++) \
66  all_constant &= tx[i].constant(); \
67  CppAD::vector<TMBad::ad_aug> ty(m); \
68  if (all_constant) { \
69  CppAD::vector<double> xd(tx.size()); \
70  for (size_t i=0; i<xd.size(); i++) xd[i] = tx[i].Value(); \
71  CppAD::vector<double> yd = ATOMIC_NAME(xd); \
72  for (size_t i=0; i<yd.size(); i++) ty[i] = yd[i]; \
73  } else { \
74  TMBad::OperatorPure* \
75  pOp = TMBad::get_glob()->getOperator<OP>(n, m); \
76  std::vector<TMBad::ad_plain> \
77  x(&tx[0], &tx[0] + tx.size()); \
78  std::vector<TMBad::ad_plain> \
79  y = TMBad::get_glob()->add_to_stack<OP>(pOp, x); \
80  for (size_t i=0; i<y.size(); i++) ty[i] = y[i]; \
81  } \
82  return ty; \
83 }) \
84 template<class dummy=void> \
85 void ATOMIC_NAME (const CppAD::vector<TMBad::ad_aug> &tx, \
86  CppAD::vector<TMBad::ad_aug> &ty) { \
87  ty = ATOMIC_NAME(tx); \
88 } \
89 IF_TMB_PRECOMPILE_ATOMICS( \
90 template \
91 CppAD::vector<double> \
92 ATOMIC_NAME<> (const CppAD::vector<double>& tx); \
93 template \
94 CppAD::vector<TMBad::ad_aug> \
95 ATOMIC_NAME<>(const CppAD::vector<TMBad::ad_aug>& tx); \
96 )
97 
98 #define TMB_ATOMIC_STATIC_FUNCTION( \
99  ATOMIC_NAME, \
100  INPUT_SIZE, \
101  ATOMIC_DOUBLE, \
102  ATOMIC_REVERSE \
103 ) \
104 template<class dummy=void> \
105 CppAD::vector<TMBad::ad_aug> ATOMIC_NAME \
106 (const CppAD::vector<TMBad::ad_aug> &x); \
107 template<class dummy=void> \
108 CppAD::vector<double> ATOMIC_NAME \
109 (const CppAD::vector<double> &tx) CSKIP_ATOMIC({ \
110  CppAD::vector<double> ty(1); \
111  ATOMIC_DOUBLE; \
112  return ty; \
113 }) \
114 template<class dummy=void> \
115 double ATOMIC_NAME (const double *tx) { \
116  double ty[1]; \
117  ATOMIC_DOUBLE; \
118  return ty[0]; \
119 } \
120 template<class dummy=void> \
121 TMBad::ad_aug ATOMIC_NAME (const TMBad::ad_aug *tx) { \
122  CppAD::vector<TMBad::ad_aug> tx_(INPUT_SIZE); \
123  for (size_t i=0; i<INPUT_SIZE; i++) tx_[i]=tx[i]; \
124  return ATOMIC_NAME(tx_)[0]; \
125 } \
126 template<class dummy=void> \
127 struct ATOMIC_NAME ## Op : TMBad::global::Operator<INPUT_SIZE, 1> { \
128  ATOMIC_NAME ## Op () {} \
129  const char* op_name() { return #ATOMIC_NAME; } \
130  void forward(TMBad::ForwardArgs<TMBad::Scalar> _args_) { \
131  TMBad::Scalar tx[INPUT_SIZE]; \
132  TMBad::Scalar ty[1] ; \
133  for (size_t i=0; i<INPUT_SIZE; i++) tx[i] = _args_.x(i); \
134  ATOMIC_DOUBLE; \
135  for (size_t i=0; i<1; i++) _args_.y(i) = ty[i]; \
136  } \
137  static const bool add_forward_replay_copy = true; \
138  template<class Type> void no_W_set_but_not_used(Type *p) { } \
139  template<class Type> void reverse(TMBad::ReverseArgs<Type> _args_) { \
140  Type tx[INPUT_SIZE]; \
141  Type ty[1] ; \
142  Type px[INPUT_SIZE]; \
143  Type py[1] ; \
144  no_W_set_but_not_used(tx); \
145  no_W_set_but_not_used(ty); \
146  no_W_set_but_not_used(py); \
147  for (size_t i=0; i<INPUT_SIZE; i++) tx[i] = _args_.x(i); \
148  for (size_t i=0; i<1 ; i++) ty[i] = _args_.y(i); \
149  for (size_t i=0; i<1 ; i++) py[i] = _args_.dy(i); \
150  ATOMIC_REVERSE; \
151  for (size_t i=0; i<INPUT_SIZE; i++) _args_.dx(i) += px[i]; \
152  } \
153  template<class Type> \
154  void forward \
155  (TMBad::ForwardArgs<Type> &args) { TMBAD_ASSERT(false); } \
156  void reverse \
157  (TMBad::ReverseArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); } \
158 }; \
159 template<class dummy> \
160 CppAD::vector<TMBad::ad_aug> ATOMIC_NAME \
161 (const CppAD::vector<TMBad::ad_aug> &tx) CSKIP_ATOMIC({ \
162  TMBad::Index m = 1; \
163  typedef ATOMIC_NAME ## Op <> OP; \
164  bool all_constant = true; \
165  for (size_t i = 0; i<tx.size(); i++) \
166  all_constant &= tx[i].constant(); \
167  CppAD::vector<TMBad::ad_aug> ty(m); \
168  if (all_constant) { \
169  CppAD::vector<double> xd(tx.size()); \
170  for (size_t i=0; i<xd.size(); i++) xd[i] = tx[i].Value(); \
171  CppAD::vector<double> yd = ATOMIC_NAME(xd); \
172  for (size_t i=0; i<yd.size(); i++) ty[i] = yd[i]; \
173  } else { \
174  TMBad::OperatorPure* \
175  pOp = TMBad::get_glob()->getOperator<OP>(); \
176  std::vector<TMBad::ad_plain> \
177  x(&tx[0], &tx[0] + tx.size()); \
178  std::vector<TMBad::ad_plain> \
179  y = TMBad::get_glob()->add_to_stack<OP>(pOp, x); \
180  for (size_t i=0; i<y.size(); i++) ty[i] = y[i]; \
181  } \
182  return ty; \
183 }) \
184 template<class dummy=void> \
185 void ATOMIC_NAME (const CppAD::vector<TMBad::ad_aug> &tx, \
186  CppAD::vector<TMBad::ad_aug> &ty) { \
187  ty = ATOMIC_NAME(tx); \
188 } \
189 IF_TMB_PRECOMPILE_ATOMICS( \
190 template \
191 CppAD::vector<double> \
192 ATOMIC_NAME<> (const CppAD::vector<double>& tx); \
193 template \
194 CppAD::vector<TMBad::ad_aug> \
195 ATOMIC_NAME<>(const CppAD::vector<TMBad::ad_aug>& tx); \
196 )
197 // Helper to forward declare atomic
198 #define TMB_ATOMIC_VECTOR_FUNCTION_DECLARE(ATOMIC_NAME) \
199 template<class dummy=void> \
200 CppAD::vector<TMBad::ad_aug> \
201 ATOMIC_NAME (const CppAD::vector<TMBad::ad_aug> &x); \
202 template<class dummy=void> \
203 CppAD::vector<double> \
204 ATOMIC_NAME (const CppAD::vector<double> &tx);
205 
217 #define TMB_ATOMIC_VECTOR_FUNCTION( \
218  ATOMIC_NAME, OUTPUT_DIM, \
219  ATOMIC_DOUBLE, \
220  ATOMIC_REVERSE \
221 ) \
222 TMB_ATOMIC_VECTOR_FUNCTION_DECLARE(ATOMIC_NAME) \
223 TMB_ATOMIC_VECTOR_FUNCTION_DEFINE( \
224  ATOMIC_NAME, OUTPUT_DIM, \
225  ATOMIC_DOUBLE, \
226  ATOMIC_REVERSE \
227 )
License: GPL v2