1 # ifndef CPPAD_LOCAL_PLAY_PLAYER_HPP
2 # define CPPAD_LOCAL_PLAY_PLAYER_HPP
3 /* --------------------------------------------------------------------------
4 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
5 
6 CppAD is distributed under the terms of the
7              Eclipse Public License Version 2.0.
8 
9 This Source Code may also be made available under the following
10 Secondary License when the conditions for such availability set forth
11 in the Eclipse Public License, Version 2.0 are satisfied:
12       GNU General Public License, Version 2.0 or later.
13 ---------------------------------------------------------------------------- */
14 
15 # include <cppad/local/play/addr_enum.hpp>
16 # include <cppad/local/play/sequential_iterator.hpp>
17 # include <cppad/local/play/subgraph_iterator.hpp>
18 # include <cppad/local/play/random_setup.hpp>
19 # include <cppad/local/atom_state.hpp>
20 # include <cppad/local/is_pod.hpp>
21 
22 namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
23 /*!
24 \file player.hpp
25 File used to define the player class.
26 */
27 
28 /*!
29 Class used to store and play back an operation sequence recording.
30 
31 \tparam Base
32 These were AD< Base > operations when recorded. Operations during playback
33 are done using the type Base .
34 */
35 
36 template <class Base>
37 class player {
38     // player<Base> must be a friend of player< AD<Base> > for base2ad to work
39     template <class AnotherBase> friend class player;
40 private:
41     // ----------------------------------------------------------------------
42     // information that defines the recording
43 
44     /// Number of independent dynamic parameters
45     size_t num_dynamic_ind_;
46 
47     /// Number of variables in the recording.
48     size_t num_var_rec_;
49 
50     /// number of vecad load opeations in the reconding
51     size_t num_var_load_rec_;
52 
53     /// Number of VecAD vectors in the recording
54     size_t num_var_vecad_rec_;
55 
56     /// The operators in the recording.
57     pod_vector<opcode_t> op_vec_;
58 
59     /// The operation argument indices in the recording
60     pod_vector<addr_t> arg_vec_;
61 
62     /// Character strings ('\\0' terminated) in the recording.
63     pod_vector<char> text_vec_;
64 
65     /// The VecAD indices in the recording.
66     pod_vector<addr_t> all_var_vecad_ind_;
67 
68     /// All of the parameters in the recording.
69     /// Use pod_maybe because Base may not be plain old data.
70     pod_vector_maybe<Base> all_par_vec_;
71 
72     /// Which elements of all_par_vec_ are dynamic parameters
73     /// (size equal number of parametrers)
74     pod_vector<bool> dyn_par_is_;
75 
76     /// mapping from dynamic parameter index to parameter index
77     /// 1: size equal to number of dynamic parameters
78     /// 2: dyn_ind2par_ind_[j] < dyn_ind2par_ind_[j+1]
79     pod_vector<addr_t> dyn_ind2par_ind_;
80 
81     /// operators for just the dynamic parameters
82     /// (size equal number of dynamic parameters)
83     pod_vector<opcode_t> dyn_par_op_;
84 
85     /// arguments for the dynamic parameter operators
86     pod_vector<addr_t> dyn_par_arg_;
87 
88     // ----------------------------------------------------------------------
89     // Information needed to use member functions that begin with random_
90     // and for using const_subgraph_iterator.
91 
92     /// index in arg_vec_ corresonding to the first argument for each operator
93     pod_vector<unsigned char> op2arg_vec_;
94 
95     /*!
96     Index of the result variable for each operator. If the operator has
97     no results, this is not defined. The invalid index num_var_rec_ is used
98     when NDEBUG is not defined. If the operator has more than one result, this
99     is the primary result; i.e., the last result. Auxillary are only used by
100     the operator and not used by other operators.
101     */
102     pod_vector<unsigned char> op2var_vec_;
103 
104     /// Mapping from primary variable index to corresponding operator index.
105     /// This is used to traverse sub-graphs of the operation sequence.
106     /// This value is valid (invalid) for primary (auxillary) variables.
107     pod_vector<unsigned char> var2op_vec_;
108 
109 public:
110     // =================================================================
111     /// default constructor
112     // set all scalars to zero to avoid valgraind warning when ani assignment
113     // occures before values get set.
player(void)114     player(void) :
115     num_dynamic_ind_(0)  ,
116     num_var_rec_(0)      ,
117     num_var_load_rec_(0)  ,
118     num_var_vecad_rec_(0)
119     { }
120     // move semantics constructor
121     // (none of the default constructor values matter to the destructor)
player(player & play)122     player(player& play)
123     {   swap(play);  }
124     // =================================================================
125     /// destructor
~player(void)126     ~player(void)
127     { }
128     // ======================================================================
129     /// type used for addressing iterators for this player
address_type(void) const130     play::addr_enum address_type(void) const
131     {
132         // required
133         size_t required = 0;
134         required = std::max(required, num_var_rec_   );  // number variables
135         required = std::max(required, op_vec_.size()  ); // number operators
136         required = std::max(required, arg_vec_.size() ); // number arguments
137         //
138         // unsigned short
139         if( required <= std::numeric_limits<unsigned short>::max() )
140             return play::unsigned_short_enum;
141         //
142         // unsigned int
143         if( required <= std::numeric_limits<unsigned int>::max() )
144             return play::unsigned_int_enum;
145         //
146         // unsigned size_t
147         CPPAD_ASSERT_UNKNOWN(
148             required <= std::numeric_limits<size_t>::max()
149         );
150         return play::size_t_enum;
151     }
152     // ===============================================================
153     /*!
154     Moving an operation sequence from a recorder to this player
155 
156     \param rec
157     the object that was used to record the operation sequence. After this
158     operation, the state of the recording is no longer defined. For example,
159     the pod_vector member variables in this have been swapped with rec.
160 
161     \param n_ind
162     the number of independent variables (only used for error checking
163     when NDEBUG is not defined).
164 
165     \par
166     Use an assert to check that the length of the following vectors is
167     less than the maximum possible value for addr_t; i.e., that an index
168     in these vectors can be represented using the type addr_t:
169     op_vec_, all_var_vecad_ind_, arg_vec_, test_vec_, all_par_vec_, text_vec_,
170     dyn_par_arg_.
171     */
get_recording(recorder<Base> & rec,size_t n_ind)172     void get_recording(recorder<Base>& rec, size_t n_ind)
173     {
174 # ifndef NDEBUG
175         size_t addr_t_max = size_t( std::numeric_limits<addr_t>::max() );
176 # endif
177         // just set size_t values
178         num_dynamic_ind_    = rec.num_dynamic_ind_;
179         num_var_rec_        = rec.num_var_rec_;
180         num_var_load_rec_   = rec.num_var_load_rec_;
181 
182         // op_vec_
183         op_vec_.swap(rec.op_vec_);
184         CPPAD_ASSERT_UNKNOWN(op_vec_.size() < addr_t_max );
185 
186         // op_arg_vec_
187         arg_vec_.swap(rec.arg_vec_);
188         CPPAD_ASSERT_UNKNOWN(arg_vec_.size()    < addr_t_max );
189 
190         // all_par_vec_
191         all_par_vec_.swap(rec.all_par_vec_);
192         CPPAD_ASSERT_UNKNOWN(all_par_vec_.size() < addr_t_max );
193 
194         // dyn_par_is_, dyn_par_op_, dyn_par_arg_
195         dyn_par_is_.swap( rec.dyn_par_is_ );
196         dyn_par_op_.swap( rec.dyn_par_op_ );
197         dyn_par_arg_.swap( rec.dyn_par_arg_ );
198         CPPAD_ASSERT_UNKNOWN(dyn_par_arg_.size() < addr_t_max );
199 
200         // text_rec_
201         text_vec_.swap(rec.text_vec_);
202         CPPAD_ASSERT_UNKNOWN(text_vec_.size() < addr_t_max );
203 
204         // all_var_vecad_ind_
205         all_var_vecad_ind_.swap(rec.all_var_vecad_ind_);
206         CPPAD_ASSERT_UNKNOWN(all_var_vecad_ind_.size() < addr_t_max );
207 
208         // num_var_vecad_rec_
209         num_var_vecad_rec_ = 0;
210         {   // all_var_vecad_ind_ contains size of each VecAD followed by
211             // the parameter indices used to inialize it.
212             size_t i = 0;
213             while( i < all_var_vecad_ind_.size() )
214             {   num_var_vecad_rec_++;
215                 i += size_t( all_var_vecad_ind_[i] ) + 1;
216             }
217             CPPAD_ASSERT_UNKNOWN( i == all_var_vecad_ind_.size() );
218         }
219 
220         // mapping from dynamic parameter index to parameter index
221         dyn_ind2par_ind_.resize( dyn_par_op_.size() );
222         size_t i_dyn = 0;
223         for(size_t i_par = 0; i_par < all_par_vec_.size(); ++i_par)
224         {   if( dyn_par_is_[i_par] )
225             {   dyn_ind2par_ind_[i_dyn] = addr_t( i_par );
226                 ++i_dyn;
227             }
228         }
229         CPPAD_ASSERT_UNKNOWN( i_dyn == dyn_ind2par_ind_.size() );
230 
231         // random access information
232         clear_random();
233 
234         // some checks
235         check_inv_op(n_ind);
236         check_variable_dag();
237         check_dynamic_dag();
238     }
239     // ----------------------------------------------------------------------
240     /*!
241     Check that InvOp operators start with second operator and are contiguous,
242     and there are n_ind of them.
243     */
244 # ifdef NDEBUG
check_inv_op(size_t n_ind) const245     void check_inv_op(size_t n_ind) const
246     {   return; }
247 # else
check_inv_op(size_t n_ind) const248     void check_inv_op(size_t n_ind) const
249     {   play::const_sequential_iterator itr = begin();
250         OpCode        op;
251         const addr_t* op_arg;
252         size_t        var_index;
253         itr.op_info(op, op_arg, var_index);
254         CPPAD_ASSERT_UNKNOWN( op == BeginOp );
255         size_t i_op = 0;
256         while( op != EndOp )
257         {   // start at second operator
258             (++itr).op_info(op, op_arg, var_index);
259             ++i_op;
260             CPPAD_ASSERT_UNKNOWN( (op == InvOp) == (i_op <= n_ind) );
261         }
262         return;
263     }
264 # endif
265     // ----------------------------------------------------------------------
266     /*!
267     Check variable graph to make sure arguments have value less
268     than or equal to the previously created variable. This is the directed
269     acyclic graph condition (DAG).
270     */
271 # ifdef NDEBUG
check_variable_dag(void) const272     void check_variable_dag(void) const
273     {   return; }
274 # else
check_variable_dag(void) const275     void check_variable_dag(void) const
276     {   play::const_sequential_iterator itr = begin();
277         OpCode        op;
278         const addr_t* op_arg;
279         size_t        var_index;
280         itr.op_info(op, op_arg, var_index);
281         CPPAD_ASSERT_UNKNOWN( op == BeginOp );
282         //
283         addr_t arg_var_bound = 0;
284         while( op != EndOp )
285         {   (++itr).op_info(op, op_arg, var_index);
286             switch(op)
287             {
288                 // cases where nothing to do
289                 case BeginOp:
290                 case EndOp:
291                 case EqppOp:
292                 case InvOp:
293                 case LdpOp:
294                 case LeppOp:
295                 case LtppOp:
296                 case NeppOp:
297                 case ParOp:
298                 case AFunOp:
299                 case FunapOp:
300                 case FunrpOp:
301                 case FunrvOp:
302                 case StppOp:
303                 break;
304 
305                 // only first argument is a variable
306                 case AbsOp:
307                 case AcosOp:
308                 case AcoshOp:
309                 case AsinOp:
310                 case AsinhOp:
311                 case AtanOp:
312                 case AtanhOp:
313                 case CosOp:
314                 case CoshOp:
315                 case DivvpOp:
316                 case ErfOp:
317                 case ErfcOp:
318                 case ExpOp:
319                 case Expm1Op:
320                 case LevpOp:
321                 case LogOp:
322                 case Log1pOp:
323                 case LtvpOp:
324                 case PowvpOp:
325                 case SignOp:
326                 case SinOp:
327                 case SinhOp:
328                 case SqrtOp:
329                 case SubvpOp:
330                 case TanOp:
331                 case TanhOp:
332                 case FunavOp:
333                 case ZmulvpOp:
334                 CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound );
335                 break;
336 
337                 // only second argument is a variable
338                 case AddpvOp:
339                 case DisOp:
340                 case DivpvOp:
341                 case EqpvOp:
342                 case LdvOp:
343                 case LepvOp:
344                 case LtpvOp:
345                 case MulpvOp:
346                 case NepvOp:
347                 case PowpvOp:
348                 case StvpOp:
349                 case SubpvOp:
350                 case ZmulpvOp:
351                 CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound );
352                 break;
353 
354                 // only first and second arguments are variables
355                 case AddvvOp:
356                 case DivvvOp:
357                 case EqvvOp:
358                 case LevvOp:
359                 case LtvvOp:
360                 case MulvvOp:
361                 case NevvOp:
362                 case PowvvOp:
363                 case SubvvOp:
364                 case ZmulvvOp:
365                 CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound );
366                 CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound );
367                 break;
368 
369                 // StpvOp
370                 case StpvOp:
371                 CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound );
372                 break;
373 
374                 // StvvOp
375                 case StvvOp:
376                 CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound );
377                 CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound );
378                 break;
379 
380                 // CSumOp
381                 case CSumOp:
382                 {   CPPAD_ASSERT_UNKNOWN( 5 < op_arg[2] );
383                     for(addr_t j = 5; j < op_arg[2]; j++)
384                         CPPAD_ASSERT_UNKNOWN(op_arg[j] <= arg_var_bound);
385                 }
386                 itr.correct_before_increment();
387                 break;
388 
389                 // CExpOp
390                 case CExpOp:
391                 if( op_arg[1] & 1 )
392                     CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound);
393                 if( op_arg[1] & 2 )
394                     CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound);
395                 if( op_arg[1] & 4 )
396                     CPPAD_ASSERT_UNKNOWN( op_arg[4] <= arg_var_bound);
397                 if( op_arg[1] & 8 )
398                     CPPAD_ASSERT_UNKNOWN( op_arg[5] <= arg_var_bound);
399                 break;
400 
401                 // PriOp
402                 case PriOp:
403                 if( op_arg[0] & 1 )
404                     CPPAD_ASSERT_UNKNOWN( op_arg[1] <= arg_var_bound);
405                 if( op_arg[0] & 2 )
406                     CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound);
407                 break;
408 
409                 // CSkipOp
410                 case CSkipOp:
411                 if( op_arg[1] & 1 )
412                     CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound);
413                 if( op_arg[1] & 2 )
414                     CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound);
415                 itr.correct_before_increment();
416                 break;
417 
418                 default:
419                 CPPAD_ASSERT_UNKNOWN(false);
420                 break;
421 
422 
423             }
424             if( NumRes(op) > 0 )
425             {   if( var_index > 0 )
426                 {   CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) < var_index);
427                 }
428                 else
429                 {   CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) == var_index);
430                 }
431                 //
432                 arg_var_bound = addr_t(var_index);
433             }
434         }
435         return;
436     }
437 # endif
438     // ----------------------------------------------------------------------
439     /*!
440     Check dynamic parameter graph to make sure arguments have value less
441     than or equal to the previously created dynamic parameter.
442     This is the directed acyclic graph condition (DAG).
443     */
444 # ifdef NDEBUG
check_dynamic_dag(void) const445     void check_dynamic_dag(void) const
446     {   return; }
447 # else
check_dynamic_dag(void) const448     void check_dynamic_dag(void) const
449     {   // number of dynamic parameters
450         size_t num_dyn = dyn_par_op_.size();
451         //
452         size_t i_arg = 0; // initialize dynamic parameter argument index
453         for(size_t i_dyn = 0; i_dyn < num_dyn; ++i_dyn)
454         {   // i_par is parameter index
455             addr_t i_par = dyn_ind2par_ind_[i_dyn];
456             CPPAD_ASSERT_UNKNOWN( dyn_par_is_[i_par] );
457             //
458             // operator for this dynamic parameter
459             op_code_dyn op = op_code_dyn( dyn_par_op_[i_dyn] );
460             //
461             // number of arguments for this dynamic parameter
462             size_t n_arg       = num_arg_dyn(op);
463             if( op == atom_dyn )
464             {   size_t n = size_t( dyn_par_arg_[i_arg + 1] );
465                 size_t m = size_t( dyn_par_arg_[i_arg + 2] );
466                 n_arg    = 5 + n + m;
467                 CPPAD_ASSERT_UNKNOWN(
468                     n_arg == size_t( dyn_par_arg_[i_arg + 4 + n + m] )
469                 );
470                 for(size_t i = 4; i < n - 1; ++i)
471                     CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] <  i_par );
472 # ifndef NDEBUG
473                 for(size_t i = 4+n; i < 4+n+m; ++i)
474                 {   addr_t j_par = dyn_par_arg_[i_arg + i];
475                     CPPAD_ASSERT_UNKNOWN( (j_par == 0) || (j_par >= i_par) );
476                 }
477 # endif
478             }
479             else
480             {   size_t num_non_par = num_non_par_arg_dyn(op);
481                 for(size_t i = num_non_par; i < n_arg; ++i)
482                     CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par);
483             }
484             //
485             // next dynamic parameter
486             i_arg += n_arg;
487         }
488         return;
489     }
490 # endif
491     // ===============================================================
492     /*!
493     Copy a player<Base> to another player<Base>
494 
495     \param play
496     object that contains the operatoion sequence to copy.
497     */
operator =(const player & play)498     void operator=(const player& play)
499     {
500         // size_t objects
501         num_dynamic_ind_    = play.num_dynamic_ind_;
502         num_var_rec_        = play.num_var_rec_;
503         num_var_load_rec_   = play.num_var_load_rec_;
504         num_var_vecad_rec_  = play.num_var_vecad_rec_;
505         //
506         // pod_vectors
507         op_vec_             = play.op_vec_;
508         arg_vec_            = play.arg_vec_;
509         text_vec_           = play.text_vec_;
510         all_var_vecad_ind_  = play.all_var_vecad_ind_;
511         dyn_par_is_         = play.dyn_par_is_;
512         dyn_ind2par_ind_    = play.dyn_ind2par_ind_;
513         dyn_par_op_         = play.dyn_par_op_;
514         dyn_par_arg_        = play.dyn_par_arg_;
515         op2arg_vec_         = play.op2arg_vec_;
516         op2var_vec_         = play.op2var_vec_;
517         var2op_vec_         = play.var2op_vec_;
518         //
519         // pod_maybe_vectors
520         all_par_vec_        = play.all_par_vec_;
521     }
522     // ===============================================================
523     /// Create a player< AD<Base> > from this player<Base>
base2ad(void) const524     player< AD<Base> > base2ad(void) const
525     {   player< AD<Base> > play;
526         //
527         // size_t objects
528         play.num_dynamic_ind_    = num_dynamic_ind_;
529         play.num_var_rec_        = num_var_rec_;
530         play.num_var_load_rec_   = num_var_load_rec_;
531         play.num_var_vecad_rec_  = num_var_vecad_rec_;
532         //
533         // pod_vectors
534         play.op_vec_             = op_vec_;
535         play.arg_vec_            = arg_vec_;
536         play.text_vec_           = text_vec_;
537         play.all_var_vecad_ind_  = all_var_vecad_ind_;
538         play.dyn_par_is_         = dyn_par_is_;
539         play.dyn_ind2par_ind_    = dyn_ind2par_ind_;
540         play.dyn_par_op_         = dyn_par_op_;
541         play.dyn_par_arg_        = dyn_par_arg_;
542         play.op2arg_vec_         = op2arg_vec_;
543         play.op2var_vec_         = op2var_vec_;
544         play.var2op_vec_         = var2op_vec_;
545         //
546         // pod_maybe_vector< AD<Base> > = pod_maybe_vector<Base>
547         play.all_par_vec_.resize( all_par_vec_.size() );
548         for(size_t i = 0; i < all_par_vec_.size(); ++i)
549             play.all_par_vec_[i] = all_par_vec_[i];
550         //
551         return play;
552     }
553     // ===============================================================
554     /// swap this recording with another recording
555     /// (used for move semantics version of ADFun assignment operation)
swap(player & other)556     void swap(player& other)
557     {   // size_t objects
558         std::swap(num_dynamic_ind_,    other.num_dynamic_ind_);
559         std::swap(num_var_rec_,        other.num_var_rec_);
560         std::swap(num_var_load_rec_,   other.num_var_load_rec_);
561         std::swap(num_var_vecad_rec_,  other.num_var_vecad_rec_);
562         //
563         // pod_vectors
564         op_vec_.swap(             other.op_vec_);
565         arg_vec_.swap(            other.arg_vec_);
566         text_vec_.swap(           other.text_vec_);
567         all_var_vecad_ind_.swap(  other.all_var_vecad_ind_);
568         dyn_par_is_.swap(         other.dyn_par_is_);
569         dyn_ind2par_ind_.swap(    other.dyn_ind2par_ind_);
570         dyn_par_op_.swap(         other.dyn_par_op_);
571         dyn_par_arg_.swap(        other.dyn_par_arg_);
572         op2arg_vec_.swap(         other.op2arg_vec_);
573         op2var_vec_.swap(         other.op2var_vec_);
574         var2op_vec_.swap(         other.var2op_vec_);
575         //
576         // pod_maybe_vectors
577         all_par_vec_.swap(    other.all_par_vec_);
578     }
579     // move semantics assignment
operator =(player && play)580     void operator=(player&& play)
581     {   swap(play); }
582     // =================================================================
583     /// Enable use of const_subgraph_iterator and member functions that begin
584     // with random_(no work if already setup).
585     template <class Addr>
setup_random(void)586     void setup_random(void)
587     {   play::random_setup(
588             num_var_rec_                               ,
589             op_vec_                                    ,
590             arg_vec_                                   ,
591             op2arg_vec_.pod_vector_ptr<Addr>()         ,
592             op2var_vec_.pod_vector_ptr<Addr>()         ,
593             var2op_vec_.pod_vector_ptr<Addr>()
594         );
595     }
596     /// Free memory used for functions that begin with random_
597     /// and random iterators and subgraph iterators
clear_random(void)598     void clear_random(void)
599     {
600         op2arg_vec_.clear();
601         op2var_vec_.clear();
602         var2op_vec_.clear();
603         CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size() == 0  );
604         CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0  );
605         CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0  );
606     }
607     /// get non-const version of all_par_vec
all_par_vec(void)608     pod_vector_maybe<Base>& all_par_vec(void)
609     {   return all_par_vec_; }
610     /// get non-const version of all_par_vec
all_par_vec(void) const611     const pod_vector_maybe<Base>& all_par_vec(void) const
612     {   return all_par_vec_; }
613     // ================================================================
614     // const functions that retrieve infromation from this player
615     // ================================================================
616     /// const version of dynamic parameter flag
dyn_par_is(void) const617     const pod_vector<bool>& dyn_par_is(void) const
618     {   return dyn_par_is_; }
619     /// const version of dynamic parameter index to parameter index
dyn_ind2par_ind(void) const620     const pod_vector<addr_t>& dyn_ind2par_ind(void) const
621     {   return dyn_ind2par_ind_; }
622     /// const version of dynamic parameter operator
dyn_par_op(void) const623     const pod_vector<opcode_t>& dyn_par_op(void) const
624     {   return dyn_par_op_; }
625     /// const version of dynamic parameter arguments
dyn_par_arg(void) const626     const pod_vector<addr_t>& dyn_par_arg(void) const
627     {   return dyn_par_arg_; }
628     /*!
629     \brief
630     fetch an operator from the recording.
631 
632     \return
633     the i-th operator in the recording.
634 
635     \param i
636     the index of the operator in recording
637     */
GetOp(size_t i) const638     OpCode GetOp (size_t i) const
639     {   return OpCode(op_vec_[i]); }
640 
641     /*!
642     \brief
643     Fetch a VecAD index from the recording.
644 
645     \return
646     the i-th VecAD index in the recording.
647 
648     \param i
649     the index of the VecAD index in recording
650     */
GetVecInd(size_t i) const651     size_t GetVecInd (size_t i) const
652     {   return size_t( all_var_vecad_ind_[i] ); }
653 
654     /*!
655     \brief
656     Fetch a parameter from the recording.
657 
658     \return
659     the i-th parameter in the recording.
660 
661     \param i
662     the index of the parameter in recording
663     */
GetPar(size_t i) const664     Base GetPar(size_t i) const
665     {   return all_par_vec_[i]; }
666 
667     /*!
668     \brief
669     Fetch entire parameter vector from the recording.
670 
671     \return
672     the entire parameter vector.
673 
674     */
GetPar(void) const675     const Base* GetPar(void) const
676     {   return all_par_vec_.data(); }
677 
678     /*!
679     \brief
680     Fetch a '\\0' terminated string from the recording.
681 
682     \return
683     the beginning of the string.
684 
685     \param i
686     the index where the string begins.
687     */
GetTxt(size_t i) const688     const char *GetTxt(size_t i) const
689     {   CPPAD_ASSERT_UNKNOWN(i < text_vec_.size() );
690         return text_vec_.data() + i;
691     }
692 
693     /// Fetch number of independent dynamic parameters in the recording
num_dynamic_ind(void) const694     size_t num_dynamic_ind(void) const
695     {   return num_dynamic_ind_; }
696 
697     /// Fetch number of dynamic parameters in the recording
num_dynamic_par(void) const698     size_t num_dynamic_par(void) const
699     {   return dyn_par_op_.size(); }
700 
701     /// Fetch number of dynamic parameters operator arguments in the recording
num_dynamic_arg(void) const702     size_t num_dynamic_arg(void) const
703     {   return dyn_par_arg_.size(); }
704 
705     /// Fetch number of variables in the recording.
num_var_rec(void) const706     size_t num_var_rec(void) const
707     {   return num_var_rec_; }
708 
709     /// Fetch number of vecad load operations
num_var_load_rec(void) const710     size_t num_var_load_rec(void) const
711     {   return num_var_load_rec_; }
712 
713     /// Fetch number of operators in the recording.
num_op_rec(void) const714     size_t num_op_rec(void) const
715     {   return op_vec_.size(); }
716 
717     /// Fetch number of VecAD indices in the recording.
num_var_vecad_ind_rec(void) const718     size_t num_var_vecad_ind_rec(void) const
719     {   return all_var_vecad_ind_.size(); }
720 
721     /// Fetch number of VecAD vectors in the recording
num_var_vecad_rec(void) const722     size_t num_var_vecad_rec(void) const
723     {   return num_var_vecad_rec_; }
724 
725     /// Fetch number of argument indices in the recording.
num_op_arg_rec(void) const726     size_t num_op_arg_rec(void) const
727     {   return arg_vec_.size(); }
728 
729     /// Fetch number of parameters in the recording.
num_par_rec(void) const730     size_t num_par_rec(void) const
731     {   return all_par_vec_.size(); }
732 
733     /// Fetch number of characters (representing strings) in the recording.
num_text_rec(void) const734     size_t num_text_rec(void) const
735     {   return text_vec_.size(); }
736 
737     /// A measure of amount of memory used to store
738     /// the operation sequence, just lengths, not capacities.
739     /// In user api as f.size_op_seq(); see the file seq_property.omh.
size_op_seq(void) const740     size_t size_op_seq(void) const
741     {   // check assumptions made by ad_fun<Base>::size_op_seq()
742         CPPAD_ASSERT_UNKNOWN( op_vec_.size() == num_op_rec() );
743         CPPAD_ASSERT_UNKNOWN( arg_vec_.size()    == num_op_arg_rec() );
744         CPPAD_ASSERT_UNKNOWN( all_par_vec_.size() == num_par_rec() );
745         CPPAD_ASSERT_UNKNOWN( text_vec_.size() == num_text_rec() );
746         CPPAD_ASSERT_UNKNOWN( all_var_vecad_ind_.size() == num_var_vecad_ind_rec() );
747         return op_vec_.size()        * sizeof(opcode_t)
748              + arg_vec_.size()       * sizeof(addr_t)
749              + all_par_vec_.size()   * sizeof(Base)
750              + dyn_par_is_.size()    * sizeof(bool)
751              + dyn_ind2par_ind_.size() * sizeof(addr_t)
752              + dyn_par_op_.size()    * sizeof(opcode_t)
753              + dyn_par_arg_.size()   * sizeof(addr_t)
754              + text_vec_.size()      * sizeof(char)
755              + all_var_vecad_ind_.size() * sizeof(addr_t)
756         ;
757     }
758     /// A measure of amount of memory used for random access routine
759     /// In user api as f.size_random(); see the file seq_property.omh.
size_random(void) const760     size_t size_random(void) const
761     {
762 # ifndef NDEBUG
763         if( op2arg_vec_.size() == 0 )
764         {   CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 );
765             CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 );
766         }
767         else
768         {   size_t size = 0;
769             switch( address_type() )
770             {   case play::unsigned_short_enum:
771                 size = sizeof(unsigned short);
772                 break;
773                 //
774                 case play::unsigned_int_enum:
775                 size = sizeof(unsigned int);
776                 break;
777                 //
778                 case play::size_t_enum:
779                 size = sizeof(size_t);
780                 break;
781 
782                 default:
783                 CPPAD_ASSERT_UNKNOWN(false);
784                 break;
785             }
786             CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size()/size  == num_op_rec() );
787             CPPAD_ASSERT_UNKNOWN( op2var_vec_.size()/size  == num_op_rec() );
788             CPPAD_ASSERT_UNKNOWN( var2op_vec_.size()/size  == num_var_rec() );
789         }
790 # endif
791         CPPAD_ASSERT_UNKNOWN( sizeof(unsigned char) == 1 );
792         return op2arg_vec_.size()
793              + op2var_vec_.size()
794              + var2op_vec_.size()
795         ;
796     }
797     // -----------------------------------------------------------------------
798     /// const sequential iterator begin
begin(void) const799     play::const_sequential_iterator begin(void) const
800     {   size_t op_index = 0;
801         size_t num_var  = num_var_rec_;
802         return play::const_sequential_iterator(
803             num_var, &op_vec_, &arg_vec_, op_index
804         );
805     }
806     /// const sequential iterator end
end(void) const807     play::const_sequential_iterator end(void) const
808     {   size_t op_index = op_vec_.size() - 1;
809         size_t num_var  = num_var_rec_;
810         return play::const_sequential_iterator(
811             num_var, &op_vec_, &arg_vec_, op_index
812         );
813     }
814     // -----------------------------------------------------------------------
815     /// const subgraph iterator begin
begin_subgraph(const play::const_random_iterator<addr_t> & random_itr,const pod_vector<addr_t> * subgraph) const816     play::const_subgraph_iterator<addr_t>  begin_subgraph(
817         const play::const_random_iterator<addr_t>& random_itr ,
818         const pod_vector<addr_t>*                  subgraph   ) const
819     {   size_t subgraph_index = 0;
820         return play::const_subgraph_iterator<addr_t>(
821             random_itr,
822             subgraph,
823             subgraph_index
824         );
825     }
826     /// const subgraph iterator end
827     template <class Addr>
end_subgraph(const play::const_random_iterator<Addr> & random_itr,const pod_vector<addr_t> * subgraph) const828     play::const_subgraph_iterator<Addr>  end_subgraph(
829         const play::const_random_iterator<Addr>&   random_itr ,
830         const pod_vector<addr_t>*                  subgraph   ) const
831     {   size_t subgraph_index = subgraph->size() - 1;
832         return play::const_subgraph_iterator<Addr>(
833             random_itr,
834             subgraph,
835             subgraph_index
836         );
837     }
838     // -----------------------------------------------------------------------
839     /// const random iterator
840     template <class Addr>
get_random(void) const841     play::const_random_iterator<Addr> get_random(void) const
842     {   return play::const_random_iterator<Addr>(
843             op_vec_,
844             arg_vec_,
845             op2arg_vec_.pod_vector_ptr<Addr>(),
846             op2var_vec_.pod_vector_ptr<Addr>(),
847             var2op_vec_.pod_vector_ptr<Addr>()
848         );
849     }
850 };
851 
852 } } // END_CPPAD_lOCAL_NAMESPACE
853 # endif
854