CppAD: A C++ Algorithmic Differentiation Package  20171217
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
optimize_run.hpp
Go to the documentation of this file.
1 
2 # ifndef CPPAD_LOCAL_OPTIMIZE_OPTIMIZE_RUN_HPP
3 # define CPPAD_LOCAL_OPTIMIZE_OPTIMIZE_RUN_HPP
4 
5 /* --------------------------------------------------------------------------
6 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
7 
8 CppAD is distributed under multiple licenses. This distribution is under
9 the terms of the
10  Eclipse Public License Version 1.0.
11 
12 A copy of this license is included in the COPYING file of this distribution.
13 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
14 -------------------------------------------------------------------------- */
15 
16 # include <stack>
17 # include <iterator>
29 
30 /*!
31 \file optimize_run.hpp
32 Convert a player object to an optimized recorder object
33 */
34 // BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
35 namespace CppAD { namespace local { namespace optimize {
36 /*!
37 Convert a player object to an optimized recorder object
38 
39 \tparam Base
40 base type for the operator; i.e., this operation was recorded
41 using AD< \a Base > and computations by this routine are done using type
42 \a Base.
43 
44 
45 \param options
46 \li
47 If the sub-string "no_conditional_skip" appears,
48 conditional skip operations will not be generated.
49 This may make the optimize routine use significantly less memory
50 and take significantly less time.
51 \li
52 If the sub-string "no_compare_op" appears,
53 then comparison operators will be removed from the optimized tape.
54 These operators are necessary for the compare_change function to be
55 be meaningful in the resulting recording.
56 On the other hand, they are not necessary and take extra time
57 when compare_change is not used.
58 \li
59 If the sub-string "no_print_for" appears,
60 then print forward (PriOp) operators will be removed from the optimized tape.
61 These operators are useful for reporting problems evaluating derivatives
62 at independent variable values different from those used to record a function.
63 
64 \param n
65 is the number of independent variables on the tape.
66 
67 \param dep_taddr
68 On input this vector contains the indices for each of the dependent
69 variable values in the operation sequence corresponding to \a play.
70 Upon return it contains the indices for the same variables but in
71 the operation sequence corresponding to \a rec.
72 
73 \param play
74 This is the operation sequence that we are optimizing.
75 It is essentially const, except for play back state which
76 changes while it plays back the operation seqeunce.
77 
78 \param rec
79 The input contents of this recording does not matter.
80 Upon return, it contains an optimized verison of the
81 operation sequence corresponding to \a play.
82 */
83 
84 template <class Base>
86  const std::string& options ,
87  size_t n ,
88  CppAD::vector<size_t>& dep_taddr ,
89  const player<Base>* play ,
90  recorder<Base>* rec )
91 {
92  bool conditional_skip = true;
93  bool compare_op = true;
94  bool print_for_op = true;
95  size_t index = 0;
96  while( index < options.size() )
97  { while( index < options.size() && options[index] == ' ' )
98  ++index;
99  std::string option;
100  while( index < options.size() && options[index] != ' ' )
101  option += options[index++];
102  if( option != "" )
103  { if( option == "no_conditional_skip" )
104  conditional_skip = false;
105  else if( option == "no_compare_op" )
106  compare_op = false;
107  else if( option == "no_print_for_op" )
108  print_for_op = false;
109  else
110  { option += " is not a valid optimize option";
111  CPPAD_ASSERT_KNOWN( false , option.c_str() );
112  }
113  }
114  }
115  // number of operators in the player
116  const size_t num_op = play->num_op_rec();
118  num_op < size_t( std::numeric_limits<addr_t>::max() )
119  );
120 
121  // number of variables in the player
122  const size_t num_var = play->num_var_rec();
123 
124  // number of VecAD indices
125  size_t num_vecad_ind = play->num_vec_ind_rec();
126 
127  // number of VecAD vectors
128  size_t num_vecad_vec = play->num_vecad_vec_rec();
129 
130  // operator information
131  vector<struct_cexp_info> cexp_info;
132  sparse_list skip_op_true;
133  sparse_list skip_op_false;
134  vector<bool> vecad_used;
135  vector<struct_opt_op_info> opt_op_info;
137  conditional_skip,
138  compare_op,
139  print_for_op,
140  play,
141  dep_taddr,
142  cexp_info,
143  skip_op_true,
144  skip_op_false,
145  vecad_used,
146  opt_op_info
147  );
148 
149  // nan with type Base
150  Base base_nan = Base( std::numeric_limits<double>::quiet_NaN() );
151 
152  // -------------------------------------------------------------
153  // information for current operator
154  size_t i_op; // index
155  OpCode op; // operator
156  const addr_t* arg; // arguments
157  size_t i_var; // variable index of primary (last) result
158 
159  enum_user_state user_state;
160  // -------------------------------------------------------------
161  // conditional expression information
162  //
163  // Size of the conditional expression information structure.
164  // This is equal to the number of conditional expressions when
165  // conditional_skip is true, otherwise it is zero.
166  size_t num_cexp = cexp_info.size();
167  CPPAD_ASSERT_UNKNOWN( conditional_skip || num_cexp == 0 );
168  //
169  // sort the conditional expression information by max_left_right
170  // this is the conditional skip order
171  vector<size_t> cskip_order(num_cexp);
172  if( num_cexp > 0 )
173  { CppAD::vector<size_t> keys(num_cexp);
174  for(size_t i = 0; i < num_cexp; i++)
175  keys[i] = cexp_info[i].max_left_right;
176  CppAD::index_sort(keys, cskip_order);
177  }
178  // initial index in conditional skip order
179  size_t cskip_order_next = 0;
180  //
181  // initialize index in conditional expression order
182  size_t cexp_next = 0;
183 
184  // mapping from conditional expression index to conditional skip
185  // information on new tape
186  vector<struct_cskip_new> cskip_new(num_cexp);
187  //
188  // flag used to indicate that there is no conditional skip
189  // for this conditional expression
190  for(size_t i = 0; i < num_cexp; i++)
191  cskip_new[i].i_arg = 0;
192  // -------------------------------------------------------------
193 
194  // Erase all information in the old recording
195  rec->free();
196 
197  // initialize mapping from old VecAD index to new VecAD index
199  std::numeric_limits<addr_t>::max() >= num_vecad_ind
200  );
201  CppAD::vector<addr_t> new_vecad_ind(num_vecad_ind);
202  for(size_t i = 0; i < num_vecad_ind; i++)
203  new_vecad_ind[i] = addr_t( num_vecad_ind ); // invalid index
204  {
205  size_t j = 0; // index into the old set of indices
206  for(size_t i = 0; i < num_vecad_vec; i++)
207  { // length of this VecAD
208  size_t length = play->GetVecInd(j);
209  if( vecad_used[i] )
210  { // Put this VecAD vector in new recording
211  CPPAD_ASSERT_UNKNOWN(length < num_vecad_ind);
212  new_vecad_ind[j] = rec->PutVecInd(length);
213  for(size_t k = 1; k <= length; k++) new_vecad_ind[j+k] =
214  rec->PutVecInd(
215  rec->PutPar(
216  play->GetPar(
217  play->GetVecInd(j+k)
218  ) ) );
219  }
220  // start of next VecAD
221  j += length + 1;
222  }
223  CPPAD_ASSERT_UNKNOWN( j == num_vecad_ind );
224  }
225  //
226  // Mapping from old operator index to new operator information
227  // (zero is invalid except for old2new[0].new_op and old2new[0].i_var)
228  vector<struct_old2new> old2new(num_op);
229  for(size_t i = 0; i < num_op; i++)
230  { old2new[i].new_op = 0;
231  old2new[i].new_var = 0;
232  }
233 
234 
235  // temporary buffer for new argument values
236  addr_t new_arg[6];
237 
238  // temporary work space used by record_csum
239  // (decalared here to avoid realloaction of memory)
240  struct_csum_stacks csum_work;
241 
242  // tempory used to hold a size_pair
243  struct_size_pair size_pair;
244 
245  user_state = start_user;
246  i_var = 0;
247  for(i_op = 0; i_op < num_op; ++i_op)
248  { addr_t mask; // temporary used in some switch cases
249  //
250  // this operator information
251  size_t i_tmp;
252  play->get_op_info(i_op, op, arg, i_tmp);
253  if( NumRes(op) > 0 )
254  i_var = i_tmp;
255  //
256  // determine if we should insert a conditional skip here
257  bool skip = conditional_skip;
258  skip &= cskip_order_next < num_cexp;
259  skip &= op != BeginOp;
260  skip &= op != InvOp;
261  skip &= user_state == start_user;
262  if( skip )
263  { size_t j = cskip_order[cskip_order_next];
264  if( NumRes(op) > 0 )
265  skip &= cexp_info[j].max_left_right < i_var;
266  else
267  skip &= cexp_info[j].max_left_right <= i_var;
268  }
269  if( skip )
270  { size_t j = cskip_order[cskip_order_next];
271  cskip_order_next++;
272  size_t n_true = skip_op_true.number_elements(j);
273  size_t n_false = skip_op_false.number_elements(j);
274  skip &= n_true > 0 || n_false > 0;
275  if( skip )
277  size_t n_arg = 7 + n_true + n_false;
278  // reserve space for the arguments to this operator but
279  // delay setting them until we have all the new addresses
280  cskip_new[j].i_arg = rec->ReserveArg(n_arg);
281  // i_arg == 0 is used to check if conditional expression
282  // has been skipped.
283  CPPAD_ASSERT_UNKNOWN( cskip_new[j].i_arg > 0 );
284  // There is no corresponding old operator in this case
285  rec->PutOp(CSkipOp);
286  }
287  }
288  if( op == UserOp )
289  { if( user_state == start_user )
290  user_state = end_user;
291  else
292  { CPPAD_ASSERT_UNKNOWN( user_state == end_user );
293  user_state = start_user;
294  }
295  }
296  size_t previous;
297  //
299  std::numeric_limits<addr_t>::max() >= rec->num_op_rec()
300  );
301  //
302  if( opt_op_info[i_op].usage != yes_usage )
303  { if( op == CExpOp )
304  ++cexp_next;
305  }
306  else switch( op )
307  {
308  case BeginOp:
309  CPPAD_ASSERT_NARG_NRES(op, 1, 1);
310  // Put BeginOp at beginning of recording
311  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
312  old2new[i_op].new_var = rec->PutOp(BeginOp);
313  rec->PutArg(arg[0]);
314  break;
315 
316  // --------------------------------------------------------------
317  // Unary operators, argument a variable, one result
318  case AbsOp:
319  case AcosOp:
320  case AcoshOp:
321  case AsinOp:
322  case AsinhOp:
323  case AtanOp:
324  case AtanhOp:
325  case CosOp:
326  case CoshOp:
327  case ErfOp:
328  case ExpOp:
329  case Expm1Op:
330  case LogOp:
331  case Log1pOp:
332  case SignOp:
333  case SinOp:
334  case SinhOp:
335  case SqrtOp:
336  case TanOp:
337  case TanhOp:
338  previous = opt_op_info[i_op].previous;
339  if( previous > 0 )
340  { size_t j_op = previous;
341  old2new[i_op].new_var = old2new[j_op].new_var;
342  }
343  else
344  { //
345  new_arg[0] = old2new[ play->var2op(arg[0]) ].new_var;
346  rec->PutArg( new_arg[0] );
347  //
348  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
349  old2new[i_op].new_var = rec->PutOp(op);
351  new_arg[0] < old2new[play->var2op(i_var)].new_var
352  );
353  if( op == ErfOp )
354  { CPPAD_ASSERT_NARG_NRES(op, 3, 5);
355  // Error function is a special case
356  // second argument is always the parameter 0
357  // third argument is always the parameter 2 / sqrt(pi)
359  rec->PutArg( rec->PutPar( Base(0.0) ) );
360  rec->PutArg( rec->PutPar(
361  Base( 1.0 / std::sqrt( std::atan(1.0) ) )
362  ) );
363  }
364  else
365  { // some of these operators have an auxillary result;
366  // e.g. sine and cosine are computed together.
367  CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 );
368  CPPAD_ASSERT_UNKNOWN( NumRes(op) ==1 || NumRes(op) == 2 );
369  }
370  }
371  break;
372  // ---------------------------------------------------
373  // Binary operators, left variable, right parameter, one result
374  case SubvpOp:
375  // check if this is the top of a csum connection
376  if( opt_op_info[i_op].usage == csum_usage )
377  break;
378  if( opt_op_info[ play->var2op(arg[0]) ].usage == csum_usage )
379  {
380  // convert to a sequence of summation operators
381  size_pair = record_csum(
382  play ,
383  opt_op_info ,
384  old2new ,
385  i_var ,
386  rec ,
387  csum_work
388  );
389  old2new[i_op].new_op = addr_t( size_pair.i_op );
390  old2new[i_op].new_var = addr_t( size_pair.i_var );
391  // abort rest of this case
392  break;
393  }
394  case DivvpOp:
395  case PowvpOp:
396  case ZmulvpOp:
397  previous = opt_op_info[i_op].previous;
398  if( previous > 0 )
399  { size_t j_op = previous;
400  old2new[i_op].new_var = old2new[j_op].new_var;
401  }
402  else
403  { //
404  size_pair = record_vp(
405  play ,
406  old2new ,
407  i_op ,
408  rec
409  );
410  old2new[i_op].new_op = addr_t( size_pair.i_op );
411  old2new[i_op].new_var = addr_t( size_pair.i_var );
412  }
413  break;
414  // ---------------------------------------------------
415  // Binary operators, left index, right variable, one result
416  case DisOp:
417  CPPAD_ASSERT_NARG_NRES(op, 2, 1);
418  previous = opt_op_info[i_op].previous;
419  if( previous > 0 )
420  { size_t j_op = previous;
421  old2new[i_op].new_var = old2new[j_op].new_var;
422  }
423  else
424  { //
425  new_arg[0] = arg[0];
426  new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
427  rec->PutArg( new_arg[0], new_arg[1] );
428  //
429  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
430  old2new[i_op].new_var = rec->PutOp(op);
432  new_arg[1] < old2new[play->var2op(i_var)].new_var
433  );
434  }
435  break;
436 
437  // ---------------------------------------------------
438  // Binary operators, left parameter, right variable, one result
439  case SubpvOp:
440  case AddpvOp:
441  // check if this is the top of a csum connection
442  if( opt_op_info[i_op].usage == csum_usage )
443  break;
444  if( opt_op_info[ play->var2op(arg[1]) ].usage == csum_usage )
445  {
446  // convert to a sequence of summation operators
447  size_pair = record_csum(
448  play ,
449  opt_op_info ,
450  old2new ,
451  i_var ,
452  rec ,
453  csum_work
454  );
455  old2new[i_op].new_op = addr_t( size_pair.i_op );
456  old2new[i_op].new_var = addr_t( size_pair.i_var );
457  // abort rest of this case
458  break;
459  }
460  case DivpvOp:
461  case MulpvOp:
462  case PowpvOp:
463  case ZmulpvOp:
464  previous = opt_op_info[i_op].previous;
465  if( previous > 0 )
466  { size_t j_op = previous;
467  old2new[i_op].new_var = old2new[j_op].new_var;
468  }
469  else
470  { //
471  size_pair = record_pv(
472  play ,
473  old2new ,
474  i_op ,
475  rec
476  );
477  old2new[i_op].new_op = addr_t( size_pair.i_op );
478  old2new[i_op].new_var = addr_t( size_pair.i_var );
479  }
480  break;
481  // ---------------------------------------------------
482  // Binary operator, left and right variables, one result
483  case AddvvOp:
484  case SubvvOp:
485  // check if this is the top of a csum connection
486  if( opt_op_info[i_op].usage == csum_usage )
487  break;
488  if(
489  opt_op_info[ play->var2op(arg[0]) ].usage == csum_usage ||
490  opt_op_info[ play->var2op(arg[1]) ].usage == csum_usage
491  )
492  {
493  // convert to a sequence of summation operators
494  size_pair = record_csum(
495  play ,
496  opt_op_info ,
497  old2new ,
498  i_var ,
499  rec ,
500  csum_work
501  );
502  old2new[i_op].new_op = addr_t( size_pair.i_op );
503  old2new[i_op].new_var = addr_t( size_pair.i_var );
504  // abort rest of this case
505  break;
506  }
507  case DivvvOp:
508  case MulvvOp:
509  case PowvvOp:
510  case ZmulvvOp:
511  previous = opt_op_info[i_op].previous;
512  if( previous > 0 )
513  { size_t j_op = previous;
514  old2new[i_op].new_var = old2new[j_op].new_var;
515  }
516  else
517  { //
518  size_pair = record_vv(
519  play ,
520  old2new ,
521  i_op ,
522  rec
523  );
524  old2new[i_op].new_op = addr_t( size_pair.i_op );
525  old2new[i_op].new_var = addr_t( size_pair.i_var );
526  }
527  break;
528  // ---------------------------------------------------
529  // Conditional expression operators
530  case CExpOp:
531  CPPAD_ASSERT_NARG_NRES(op, 6, 1);
532  new_arg[0] = arg[0];
533  new_arg[1] = arg[1];
534  mask = 1;
535  for(size_t i = 2; i < 6; i++)
536  { if( arg[1] & mask )
537  { new_arg[i] = old2new[ play->var2op(arg[i]) ].new_var;
539  size_t(new_arg[i]) < num_var
540  );
541  }
542  else new_arg[i] = rec->PutPar(
543  play->GetPar( arg[i] )
544  );
545  mask = mask << 1;
546  }
547  rec->PutArg(
548  new_arg[0] ,
549  new_arg[1] ,
550  new_arg[2] ,
551  new_arg[3] ,
552  new_arg[4] ,
553  new_arg[5]
554  );
555  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
556  old2new[i_op].new_var = rec->PutOp(op);
557  //
558  // The new addresses for left and right are used during
559  // fill in the arguments for the CSkip operations. This does not
560  // affect max_left_right which is used during this sweep.
561  if( conditional_skip )
562  { CPPAD_ASSERT_UNKNOWN( cexp_next < num_cexp );
563  CPPAD_ASSERT_UNKNOWN( cexp_info[cexp_next].i_op == i_op );
564  cskip_new[ cexp_next ].left = new_arg[2];
565  cskip_new[ cexp_next ].right = new_arg[3];
566  ++cexp_next;
567  }
568  break;
569  // ---------------------------------------------------
570  // Operations with no arguments and no results
571  case EndOp:
572  CPPAD_ASSERT_NARG_NRES(op, 0, 0);
573  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
574  rec->PutOp(op);
575  break;
576  // ---------------------------------------------------
577  // Operations with two arguments and no results
578  case LepvOp:
579  case LtpvOp:
580  case EqpvOp:
581  case NepvOp:
582  CPPAD_ASSERT_NARG_NRES(op, 2, 0);
583  new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
584  new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
585  rec->PutArg(new_arg[0], new_arg[1]);
586  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
587  rec->PutOp(op);
588  break;
589  //
590  case LevpOp:
591  case LtvpOp:
592  CPPAD_ASSERT_NARG_NRES(op, 2, 0);
593  new_arg[0] = old2new[ play->var2op(arg[0]) ].new_var;
594  new_arg[1] = rec->PutPar( play->GetPar(arg[1]) );
595  rec->PutArg(new_arg[0], new_arg[1]);
596  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
597  rec->PutOp(op);
598  break;
599  //
600  case LevvOp:
601  case LtvvOp:
602  case EqvvOp:
603  case NevvOp:
604  CPPAD_ASSERT_NARG_NRES(op, 2, 0);
605  new_arg[0] = old2new[ play->var2op(arg[0]) ].new_var;
606  new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
607  rec->PutArg(new_arg[0], new_arg[1]);
608  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
609  rec->PutOp(op);
610  break;
611 
612  // ---------------------------------------------------
613  // Operations with no arguments and one result
614  case InvOp:
615  CPPAD_ASSERT_NARG_NRES(op, 0, 1);
616  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
617  old2new[i_op].new_var = rec->PutOp(op);
618  break;
619 
620  // ---------------------------------------------------
621  // Unary operators, argument a parameter, one result
622  case ParOp:
623  CPPAD_ASSERT_NARG_NRES(op, 1, 1);
624  new_arg[0] = rec->PutPar( play->GetPar(arg[0] ) );
625  rec->PutArg( new_arg[0] );
626  //
627  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
628  old2new[i_op].new_var = rec->PutOp(op);
629  break;
630 
631  // ---------------------------------------------------
632  // print forward operator
633  case PriOp:
634  CPPAD_ASSERT_NARG_NRES(op, 5, 0);
635  // arg[0]
636  new_arg[0] = arg[0];
637  //
638  // arg[1]
639  if( arg[0] & 1 )
640  { new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
641  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
642  }
643  else
644  { new_arg[1] = rec->PutPar( play->GetPar( arg[1] ) );
645  }
646  //
647  // arg[3]
648  if( arg[0] & 2 )
649  { new_arg[3] = old2new[ play->var2op(arg[3]) ].new_var;
650  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[3]) < num_var );
651  }
652  else
653  { new_arg[3] = rec->PutPar( play->GetPar( arg[3] ) );
654  }
655  new_arg[2] = rec->PutTxt( play->GetTxt(arg[2]) );
656  new_arg[4] = rec->PutTxt( play->GetTxt(arg[4]) );
657  //
658  rec->PutArg(
659  new_arg[0] ,
660  new_arg[1] ,
661  new_arg[2] ,
662  new_arg[3] ,
663  new_arg[4]
664  );
665  // new operator
666  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
667  // no new variable
668  rec->PutOp(op);
669  break;
670 
671  // ---------------------------------------------------
672  // VecAD operators
673 
674  // Load using a parameter index
675  case LdpOp:
676  CPPAD_ASSERT_NARG_NRES(op, 3, 1);
677  new_arg[0] = new_vecad_ind[ arg[0] ];
678  new_arg[1] = arg[1];
680  std::numeric_limits<addr_t>::max() >= rec->num_load_op_rec()
681  );
682  new_arg[2] = addr_t( rec->num_load_op_rec() );
683  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
684  rec->PutArg(
685  new_arg[0],
686  new_arg[1],
687  new_arg[2]
688  );
689  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
690  old2new[i_op].new_var = rec->PutLoadOp(op);
691  break;
692 
693  // Load using a variable index
694  case LdvOp:
695  CPPAD_ASSERT_NARG_NRES(op, 3, 1);
696  new_arg[0] = new_vecad_ind[ arg[0] ];
697  new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
699  std::numeric_limits<addr_t>::max() >= rec->num_load_op_rec()
700  );
701  new_arg[2] = addr_t( rec->num_load_op_rec() );
702  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
703  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
704  rec->PutArg(
705  new_arg[0],
706  new_arg[1],
707  new_arg[2]
708  );
709  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
710  old2new[i_op].new_var = rec->PutLoadOp(op);
711  break;
712 
713  // Store a parameter using a parameter index
714  case StppOp:
715  CPPAD_ASSERT_NARG_NRES(op, 3, 0);
716  new_arg[0] = new_vecad_ind[ arg[0] ];
717  new_arg[1] = rec->PutPar( play->GetPar(arg[1]) );
718  new_arg[2] = rec->PutPar( play->GetPar(arg[2]) );
719  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
720  rec->PutArg(
721  new_arg[0],
722  new_arg[1],
723  new_arg[2]
724  );
725  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
726  rec->PutOp(op);
727  break;
728 
729  // Store a parameter using a variable index
730  case StvpOp:
731  CPPAD_ASSERT_NARG_NRES(op, 3, 0);
732  new_arg[0] = new_vecad_ind[ arg[0] ];
733  new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
734  new_arg[2] = rec->PutPar( play->GetPar(arg[2]) );
735  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
736  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
737  rec->PutArg(
738  new_arg[0],
739  new_arg[1],
740  new_arg[2]
741  );
742  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
743  rec->PutOp(op);
744  break;
745 
746  // Store a variable using a parameter index
747  case StpvOp:
748  CPPAD_ASSERT_NARG_NRES(op, 3, 0);
749  new_arg[0] = new_vecad_ind[ arg[0] ];
750  new_arg[1] = rec->PutPar( play->GetPar(arg[1]) );
751  new_arg[2] = old2new[ play->var2op(arg[2]) ].new_var;
752  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
753  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[2]) < num_var );
754  rec->PutArg(
755  new_arg[0],
756  new_arg[1],
757  new_arg[2]
758  );
759  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
760  rec->PutOp(op);
761  break;
762 
763  // Store a variable using a variable index
764  case StvvOp:
765  CPPAD_ASSERT_NARG_NRES(op, 3, 0);
766  new_arg[0] = new_vecad_ind[ arg[0] ];
767  new_arg[1] = old2new[ play->var2op(arg[1]) ].new_var;
768  new_arg[2] = old2new[ play->var2op(arg[2]) ].new_var;
769  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
770  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
771  CPPAD_ASSERT_UNKNOWN( size_t(new_arg[2]) < num_var );
772  rec->PutArg(
773  new_arg[0],
774  new_arg[1],
775  new_arg[2]
776  );
777  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
778  rec->PutOp(op);
779  break;
780 
781  // -----------------------------------------------------------
782  // user atomic function call operators
783 
784  case UserOp:
785  CPPAD_ASSERT_NARG_NRES(op, 4, 0);
786  // user_old, user_n, user_m
787  rec->PutArg(arg[0], arg[1], arg[2], arg[3]);
788  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
789  rec->PutOp(UserOp);
790  break;
791 
792  case UsrapOp:
793  CPPAD_ASSERT_NARG_NRES(op, 1, 0);
794  new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
795  rec->PutArg(new_arg[0]);
796  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
797  rec->PutOp(UsrapOp);
798  break;
799 
800  case UsravOp:
801  CPPAD_ASSERT_NARG_NRES(op, 1, 0);
802  new_arg[0] = old2new[ play->var2op(arg[0]) ].new_var;
803  if( size_t(new_arg[0]) < num_var )
804  { rec->PutArg(new_arg[0]);
805  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
806  rec->PutOp(UsravOp);
807  }
808  else
809  { // This argument does not affect the result and
810  // has been optimized out so use nan in its place.
811  new_arg[0] = rec->PutPar( base_nan );
812  rec->PutArg(new_arg[0]);
813  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
814  rec->PutOp(UsrapOp);
815  }
816  break;
817 
818  case UsrrpOp:
819  CPPAD_ASSERT_NARG_NRES(op, 1, 0);
820  new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
821  rec->PutArg(new_arg[0]);
822  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
823  rec->PutOp(UsrrpOp);
824  break;
825 
826  case UsrrvOp:
827  CPPAD_ASSERT_NARG_NRES(op, 0, 1);
828  old2new[i_op].new_op = addr_t( rec->num_op_rec() );
829  old2new[i_op].new_var = rec->PutOp(UsrrvOp);
830  break;
831  // ---------------------------------------------------
832 
833  // all cases should be handled above
834  default:
835  CPPAD_ASSERT_UNKNOWN(false);
836 
837  }
838  }
839  // modify the dependent variable vector to new indices
840  for(size_t i = 0; i < dep_taddr.size(); i++ )
841  { dep_taddr[i] = old2new[ play->var2op(dep_taddr[i]) ].new_var;
842  CPPAD_ASSERT_UNKNOWN( size_t(dep_taddr[i]) < num_var );
843  }
844 
845 # ifndef NDEBUG
846  for(i_op = 0; i_op < num_op; i_op++)
847  { play->get_op_info(i_op, op, arg, i_var);
848  if( NumRes(op) > 0 )
850  size_t(old2new[i_op].new_op) < rec->num_op_rec()
851  );
852  }
853 # endif
854  // make sure that all the conditional expressions have been
855  // checked to see if they are still present
856  CPPAD_ASSERT_UNKNOWN( cskip_order_next == num_cexp );
857  // fill in the arguments for the CSkip operations
858  for(size_t i = 0; i < num_cexp; i++)
859  { // if cskip_new[i].i_arg == 0, this conditional expression was skipped
860  if( cskip_new[i].i_arg > 0 )
861  { struct_cexp_info info = cexp_info[i];
862  size_t n_true = skip_op_true.number_elements(i);
863  size_t n_false = skip_op_false.number_elements(i);
864  size_t i_arg = cskip_new[i].i_arg;
865  size_t left = cskip_new[i].left;
866  size_t right = cskip_new[i].right;
867  rec->ReplaceArg(i_arg++, info.cop );
868  rec->ReplaceArg(i_arg++, info.flag );
869  rec->ReplaceArg(i_arg++, left );
870  rec->ReplaceArg(i_arg++, right );
871  rec->ReplaceArg(i_arg++, n_true );
872  rec->ReplaceArg(i_arg++, n_false );
873  sparse_list::const_iterator itr_true(skip_op_true, i);
874  while( *itr_true != skip_op_true.end() )
875  { i_op = *itr_true;
876  // opt_op_info[i_op].usage == yes_usage
877  CPPAD_ASSERT_UNKNOWN( old2new[i_op].new_op != 0 );
878  rec->ReplaceArg(i_arg++, old2new[i_op].new_op );
879  //
880  ++itr_true;
881  }
882  sparse_list::const_iterator itr_false(skip_op_false, i);
883  while( *itr_false != skip_op_false.end() )
884  { i_op = *itr_false;
885  // opt_op_info[i_op].usage == yes_usage
886  CPPAD_ASSERT_UNKNOWN( old2new[i_op].new_op != 0 );
887  rec->ReplaceArg(i_arg++, old2new[i_op].new_op );
888  //
889  ++itr_false;
890  }
891  rec->ReplaceArg(i_arg++, n_true + n_false);
892 # ifndef NDEBUG
893  size_t n_arg = 7 + n_true + n_false;
894  CPPAD_ASSERT_UNKNOWN( cskip_new[i].i_arg + n_arg == i_arg );
895 # endif
896  }
897  }
898 }
899 
900 } } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
901 
902 # endif
This operator is only used once, it is a summation operator, and its parrent is a summation operator...
Definition: usage.hpp:31
#define CPPAD_ASSERT_KNOWN(exp, msg)
Check that exp is true, if not print msg and terminate execution.
size_t end(void) const
Fetch end for this vector of sets object.
Vector of sets of positive integers, each set stored as a singly linked list.
Definition: sparse_list.hpp:35
addr_t PutOp(OpCode op)
Put next operator in the operation sequence.
Definition: recorder.hpp:185
size_t num_vec_ind_rec(void) const
Fetch number of VecAD indices in the recording.
Definition: player.hpp:626
CPPAD_TAPE_ADDR_TYPE addr_t
Definition: declare_ad.hpp:44
struct_size_pair record_vv(const player< Base > *play, const CppAD::vector< struct struct_old2new > &old2new, size_t i_op, recorder< Base > *rec)
Record an operation of the form (variable op variable).
Definition: record_vv.hpp:40
addr_t PutTxt(const char *text)
Put a character string in the text for this recording.
Definition: recorder.hpp:585
std::complex< double > atan(const std::complex< double > &x)
const char * GetTxt(size_t i) const
Fetch a &#39;\0&#39; terminated string from the recording.
Definition: player.hpp:608
size_t NumArg(OpCode op)
Number of arguments for a specified operator.
Definition: op_code.hpp:175
Record an operation of the form (variable op variable).
size_t ReserveArg(size_t n_arg)
Reserve space for arguments, but delay placing values there.
Definition: recorder.hpp:550
Class used to store and play back an operation sequence recording.
Definition: declare_ad.hpp:27
size_t num_load_op_rec(void) const
Number of LdpOp and LdvOp operations currently in the recording.
Definition: recorder.hpp:140
Information about one cumulative summation operation.
Definition: csum_stacks.hpp:27
size_t GetVecInd(size_t i) const
Fetch a VecAD index from the recording.
Definition: player.hpp:571
void PutArg(addr_t arg0)
Put one operation argument index in the recording.
Definition: recorder.hpp:392
void optimize_run(const std::string &options, size_t n, CppAD::vector< size_t > &dep_taddr, const player< Base > *play, recorder< Base > *rec)
Convert a player object to an optimized recorder object.
size_t NumRes(OpCode op)
Number of variables resulting from the specified operation.
Definition: op_code.hpp:281
size_t number_elements(size_t i) const
Count number of elements in a set.
Information that maps old an old operator to a new opeator and new variable.
next UserOp marks end of a user atomic call
Definition: user_state.hpp:28
addr_t PutPar(const Base &par)
Find or add a parameter to the current vector of parameters.
Definition: recorder.hpp:314
addr_t PutLoadOp(OpCode op)
Put a vecad load operator in the operation sequence (special case)
Definition: recorder.hpp:243
size_t size(void) const
number of elements currently in this vector.
Definition: vector.hpp:387
OpCode
Type used to distinguish different AD&lt; Base &gt; atomic operations.
Definition: op_code.hpp:49
Class used to store an operation sequence while it is being recorded (the operation sequence is copie...
Definition: declare_ad.hpp:28
next UserOp marks beginning of a user atomic call
Definition: user_state.hpp:19
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
Information about one conditional expression.
Definition: cexp_info.hpp:27
Information for one variable and one operation sequence.
void free(void)
Frees all information in recording.
Definition: recorder.hpp:94
AD< Base > sqrt(const AD< Base > &x)
void index_sort(const VectorKey &keys, VectorSize &ind)
Compute the indices that sort a vector of keys.
Definition: index_sort.hpp:140
Information about one conditional expression.
size_t num_vecad_vec_rec(void) const
Fetch number of VecAD vectors in the recording.
Definition: player.hpp:630
size_t i_var
operator index for this variable
Definition: size_pair.hpp:27
#define CPPAD_ASSERT_UNKNOWN(exp)
Check that exp is true, if not terminate execution.
void get_opt_op_info(bool conditional_skip, bool compare_op, bool print_for_op, const player< Base > *play, const vector< size_t > &dep_taddr, vector< struct_cexp_info > &cexp_info, sparse_list &skip_op_true, sparse_list &skip_op_false, vector< bool > &vecad_used, vector< struct_opt_op_info > &opt_op_info)
Get variable to operator map and operator basic operator information.
size_t num_op_rec(void) const
Fetch number of operators in the recording.
Definition: player.hpp:622
Record an operation of the form (variable op parameter).
#define CPPAD_ASSERT_NARG_NRES(op, n_arg, n_res)
Check that operator op has the specified number of of arguments and results.
Information about one old variable that is part of a new CSumOp operation.
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
CompareOp cop
comparision operator for this conditional expression
Definition: cexp_info.hpp:55
This operator is used one or more times.
Definition: usage.hpp:23
size_t flag
(flag &amp; 1) is true if and only if left is a variable (flag &amp; 2) is true if and only if right is a var...
Definition: cexp_info.hpp:33
addr_t PutVecInd(size_t vec_ind)
Add a value to the end of the current vector of VecAD indices.
Definition: recorder.hpp:289
cons_iterator for one set of positive integers in a sparse_list object.
Base GetPar(size_t i) const
Fetch a parameter from the recording.
Definition: player.hpp:584
struct_size_pair record_vp(const player< Base > *play, const CppAD::vector< struct struct_old2new > &old2new, size_t i_op, recorder< Base > *rec)
Record an operation of the form (variable op parameter).
Definition: record_vp.hpp:42
Record an operation of the form (parameter op variable).
Recording a cummulative cummulative summation.
struct_size_pair record_pv(const player< Base > *play, const CppAD::vector< struct struct_old2new > &old2new, size_t i_op, recorder< Base > *rec)
Record an operation of the form (parameter op variable).
Definition: record_pv.hpp:41
void ReplaceArg(size_t i_arg, size_t value)
Replace an argument value in the recording (intended to fill in reserved values). ...
Definition: recorder.hpp:569
size_t num_var_rec(void) const
Fetch number of variables in the recording.
Definition: player.hpp:614
Information about one cumulative summation operation.