CppAD: A C++ Algorithmic Differentiation Package  20130102
player.hpp
Go to the documentation of this file.
00001 /* $Id$ */
00002 # ifndef CPPAD_PLAYER_INCLUDED
00003 # define CPPAD_PLAYER_INCLUDED
00004 
00005 /* --------------------------------------------------------------------------
00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
00007 
00008 CppAD is distributed under multiple licenses. This distribution is under
00009 the terms of the 
00010                     Eclipse Public License Version 1.0.
00011 
00012 A copy of this license is included in the COPYING file of this distribution.
00013 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
00014 -------------------------------------------------------------------------- */
00015 
00016 CPPAD_BEGIN_NAMESPACE
00017 /*!
00018 \defgroup player_hpp player.hpp
00019 \{
00020 \file player.hpp
00021 File used to define the player class.
00022 */
00023 
00024 
00025 /*!
00026 Class used to store and play back an operation sequence recording.
00027 
00028 \tparam Base
00029 These were AD< \a Base > operations when recorded. Operations during playback
00030 are done using the type  \a Base .
00031 */
00032 template <class Base>
00033 class player {
00034 
00035 // -------------- Variables that define the recording -----------------------
00036 private:
00037      /// Number of variables in the recording.
00038      size_t    num_rec_var_;
00039 
00040      /// The operators in the recording.
00041      pod_vector<CPPAD_OP_CODE_TYPE> rec_op_;
00042 
00043      /// Number of VecAD vectors in the recording
00044      size_t    num_rec_vecad_vec_;
00045 
00046      /// The VecAD indices in the recording.
00047      pod_vector<addr_t> rec_vecad_ind_;
00048 
00049      /// The operation argument indices in the recording
00050      pod_vector<addr_t> rec_op_arg_;
00051 
00052      /// The parameters in the recording.
00053      /// Note that Base may not be plain old data, so use false in consructor.
00054      pod_vector<Base> rec_par_;
00055 
00056      /// Character strings ('\\0' terminated) in the recording.
00057      pod_vector<char> rec_text_;
00058 
00059 
00060 // --------------- Functions used to create and maniplate a recording -------
00061 public:
00062      /// Default constructor
00063      player(void) : 
00064      num_rec_var_(0)                                      ,
00065      rec_op_( std::numeric_limits<addr_t>::max() )        ,
00066      rec_vecad_ind_( std::numeric_limits<addr_t>::max() ) ,
00067      rec_op_arg_( std::numeric_limits<addr_t>::max() )    ,
00068      rec_par_( std::numeric_limits<addr_t>::max() )       ,
00069      rec_text_( std::numeric_limits<addr_t>::max() )
00070      { }
00071 
00072      /// Destructor
00073      ~player(void)
00074      { }
00075 
00076      // ===============================================================
00077      // Begin two functions with idential code but different argument types.
00078      /*!  
00079      Moving an operation sequence from a recorder to a player
00080  
00081      \param rec
00082      the object that was used to record the operation sequence.  After this 
00083      operation, the state of the recording is no longer defined. For example,
00084      the \c pod_vector member variables in \c this have been swapped with
00085      \c rec .
00086      */
00087      void get(recorder<Base>& rec)
00088      {    size_t i;
00089 
00090           // Var
00091           num_rec_var_        = rec.num_rec_var_;
00092 
00093           // Op
00094           rec_op_.swap(rec.rec_op_);
00095 
00096           // VecInd
00097           rec_vecad_ind_.swap(rec.rec_vecad_ind_);
00098 
00099           // Arg
00100           rec_op_arg_.swap(rec.rec_op_arg_);
00101 
00102           // Par
00103           rec_par_.swap(rec.rec_par_);
00104 
00105           // Txt
00106           rec_text_.swap(rec.rec_text_);
00107 
00108           // set the number of VecAD vectors
00109           num_rec_vecad_vec_ = 0;
00110           for(i = 0; i < rec_vecad_ind_.size(); i += rec_vecad_ind_[i] + 1)
00111                num_rec_vecad_vec_++;
00112           // rec_vecad_ind_ contains size of each VecAD followed by
00113           // the parameter indices used to iniialize it.
00114           CPPAD_ASSERT_UNKNOWN( i == rec_vecad_ind_.size() );
00115      }
00116 
00117      /*!  
00118      Copying an operation sequence from one player to another
00119  
00120      \param play
00121      the object that contains the operatoion sequence to copy.
00122      */
00123      void operator=(const player& play)
00124      {    
00125           // Var
00126           num_rec_var_        = play.num_rec_var_;
00127 
00128           // Op
00129           rec_op_             = play.rec_op_;
00130 
00131           // VecInd
00132           num_rec_vecad_vec_  = play.num_rec_vecad_vec_;
00133           rec_vecad_ind_      = play.rec_vecad_ind_;
00134 
00135           // Arg
00136           rec_op_arg_         = play.rec_op_arg_;
00137 
00138           // Par
00139           rec_par_            = play.rec_par_;
00140 
00141           // Txt
00142           rec_text_           = play.rec_text_;
00143      }
00144      // End two functions with idential code but different argument types.
00145      // ===============================================================
00146 
00147      /// Erase all information in an operation sequence player.
00148      void Erase(void)
00149      {    
00150           num_rec_var_       = 0;
00151           num_rec_vecad_vec_ = 0;
00152 
00153           rec_op_.erase();
00154           rec_vecad_ind_.erase();
00155           rec_op_arg_.erase();
00156           rec_par_.erase();
00157           rec_text_.erase();
00158      }
00159 
00160 // ------------------ Old method of palying back a recording -----------------
00161 public:
00162      /*! 
00163      \brief 
00164      Fetch an operator from the recording.
00165 
00166      \return 
00167      the i-th operator in the recording.
00168 
00169      \param i
00170      the index of the operator in recording
00171      */
00172      OpCode GetOp (size_t i) const
00173      {    return OpCode(rec_op_[i]); }
00174 
00175      /*! 
00176      \brief 
00177      Fetch a VecAD index from the recording.
00178 
00179      \return 
00180      the i-th VecAD index in the recording.
00181 
00182      \param i
00183      the index of the VecAD index in recording
00184      */
00185      size_t GetVecInd (size_t i) const
00186      {    return rec_vecad_ind_[i]; }
00187 
00188      /*! 
00189      \brief 
00190      Fetch a parameter from the recording.
00191 
00192      \return 
00193      the i-th parameter in the recording.
00194 
00195      \param i
00196      the index of the parameter in recording
00197      */
00198      Base GetPar(size_t i) const
00199      {    return rec_par_[i]; }
00200 
00201      /*! 
00202      \brief 
00203      Fetch entire parameter vector from the recording.
00204 
00205      \return 
00206      the entire parameter vector.
00207 
00208      */
00209      const Base* GetPar(void) const
00210      {    return rec_par_.data(); }
00211 
00212      /*! 
00213      \brief 
00214      Fetch a '\\0' terminated string from the recording.
00215 
00216      \return 
00217      the beginning of the string.
00218 
00219      \param i
00220      the index where the string begins. 
00221      */
00222      const char *GetTxt(size_t i) const
00223      {    CPPAD_ASSERT_UNKNOWN(i < rec_text_.size() );
00224           return rec_text_.data() + i;
00225      }
00226      
00227      /*!
00228      \brief
00229      Replace an argument index in the recording.
00230 
00231      \param i
00232      is the index, in argument indices, that is to be replaced.
00233 
00234      \param value
00235      is the new normal index value.
00236      */
00237      void ReplaceInd(size_t i, size_t value)
00238      {    rec_op_arg_[i] =  static_cast<addr_t>( value ); }
00239 
00240      /// Fetch number of variables in the recording.
00241      size_t num_rec_var(void) const
00242      {    return num_rec_var_; }
00243 
00244      /// Fetch number of operators in the recording.
00245      size_t num_rec_op(void) const
00246      {    return rec_op_.size(); }
00247 
00248      /// Fetch number of VecAD indices in the recording.
00249      size_t num_rec_vecad_ind(void) const
00250      {    return rec_vecad_ind_.size(); }
00251 
00252      /// Fetch number of VecAD vectors in the recording
00253      size_t num_rec_vecad_vec(void) const
00254      {    return num_rec_vecad_vec_; }
00255 
00256      /// Fetch number of argument indices in the recording.
00257      size_t num_rec_op_arg(void) const
00258      {    return rec_op_arg_.size(); }
00259 
00260      /// Fetch number of parameters in the recording.
00261      size_t num_rec_par(void) const
00262      {    return rec_par_.size(); }
00263 
00264      /// Fetch number of characters (representing strings) in the recording.
00265      size_t num_rec_text(void) const
00266      {    return rec_text_.size(); }
00267 
00268      /// Fetch a rough measure of amount of memory used to store recording
00269      /// (just lengths, not capacities). 
00270      size_t Memory(void) const
00271      {    return rec_op_.size()        * sizeof(OpCode) 
00272                + rec_op_arg_.size()    * sizeof(addr_t)
00273                + rec_par_.size()       * sizeof(Base)
00274                + rec_text_.size()      * sizeof(char)
00275                + rec_vecad_ind_.size() * sizeof(addr_t)
00276           ;
00277      }
00278 
00279 // ------------- Variables used for new methog of playing back a recording ---
00280 private:
00281      /// Current operator
00282      OpCode    op_;
00283 
00284      /// Index in recording corresponding to current operator
00285      size_t    op_index_;
00286 
00287      /// Current offset of the argument indices in rec_op_arg_ 
00288      size_t    op_arg_;
00289 
00290      /// Index for primary (last) variable corresponding to current operator
00291      size_t    var_index_;
00292 
00293 // ----------- Functions used in new method for palying back a recording ---
00294 public:
00295      /*!
00296      Start a play back of the recording during a forward sweep.
00297 
00298      Use repeated calls to next_forward to play back one operator at a time.
00299 
00300      \param op
00301      The input value of op does not matter. Its output value is the
00302      first operator in the recording; i.e., BeginOp.
00303 
00304      \param op_arg
00305      The input value of *op_arg does not matter. Its output value is the
00306      beginning of the vector of argument indices for the first operation;
00307      i.e., 0
00308 
00309      \param op_index
00310      The input value of op_index does not matter. Its output value
00311      is the index of the next first operator in the recording; i.e., 0.
00312 
00313      \param var_index
00314      The input value of var_index does not matter. Its output value is the
00315      index of the primary (last) result corresponding to the the first
00316      operator (which must be a BeginOp); i.e., 0.
00317      */
00318      void start_forward(
00319      OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
00320      {
00321           op        = op_          = OpCode( rec_op_[0] ); 
00322           op_arg_   = 0;
00323           op_arg    = rec_op_arg_.data();
00324           op_index  = op_index_    = 0;
00325           var_index = var_index_   = 0;
00326 
00327           CPPAD_ASSERT_UNKNOWN( op_  == BeginOp );
00328           CPPAD_ASSERT_NARG_NRES(op_, 0, 1);
00329 
00330           return;
00331      }
00332 
00333      /*!
00334      Fetch the next operator during a forward sweep.
00335 
00336      Use start_forward to initialize to the first operator; i.e.,
00337      the BeginOp at the beginning of the recording. 
00338 
00339      \param op
00340      The input value of op does not matter. Its output value is the
00341      next operator in the recording.
00342      For speed, \c next_forward does not check for the special case
00343      of <tt>op == CSumOp</tt>. In this case, the other return values
00344      from \c next_forward must be corrected by a call to \c forward_csum.
00345 
00346      \param op_arg
00347      The input value of *op_arg does not matter. Its output value is the
00348      beginning of the vector of argument indices for this operation.
00349 
00350      \param op_index
00351      The input value of op_index does not matter. Its output value
00352      is the index of the next operator in the recording. Thus the ouput
00353      value following the previous call to start_forward is one. In addition,
00354      the output value increases by one with each call to next_forward. 
00355 
00356      \param var_index
00357      The input value of var_index does not matter. Its output value is the
00358      index of the primary (last) result corresponding to the operator op.
00359      */
00360 
00361      void next_forward(
00362      OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
00363      {    using CppAD::NumRes;
00364           using CppAD::NumArg;
00365 
00366           // index for the next operator 
00367           op_index    = ++op_index_;
00368 
00369           // first argument for next operator 
00370           op_arg_    += NumArg(op_);                   // index
00371           op_arg      = op_arg_ + rec_op_arg_.data();  // pointer
00372 
00373           // next operator
00374           op          = op_         = OpCode( rec_op_[ op_index_ ] );
00375 
00376           // index for last result for next operator
00377           var_index   = var_index_ += NumRes(op);
00378 
00379           CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
00380           CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
00381      }
00382      /*!
00383      Correct \c next_forward return values when <tt>op == CSumOp</tt>.
00384 
00385      \param op
00386      The input value of op must be the return value from the previous
00387      call to \c next_forward and must be \c CSumOp.
00388 
00389      \param op_arg
00390      The input value of *op_arg must be the return value from the 
00391      previous call to \c next_forward. Its output value is the
00392      beginning of the vector of argument indices for this operation.
00393 
00394      \param op_index
00395      The input value of op_index does must be the return value from the
00396      previous call to \c next_forward. Its output value
00397      is the index of this operator in the recording. 
00398 
00399      \param var_index
00400      The input value of var_index must be the return value from the
00401      previous call to \c next_forward. Its output value is the
00402      index of the primary (last) result corresponding to this.
00403      */
00404      void forward_csum(
00405      OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
00406      {    using CppAD::NumRes;
00407           using CppAD::NumArg;
00408           CPPAD_ASSERT_UNKNOWN( op == CSumOp );
00409           CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
00410           CPPAD_ASSERT_UNKNOWN(
00411           op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
00412           );
00413           /*
00414           The only thing that really needs fixing is op_arg_.
00415           Actual number of arugments for this operator is
00416                op_arg[0] + op_arg[1] + 4.
00417           We must change op_arg_ so that when you add NumArg(CSumOp)
00418           you get first argument for next operator in sequence.
00419           */
00420           op_arg_    += op_arg[0] + op_arg[1] + 4;
00421 
00422           CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
00423           CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
00424      }
00425      /*!
00426      Get a non-constant version of op_arg returned by previous next_forward
00427 
00428      \return
00429      The return value is equal to the return value of op_arg 
00430      corresponding to the previous call to next_forward.
00431      */
00432      addr_t* forward_non_const_arg(void)
00433      {    return op_arg_ + rec_op_arg_.data(); }
00434 
00435      /*!
00436      Start a play back of the recording during a reverse sweep.
00437 
00438      Use repeated calls to next_reverse to play back one operator at a time.
00439 
00440      \param op
00441      The input value of op does not matter. Its output value is the
00442      last operator in the recording; i.e., EndOp.
00443 
00444      \param op_arg
00445      The input value of *op_arg does not matter. Its output value is the
00446      beginning of the vector of argument indices for the last operation;
00447      (there are no arguments for the last operation so \a op_arg is invalid).
00448 
00449      \param op_index
00450      The input value of op_index does not matter. Its output value
00451      is the index of the last operator in the recording.
00452 
00453      \param var_index
00454      The input value of var_index does not matter. Its output value is the
00455      index of the primary (last) result corresponding to the the last
00456      operator (which must be a EndOp).
00457      (there are no results for the last operation 
00458      so \a var_index is invalid).
00459      */
00460 
00461      void start_reverse(
00462      OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
00463      {
00464           op_arg_     = rec_op_arg_.size();                // index
00465           op_arg      = op_arg_ + rec_op_arg_.data();      // pointer
00466 
00467           op_index    = op_index_   = rec_op_.size() - 1; 
00468           var_index   = var_index_  = num_rec_var_ - 1;
00469 
00470           op          = op_         = OpCode( rec_op_[ op_index_ ] );
00471           CPPAD_ASSERT_UNKNOWN( op_ == EndOp );
00472           CPPAD_ASSERT_NARG_NRES(op, 0, 0);
00473           return;
00474      }
00475 
00476      /*!
00477      Fetch the next operator during a reverse sweep.
00478 
00479      Use start_reverse to initialize to reverse play back.
00480      The first call to next_reverse (after start_reverse) will give the 
00481         last operator in the recording.
00482 
00483      \param op
00484      The input value of op does not matter. Its output value is the
00485      next operator in the recording (in reverse order).
00486      The last operator sets op equal to EndOp.
00487 
00488      \param op_arg
00489      The input value of *op_arg does not matter. Its output value is the
00490      beginning of the vector of argument indices for this operation.
00491      The last operator sets op_arg equal to the beginning of the 
00492      argument indices for the entire recording.
00493      For speed, \c next_reverse does not check for the special case
00494      of <tt>op == CSumOp</tt>. In this case, the other return values
00495      from \c next_reverse must be corrected by a call to \c reverse_csum.
00496 
00497 
00498      \param op_index
00499      The input value of op_index does not matter. Its output value
00500      is the index of this operator in the recording. Thus the output
00501      value following the previous call to start_reverse is equal to 
00502      the number of variables in the recording minus one.
00503      In addition, the output value decreases by one with each call to
00504      next_reverse.
00505      The last operator sets op_index equal to 0.
00506 
00507      \param var_index
00508      The input value of var_index does not matter. Its output value is the
00509      index of the primary (last) result corresponding to the operator op.
00510      The last operator sets var_index equal to 0 (corresponding to BeginOp
00511      at beginning of operation sequence).
00512      */
00513 
00514      void next_reverse(
00515      OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
00516      {    using CppAD::NumRes;
00517           using CppAD::NumArg;
00518 
00519           // index of the last result for the next operator
00520           CPPAD_ASSERT_UNKNOWN( var_index_ >= NumRes(op_) );
00521           var_index   = var_index_ -= NumRes(op_);
00522 
00523           // next operator
00524           CPPAD_ASSERT_UNKNOWN( op_index_  > 0 );
00525           op_index    = --op_index_;                                  // index
00526           op          = op_         = OpCode( rec_op_[ op_index_ ] ); // value
00527 
00528           // first argument for next operator
00529           CPPAD_ASSERT_UNKNOWN( op_arg_ >= NumArg(op)  );
00530           op_arg_    -= NumArg(op);                            // index
00531           op_arg      = op_arg_ + rec_op_arg_.data();          // pointer
00532      }
00533      /*!
00534      Correct \c next_reverse return values when <tt>op == CSumOp</tt>.
00535 
00536      \param op
00537      The input value of op must be the return value from the previous
00538      call to \c next_reverse and must be \c CSumOp.
00539 
00540      \param op_arg
00541      The input value of *op_arg must be the return value from the 
00542      previous call to \c next_reverse. Its output value is the
00543      beginning of the vector of argument indices for this operation.
00544 
00545      \param op_index
00546      The input value of op_index must be the return value from the
00547      previous call to \c next_reverse. Its output value
00548      is the index of the this operator in the recording. 
00549 
00550      \param var_index
00551      The input value of var_index must be the return value from the 
00552      previous call to \c next_reverse. Its output value is the
00553      index of the primary (last) result corresponding to this operator.
00554      */
00555 
00556      void reverse_csum(
00557      OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
00558      {    using CppAD::NumRes;
00559           using CppAD::NumArg;
00560           CPPAD_ASSERT_UNKNOWN( op == CSumOp );
00561           CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
00562           /*
00563           The things needs fixing are op_arg_ and op_arg. Currently, 
00564           op_arg points first arugment for the previous operator.
00565           */
00566           --op_arg;
00567           op_arg_    -= (op_arg[0] + 4);
00568           op_arg      = op_arg_ + rec_op_arg_.data();
00569 
00570           CPPAD_ASSERT_UNKNOWN(
00571           op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
00572           );
00573           CPPAD_ASSERT_UNKNOWN( op_index_  < rec_op_.size() );
00574           CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
00575           CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
00576      }
00577 
00578 };
00579 
00580 /*! \} */
00581 CPPAD_END_NAMESPACE
00582 # endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines