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

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

Delay setting CSkip arguments so can map old variable address to new addresses.

  • Property svn:keywords set to Id
File size: 20.0 KB
Line 
1/* $Id: player.hpp 2967 2013-10-18 17:03:40Z 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 index in the recording.
230
231        \param i
232        is the index, in argument indices, that is to be replaced.
233
234        \param value
235        is the new normal index value.
236        */
237        void ReplaceInd(size_t i, size_t value)
238        {       rec_op_arg_[i] =  static_cast<addr_t>( value ); }
239
240        /// Fetch number of variables in the recording.
241        size_t num_rec_var(void) const
242        {       return num_rec_var_; }
243
244        /// Fetch number of operators in the recording.
245        size_t num_rec_op(void) const
246        {       return rec_op_.size(); }
247
248        /// Fetch number of VecAD indices in the recording.
249        size_t num_rec_vecad_ind(void) const
250        {       return rec_vecad_ind_.size(); }
251
252        /// Fetch number of VecAD vectors in the recording
253        size_t num_rec_vecad_vec(void) const
254        {       return num_rec_vecad_vec_; }
255
256        /// Fetch number of argument indices in the recording.
257        size_t num_rec_op_arg(void) const
258        {       return rec_op_arg_.size(); }
259
260        /// Fetch number of parameters in the recording.
261        size_t num_rec_par(void) const
262        {       return rec_par_.size(); }
263
264        /// Fetch number of characters (representing strings) in the recording.
265        size_t num_rec_text(void) const
266        {       return rec_text_.size(); }
267
268        /// Fetch a rough measure of amount of memory used to store recording
269        /// (just lengths, not capacities).
270        size_t Memory(void) const
271        {       return rec_op_.size()        * sizeof(OpCode) 
272                     + rec_op_arg_.size()    * sizeof(addr_t)
273                     + rec_par_.size()       * sizeof(Base)
274                     + rec_text_.size()      * sizeof(char)
275                     + rec_vecad_ind_.size() * sizeof(addr_t)
276                ;
277        }
278
279// ------------- Variables used for new methog of playing back a recording ---
280private:
281        /// Current operator
282        OpCode    op_;
283
284        /// Index in recording corresponding to current operator
285        size_t    op_index_;
286
287        /// Current offset of the argument indices in rec_op_arg_
288        size_t    op_arg_;
289
290        /// Index for primary (last) variable corresponding to current operator
291        size_t    var_index_;
292
293// ----------- Functions used in new method for palying back a recording ---
294public:
295        /*!
296        Start a play back of the recording during a forward sweep.
297
298        Use repeated calls to next_forward to play back one operator at a time.
299
300        \param op
301        The input value of op does not matter. Its output value is the
302        first operator in the recording; i.e., BeginOp.
303
304        \param op_arg
305        The input value of *op_arg does not matter. Its output value is the
306        beginning of the vector of argument indices for the first operation;
307        i.e., 0
308
309        \param op_index
310        The input value of op_index does not matter. Its output value
311        is the index of the next first operator in the recording; i.e., 0.
312
313        \param var_index
314        The input value of var_index does not matter. Its output value is the
315        index of the primary (last) result corresponding to the the first
316        operator (which must be a BeginOp); i.e., 0.
317        */
318        void start_forward(
319        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
320        {
321                op        = op_          = OpCode( rec_op_[0] ); 
322                op_arg_   = 0;
323                op_arg    = rec_op_arg_.data();
324                op_index  = op_index_    = 0;
325                var_index = var_index_   = 0;
326
327                CPPAD_ASSERT_UNKNOWN( op_  == BeginOp );
328                CPPAD_ASSERT_NARG_NRES(op_, 0, 1);
329
330                return;
331        }
332
333        /*!
334        Fetch the next operator during a forward sweep.
335
336        Use start_forward to initialize to the first operator; i.e.,
337        the BeginOp at the beginning of the recording.
338
339        \param op
340        The input value of op does not matter. Its output value is the
341        next operator in the recording.
342        For speed, \c next_forward does not check for the special cases
343        where  <tt>op == CSumOp</tt> or <tt>op == CSkipOp</tt>. In these cases,
344        the other return values from \c next_forward must be corrected by a call
345        to \c forward_csum or \c forward_cskip respectively.
346
347        \param op_arg
348        The input value of *op_arg does not matter. Its output value is the
349        beginning of the vector of argument indices for this operation.
350
351        \param op_index
352        The input value of op_index does not matter. Its output value
353        is the index of the next operator in the recording. Thus the ouput
354        value following the previous call to start_forward is one. In addition,
355        the output value increases by one with each call to next_forward.
356
357        \param var_index
358        The input value of var_index does not matter. Its output value is the
359        index of the primary (last) result corresponding to the operator op.
360        */
361
362        void next_forward(
363        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
364        {       using CppAD::NumRes;
365                using CppAD::NumArg;
366
367                // index for the next operator
368                op_index    = ++op_index_;
369
370                // first argument for next operator
371                op_arg_    += NumArg(op_);                   // index
372                op_arg      = op_arg_ + rec_op_arg_.data();  // pointer
373
374                // next operator
375                op          = op_         = OpCode( rec_op_[ op_index_ ] );
376
377                // index for last result for next operator
378                var_index   = var_index_ += NumRes(op);
379
380                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
381                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
382        }
383        /*!
384        Correct \c next_forward return values when <tt>op == CSumOp</tt>.
385
386        \param op
387        The input value of op must be the return value from the previous
388        call to \c next_forward and must be \c CSumOp.
389
390        \param op_arg
391        The input value of *op_arg must be the return value from the
392        previous call to \c next_forward. Its output value is the
393        beginning of the vector of argument indices for this operation.
394
395        \param op_index
396        The input value of op_index does must be the return value from the
397        previous call to \c next_forward. Its output value
398        is the index of this operator in the recording.
399
400        \param var_index
401        The input value of var_index must be the return value from the
402        previous call to \c next_forward. Its output value is the
403        index of the primary (last) result corresponding to this.
404        */
405        void forward_csum(
406        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
407        {       using CppAD::NumRes;
408                using CppAD::NumArg;
409                CPPAD_ASSERT_UNKNOWN( op == CSumOp );
410                CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
411                CPPAD_ASSERT_UNKNOWN(
412                op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
413                );
414                /*
415                The only thing that really needs fixing is op_arg_.
416                Actual number of arugments for this operator is
417                        op_arg[0] + op_arg[1] + 4.
418                We must change op_arg_ so that when you add NumArg(CSumOp)
419                you get first argument for next operator in sequence.
420                */
421                op_arg_    += op_arg[0] + op_arg[1] + 4;
422
423                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
424                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
425        }
426        /*!
427        Correct \c next_forward return values when <tt>op == CSkipOp</tt>.
428
429        \param op
430        The input value of op must be the return value from the previous
431        call to \c next_forward and must be \c CSkipOp.
432
433        \param op_arg
434        The input value of *op_arg must be the return value from the
435        previous call to \c next_forward. Its output value is the
436        beginning of the vector of argument indices for this operation.
437
438        \param op_index
439        The input value of op_index does must be the return value from the
440        previous call to \c next_forward. Its output value
441        is the index of this operator in the recording.
442
443        \param var_index
444        The input value of var_index must be the return value from the
445        previous call to \c next_forward. Its output value is the
446        index of the primary (last) result corresponding to this.
447        */
448        void forward_cskip(
449        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
450        {       using CppAD::NumRes;
451                using CppAD::NumArg;
452                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
453                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
454                CPPAD_ASSERT_UNKNOWN(
455                op_arg[4] + op_arg[5] == op_arg[ 6 + op_arg[4] + op_arg[5] ]
456                );
457                /*
458                The only thing that really needs fixing is op_arg_.
459                Actual number of arugments for this operator is
460                        7 + op_arg[4] + op_arg[5]
461                We must change op_arg_ so that when you add NumArg(CSkipOp)
462                you get first argument for next operator in sequence.
463                */
464                op_arg_    += 7 + op_arg[4] + op_arg[5];
465
466                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
467                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
468        }
469        /*!
470        Get a non-constant version of op_arg returned by previous next_forward
471
472        \return
473        The return value is equal to the return value of op_arg
474        corresponding to the previous call to next_forward.
475        */
476        addr_t* forward_non_const_arg(void)
477        {       return op_arg_ + rec_op_arg_.data(); }
478
479        /*!
480        Start a play back of the recording during a reverse sweep.
481
482        Use repeated calls to next_reverse to play back one operator at a time.
483
484        \param op
485        The input value of op does not matter. Its output value is the
486        last operator in the recording; i.e., EndOp.
487
488        \param op_arg
489        The input value of *op_arg does not matter. Its output value is the
490        beginning of the vector of argument indices for the last operation;
491        (there are no arguments for the last operation so \a op_arg is invalid).
492
493        \param op_index
494        The input value of op_index does not matter. Its output value
495        is the index of the last operator in the recording.
496
497        \param var_index
498        The input value of var_index does not matter. Its output value is the
499        index of the primary (last) result corresponding to the the last
500        operator (which must be a EndOp).
501        (there are no results for the last operation
502        so \a var_index is invalid).
503        */
504
505        void start_reverse(
506        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
507        {
508                op_arg_     = rec_op_arg_.size();                // index
509                op_arg      = op_arg_ + rec_op_arg_.data();      // pointer
510
511                op_index    = op_index_   = rec_op_.size() - 1; 
512                var_index   = var_index_  = num_rec_var_ - 1;
513
514                op          = op_         = OpCode( rec_op_[ op_index_ ] );
515                CPPAD_ASSERT_UNKNOWN( op_ == EndOp );
516                CPPAD_ASSERT_NARG_NRES(op, 0, 0);
517                return;
518        }
519
520        /*!
521        Fetch the next operator during a reverse sweep.
522
523        Use start_reverse to initialize to reverse play back.
524        The first call to next_reverse (after start_reverse) will give the
525        last operator in the recording.
526
527        \param op
528        The input value of op does not matter. Its output value is the
529        next operator in the recording (in reverse order).
530        The last operator sets op equal to EndOp.
531
532        \param op_arg
533        The input value of *op_arg does not matter. Its output value is the
534        beginning of the vector of argument indices for this operation.
535        The last operator sets op_arg equal to the beginning of the
536        argument indices for the entire recording.
537        For speed, \c next_reverse does not check for the special cases
538        <tt>op == CSumOp</tt> or <tt>op == CSkipOp</tt>. In these cases, the other
539        return values from \c next_reverse must be corrected by a call to
540        \c reverse_csum or \c reverse_cskip respectively.
541
542
543        \param op_index
544        The input value of op_index does not matter. Its output value
545        is the index of this operator in the recording. Thus the output
546        value following the previous call to start_reverse is equal to
547        the number of variables in the recording minus one.
548        In addition, the output value decreases by one with each call to
549        next_reverse.
550        The last operator sets op_index equal to 0.
551
552        \param var_index
553        The input value of var_index does not matter. Its output value is the
554        index of the primary (last) result corresponding to the operator op.
555        The last operator sets var_index equal to 0 (corresponding to BeginOp
556        at beginning of operation sequence).
557        */
558
559        void next_reverse(
560        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
561        {       using CppAD::NumRes;
562                using CppAD::NumArg;
563
564                // index of the last result for the next operator
565                CPPAD_ASSERT_UNKNOWN( var_index_ >= NumRes(op_) );
566                var_index   = var_index_ -= NumRes(op_);
567
568                // next operator
569                CPPAD_ASSERT_UNKNOWN( op_index_  > 0 );
570                op_index    = --op_index_;                                  // index
571                op          = op_         = OpCode( rec_op_[ op_index_ ] ); // value
572
573                // first argument for next operator
574                CPPAD_ASSERT_UNKNOWN( op_arg_ >= NumArg(op)  );
575                op_arg_    -= NumArg(op);                            // index
576                op_arg      = op_arg_ + rec_op_arg_.data();          // pointer
577        }
578        /*!
579        Correct \c next_reverse return values when <tt>op == CSumOp</tt>.
580
581        \param op
582        The input value of op must be the return value from the previous
583        call to \c next_reverse and must be \c CSumOp.
584
585        \param op_arg
586        The input value of *op_arg must be the return value from the
587        previous call to \c next_reverse. Its output value is the
588        beginning of the vector of argument indices for this operation.
589
590        \param op_index
591        The input value of op_index must be the return value from the
592        previous call to \c next_reverse. Its output value
593        is the index of the this operator in the recording.
594
595        \param var_index
596        The input value of var_index must be the return value from the
597        previous call to \c next_reverse. Its output value is the
598        index of the primary (last) result corresponding to this operator.
599        */
600
601        void reverse_csum(
602        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
603        {       using CppAD::NumRes;
604                using CppAD::NumArg;
605                CPPAD_ASSERT_UNKNOWN( op == CSumOp );
606                CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
607                /*
608                The things needs fixing are op_arg_ and op_arg. Currently,
609                op_arg points first arugment for the previous operator.
610                */
611                --op_arg;
612                op_arg_    -= (op_arg[0] + 4);
613                op_arg      = op_arg_ + rec_op_arg_.data();
614
615                CPPAD_ASSERT_UNKNOWN(
616                op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
617                );
618                CPPAD_ASSERT_UNKNOWN( op_index_  < rec_op_.size() );
619                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
620                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
621        }
622        /*!
623        Correct \c next_reverse return values when <tt>op == CSkipOp</tt>.
624
625        \param op
626        The input value of op must be the return value from the previous
627        call to \c next_reverse and must be \c CSkipOp.
628
629        \param op_arg
630        The input value of *op_arg must be the return value from the
631        previous call to \c next_reverse. Its output value is the
632        beginning of the vector of argument indices for this operation.
633
634        \param op_index
635        The input value of op_index must be the return value from the
636        previous call to \c next_reverse. Its output value
637        is the index of the this operator in the recording.
638
639        \param var_index
640        The input value of var_index must be the return value from the
641        previous call to \c next_reverse. Its output value is the
642        index of the primary (last) result corresponding to this operator.
643        */
644
645        void reverse_cskip(
646        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
647        {       using CppAD::NumRes;
648                using CppAD::NumArg;
649                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
650                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
651                /*
652                The things needs fixing are op_arg_ and op_arg. Currently,
653                op_arg points first arugment for the previous operator.
654                */
655                --op_arg;
656                op_arg_    -= (op_arg[0] + 4);
657                op_arg      = op_arg_ + rec_op_arg_.data();
658
659                CPPAD_ASSERT_UNKNOWN(
660                op_arg[1] + op_arg[2] == op_arg[ 3 + op_arg[1] + op_arg[2] ]
661                );
662                CPPAD_ASSERT_UNKNOWN( op_index_  < rec_op_.size() );
663                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
664                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
665        }
666
667};
668
669/*! \} */
670} // END_CPPAD_NAMESPACE
671# endif
Note: See TracBrowser for help on using the repository browser.