CppAD: A C++ Algorithmic Differentiation Package  20130918
recorder.hpp
Go to the documentation of this file.
00001 /* $Id$ */
00002 # ifndef CPPAD_RECORDER_INCLUDED
00003 # define CPPAD_RECORDER_INCLUDED
00004 /* --------------------------------------------------------------------------
00005 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-14 Bradley M. Bell
00006 
00007 CppAD is distributed under multiple licenses. This distribution is under
00008 the terms of the 
00009                     Eclipse Public License Version 1.0.
00010 
00011 A copy of this license is included in the COPYING file of this distribution.
00012 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
00013 -------------------------------------------------------------------------- */
00014 # include <cppad/local/hash_code.hpp>
00015 # include <cppad/local/pod_vector.hpp>
00016 
00017 namespace CppAD { // BEGIN_CPPAD_NAMESPACE
00018 /*!
00019 \file recorder.hpp
00020 File used to define the recorder class.
00021 */
00022 
00023 /*!
00024 Class used to store an operation sequence while it is being recorded
00025 (the operation sequence is copied to the player class for playback).
00026 
00027 \tparam Base
00028 This is an AD< \a Base > operation sequence recording; i.e.,
00029 it records operations of type AD< \a Base >.
00030 */
00031 template <class Base>
00032 class recorder {
00033      friend class player<Base>;
00034 
00035 private:
00036      /// offset for this thread in the static hash table
00037      const size_t thread_offset_;
00038 
00039      /// Number of variables in the recording.
00040      size_t    num_var_rec_;
00041 
00042      /// Number vecad load operations (LdpOp or LdvOp) currently in recording.
00043      size_t    num_load_op_rec_;
00044 
00045      /// The operators in the recording.
00046      pod_vector<CPPAD_OP_CODE_TYPE> op_rec_;
00047 
00048      /// The VecAD indices in the recording.
00049      pod_vector<addr_t> vecad_ind_rec_;
00050 
00051      /// The argument indices in the recording
00052      pod_vector<addr_t> op_arg_rec_;
00053 
00054      /// The parameters in the recording.
00055      /// Note that Base may not be plain old data, so use false in consructor.
00056      pod_vector<Base> par_rec_;
00057 
00058      /// Character strings ('\\0' terminated) in the recording.
00059      pod_vector<char> text_rec_;
00060 // ---------------------- Public Functions -----------------------------------
00061 public:
00062      /// Default constructor
00063      recorder(void) : 
00064      thread_offset_( thread_alloc::thread_num() * CPPAD_HASH_TABLE_SIZE ) ,
00065      num_var_rec_(0)                                      ,
00066      num_load_op_rec_(0)                                  ,
00067      op_rec_( std::numeric_limits<addr_t>::max() )        ,
00068      vecad_ind_rec_( std::numeric_limits<addr_t>::max() ) ,
00069      op_arg_rec_( std::numeric_limits<addr_t>::max() )    ,
00070      par_rec_( std::numeric_limits<addr_t>::max() )       ,
00071      text_rec_( std::numeric_limits<addr_t>::max() )
00072      { }
00073 
00074      /// Destructor
00075      ~recorder(void)
00076      { }
00077 
00078      /*!
00079      Frees all information in recording.
00080 
00081      Frees the operation sequence store in this recording 
00082      (the operation sequence is empty after this operation).
00083      The buffers used to store the current recording are returned
00084      to the system (so as to conserve on memory).
00085      */
00086      void free(void)
00087      {    num_var_rec_     = 0;
00088           num_load_op_rec_ = 0;
00089           op_rec_.free();
00090           vecad_ind_rec_.free();
00091           op_arg_rec_.free();
00092           par_rec_.free();
00093           text_rec_.free();
00094      }
00095      /// Put next operator in the operation sequence.
00096      inline size_t PutOp(OpCode op);
00097      /// Put a vecad load operator in the operation sequence (special case)
00098      inline size_t PutLoadOp(OpCode op);
00099      /// Add a value to the end of the current vector of VecAD indices.
00100      inline size_t PutVecInd(size_t vec_ind);
00101      /// Find or add a parameter to the current vector of parameters.
00102      inline size_t PutPar(const Base &par);
00103      /// Put one operation argument index in the recording
00104      inline void PutArg(addr_t arg0); 
00105      /// Put two operation argument index in the recording
00106      inline void PutArg(addr_t arg0, addr_t arg1); 
00107      /// Put three operation argument index in the recording
00108      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2); 
00109      /// Put four operation argument index in the recording
00110      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3); 
00111      /// Put five operation argument index in the recording
00112      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
00113           addr_t arg4);
00114      /// Put six operation argument index in the recording
00115      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
00116           addr_t arg4, addr_t arg5);
00117 
00118      // Reserve space for a specified number of arguments
00119      inline size_t ReserveArg(size_t n_arg);
00120 
00121      // Replace an argument value
00122      void ReplaceArg(size_t i_arg, size_t value);
00123 
00124      /// Put a character string in the text for this recording.
00125      inline size_t PutTxt(const char *text);
00126 
00127      /// Number of variables currently stored in the recording.
00128      size_t num_var_rec(void) const
00129      {    return num_var_rec_; }
00130 
00131      /// Number of LdpOp and LdvOp operations currently in the recording.
00132      size_t num_load_op_rec(void) const
00133      {    return num_load_op_rec_; }
00134 
00135      /// Number of operators currently stored in the recording.
00136      size_t num_op_rec(void) const
00137      {    return  op_rec_.size(); }
00138 
00139      /// Approximate amount of memory used by the recording 
00140      size_t Memory(void) const
00141      {    return op_rec_.capacity()        * sizeof(CPPAD_OP_CODE_TYPE) 
00142                + vecad_ind_rec_.capacity() * sizeof(size_t)
00143                + op_arg_rec_.capacity()    * sizeof(addr_t)
00144                + par_rec_.capacity()       * sizeof(Base)
00145                + text_rec_.capacity()      * sizeof(char);
00146      }
00147 };
00148 
00149 /*!
00150 Put next operator in the operation sequence.
00151 
00152 This sets the op code for the next operation in this recording.
00153 This call must be followed by putting the corresponding 
00154 \verbatim
00155      NumArg(op)
00156 \endverbatim
00157 argument indices in the recording.
00158 
00159 \param op
00160 Is the op code corresponding to the the operation that is being
00161 recorded (which must not be LdpOp or LdvOp).
00162 
00163 \return
00164 The return value is the index of the primary (last) variable 
00165 corresponding to the result of this operation. 
00166 The number of variables corresponding to the operation is given by
00167 \verbatim
00168      NumRes(op)
00169 \endverbatim
00170 With each call to PutOp or PutLoadOp,
00171 the return index increases by the number of variables corresponding
00172 to the call.
00173 This index starts at zero after the default constructor
00174 and after each call to Erase.
00175 */
00176 template <class Base>
00177 inline size_t recorder<Base>::PutOp(OpCode op)
00178 {    size_t i    = op_rec_.extend(1);
00179      op_rec_[i]  = static_cast<CPPAD_OP_CODE_TYPE>(op);
00180      CPPAD_ASSERT_UNKNOWN( op_rec_.size() == i + 1 );
00181      CPPAD_ASSERT_UNKNOWN( (op != LdpOp) & (op != LdvOp) );
00182 
00183      // first operator should be a BeginOp and NumRes( BeginOp ) > 0
00184      num_var_rec_ += NumRes(op);
00185      CPPAD_ASSERT_UNKNOWN( num_var_rec_ > 0 );
00186 
00187      return num_var_rec_ - 1;
00188 }
00189 
00190 /*!
00191 Put next LdpOp or LdvOp operator in operation sequence (special cases).
00192 
00193 This sets the op code for the next operation in this recording.
00194 This call must be followed by putting the corresponding 
00195 \verbatim
00196      NumArg(op)
00197 \endverbatim
00198 argument indices in the recording.
00199 
00200 \param op
00201 Is the op code corresponding to the the operation that is being
00202 recorded (which must be LdpOp or LdvOp).
00203 
00204 \return
00205 The return value is the index of the primary (last) variable 
00206 corresponding to the result of this operation. 
00207 The number of variables corresponding to the operation is given by
00208 \verbatim
00209      NumRes(op)
00210 \endverbatim
00211 which must be one for this operation.
00212 With each call to PutLoadOp or PutOp,
00213 the return index increases by the number of variables corresponding
00214 to this call to the call.
00215 This index starts at zero after the default constructor
00216 and after each call to Erase.
00217 
00218 \par num_load_op_rec()
00219 The return value for <code>num_load_op_rec()</code> 
00220 increases by one after each call to this function
00221 (and starts at zero after the default constructor or Erase).
00222 */
00223 template <class Base>
00224 inline size_t recorder<Base>::PutLoadOp(OpCode op)
00225 {    size_t i    = op_rec_.extend(1);
00226      op_rec_[i]  = static_cast<CPPAD_OP_CODE_TYPE>(op);
00227      CPPAD_ASSERT_UNKNOWN( op_rec_.size() == i + 1 );
00228      CPPAD_ASSERT_UNKNOWN( (op == LdpOp) | (op == LdvOp) );
00229 
00230      // first operator should be a BeginOp and NumRes( BeginOp ) > 0
00231      num_var_rec_ += NumRes(op);
00232      CPPAD_ASSERT_UNKNOWN( num_var_rec_ > 0 );
00233 
00234      // count this vecad load operation
00235      num_load_op_rec_++;
00236 
00237      return num_var_rec_ - 1;
00238 }
00239 
00240 /*!
00241 Add a value to the end of the current vector of VecAD indices.
00242 
00243 For each VecAD vector, this routine is used to store the length
00244 of the vector followed by the parameter index corresponding to each
00245 value in the vector.
00246 This value for the elements of the VecAD vector corresponds to the
00247 beginning of the operation sequence.
00248 
00249 \param vec_ind
00250 is the index to be palced at the end of the vector of VecAD indices.
00251 
00252 \return
00253 is the index in the vector of VecAD indices corresponding to this value.
00254 This index starts at zero after the recorder default constructor
00255 and after each call to Erase.
00256 It increments by one for each call to PutVecInd..
00257 */
00258 template <class Base>
00259 inline size_t recorder<Base>::PutVecInd(size_t vec_ind)
00260 {    size_t i          = vecad_ind_rec_.extend(1);
00261      vecad_ind_rec_[i] = vec_ind;
00262      CPPAD_ASSERT_UNKNOWN( vecad_ind_rec_.size() == i + 1 );
00263 
00264      return i;
00265 }
00266 
00267 /*!
00268 Find or add a parameter to the current vector of parameters.
00269 
00270 \param par
00271 is the parameter to be found or placed in the vector of parameters.
00272 
00273 \return
00274 is the index in the parameter vector corresponding to this parameter value.
00275 This value is not necessarily placed at the end of the vector
00276 (because values that are identically equal may be reused).
00277 */
00278 template <class Base>
00279 size_t recorder<Base>::PutPar(const Base &par)
00280 {    static size_t   hash_table[CPPAD_HASH_TABLE_SIZE * CPPAD_MAX_NUM_THREADS];
00281      size_t          i;
00282      size_t          code;
00283 
00284      CPPAD_ASSERT_UNKNOWN( 
00285           thread_offset_ / CPPAD_HASH_TABLE_SIZE
00286           == 
00287           thread_alloc::thread_num() 
00288      );
00289 
00290      // get hash code for this value
00291      code = static_cast<size_t>( hash_code(par) );
00292      CPPAD_ASSERT_UNKNOWN( code < CPPAD_HASH_TABLE_SIZE );
00293 
00294      // If we have a match, return the parameter index
00295      i = hash_table[code + thread_offset_];
00296      if( i < par_rec_.size() && IdenticalEqualPar(par_rec_[i], par) )
00297                return i;
00298      
00299      // place a new value in the table
00300      i           = par_rec_.extend(1);
00301      par_rec_[i] = par;
00302      CPPAD_ASSERT_UNKNOWN( par_rec_.size() == i + 1 );
00303 
00304      // make the hash code point to this new value
00305      hash_table[code + thread_offset_] = i;
00306 
00307      // return the parameter index
00308      return i;
00309 }
00310 // -------------------------- PutArg --------------------------------------
00311 /*!
00312 Prototype for putting operation argument indices in the recording.
00313 
00314 The following syntax
00315 \verbatim
00316      rec.PutArg(arg0)
00317      rec.PutArg(arg0, arg1)
00318      .
00319      .
00320      .
00321      rec.PutArg(arg0, arg1, ..., arg5)
00322 \endverbatim
00323 places the values passed to PutArg at the current end of the
00324 operation argument indices for the recording.
00325 \a arg0 comes before \a arg1, etc.
00326 The proper number of operation argument indices 
00327 corresponding to the operation code op is given by
00328 \verbatim
00329      NumArg(op)
00330 \endverbatim
00331 The number of the operation argument indices starts at zero
00332 after the default constructor and each call to Erase.
00333 It increases by the number of indices placed by each call to PutArg.
00334 */
00335 inline void prototype_put_arg(void)
00336 {    // This routine should not be called
00337      CPPAD_ASSERT_UNKNOWN(false);
00338 }
00339 /*!
00340 Put one operation argument index in the recording
00341 
00342 \param arg0
00343 The operation argument index
00344 
00345 \copydetails prototype_put_arg 
00346 */
00347 template <class Base>
00348 inline void recorder<Base>::PutArg(addr_t arg0)
00349 { 
00350      size_t i       = op_arg_rec_.extend(1);
00351      op_arg_rec_[i] =  static_cast<addr_t>( arg0 );
00352      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + 1 );
00353 }
00354 /*!
00355 Put two operation argument index in the recording
00356 
00357 \param arg0
00358 First operation argument index.
00359 
00360 \param arg1
00361 Second operation argument index.
00362 
00363 \copydetails prototype_put_arg 
00364 */
00365 template <class Base>
00366 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1)
00367 { 
00368      size_t i         = op_arg_rec_.extend(2);
00369      op_arg_rec_[i++] =  static_cast<addr_t>( arg0 );
00370      op_arg_rec_[i]   =  static_cast<addr_t>( arg1 );
00371      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + 1 );
00372 }
00373 /*!
00374 Put three operation argument index in the recording
00375 
00376 \param arg0
00377 First operation argument index.
00378 
00379 \param arg1
00380 Second operation argument index.
00381 
00382 \param arg2
00383 Third operation argument index.
00384 
00385 \copydetails prototype_put_arg 
00386 */
00387 template <class Base>
00388 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2)
00389 { 
00390      size_t i         = op_arg_rec_.extend(3);
00391      op_arg_rec_[i++] =  static_cast<addr_t>( arg0 );
00392      op_arg_rec_[i++] =  static_cast<addr_t>( arg1 );
00393      op_arg_rec_[i]   =  static_cast<addr_t>( arg2 );
00394      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + 1 );
00395 }
00396 /*!
00397 Put four operation argument index in the recording
00398 
00399 \param arg0
00400 First operation argument index.
00401 
00402 \param arg1
00403 Second operation argument index.
00404 
00405 \param arg2
00406 Third operation argument index.
00407 
00408 \param arg3
00409 Fourth operation argument index.
00410 
00411 \copydetails prototype_put_arg 
00412 */
00413 template <class Base>
00414 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
00415      addr_t arg3)
00416 { 
00417      size_t i         = op_arg_rec_.extend(4);
00418      op_arg_rec_[i++] =  static_cast<addr_t>( arg0 );
00419      op_arg_rec_[i++] =  static_cast<addr_t>( arg1 );
00420      op_arg_rec_[i++] =  static_cast<addr_t>( arg2 );
00421      op_arg_rec_[i]   =  static_cast<addr_t>( arg3 );
00422      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + 1 );
00423 
00424 }
00425 /*!
00426 Put five operation argument index in the recording
00427 
00428 \param arg0
00429 First operation argument index.
00430 
00431 \param arg1
00432 Second operation argument index.
00433 
00434 \param arg2
00435 Third operation argument index.
00436 
00437 \param arg3
00438 Fourth operation argument index.
00439 
00440 \param arg4
00441 Fifth operation argument index.
00442 
00443 \copydetails prototype_put_arg 
00444 */
00445 template <class Base>
00446 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
00447      addr_t arg3, addr_t arg4)
00448 { 
00449      size_t i         = op_arg_rec_.extend(5);
00450      op_arg_rec_[i++] =  static_cast<addr_t>( arg0 );
00451      op_arg_rec_[i++] =  static_cast<addr_t>( arg1 );
00452      op_arg_rec_[i++] =  static_cast<addr_t>( arg2 );
00453      op_arg_rec_[i++] =  static_cast<addr_t>( arg3 );
00454      op_arg_rec_[i]   =  static_cast<addr_t>( arg4 );
00455      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + 1 );
00456 
00457 }
00458 /*!
00459 Put six operation argument index in the recording
00460 
00461 \param arg0
00462 First operation argument index.
00463 
00464 \param arg1
00465 Second operation argument index.
00466 
00467 \param arg2
00468 Third operation argument index.
00469 
00470 \param arg3
00471 Fourth operation argument index.
00472 
00473 \param arg4
00474 Fifth operation argument index.
00475 
00476 \param arg5
00477 Sixth operation argument index.
00478 
00479 \copydetails prototype_put_arg 
00480 */
00481 template <class Base>
00482 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, 
00483      addr_t arg3, addr_t arg4, addr_t arg5)
00484 { 
00485      size_t i         = op_arg_rec_.extend(6);
00486      op_arg_rec_[i++] =  static_cast<addr_t>( arg0 );
00487      op_arg_rec_[i++] =  static_cast<addr_t>( arg1 );
00488      op_arg_rec_[i++] =  static_cast<addr_t>( arg2 );
00489      op_arg_rec_[i++] =  static_cast<addr_t>( arg3 );
00490      op_arg_rec_[i++] =  static_cast<addr_t>( arg4 );
00491      op_arg_rec_[i]   =  static_cast<addr_t>( arg5 );
00492      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + 1 );
00493 }
00494 // --------------------------------------------------------------------------
00495 /*!
00496 Reserve space for arguments, but delay placing values there.
00497 
00498 \param n_arg
00499 number of arguements to reserve space for
00500 
00501 \return
00502 is the index in the argument vector corresponding to the
00503 first of the arguments being reserved.
00504 */
00505 template <class Base>
00506 inline size_t recorder<Base>::ReserveArg(size_t n_arg)
00507 { 
00508      size_t i = op_arg_rec_.extend(n_arg);
00509      CPPAD_ASSERT_UNKNOWN( op_arg_rec_.size() == i + n_arg );
00510      return i;
00511 }
00512 
00513 /*!
00514 \brief
00515 Replace an argument value in the recording 
00516 (intended to fill in reserved values).
00517 
00518 \param i_arg
00519 is the index, in argument vector, for the value that is replaced.
00520 
00521 \param value
00522 is the new value for the argument with the specified index.
00523 */
00524 template <class Base>
00525 inline void recorder<Base>::ReplaceArg(size_t i_arg, size_t value)
00526 {    op_arg_rec_[i_arg] =  static_cast<addr_t>( value ); }
00527 // --------------------------------------------------------------------------
00528 /*!
00529 Put a character string in the text for this recording.
00530 
00531 \param text
00532 is a '\\0' terminated character string that is to be put in the
00533 vector of characters corresponding to this recording.
00534 The terminator '\\0' will be included.
00535 
00536 \return
00537 is the offset with in the text vector for this recording at which
00538 the character string starts.
00539 */
00540 template <class Base>
00541 inline size_t recorder<Base>::PutTxt(const char *text)
00542 {
00543      // determine length of the text including terminating '\0'
00544      size_t n = 0;
00545      while( text[n] != '\0' )
00546           n++;
00547      CPPAD_ASSERT_UNKNOWN( n <= 1000 ); 
00548      n++;
00549      CPPAD_ASSERT_UNKNOWN( text[n-1] == '\0' );
00550 
00551      // copy text including terminating '\0'
00552      size_t i = text_rec_.extend(n); 
00553      size_t j;
00554      for(j = 0; j < n; j++)
00555           text_rec_[i + j] = text[j];
00556      CPPAD_ASSERT_UNKNOWN( text_rec_.size() == i + n );
00557 
00558      return i;
00559 }
00560 // -------------------------------------------------------------------------
00561 
00562 
00563 } // END_CPPAD_NAMESPACE
00564 # endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines