CppAD: A C++ Algorithmic Differentiation Package  20171217
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
get_opt_op_info.hpp
Go to the documentation of this file.
1 # ifndef CPPAD_LOCAL_OPTIMIZE_GET_OPT_OP_INFO_HPP
2 # define CPPAD_LOCAL_OPTIMIZE_GET_OPT_OP_INFO_HPP
3 
4 /* --------------------------------------------------------------------------
5 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
6 
7 CppAD is distributed under multiple licenses. This distribution is under
8 the terms of the
9  Eclipse Public License Version 1.0.
10 
11 A copy of this license is included in the COPYING file of this distribution.
12 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
13 -------------------------------------------------------------------------- */
14 /*!
15 \file opt_op_info.hpp
16 Create operator information tables
17 */
18 
23 
24 // BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
25 namespace CppAD { namespace local { namespace optimize {
26 
27 /// Is this an addition or subtraction operator
28 inline bool add_or_subtract(OpCode op)
29 { bool result;
30  switch(op)
31  {
32  case AddpvOp:
33  case AddvvOp:
34  case SubpvOp:
35  case SubvpOp:
36  case SubvvOp:
37  result = true;
38  break;
39 
40  default:
41  result = false;
42  break;
43  }
44  return result;
45 }
46 
47 
48 /*!
49 Increarse argument usage and propagate cexp_set from result to argument.
50 
51 \param play
52 is the player for the old operation sequence.
53 
54 \param sum_result
55 is result an addition or subtraction operator (passed for speed so
56 do not need to call add_or_subtract for result).
57 
58 \param i_result
59 is the operator index for the result operator.
60 
61 \param i_arg
62 is the operator index for the argument to the result operator.
63 
64 \param opt_op_info
65 structure that holds the information for each of the operators.
66 The output value of opt_op_info[i_arg].usage is increased; to be specific,
67 If sum_result is true and the input value of opt_op_info[i_arg].usage
68 is no_usage, its output value is csum_usage.
69 Otherwise, the output value of opt_op_info[i_arg].usage is yes_usage.
70 
71 \param cexp_set
72 This is a vector of sets with one set for each operator. We denote
73 the i-th set by set[i].
74 
75 \li
76 In the special case where cexp_set.n_set() is zero,
77 cexp_set is not changed.
78 
79 \li
80 If cexp_set.n_set() != 0 and opt_op_info[i_arg].usage == no_usage,
81 the input value of set[i_arg] must be empty.
82 In this case the output value if set[i_arg] is equal to set[i_result]
83 (which may also be empty).
84 
85 \li
86 If cexp_set.n_set() != 0 and opt_op_info[i_arg].usage != no_usage,
87 the output value of set[i_arg] is the intersection of
88 its input value and set[i_result].
89 */
90 template <class Base>
92  const player<Base>* play ,
93  bool sum_result ,
94  size_t i_result ,
95  size_t i_arg ,
96  vector<struct_opt_op_info>& opt_op_info ,
97  sparse_list& cexp_set )
98 {
99  // cexp_set
100  if( cexp_set.n_set() > 0 )
101  { if( opt_op_info[i_arg].usage == no_usage )
102  { // set[i_arg] = set[i_result]
103  cexp_set.assignment(i_arg, i_result, cexp_set);
104  }
105  else
106  { // set[i_arg] = set[i_arg] intersect set[i_result]
107  cexp_set.binary_intersection(i_arg, i_arg, i_result, cexp_set);
108  }
109  }
110  // usage
111  bool csum = sum_result && opt_op_info[i_arg].usage == no_usage;
112  if( csum )
113  { OpCode op_a = play->GetOp(i_arg);
114  csum = add_or_subtract( op_a );
115  }
116  if( csum )
117  opt_op_info[i_arg].usage = csum_usage;
118  else
119  opt_op_info[i_arg].usage = yes_usage;
120  //
121  return;
122 }
123 
124 /*!
125 Get variable to operator map and operator basic operator information
126 
127 \tparam Base
128 base type for the operator; i.e., this operation was recorded
129 using AD< \a Base > and computations by this routine are done using type
130 \a Base.
131 
132 \param conditional_skip
133 If conditional_skip this is true, the conditional expression information
134 cexp_info will be calculated.
135 This may be time intensive and may not have much benefit in the optimized
136 recording.
137 
138 \param compare_op
139 if this is true, arguments are considered used if they appear in compare
140 operators. This is a side effect because compare operators have boolean
141 results (and the result is not in the tape; i.e. NumRes(op) is zero
142 for these operators. (This is an example of a side effect.)
143 
144 \param print_for_op
145 if this is true, arguments are considered used if they appear in
146 print forward operators; i.e., PriOp.
147 This is also a side effect; i.e. NumRes(PriOp) is zero.
148 
149 \param play
150 This is the old operation sequence.
151 
152 \param dep_taddr
153 is a vector of variable indices for the dependent variables.
154 
155 \param cexp_info
156 The input size of this vector must be zero.
157 If conditional_skip is false, cexp_info is not changed.
158 Otherwise,
159 upon return cexp_info has size equal to the number of conditional expressions
160 in the operation sequence; i.e., the number of CExpOp operators.
161 The value cexp_info[j] is the information corresponding to the j-th
162 conditional expression in the operation sequence.
163 This vector is in the same order as the operation sequence; i.e.
164 if j1 > j2, cexp_info[j1].i_op > cexp_info[j2].i_op.
165 Note that skip_op_true and skip_op_false could be part of this structure,
166 but then we would allocate and deallocate two vectors for each conditonal
167 expression in the operation sequence.
168 
169 \param skip_op_true
170 This vector of sets is empty on input.
171 Upon return, the j-th set is the operators that are not used when
172 comparison result for cexp_info[j] is true.
173 Note that UsrapOp, UsravOp, UsrrpOp, and UsrrvOp, are not in this
174 set and should be skipped when the corresponding UserOp are skipped.
175 
176 \param skip_op_false
177 This vector of sets is empty on input.
178 Upon return, the j-th set is the operators that are not used when
179 comparison result for cexp_info[j] is false.
180 Note that UsrapOp, UsravOp, UsrrpOp, and UsrrvOp, are not in this
181 set and should be skipped when the corresponding UserOp are skipped.
182 
183 \param vecad_used
184 The input size of this vector must be zero.
185 Upon retun it has size equal to the number of VecAD vectors
186 in the operations sequences; i.e., play->num_vecad_vec_rec().
187 The VecAD vectors are indexed in the order that thier indices apprear
188 in the one large play->GetVecInd that holds all the VecAD vectors.
189 
190 \param opt_op_info
191 The input size of this vector must be zero.
192 Upon return it has size equal to the number of operators
193 in the operation sequence; i.e., num_op = play->nun_var_rec().
194 The value opt_op_info[i]
195 have been set to the values corresponding to the i-th operator
196 in the operation sequence.
197 */
198 
199 template <class Base>
201  bool conditional_skip ,
202  bool compare_op ,
203  bool print_for_op ,
204  const player<Base>* play ,
205  const vector<size_t>& dep_taddr ,
206  vector<struct_cexp_info>& cexp_info ,
207  sparse_list& skip_op_true ,
208  sparse_list& skip_op_false ,
209  vector<bool>& vecad_used ,
210  vector<struct_opt_op_info>& opt_op_info )
211 {
212  CPPAD_ASSERT_UNKNOWN( cexp_info.size() == 0 );
213  CPPAD_ASSERT_UNKNOWN( vecad_used.size() == 0 );
214  CPPAD_ASSERT_UNKNOWN( opt_op_info.size() == 0 );
215 
216  // number of operators in the tape
217  const size_t num_op = play->num_op_rec();
218  opt_op_info.resize( num_op );
219  //
220  // initialize mapping from variable index to operator index
222  std::numeric_limits<addr_t>::max() >= num_op
223  );
224  //
225  // information set by forward_user
226  size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
227  enum_user_state user_state;
228  //
229  // ----------------------------------------------------------------------
230  // Forward pass to determine num_cexp_op
231  // ----------------------------------------------------------------------
232  OpCode op; // operator
233  const addr_t* arg; // arguments
234  size_t i_op; // operator index
235  size_t i_var; // variable index of first result
236  i_op = 0;
237  play->get_op_info(i_op, op, arg, i_var);
238  CPPAD_ASSERT_UNKNOWN( op == BeginOp );
240  CPPAD_ASSERT_UNKNOWN( i_op == 0 );
241  CPPAD_ASSERT_UNKNOWN( i_var == 0 );
242  //
243  size_t num_cexp_op = 0;
244  user_state = start_user;
245  while(op != EndOp)
246  { // next operator
247  play->get_op_info(++i_op, op, arg, i_var);
248  //
249  if( op == CExpOp )
250  { // count the number of conditional expressions.
251  ++num_cexp_op;
252  }
253  }
254  // vector that maps conditional expression index to operator index
255  vector<size_t> cexp2op( num_cexp_op );
256  // ----------------------------------------------------------------------
257  // Reverse pass to compute usage and cexp_set for each operator
258  // ----------------------------------------------------------------------
259  // work space used by user defined atomic functions
260  typedef std::set<size_t> size_set;
261  vector<Base> user_x; // parameters in x as integers
262  vector<size_t> user_ix; // variables indices for argument vector
263  vector<size_set> user_r_set; // set sparsity pattern for result
264  vector<size_set> user_s_set; // set sparisty pattern for argument
265  vector<bool> user_r_bool; // bool sparsity pattern for result
266  vector<bool> user_s_bool; // bool sparisty pattern for argument
267  vectorBool user_r_pack; // pack sparsity pattern for result
268  vectorBool user_s_pack; // pack sparisty pattern for argument
269  //
270  atomic_base<Base>* user_atom = CPPAD_NULL; // current user atomic function
271  bool user_pack = false; // sparsity pattern type is pack
272  bool user_bool = false; // sparsity pattern type is bool
273  bool user_set = false; // sparsity pattern type is set
274  // -----------------------------------------------------------------------
275  // vecad information
276  size_t num_vecad = play->num_vecad_vec_rec();
277  size_t num_vecad_ind = play->num_vec_ind_rec();
278  //
279  vecad_used.resize(num_vecad);
280  for(size_t i = 0; i < num_vecad; i++)
281  vecad_used[i] = false;
282  //
283  vector<size_t> arg2vecad(num_vecad_ind);
284  for(size_t i = 0; i < num_vecad_ind; i++)
285  arg2vecad[i] = num_vecad; // invalid value
286  size_t arg_0 = 1; // value of arg[0] for theh first vecad
287  for(size_t i = 0; i < num_vecad; i++)
288  {
289  // mapping from arg[0] value to index for this vecad object.
290  arg2vecad[arg_0] = i;
291  //
292  // length of this vecad object
293  size_t length = play->GetVecInd(arg_0 - 1);
294  //
295  // set to proper index in GetVecInd for next VecAD arg[0] value
296  arg_0 += length + 1;
297  }
298  CPPAD_ASSERT_UNKNOWN( arg_0 == num_vecad_ind + 1 );
299  // -----------------------------------------------------------------------
300  // parameter information (used by atomic function calls)
301  size_t num_par = play->num_par_rec();
302  const Base* parameter = CPPAD_NULL;
303  if( num_par > 0 )
304  parameter = play->GetPar();
305  // -----------------------------------------------------------------------
306  // Set of conditional expressions comparisons that usage of each
307  /// operator depends on. The operator can be skipped if any of the
308  // comparisons results in the set holds. A set for operator i_op is
309  // not defined and left empty when opt_op_info[i_op].usage = no_usage.
310  /// It is also left empty for the result of any VecAD operations.
311  sparse_list cexp_set;
312  //
313  // number of sets
314  size_t num_set = 0;
315  if( conditional_skip && num_cexp_op > 0)
316  num_set = num_op;
317  //
318  // conditional expression index = element / 2
319  // conditional expression compare = bool ( element % 2)
320  size_t end_set = 2 * num_cexp_op;
321  //
322  if( num_set > 0 )
323  cexp_set.resize(num_set, end_set);
324  // -----------------------------------------------------------------------
325  //
326  // initialize operator usage
327  for(size_t i = 0; i < num_op; i++)
328  opt_op_info[i].usage = no_usage;
329  for(size_t i = 0; i < dep_taddr.size(); i++)
330  { i_op = play->var2op(dep_taddr[i]);
331  opt_op_info[i_op].usage = yes_usage; // dependent variables
332  }
333  //
334  // Initialize reverse pass
335  size_t last_user_i_op = 0;
336  size_t cexp_index = num_cexp_op;
337  user_state = end_user;
338  i_op = num_op;
339  while(i_op != 0 )
340  { --i_op;
341  //
342  // this operator information
343  play->get_op_info(i_op, op, arg, i_var);
344  //
345  // Is the result of this operation used.
346  // (This only makes sense when NumRes(op) > 0.)
347  enum_usage use_result = opt_op_info[i_op].usage;
348  //
349  bool sum_op = false;
350  switch( op )
351  {
352  // =============================================================
353  // normal operators
354  // =============================================================
355 
356  // Only one variable with index arg[0]
357  case SubvpOp:
358  sum_op = true;
359  //
360  case AbsOp:
361  case AcosOp:
362  case AcoshOp:
363  case AsinOp:
364  case AsinhOp:
365  case AtanOp:
366  case AtanhOp:
367  case CosOp:
368  case CoshOp:
369  case DivvpOp:
370  case ErfOp:
371  case ExpOp:
372  case Expm1Op:
373  case LogOp:
374  case Log1pOp:
375  case PowvpOp:
376  case SignOp:
377  case SinOp:
378  case SinhOp:
379  case SqrtOp:
380  case TanOp:
381  case TanhOp:
382  case ZmulvpOp:
383  CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
384  if( use_result != no_usage )
385  { size_t j_op = play->var2op(arg[0]);
387  play, sum_op, i_op, j_op, opt_op_info, cexp_set
388  );
389  }
390  break; // --------------------------------------------
391 
392  // Only one variable with index arg[1]
393  case AddpvOp:
394  case SubpvOp:
395  sum_op = true;
396  //
397  case DisOp:
398  case DivpvOp:
399  case MulpvOp:
400  case PowpvOp:
401  case ZmulpvOp:
402  CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
403  if( use_result != no_usage )
404  { size_t j_op = play->var2op(arg[1]);
406  play, sum_op, i_op, j_op, opt_op_info, cexp_set
407  );
408  }
409  break; // --------------------------------------------
410 
411  // arg[0] and arg[1] are the only variables
412  case AddvvOp:
413  case SubvvOp:
414  sum_op = true;
415  //
416  case DivvvOp:
417  case MulvvOp:
418  case PowvvOp:
419  case ZmulvvOp:
420  CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
421  if( use_result != no_usage )
422  { for(size_t i = 0; i < 2; i++)
423  { size_t j_op = play->var2op(arg[i]);
425  play, sum_op, i_op, j_op, opt_op_info, cexp_set
426  );
427  }
428  }
429  break; // --------------------------------------------
430 
431  // Conditional expression operators
432  // arg[2], arg[3], arg[4], arg[5] are parameters or variables
433  case CExpOp:
434  --cexp_index;
435  cexp2op[ cexp_index ] = i_op;
436  CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
437  if( use_result != no_usage )
439  // propgate from result to left argument
440  if( arg[1] & 1 )
441  { size_t j_op = play->var2op(arg[2]);
443  play, sum_op, i_op, j_op, opt_op_info, cexp_set
444  );
445  }
446  // propgate from result to right argument
447  if( arg[1] & 2 )
448  { size_t j_op = play->var2op(arg[3]);
450  play, sum_op, i_op, j_op, opt_op_info, cexp_set
451  );
452  }
453  // are if_true and if_false cases the same variable
454  bool same_variable = bool(arg[1] & 4) && bool(arg[1] & 8);
455  same_variable &= arg[4] == arg[5];
456  //
457  // if_true
458  if( arg[1] & 4 )
459  { size_t j_op = play->var2op(arg[4]);
460  bool can_skip = conditional_skip & (! same_variable);
461  can_skip &= opt_op_info[j_op].usage == no_usage;
463  play, sum_op, i_op, j_op, opt_op_info, cexp_set
464  );
465  if( can_skip )
466  { // j_op corresponds to the value used when the
467  // comparison result is true. It can be skipped when
468  // the comparison is false (0).
469  size_t element = 2 * cexp_index + 0;
470  cexp_set.add_element(j_op, element);
471  //
472  opt_op_info[j_op].usage = yes_usage;
473  }
474  }
475  //
476  // if_false
477  if( arg[1] & 8 )
478  { size_t j_op = play->var2op(arg[5]);
479  bool can_skip = conditional_skip & (! same_variable);
480  can_skip &= opt_op_info[j_op].usage == no_usage;
482  play, sum_op, i_op, j_op, opt_op_info, cexp_set
483  );
484  if( can_skip )
485  { // j_op corresponds to the value used when the
486  // comparison result is false. It can be skipped when
487  // the comparison is true (0).
488  size_t element = 2 * cexp_index + 1;
489  cexp_set.add_element(j_op, element);
490  //
491  opt_op_info[j_op].usage = yes_usage;
492  }
493  }
494  }
495  break; // --------------------------------------------
496 
497  // Operations that are never used
498  // (new CSkip options are generated if conditional_skip is true)
499  case CSkipOp:
500  case ParOp:
501  break;
502 
503  // Operators that are always used
504  case InvOp:
505  case BeginOp:
506  case EndOp:
507  opt_op_info[i_op].usage = yes_usage;
508  break; // -----------------------------------------------
509 
510  // The print forward operator
511  case PriOp:
512  CPPAD_ASSERT_NARG_NRES(op, 5, 0);
513  if( print_for_op )
514  { opt_op_info[i_op].usage = yes_usage;
515  if( arg[0] & 1 )
516  { // arg[1] is a variable
517  size_t j_op = play->var2op(arg[1]);
519  play, sum_op, i_op, j_op, opt_op_info, cexp_set
520  );
521  }
522  if( arg[0] & 2 )
523  { // arg[3] is a variable
524  size_t j_op = play->var2op(arg[3]);
526  play, sum_op, i_op, j_op, opt_op_info, cexp_set
527  );
528  }
529  }
530  break; // -----------------------------------------------------
531 
532  // =============================================================
533  // Comparison operators
534  // =============================================================
535 
536  // Compare operators where arg[1] is only variable
537  case LepvOp:
538  case LtpvOp:
539  case EqpvOp:
540  case NepvOp:
541  CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
542  if( compare_op )
543  { opt_op_info[i_op].usage = yes_usage;
544  //
545  size_t j_op = play->var2op(arg[1]);
547  play, sum_op, i_op, j_op, opt_op_info, cexp_set
548  );
549  }
550  break; // ----------------------------------------------
551 
552  // Compare operators where arg[0] is only variable
553  case LevpOp:
554  case LtvpOp:
555  CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
556  if( compare_op )
557  { opt_op_info[i_op].usage = yes_usage;
558  //
559  size_t j_op = play->var2op(arg[0]);
561  play, sum_op, i_op, j_op, opt_op_info, cexp_set
562  );
563  }
564  break; // ----------------------------------------------
565 
566  // Compare operators where arg[0] and arg[1] are variables
567  case LevvOp:
568  case LtvvOp:
569  case EqvvOp:
570  case NevvOp:
571  if( compare_op )
572  CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
573  if( compare_op )
574  { opt_op_info[i_op].usage = yes_usage;
575  //
576  for(size_t i = 0; i < 2; i++)
577  { size_t j_op = play->var2op(arg[i]);
579  play, sum_op, i_op, j_op, opt_op_info, cexp_set
580  );
581  }
582  }
583  break; // ----------------------------------------------
584 
585  // =============================================================
586  // VecAD operators
587  // =============================================================
588 
589  // load operator using a parameter index
590  case LdpOp:
591  CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
592  if( use_result != no_usage )
593  { size_t i_vec = arg2vecad[ arg[0] ];
594  vecad_used[i_vec] = true;
595  }
596  break; // --------------------------------------------
597 
598  // load operator using a variable index
599  case LdvOp:
600  CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
601  if( use_result != no_usage )
602  { size_t i_vec = arg2vecad[ arg[0] ];
603  vecad_used[i_vec] = true;
604  //
605  size_t j_op = play->var2op(arg[1]);
606  opt_op_info[j_op].usage = yes_usage;
607  }
608  break; // --------------------------------------------
609 
610  // Store a variable using a parameter index
611  case StpvOp:
612  CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
613  if( vecad_used[ arg2vecad[ arg[0] ] ] )
614  { opt_op_info[i_op].usage = yes_usage;
615  //
616  size_t j_op = play->var2op(arg[2]);
617  opt_op_info[j_op].usage = yes_usage;
618  }
619  break; // --------------------------------------------
620 
621  // Store a variable using a variable index
622  case StvvOp:
623  CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
624  if( vecad_used[ arg2vecad[ arg[0] ] ] )
625  { opt_op_info[i_op].usage = yes_usage;
626  //
627  size_t j_op = play->var2op(arg[1]);
628  opt_op_info[j_op].usage = yes_usage;
629  size_t k_op = play->var2op(arg[2]);
630  opt_op_info[k_op].usage = yes_usage;
631  }
632  break; // -----------------------------------------------------
633 
634  // =============================================================
635  // cumulative summation operator
636  // ============================================================
637  case CSumOp:
638  CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
639  {
640  size_t num_add = size_t( arg[0] );
641  size_t num_sub = size_t( arg[1] );
642  for(size_t i = 0; i < num_add + num_sub; i++)
643  { size_t j_op = play->var2op( arg[3 + i] );
645  play, sum_op, i_op, j_op, opt_op_info, cexp_set
646  );
647  }
648  }
649  // =============================================================
650  // user defined atomic operators
651  // ============================================================
652 
653  case UserOp:
654  // start or end atomic operation sequence
655  if( user_state == end_user )
656  { // revese_user using opt_op_info instead of play
657  size_t user_index = arg[0];
658  user_old = arg[1];
659  user_n = arg[2];
660  user_m = arg[3];
661  user_j = user_n;
662  user_i = user_m;
663  user_state = ret_user;
664  user_atom = atomic_base<Base>::class_object(user_index);
665  // -------------------------------------------------------
666  last_user_i_op = i_op;
667  CPPAD_ASSERT_UNKNOWN( i_op > user_n + user_m + 1 );
669  opt_op_info[last_user_i_op].usage == no_usage
670  );
671 # ifndef NDEBUG
672  if( cexp_set.n_set() > 0 )
673  { sparse_list_const_iterator itr(cexp_set, last_user_i_op);
674  CPPAD_ASSERT_UNKNOWN( *itr == cexp_set.end() );
675  }
676 # endif
677  //
678  user_x.resize( user_n );
679  user_ix.resize( user_n );
680  //
681  user_pack = user_atom->sparsity() ==
683  user_bool = user_atom->sparsity() ==
685  user_set = user_atom->sparsity() ==
687  CPPAD_ASSERT_UNKNOWN( user_pack || user_bool || user_set );
688  //
689  // Note that q is one for this call the sparsity calculation
690  if( user_pack )
691  { user_r_pack.resize( user_m );
692  user_s_pack.resize( user_n );
693  for(size_t i = 0; i < user_m; i++)
694  user_r_pack[ i ] = false;
695  }
696  if( user_bool )
697  { user_r_bool.resize( user_m );
698  user_s_bool.resize( user_n );
699  for(size_t i = 0; i < user_m; i++)
700  user_r_bool[ i ] = false;
701  }
702  if( user_set )
703  { user_s_set.resize(user_n);
704  user_r_set.resize(user_m);
705  for(size_t i = 0; i < user_m; i++)
706  user_r_set[i].clear();
707  }
708  }
709  else
710  { // reverse_user using opt_op_info instead of play
711  CPPAD_ASSERT_UNKNOWN( user_state == start_user );
712  CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) );
713  CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) );
714  CPPAD_ASSERT_UNKNOWN( user_j == 0 );
715  CPPAD_ASSERT_UNKNOWN( user_i == 0 );
716  user_state = end_user;
717  // -------------------------------------------------------
719  i_op + user_n + user_m + 1 == last_user_i_op
720  );
721  // call users function for this operation
722  user_atom->set_old(user_old);
723  bool user_ok = false;
724  size_t user_q = 1; // as if sum of dependent variables
725  if( user_pack )
726  { user_ok = user_atom->rev_sparse_jac(
727  user_q, user_r_pack, user_s_pack, user_x
728  );
729  if( ! user_ok ) user_ok = user_atom->rev_sparse_jac(
730  user_q, user_r_pack, user_s_pack
731  );
732  }
733  if( user_bool )
734  { user_ok = user_atom->rev_sparse_jac(
735  user_q, user_r_bool, user_s_bool, user_x
736  );
737  if( ! user_ok ) user_ok = user_atom->rev_sparse_jac(
738  user_q, user_r_bool, user_s_bool
739  );
740  }
741  if( user_set )
742  { user_ok = user_atom->rev_sparse_jac(
743  user_q, user_r_set, user_s_set, user_x
744  );
745  if( ! user_ok ) user_ok = user_atom->rev_sparse_jac(
746  user_q, user_r_set, user_s_set
747  );
748  }
749  if( ! user_ok )
750  { std::string s =
751  "Optimizing an ADFun object"
752  " that contains the atomic function\n\t";
753  s += user_atom->afun_name();
754  s += "\nCurrent atomic_sparsity is set to ";
755  //
756  if( user_set )
757  s += "set_sparsity_enum.\n";
758  if( user_bool )
759  s += "bool_sparsity_enum.\n";
760  if( user_pack )
761  s += "pack_sparsity_enum.\n";
762  //
763  s += "This version of rev_sparse_jac returned false";
764  CPPAD_ASSERT_KNOWN(false, s.c_str() );
765  }
766 
767  if( opt_op_info[last_user_i_op].usage != no_usage )
768  for(size_t j = 0; j < user_n; j++)
769  if( user_ix[j] > 0 )
770  { // This user argument is a variable
771  bool use_arg_j = false;
772  if( user_set )
773  { if( ! user_s_set[j].empty() )
774  use_arg_j = true;
775  }
776  if( user_bool )
777  { if( user_s_bool[j] )
778  use_arg_j = true;
779  }
780  if( user_pack )
781  { if( user_s_pack[j] )
782  use_arg_j = true;
783  }
784  if( use_arg_j )
785  { size_t j_op = play->var2op(user_ix[j]);
787  sum_op, last_user_i_op, j_op, opt_op_info, cexp_set
788  );
789  }
790  }
791  // copy set infomation from last to first
792  if( cexp_set.n_set() > 0 )
793  cexp_set.assignment(i_op, last_user_i_op, cexp_set);
794  // copy user information from last to all the user operators
795  // for this call
796  for(size_t j = 0; j < user_n + user_m + 1; ++j)
797  opt_op_info[i_op + j].usage = opt_op_info[last_user_i_op].usage;
798  }
799  break; // -------------------------------------------------------
800 
801  case UsrapOp:
802  // parameter argument in an atomic operation sequence
803  CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
804  //
805  // reverse_user using opt_op_info instead of play
806  CPPAD_ASSERT_NARG_NRES(op, 1, 0);
807  CPPAD_ASSERT_UNKNOWN( 0 < user_j && user_j < user_n );
808  --user_j;
809  if( user_j == 0 )
810  user_state = start_user;
811  // -------------------------------------------------------------
812  user_ix[user_j] = 0;
813  //
814  // parameter arguments
815  user_x[user_j] = parameter[arg[0]];
816  //
817  break;
818 
819  case UsravOp:
820  // variable argument in an atomic operation sequence
821  CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
822  //
823  // reverse_user using opt_op_info instead of play
824  CPPAD_ASSERT_NARG_NRES(op, 1, 0);
825  CPPAD_ASSERT_UNKNOWN( 0 < user_j && user_j <= user_n );
826  --user_j;
827  if( user_j == 0 )
828  user_state = start_user;
829  // -------------------------------------------------------------
830  user_ix[user_j] = arg[0];
831  //
832  // variable arguments as parameters
833  user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN();
834  //
835  break;
836 
837  case UsrrvOp:
838  // variable result in an atomic operation sequence
839  //
840  // reverse_user using opt_op_info instead of play
841  CPPAD_ASSERT_NARG_NRES(op, 0, 1);
842  CPPAD_ASSERT_UNKNOWN( 0 < user_i && user_i <= user_m );
843  --user_i;
844  if( user_i == 0 )
845  user_state = arg_user;
846  // -------------------------------------------------------------
847  if( use_result )
848  { if( user_set )
849  user_r_set[user_i].insert(0);
850  if( user_bool )
851  user_r_bool[user_i] = true;
852  if( user_pack )
853  user_r_pack[user_i] = true;
854  //
856  play, sum_op, i_op, last_user_i_op, opt_op_info, cexp_set
857  );
858  }
859  break; // --------------------------------------------------------
860 
861  case UsrrpOp:
862  CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
863  //
864  // reverse_user using opt_op_info instead of play
865  CPPAD_ASSERT_NARG_NRES(op, 0, 1);
866  CPPAD_ASSERT_UNKNOWN( 0 < user_i && user_i < user_m );
867  --user_i;
868  if( user_i == 0 )
869  user_state = arg_user;
870  break;
871  // ============================================================
872 
873  // all cases should be handled above
874  default:
876  }
877  }
878  // ----------------------------------------------------------------------
879  // compute previous in opt_op_info
880  // ----------------------------------------------------------------------
881  sparse_list hash_table_op;
882  hash_table_op.resize(CPPAD_HASH_TABLE_SIZE, num_op);
883  //
884  user_state = start_user;
885  for(i_op = 0; i_op < num_op; ++i_op)
886  { opt_op_info[i_op].previous = 0;
887 
888  if( opt_op_info[i_op].usage == yes_usage )
889  switch( play->GetOp(i_op) )
890  {
891  case NumberOp:
892  CPPAD_ASSERT_UNKNOWN(false);
893  break;
894 
895  case BeginOp:
896  case CExpOp:
897  case CSkipOp:
898  case CSumOp:
899  case EndOp:
900  case InvOp:
901  case LdpOp:
902  case LdvOp:
903  case ParOp:
904  case PriOp:
905  case StppOp:
906  case StpvOp:
907  case StvpOp:
908  case StvvOp:
909  case UserOp:
910  case UsrapOp:
911  case UsravOp:
912  case UsrrpOp:
913  case UsrrvOp:
914  // these operators never match pevious operators
915  break;
916 
917  case AbsOp:
918  case AcosOp:
919  case AcoshOp:
920  case AddpvOp:
921  case AddvvOp:
922  case AsinOp:
923  case AsinhOp:
924  case AtanOp:
925  case AtanhOp:
926  case CosOp:
927  case CoshOp:
928  case DisOp:
929  case DivpvOp:
930  case DivvpOp:
931  case DivvvOp:
932  case EqpvOp:
933  case EqvvOp:
934  case ErfOp:
935  case ExpOp:
936  case Expm1Op:
937  case LepvOp:
938  case LevpOp:
939  case LevvOp:
940  case LogOp:
941  case Log1pOp:
942  case LtpvOp:
943  case LtvpOp:
944  case LtvvOp:
945  case MulpvOp:
946  case MulvvOp:
947  case NepvOp:
948  case NevvOp:
949  case PowpvOp:
950  case PowvpOp:
951  case PowvvOp:
952  case SignOp:
953  case SinOp:
954  case SinhOp:
955  case SqrtOp:
956  case SubpvOp:
957  case SubvpOp:
958  case SubvvOp:
959  case TanOp:
960  case TanhOp:
961  case ZmulpvOp:
962  case ZmulvpOp:
963  case ZmulvvOp:
964  // check for a previous match
965  match_op(play, opt_op_info, i_op, hash_table_op );
966  if( opt_op_info[i_op].previous != 0 )
967  { // like a unary operator that assigns i_op equal to previous.
968  size_t previous = opt_op_info[i_op].previous;
969  bool sum_op = false;
970  CPPAD_ASSERT_UNKNOWN( previous < i_op );
972  play, sum_op, i_op, previous, opt_op_info, cexp_set
973  );
974  }
975  break;
976  }
977  }
978  // ----------------------------------------------------------------------
979  // compute cexp_info
980  // ----------------------------------------------------------------------
981  if( cexp_set.n_set() == 0 )
982  return;
983  //
984  // initialize information for each conditional expression
985  cexp_info.resize(num_cexp_op);
986  skip_op_true.resize(num_cexp_op, num_op);
987  skip_op_false.resize(num_cexp_op, num_op);
988  //
989  for(size_t i = 0; i < num_cexp_op; i++)
991  opt_op_info[i].previous == 0 || opt_op_info[i].usage == yes_usage
992  );
993  i_op = cexp2op[i];
994  play->get_op_info(i_op, op, arg, i_var);
995  CPPAD_ASSERT_UNKNOWN( op == CExpOp );
996  //
997  struct_cexp_info info;
998  info.i_op = i_op;
999  info.cop = CompareOp( arg[0] );
1000  info.flag = arg[1];
1001  info.left = arg[2];
1002  info.right = arg[3];
1003  //
1004  // max_left_right
1005  size_t index = 0;
1006  if( arg[1] & 1 )
1007  index = std::max(index, info.left);
1008  if( arg[1] & 2 )
1009  index = std::max(index, info.right);
1010  CPPAD_ASSERT_UNKNOWN( index > 0 );
1011  info.max_left_right = index;
1012  //
1013  cexp_info[i] = info;
1014  };
1015  // Determine which operators can be conditionally skipped
1016  i_op = 0;
1017  while(i_op < num_op)
1018  { size_t j_op = i_op;
1019  bool keep = opt_op_info[i_op].usage != no_usage;
1020  keep &= opt_op_info[i_op].usage != csum_usage;
1021  keep &= opt_op_info[i_op].previous == 0;
1022  if( keep )
1023  { sparse_list_const_iterator itr(cexp_set, i_op);
1024  if( *itr != cexp_set.end() )
1025  { if( play->GetOp(i_op) == UserOp )
1026  { // i_op is the first operations in this user atomic call.
1027  // Find the last operation in this call.
1028  ++j_op;
1029  while( play->GetOp(j_op) != UserOp )
1030  { switch( play->GetOp(j_op) )
1031  { case UsrapOp:
1032  case UsravOp:
1033  case UsrrpOp:
1034  case UsrrvOp:
1035  break;
1036 
1037  default:
1038  CPPAD_ASSERT_UNKNOWN(false);
1039  }
1040  ++j_op;
1041  }
1042  }
1043  }
1044  while( *itr != cexp_set.end() )
1045  { size_t element = *itr;
1046  size_t index = element / 2;
1047  bool compare = bool( element % 2 );
1048  if( compare == false )
1049  { // cexp_info[index].skip_op_false.push_back(i_op);
1050  skip_op_false.add_element(index, i_op);
1051  if( j_op != i_op )
1052  { // cexp_info[index].skip_op_false.push_back(j_op);
1053  skip_op_false.add_element(index, j_op);
1054  }
1055  }
1056  else
1057  { // cexp_info[index].skip_op_true.push_back(i_op);
1058  skip_op_true.add_element(index, i_op);
1059  if( j_op != i_op )
1060  { // cexp_info[index].skip_op_true.push_back(j_op);
1061  skip_op_true.add_element(index, j_op);
1062  }
1063  }
1064  ++itr;
1065  }
1066  }
1067  CPPAD_ASSERT_UNKNOWN( i_op <= j_op );
1068  i_op += (1 + j_op) - i_op;
1069  }
1070  return;
1071 }
1072 
1073 } } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
1074 
1075 # endif
This operator is only used once, it is a summation operator, and its parrent is a summation operator...
Definition: usage.hpp:31
virtual bool rev_sparse_jac(size_t q, const vector< std::set< size_t > > &rt, vector< std::set< size_t > > &st, const vector< Base > &x)
Link, after case split, from rev_jac_sweep to atomic_base.
void assignment(size_t this_target, size_t other_source, const sparse_list &other)
Assign one set equal to another set.
#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
This operator is not used.
Definition: usage.hpp:20
size_t num_par_rec(void) const
Fetch number of parameters in the recording.
Definition: player.hpp:638
void add_element(size_t i, size_t element)
Add one element to a set.
size_t max_left_right
maximum variable index between left and right (ignoring parameters).
Definition: cexp_info.hpp:42
The CppAD Simple Vector template class.
Definition: vector.hpp:338
void binary_intersection(size_t this_target, size_t this_left, size_t other_right, const sparse_list &other)
Assign a set equal to the intersection of two other sets.
static std::vector< atomic_base * > & class_object(void)
List of all the object in this class.
Definition: atomic_base.hpp:83
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
static Float quiet_NaN(void)
not a number
next UsrrpOp (UsrrvOp) is a parameter (variable) result
Definition: user_state.hpp:25
size_t NumArg(OpCode op)
Number of arguments for a specified operator.
Definition: op_code.hpp:175
Class used to store and play back an operation sequence recording.
Definition: declare_ad.hpp:27
size_t GetVecInd(size_t i) const
Fetch a VecAD index from the recording.
Definition: player.hpp:571
Check if current operator matches a previous operator.
void resize(size_t n)
change the number of elements in this vector.
Definition: vector.hpp:399
size_t NumRes(OpCode op)
Number of variables resulting from the specified operation.
Definition: op_code.hpp:281
void match_op(const player< Base > *play, vector< struct_opt_op_info > &opt_op_info, size_t current, sparse_list &hash_table_op)
Search for a previous operator that matches the current one.
Definition: match_op.hpp:69
Create operator information tables.
next UserOp marks end of a user atomic call
Definition: user_state.hpp:28
size_t left
variable or parameter index for left comparison operand
Definition: cexp_info.hpp:36
virtual void set_old(size_t id)
Set value of id (used by deprecated old_atomic class)
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
void usage_cexp_result2arg(const player< Base > *play, bool sum_result, size_t i_result, size_t i_arg, vector< struct_opt_op_info > &opt_op_info, sparse_list &cexp_set)
Increarse argument usage and propagate cexp_set from result to argument.
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
Information about one conditional expression.
Definition: cexp_info.hpp:27
option_enum sparsity(void) const
current sparsity setting
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
next UsrapOp (UsravOp) is a parameter (variable) argument
Definition: user_state.hpp:22
size_t right
variable or parameter index for right comparison operand
Definition: cexp_info.hpp:39
#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.
void resize(size_t n_set, size_t end)
Start a new vector of sets.
size_t num_op_rec(void) const
Fetch number of operators in the recording.
Definition: player.hpp:622
#define CPPAD_ASSERT_NARG_NRES(op, n_arg, n_res)
Check that operator op has the specified number of of arguments and results.
size_t n_set(void) const
Fetch n_set for vector of sets object.
const std::string & afun_name(void) const
Name corresponding to a base_atomic object.
bool add_or_subtract(OpCode op)
Is this an addition or subtraction operator.
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
void resize(size_t n)
change number of elements in this vector
Definition: vector.hpp:721
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
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
size_t i_op
The operator index for this conditional expression operation.
Definition: cexp_info.hpp:29
OpCode GetOp(size_t i) const
fetch an operator from the recording.
Definition: player.hpp:558
#define CPPAD_HASH_TABLE_SIZE
the codes retruned by hash_code are between zero and CPPAD_HASH_TABLE_SIZE minus one.
Definition: base_hash.hpp:82