source: branches/opt_cond_exp/cppad/local/player.hpp @ 2980

Last change on this file since 2980 was 2980, checked in by bradbell, 7 years ago

Use index instead of pointer because pointer can become invalid when vector grows.

  • Property svn:keywords set to Id
File size: 20.1 KB
Line 
1/* $Id: player.hpp 2980 2013-10-20 23:33:35Z bradbell $ */
2# ifndef CPPAD_PLAYER_INCLUDED
3# define CPPAD_PLAYER_INCLUDED
4
5/* --------------------------------------------------------------------------
6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
7
8CppAD is distributed under multiple licenses. This distribution is under
9the terms of the
10                    Eclipse Public License Version 1.0.
11
12A copy of this license is included in the COPYING file of this distribution.
13Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
14-------------------------------------------------------------------------- */
15
16namespace CppAD { // BEGIN_CPPAD_NAMESPACE
17/*!
18\defgroup player_hpp player.hpp
19\{
20\file player.hpp
21File used to define the player class.
22*/
23
24
25/*!
26Class used to store and play back an operation sequence recording.
27
28\tparam Base
29These were AD< \a Base > operations when recorded. Operations during playback
30are done using the type  \a Base .
31*/
32template <class Base>
33class player {
34
35// -------------- Variables that define the recording -----------------------
36private:
37        /// Number of variables in the recording.
38        size_t    num_rec_var_;
39
40        /// The operators in the recording.
41        pod_vector<CPPAD_OP_CODE_TYPE> rec_op_;
42
43        /// Number of VecAD vectors in the recording
44        size_t    num_rec_vecad_vec_;
45
46        /// The VecAD indices in the recording.
47        pod_vector<addr_t> rec_vecad_ind_;
48
49        /// The operation argument indices in the recording
50        pod_vector<addr_t> rec_op_arg_;
51
52        /// The parameters in the recording.
53        /// Note that Base may not be plain old data, so use false in consructor.
54        pod_vector<Base> rec_par_;
55
56        /// Character strings ('\\0' terminated) in the recording.
57        pod_vector<char> rec_text_;
58
59
60// --------------- Functions used to create and maniplate a recording -------
61public:
62        /// Default constructor
63        player(void) : 
64        num_rec_var_(0)                                      ,
65        rec_op_( std::numeric_limits<addr_t>::max() )        ,
66        rec_vecad_ind_( std::numeric_limits<addr_t>::max() ) ,
67        rec_op_arg_( std::numeric_limits<addr_t>::max() )    ,
68        rec_par_( std::numeric_limits<addr_t>::max() )       ,
69        rec_text_( std::numeric_limits<addr_t>::max() )
70        { }
71
72        /// Destructor
73        ~player(void)
74        { }
75
76        // ===============================================================
77        // Begin two functions with idential code but different argument types.
78        /*! 
79        Moving an operation sequence from a recorder to a player
80 
81        \param rec
82        the object that was used to record the operation sequence.  After this
83        operation, the state of the recording is no longer defined. For example,
84        the \c pod_vector member variables in \c this have been swapped with
85        \c rec .
86        */
87        void get(recorder<Base>& rec)
88        {       size_t i;
89
90                // Var
91                num_rec_var_        = rec.num_rec_var_;
92
93                // Op
94                rec_op_.swap(rec.rec_op_);
95
96                // VecInd
97                rec_vecad_ind_.swap(rec.rec_vecad_ind_);
98
99                // Arg
100                rec_op_arg_.swap(rec.rec_op_arg_);
101
102                // Par
103                rec_par_.swap(rec.rec_par_);
104
105                // Txt
106                rec_text_.swap(rec.rec_text_);
107
108                // set the number of VecAD vectors
109                num_rec_vecad_vec_ = 0;
110                for(i = 0; i < rec_vecad_ind_.size(); i += rec_vecad_ind_[i] + 1)
111                        num_rec_vecad_vec_++;
112                // rec_vecad_ind_ contains size of each VecAD followed by
113                // the parameter indices used to iniialize it.
114                CPPAD_ASSERT_UNKNOWN( i == rec_vecad_ind_.size() );
115        }
116
117        /*! 
118        Copying an operation sequence from one player to another
119 
120        \param play
121        the object that contains the operatoion sequence to copy.
122        */
123        void operator=(const player& play)
124        {       
125                // Var
126                num_rec_var_        = play.num_rec_var_;
127
128                // Op
129                rec_op_             = play.rec_op_;
130
131                // VecInd
132                num_rec_vecad_vec_  = play.num_rec_vecad_vec_;
133                rec_vecad_ind_      = play.rec_vecad_ind_;
134
135                // Arg
136                rec_op_arg_         = play.rec_op_arg_;
137
138                // Par
139                rec_par_            = play.rec_par_;
140
141                // Txt
142                rec_text_           = play.rec_text_;
143        }
144        // End two functions with idential code but different argument types.
145        // ===============================================================
146
147        /// Erase all information in an operation sequence player.
148        void Erase(void)
149        {       
150                num_rec_var_       = 0;
151                num_rec_vecad_vec_ = 0;
152
153                rec_op_.erase();
154                rec_vecad_ind_.erase();
155                rec_op_arg_.erase();
156                rec_par_.erase();
157                rec_text_.erase();
158        }
159
160// ------------------ Old method of palying back a recording -----------------
161public:
162        /*!
163        \brief
164        Fetch an operator from the recording.
165
166        \return
167        the i-th operator in the recording.
168
169        \param i
170        the index of the operator in recording
171        */
172        OpCode GetOp (size_t i) const
173        {       return OpCode(rec_op_[i]); }
174
175        /*!
176        \brief
177        Fetch a VecAD index from the recording.
178
179        \return
180        the i-th VecAD index in the recording.
181
182        \param i
183        the index of the VecAD index in recording
184        */
185        size_t GetVecInd (size_t i) const
186        {       return rec_vecad_ind_[i]; }
187
188        /*!
189        \brief
190        Fetch a parameter from the recording.
191
192        \return
193        the i-th parameter in the recording.
194
195        \param i
196        the index of the parameter in recording
197        */
198        Base GetPar(size_t i) const
199        {       return rec_par_[i]; }
200
201        /*!
202        \brief
203        Fetch entire parameter vector from the recording.
204
205        \return
206        the entire parameter vector.
207
208        */
209        const Base* GetPar(void) const
210        {       return rec_par_.data(); }
211
212        /*!
213        \brief
214        Fetch a '\\0' terminated string from the recording.
215
216        \return
217        the beginning of the string.
218
219        \param i
220        the index where the string begins.
221        */
222        const char *GetTxt(size_t i) const
223        {       CPPAD_ASSERT_UNKNOWN(i < rec_text_.size() );
224                return rec_text_.data() + i;
225        }
226       
227        /*!
228        \brief
229        Replace an argument value in the recording.
230        2DO: change name of this routine to ReplaceArg.
231
232        \param i
233        is the index, in the recording argument vector,
234        of the value that is to be replaced.
235
236        \param value
237        is the new argument value.
238        */
239        void ReplaceInd(size_t i, size_t value)
240        {       rec_op_arg_[i] =  static_cast<addr_t>( value ); }
241
242        /// Fetch number of variables in the recording.
243        size_t num_rec_var(void) const
244        {       return num_rec_var_; }
245
246        /// Fetch number of operators in the recording.
247        size_t num_rec_op(void) const
248        {       return rec_op_.size(); }
249
250        /// Fetch number of VecAD indices in the recording.
251        size_t num_rec_vecad_ind(void) const
252        {       return rec_vecad_ind_.size(); }
253
254        /// Fetch number of VecAD vectors in the recording
255        size_t num_rec_vecad_vec(void) const
256        {       return num_rec_vecad_vec_; }
257
258        /// Fetch number of argument indices in the recording.
259        size_t num_rec_op_arg(void) const
260        {       return rec_op_arg_.size(); }
261
262        /// Fetch number of parameters in the recording.
263        size_t num_rec_par(void) const
264        {       return rec_par_.size(); }
265
266        /// Fetch number of characters (representing strings) in the recording.
267        size_t num_rec_text(void) const
268        {       return rec_text_.size(); }
269
270        /// Fetch a rough measure of amount of memory used to store recording
271        /// (just lengths, not capacities).
272        size_t Memory(void) const
273        {       return rec_op_.size()        * sizeof(OpCode) 
274                     + rec_op_arg_.size()    * sizeof(addr_t)
275                     + rec_par_.size()       * sizeof(Base)
276                     + rec_text_.size()      * sizeof(char)
277                     + rec_vecad_ind_.size() * sizeof(addr_t)
278                ;
279        }
280
281// ------------- Variables used for new methog of playing back a recording ---
282private:
283        /// Current operator
284        OpCode    op_;
285
286        /// Index in recording corresponding to current operator
287        size_t    op_index_;
288
289        /// Current offset of the argument indices in rec_op_arg_
290        size_t    op_arg_;
291
292        /// Index for primary (last) variable corresponding to current operator
293        size_t    var_index_;
294
295// ----------- Functions used in new method for palying back a recording ---
296public:
297        /*!
298        Start a play back of the recording during a forward sweep.
299
300        Use repeated calls to next_forward to play back one operator at a time.
301
302        \param op
303        The input value of op does not matter. Its output value is the
304        first operator in the recording; i.e., BeginOp.
305
306        \param op_arg
307        The input value of *op_arg does not matter. Its output value is the
308        beginning of the vector of argument indices for the first operation;
309        i.e., 0
310
311        \param op_index
312        The input value of op_index does not matter. Its output value
313        is the index of the next first operator in the recording; i.e., 0.
314
315        \param var_index
316        The input value of var_index does not matter. Its output value is the
317        index of the primary (last) result corresponding to the the first
318        operator (which must be a BeginOp); i.e., 0.
319        */
320        void start_forward(
321        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
322        {
323                op        = op_          = OpCode( rec_op_[0] ); 
324                op_arg_   = 0;
325                op_arg    = rec_op_arg_.data();
326                op_index  = op_index_    = 0;
327                var_index = var_index_   = 0;
328
329                CPPAD_ASSERT_UNKNOWN( op_  == BeginOp );
330                CPPAD_ASSERT_NARG_NRES(op_, 0, 1);
331
332                return;
333        }
334
335        /*!
336        Fetch the next operator during a forward sweep.
337
338        Use start_forward to initialize to the first operator; i.e.,
339        the BeginOp at the beginning of the recording.
340
341        \param op
342        The input value of op does not matter. Its output value is the
343        next operator in the recording.
344        For speed, \c next_forward does not check for the special cases
345        where  <tt>op == CSumOp</tt> or <tt>op == CSkipOp</tt>. In these cases,
346        the other return values from \c next_forward must be corrected by a call
347        to \c forward_csum or \c forward_cskip respectively.
348
349        \param op_arg
350        The input value of *op_arg does not matter. Its output value is the
351        beginning of the vector of argument indices for this operation.
352
353        \param op_index
354        The input value of op_index does not matter. Its output value
355        is the index of the next operator in the recording. Thus the ouput
356        value following the previous call to start_forward is one. In addition,
357        the output value increases by one with each call to next_forward.
358
359        \param var_index
360        The input value of var_index does not matter. Its output value is the
361        index of the primary (last) result corresponding to the operator op.
362        */
363
364        void next_forward(
365        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
366        {       using CppAD::NumRes;
367                using CppAD::NumArg;
368
369                // index for the next operator
370                op_index    = ++op_index_;
371
372                // first argument for next operator
373                op_arg_    += NumArg(op_);                   // index
374                op_arg      = op_arg_ + rec_op_arg_.data();  // pointer
375
376                // next operator
377                op          = op_         = OpCode( rec_op_[ op_index_ ] );
378
379                // index for last result for next operator
380                var_index   = var_index_ += NumRes(op);
381
382                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
383                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
384        }
385        /*!
386        Correct \c next_forward return values when <tt>op == CSumOp</tt>.
387
388        \param op
389        The input value of op must be the return value from the previous
390        call to \c next_forward and must be \c CSumOp.
391
392        \param op_arg
393        The input value of *op_arg must be the return value from the
394        previous call to \c next_forward. Its output value is the
395        beginning of the vector of argument indices for this operation.
396
397        \param op_index
398        The input value of op_index does must be the return value from the
399        previous call to \c next_forward. Its output value
400        is the index of this operator in the recording.
401
402        \param var_index
403        The input value of var_index must be the return value from the
404        previous call to \c next_forward. Its output value is the
405        index of the primary (last) result corresponding to this.
406        */
407        void forward_csum(
408        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
409        {       using CppAD::NumRes;
410                using CppAD::NumArg;
411                CPPAD_ASSERT_UNKNOWN( op == CSumOp );
412                CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
413                CPPAD_ASSERT_UNKNOWN(
414                op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
415                );
416                /*
417                The only thing that really needs fixing is op_arg_.
418                Actual number of arugments for this operator is
419                        op_arg[0] + op_arg[1] + 4.
420                We must change op_arg_ so that when you add NumArg(CSumOp)
421                you get first argument for next operator in sequence.
422                */
423                op_arg_    += op_arg[0] + op_arg[1] + 4;
424
425                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
426                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
427        }
428        /*!
429        Correct \c next_forward return values when <tt>op == CSkipOp</tt>.
430
431        \param op
432        The input value of op must be the return value from the previous
433        call to \c next_forward and must be \c CSkipOp.
434
435        \param op_arg
436        The input value of *op_arg must be the return value from the
437        previous call to \c next_forward. Its output value is the
438        beginning of the vector of argument indices for this operation.
439
440        \param op_index
441        The input value of op_index does must be the return value from the
442        previous call to \c next_forward. Its output value
443        is the index of this operator in the recording.
444
445        \param var_index
446        The input value of var_index must be the return value from the
447        previous call to \c next_forward. Its output value is the
448        index of the primary (last) result corresponding to this.
449        */
450        void forward_cskip(
451        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
452        {       using CppAD::NumRes;
453                using CppAD::NumArg;
454                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
455                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
456                CPPAD_ASSERT_UNKNOWN(
457                op_arg[4] + op_arg[5] == op_arg[ 6 + op_arg[4] + op_arg[5] ]
458                );
459                /*
460                The only thing that really needs fixing is op_arg_.
461                Actual number of arugments for this operator is
462                        7 + op_arg[4] + op_arg[5]
463                We must change op_arg_ so that when you add NumArg(CSkipOp)
464                you get first argument for next operator in sequence.
465                */
466                op_arg_    += 7 + op_arg[4] + op_arg[5];
467
468                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
469                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
470        }
471        /*!
472        Get a non-constant version of op_arg returned by previous next_forward
473
474        \return
475        The return value is equal to the return value of op_arg
476        corresponding to the previous call to next_forward.
477        */
478        addr_t* forward_non_const_arg(void)
479        {       return op_arg_ + rec_op_arg_.data(); }
480
481        /*!
482        Start a play back of the recording during a reverse sweep.
483
484        Use repeated calls to next_reverse to play back one operator at a time.
485
486        \param op
487        The input value of op does not matter. Its output value is the
488        last operator in the recording; i.e., EndOp.
489
490        \param op_arg
491        The input value of *op_arg does not matter. Its output value is the
492        beginning of the vector of argument indices for the last operation;
493        (there are no arguments for the last operation so \a op_arg is invalid).
494
495        \param op_index
496        The input value of op_index does not matter. Its output value
497        is the index of the last operator in the recording.
498
499        \param var_index
500        The input value of var_index does not matter. Its output value is the
501        index of the primary (last) result corresponding to the the last
502        operator (which must be a EndOp).
503        (there are no results for the last operation
504        so \a var_index is invalid).
505        */
506
507        void start_reverse(
508        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
509        {
510                op_arg_     = rec_op_arg_.size();                // index
511                op_arg      = op_arg_ + rec_op_arg_.data();      // pointer
512
513                op_index    = op_index_   = rec_op_.size() - 1; 
514                var_index   = var_index_  = num_rec_var_ - 1;
515
516                op          = op_         = OpCode( rec_op_[ op_index_ ] );
517                CPPAD_ASSERT_UNKNOWN( op_ == EndOp );
518                CPPAD_ASSERT_NARG_NRES(op, 0, 0);
519                return;
520        }
521
522        /*!
523        Fetch the next operator during a reverse sweep.
524
525        Use start_reverse to initialize to reverse play back.
526        The first call to next_reverse (after start_reverse) will give the
527        last operator in the recording.
528
529        \param op
530        The input value of op does not matter. Its output value is the
531        next operator in the recording (in reverse order).
532        The last operator sets op equal to EndOp.
533
534        \param op_arg
535        The input value of *op_arg does not matter. Its output value is the
536        beginning of the vector of argument indices for this operation.
537        The last operator sets op_arg equal to the beginning of the
538        argument indices for the entire recording.
539        For speed, \c next_reverse does not check for the special cases
540        <tt>op == CSumOp</tt> or <tt>op == CSkipOp</tt>. In these cases, the other
541        return values from \c next_reverse must be corrected by a call to
542        \c reverse_csum or \c reverse_cskip respectively.
543
544
545        \param op_index
546        The input value of op_index does not matter. Its output value
547        is the index of this operator in the recording. Thus the output
548        value following the previous call to start_reverse is equal to
549        the number of variables in the recording minus one.
550        In addition, the output value decreases by one with each call to
551        next_reverse.
552        The last operator sets op_index equal to 0.
553
554        \param var_index
555        The input value of var_index does not matter. Its output value is the
556        index of the primary (last) result corresponding to the operator op.
557        The last operator sets var_index equal to 0 (corresponding to BeginOp
558        at beginning of operation sequence).
559        */
560
561        void next_reverse(
562        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
563        {       using CppAD::NumRes;
564                using CppAD::NumArg;
565
566                // index of the last result for the next operator
567                CPPAD_ASSERT_UNKNOWN( var_index_ >= NumRes(op_) );
568                var_index   = var_index_ -= NumRes(op_);
569
570                // next operator
571                CPPAD_ASSERT_UNKNOWN( op_index_  > 0 );
572                op_index    = --op_index_;                                  // index
573                op          = op_         = OpCode( rec_op_[ op_index_ ] ); // value
574
575                // first argument for next operator
576                CPPAD_ASSERT_UNKNOWN( op_arg_ >= NumArg(op)  );
577                op_arg_    -= NumArg(op);                            // index
578                op_arg      = op_arg_ + rec_op_arg_.data();          // pointer
579        }
580        /*!
581        Correct \c next_reverse return values when <tt>op == CSumOp</tt>.
582
583        \param op
584        The input value of op must be the return value from the previous
585        call to \c next_reverse and must be \c CSumOp.
586
587        \param op_arg
588        The input value of *op_arg must be the return value from the
589        previous call to \c next_reverse. Its output value is the
590        beginning of the vector of argument indices for this operation.
591
592        \param op_index
593        The input value of op_index must be the return value from the
594        previous call to \c next_reverse. Its output value
595        is the index of the this operator in the recording.
596
597        \param var_index
598        The input value of var_index must be the return value from the
599        previous call to \c next_reverse. Its output value is the
600        index of the primary (last) result corresponding to this operator.
601        */
602
603        void reverse_csum(
604        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
605        {       using CppAD::NumRes;
606                using CppAD::NumArg;
607                CPPAD_ASSERT_UNKNOWN( op == CSumOp );
608                CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
609                /*
610                The things needs fixing are op_arg_ and op_arg. Currently,
611                op_arg points first arugment for the previous operator.
612                */
613                --op_arg;
614                op_arg_    -= (op_arg[0] + 4);
615                op_arg      = op_arg_ + rec_op_arg_.data();
616
617                CPPAD_ASSERT_UNKNOWN(
618                op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
619                );
620                CPPAD_ASSERT_UNKNOWN( op_index_  < rec_op_.size() );
621                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
622                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
623        }
624        /*!
625        Correct \c next_reverse return values when <tt>op == CSkipOp</tt>.
626
627        \param op
628        The input value of op must be the return value from the previous
629        call to \c next_reverse and must be \c CSkipOp.
630
631        \param op_arg
632        The input value of *op_arg must be the return value from the
633        previous call to \c next_reverse. Its output value is the
634        beginning of the vector of argument indices for this operation.
635
636        \param op_index
637        The input value of op_index must be the return value from the
638        previous call to \c next_reverse. Its output value
639        is the index of the this operator in the recording.
640
641        \param var_index
642        The input value of var_index must be the return value from the
643        previous call to \c next_reverse. Its output value is the
644        index of the primary (last) result corresponding to this operator.
645        */
646
647        void reverse_cskip(
648        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
649        {       using CppAD::NumRes;
650                using CppAD::NumArg;
651                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
652                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
653                /*
654                The things needs fixing are op_arg_ and op_arg. Currently,
655                op_arg points first arugment for the previous operator.
656                */
657                --op_arg;
658                op_arg_    -= (op_arg[0] + 4);
659                op_arg      = op_arg_ + rec_op_arg_.data();
660
661                CPPAD_ASSERT_UNKNOWN(
662                op_arg[1] + op_arg[2] == op_arg[ 3 + op_arg[1] + op_arg[2] ]
663                );
664                CPPAD_ASSERT_UNKNOWN( op_index_  < rec_op_.size() );
665                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
666                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
667        }
668
669};
670
671/*! \} */
672} // END_CPPAD_NAMESPACE
673# endif
Note: See TracBrowser for help on using the repository browser.