CppAD: A C++ Algorithmic Differentiation Package  20171217
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
record_csum.hpp
Go to the documentation of this file.
1 # ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
2 # define CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
3 /* --------------------------------------------------------------------------
4 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
5 
6 CppAD is distributed under multiple licenses. This distribution is under
7 the terms of the
8  Eclipse Public License Version 1.0.
9 
10 A copy of this license is included in the COPYING file of this distribution.
11 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
12 -------------------------------------------------------------------------- */
13 /*!
14 \file record_csum.hpp
15 Recording a cummulative cummulative summation.
16 */
18 
19 // BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
20 namespace CppAD { namespace local { namespace optimize {
21 /*!
22 Recording a cummulative cummulative summation.
23 
24 \param play
25 player object corresponding to the old recroding.
26 
27 \param opt_op_info
28 mapping from old index to operator index to operator information
29 
30 \param old2new
31 mapping from old operator index to information about the new recording.
32 
33 \param current
34 is the index in the old operation sequence for
35 the variable corresponding to the result for the current operator.
36 We use the notation i_op = play->var2op(current).
37 It follows that NumRes( opt_op_info[i_op].op ) > 0.
38 If 0 < j_op < i_op, either opt_op_info[j_op].usage == csum_usage,
39 opt_op_info[j_op].usage = no_usage, or old2new[j_op].new_var != 0.
40 
41 \param rec
42 is the object that will record the new operations.
43 
44 \return
45 is the operator and variable indices in the new operation sequence.
46 
47 \param work
48 Is temporary work space. On input and output,
49 work.op_stack, work.add_stack, and work.sub_stack, are all empty.
50 These stacks are passed in so that they are created once
51 and then be reused with calls to record_csum.
52 
53 \par Assumptions
54 opt_op_info[i_o].op
55 must be one of AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp.
56 opt_op_info[i_op].usage != no_usage and ! opt_op_info[i_op].usage == csum_usage.
57 Furthermore opt_op_info[j_op].usage == csum_usage is true from some
58 j_op that corresponds to a variable that is an argument to
59 opt_op_info[i_op].
60 */
61 
62 template <class Base>
64  const player<Base>* play ,
65  const vector<struct_opt_op_info>& opt_op_info ,
67  size_t current ,
68  recorder<Base>* rec ,
69  // local information passed so stacks need not be allocated for every call
70  struct_csum_stacks& work )
71 {
72 # ifndef NDEBUG
73  // number of parameters corresponding to the old operation sequence.
74  size_t npar = play->num_par_rec();
75 # endif
76 
77  // vector of length npar containing the parameters the old operation
78  // sequence; i.e., given a parameter index i < npar, the corresponding
79  // parameter value is par[i].
80  const Base* par = play->GetPar();
81 
82  // check assumption about work space
83  CPPAD_ASSERT_UNKNOWN( work.op_stack.empty() );
84  CPPAD_ASSERT_UNKNOWN( work.add_stack.empty() );
85  CPPAD_ASSERT_UNKNOWN( work.sub_stack.empty() );
86  //
87  size_t i_op = play->var2op(current);
88  CPPAD_ASSERT_UNKNOWN( ! ( opt_op_info[i_op].usage == csum_usage ) );
89  //
90  // information corresponding to the root node in the cummulative summation
91  struct struct_csum_variable var;
92  size_t not_used;
93  play->get_op_info(i_op, var.op, var.arg, not_used);
94  var.add = true; // was parrent operator positive or negative
95  //
96  // initialize stack as containing this one operator
97  work.op_stack.push( var );
98  //
99  // initialize sum of parameter values as zero
100  Base sum_par(0);
101  //
102 # ifndef NDEBUG
103  bool ok = false;
104  if( var.op == SubvpOp )
105  ok = opt_op_info[ play->var2op(var.arg[0]) ].usage == csum_usage;
106  if( var.op == AddpvOp || var.op == SubpvOp )
107  ok = opt_op_info[ play->var2op(var.arg[1]) ].usage == csum_usage;
108  if( var.op == AddvvOp || var.op == SubvvOp )
109  { ok = opt_op_info[ play->var2op(var.arg[0]) ].usage == csum_usage;
110  ok |= opt_op_info[ play->var2op(var.arg[1]) ].usage == csum_usage;
111  }
112  CPPAD_ASSERT_UNKNOWN( ok );
113 # endif
114  //
115  // while there are operators left on the stack
116  while( ! work.op_stack.empty() )
117  { // get this summation operator
118  var = work.op_stack.top();
119  work.op_stack.pop();
120  OpCode op = var.op;
121  const addr_t* arg = var.arg;
122  bool add = var.add;
123  //
124  // process first argument to this operator
125  switch(op)
126  { // cases where first argument is a parameter
127  case AddpvOp:
128  case SubpvOp:
129  CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
130  // first argument has same sign as parent node
131  if( add )
132  sum_par += par[arg[0]];
133  else sum_par -= par[arg[0]];
134  break;
135 
136  // cases where first argument is a variable
137  case AddvvOp:
138  case SubvpOp:
139  case SubvvOp:
140  //
141  // check if the first argument has csum usage
142  if( opt_op_info[play->var2op(arg[0])].usage == csum_usage )
144  size_t( old2new[ play->var2op(arg[0]) ].new_var) == 0
145  );
146  // push the operator corresponding to the first argument
147  size_t i_op_tmp = play->var2op(arg[0]);
148  play->get_op_info(i_op_tmp, var.op, var.arg, not_used);
149  // first argument has same sign as parent node
150  var.add = add;
151  work.op_stack.push( var );
152  }
153  else
154  { // there are no nodes below this one
155  CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < current );
156  if( add )
157  work.add_stack.push(arg[0]);
158  else work.sub_stack.push(arg[0]);
159  }
160  break;
161 
162  default:
163  CPPAD_ASSERT_UNKNOWN(false);
164  }
165  // process second argument to this operator
166  switch(op)
167  { // cases where second argument is a parameter
168  case SubvpOp:
169  CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar );
170  // second argument has opposite sign of parent node
171  if( add )
172  sum_par -= par[arg[1]];
173  else sum_par += par[arg[1]];
174  break;
175 
176  // cases where second argument is a variable and has opposite sign
177  case SubvvOp:
178  case SubpvOp:
179  add = ! add;
180 
181  // cases where second argument is a variable and has same sign
182  case AddvvOp:
183  case AddpvOp:
184  // check if the second argument has csum usage
185  if( opt_op_info[play->var2op(arg[1])].usage == csum_usage )
187  size_t( old2new[ play->var2op(arg[1]) ].new_var) == 0
188  );
189  // push the operator corresoponding to the second arugment
190  size_t i_op_tmp = play->var2op(arg[1]);
191  play->get_op_info(i_op_tmp, var.op, var.arg, not_used);
192  var.add = add;
193  work.op_stack.push( var );
194  }
195  else
196  { // there are no nodes below this one
197  CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < current );
198  if( add )
199  work.add_stack.push(arg[1]);
200  else work.sub_stack.push(arg[1]);
201  }
202  break;
203 
204  default:
205  CPPAD_ASSERT_UNKNOWN(false);
206  }
207  }
208  // number of variables to add in this cummulative sum operator
209  size_t n_add = work.add_stack.size();
210  // number of variables to subtract in this cummulative sum operator
211  size_t n_sub = work.sub_stack.size();
212  //
214  std::numeric_limits<addr_t>::max() >= n_add + n_sub
215  );
216  //
217  rec->PutArg( addr_t(n_add) ); // arg[0]
218  rec->PutArg( addr_t(n_sub) ); // arg[1]
219  addr_t new_arg = rec->PutPar(sum_par);
220  rec->PutArg(new_arg); // arg[2]
221  // addition arguments
222  for(size_t i = 0; i < n_add; i++)
223  { CPPAD_ASSERT_UNKNOWN( ! work.add_stack.empty() );
224  size_t old_arg = work.add_stack.top();
225  new_arg = old2new[ play->var2op(old_arg) ].new_var;
226  CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current );
227  rec->PutArg(new_arg); // arg[3+i]
228  work.add_stack.pop();
229  }
230  // subtraction arguments
231  for(size_t i = 0; i < n_sub; i++)
232  { CPPAD_ASSERT_UNKNOWN( ! work.sub_stack.empty() );
233  size_t old_arg = work.sub_stack.top();
234  new_arg = old2new[ play->var2op(old_arg) ].new_var;
235  CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current );
236  rec->PutArg(new_arg); // arg[3 + arg[0] + i]
237  work.sub_stack.pop();
238  }
239  // number of additions plus number of subtractions
240  rec->PutArg( addr_t(n_add + n_sub) ); // arg[3 + arg[0] + arg[1]]
241  //
242  // return value
243  struct_size_pair ret;
244  ret.i_op = rec->num_op_rec();
245  ret.i_var = rec->PutOp(CSumOp);
246  //
247  return ret;
248 }
249 
250 } } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
251 
252 
253 # endif
This operator is only used once, it is a summation operator, and its parrent is a summation operator...
Definition: usage.hpp:31
addr_t PutOp(OpCode op)
Put next operator in the operation sequence.
Definition: recorder.hpp:185
size_t num_par_rec(void) const
Fetch number of parameters in the recording.
Definition: player.hpp:638
Information about one old variable that is part of a new CSumOp operation.
The CppAD Simple Vector template class.
Definition: vector.hpp:338
CPPAD_TAPE_ADDR_TYPE addr_t
Definition: declare_ad.hpp:44
Class used to store and play back an operation sequence recording.
Definition: declare_ad.hpp:27
Information about one cumulative summation operation.
Definition: csum_stacks.hpp:27
std::stack< struct struct_csum_variable > op_stack
old operator indices for this cummulative summation
Definition: csum_stacks.hpp:29
void PutArg(addr_t arg0)
Put one operation argument index in the recording.
Definition: recorder.hpp:392
Information that maps old an old operator to a new opeator and new variable.
OpCode op
Operator for which this old variable is the result, NumRes(op) &gt; 0.
addr_t PutPar(const Base &par)
Find or add a parameter to the current vector of parameters.
Definition: recorder.hpp:314
OpCode
Type used to distinguish different AD&lt; Base &gt; atomic operations.
Definition: op_code.hpp:49
std::stack< size_t > sub_stack
old variavle indices to be subtracted
Definition: csum_stacks.hpp:33
Class used to store an operation sequence while it is being recorded (the operation sequence is copie...
Definition: declare_ad.hpp:28
const addr_t * arg
Pointer to first argument (child) for this old operator. Set by the reverse sweep at beginning of opt...
void get_op_info(size_t op_index, OpCode &op, const addr_t *&op_arg, size_t &var_index) const
fetch the information corresponding to an operator
Definition: player.hpp:485
struct_size_pair record_csum(const player< Base > *play, const vector< struct_opt_op_info > &opt_op_info, const CppAD::vector< struct struct_old2new > &old2new, size_t current, recorder< Base > *rec, struct_csum_stacks &work)
Recording a cummulative cummulative summation.
Definition: record_csum.hpp:63
size_t i_var
operator index for this variable
Definition: size_pair.hpp:27
std::stack< size_t > add_stack
old variable indices to be added
Definition: csum_stacks.hpp:31
#define CPPAD_ASSERT_UNKNOWN(exp)
Check that exp is true, if not terminate execution.
size_t num_op_rec(void) const
Number of operators currently stored in the recording.
Definition: recorder.hpp:144
size_t var2op(size_t var_index) const
fetch the operator corresponding to a primary variable
Definition: player.hpp:461
Base GetPar(size_t i) const
Fetch a parameter from the recording.
Definition: player.hpp:584
bool add
Was this old variable added to the summation (if not it was subtracted)