CppAD: A C++ Algorithmic Differentiation Package  20130102
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-12 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 CPPAD_BEGIN_NAMESPACE
00018 /*!
00019 \defgroup recorder_hpp recorder.hpp
00020 \{
00021 \file recorder.hpp
00022 File used to define the recorder class.
00023 */
00024 
00025 /*!
00026 Class used to store an operation sequence while it is being recorded
00027 (the operation sequence is copied to the player class for playback).
00028 
00029 \tparam Base
00030 This is an AD< \a Base > operation sequence recording; i.e.,
00031 it records operations of type AD< \a Base >.
00032 */
00033 template <class Base>
00034 class recorder {
00035      friend class player<Base>;
00036 
00037 private:
00038      /// offset for this thread in the static hash table
00039      const size_t thread_offset_;
00040 
00041      /// Number of variables in the recording.
00042      size_t    num_rec_var_;
00043 
00044      /// The operators in the recording.
00045      pod_vector<CPPAD_OP_CODE_TYPE> rec_op_;
00046 
00047      /// The VecAD indices in the recording.
00048      pod_vector<addr_t> rec_vecad_ind_;
00049 
00050      /// The argument indices in the recording
00051      pod_vector<addr_t> rec_op_arg_;
00052 
00053      /// The parameters in the recording.
00054      /// Note that Base may not be plain old data, so use false in consructor.
00055      pod_vector<Base> rec_par_;
00056 
00057      /// Character strings ('\\0' terminated) in the recording.
00058      pod_vector<char> rec_text_;
00059 // ---------------------- Public Functions -----------------------------------
00060 public:
00061      /// Default constructor
00062      recorder(void) : 
00063      thread_offset_( thread_alloc::thread_num() * CPPAD_HASH_TABLE_SIZE ) ,
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      ~recorder(void)
00074      { }
00075 
00076      /*!
00077      Frees all information in recording.
00078 
00079      Frees the operation sequence store in this recording 
00080      (the operation sequence is empty after this operation).
00081      The buffers used to store the current recording are returned
00082      to the system (so as to conserve on memory).
00083      */
00084      void free(void)
00085      {    num_rec_var_  = 0;
00086           rec_op_.free();
00087           rec_vecad_ind_.free();
00088           rec_op_arg_.free();
00089           rec_par_.free();
00090           rec_text_.free();
00091      }
00092      /// Start recording the next operator in the operation sequence.
00093      inline size_t PutOp(OpCode op);
00094      /// Add a value to the end of the current vector of VecAD indices.
00095      inline size_t PutVecInd(size_t vec_ind);
00096      /// Find or add a parameter to the current vector of parameters.
00097      inline size_t PutPar(const Base &par);
00098      /// Put one operation argument index in the recording
00099      inline void PutArg(addr_t arg0); 
00100      /// Put two operation argument index in the recording
00101      inline void PutArg(addr_t arg0, addr_t arg1); 
00102      /// Put three operation argument index in the recording
00103      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2); 
00104      /// Put four operation argument index in the recording
00105      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3); 
00106      /// Put five operation argument index in the recording
00107      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
00108           addr_t arg4);
00109      /// Put six operation argument index in the recording
00110      inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
00111           addr_t arg4, addr_t arg5);
00112 
00113      /// Put a character string in the text for this recording.
00114      inline size_t PutTxt(const char *text);
00115 
00116      /// Number of variables currently stored in the recording.
00117      size_t num_rec_var(void) const
00118      {    return num_rec_var_; }
00119 
00120      /// Approximate amount of memory used by the recording 
00121      size_t Memory(void) const
00122      {    return rec_op_.capacity()        * sizeof(CPPAD_OP_CODE_TYPE) 
00123                + rec_vecad_ind_.capacity() * sizeof(size_t)
00124                + rec_op_arg_.capacity()    * sizeof(addr_t)
00125                + rec_par_.capacity()       * sizeof(Base)
00126                + rec_text_.capacity()      * sizeof(char);
00127      }
00128 };
00129 
00130 /*!
00131 Start recording the next operator in the operation sequence.
00132 
00133 This sets the op code for the next operation in this recording.
00134 This call must be followed by putting the corresponding 
00135 \verbatim
00136      NumArg(op)
00137 \endverbatim
00138 argument indices in the recording.
00139 
00140 \param op
00141 Is the op code corresponding to the the operation that is being
00142 recorded. 
00143 
00144 \return
00145 The return value is the index of the primary (last) variable 
00146 corresponding to the result of this operation. 
00147 The number of variables corresponding to the operation is given by
00148 \verbatim
00149      NumRes(op)
00150 \endverbatim
00151 With each call to PutOp 
00152 the return index increases by the number of variables corresponding
00153 to this call to PutOp.
00154 This index starts at zero after the default constructor
00155 and after each call to Erase.
00156 */
00157 template <class Base>
00158 inline size_t recorder<Base>::PutOp(OpCode op)
00159 {    size_t i    = rec_op_.extend(1);
00160      rec_op_[i]  = static_cast<CPPAD_OP_CODE_TYPE>(op);
00161      CPPAD_ASSERT_UNKNOWN( rec_op_.size() == i + 1 );
00162 
00163      // first operator should be a BeginOp and NumRes( BeginOp ) > 0
00164      num_rec_var_ += NumRes(op);
00165      CPPAD_ASSERT_UNKNOWN( num_rec_var_ > 0 );
00166 
00167      return num_rec_var_ - 1;
00168 }
00169 
00170 /*!
00171 Add a value to the end of the current vector of VecAD indices.
00172 
00173 For each VecAD vector, this routine is used to store the length
00174 of the vector followed by the parameter index corresponding to each
00175 value in the vector.
00176 This value for the elements of the VecAD vector corresponds to the
00177 beginning of the operation sequence.
00178 
00179 \param vec_ind
00180 is the index to be palced at the end of the vector of VecAD indices.
00181 
00182 \return
00183 is the index in the vector of VecAD indices corresponding to this value.
00184 This index starts at zero after the recorder default constructor
00185 and after each call to Erase.
00186 It increments by one for each call to PutVecInd..
00187 */
00188 template <class Base>
00189 inline size_t recorder<Base>::PutVecInd(size_t vec_ind)
00190 {    size_t i          = rec_vecad_ind_.extend(1);
00191      rec_vecad_ind_[i] = vec_ind;
00192      CPPAD_ASSERT_UNKNOWN( rec_vecad_ind_.size() == i + 1 );
00193 
00194      return i;
00195 }
00196 
00197 /*!
00198 Find or add a parameter to the current vector of parameters.
00199 
00200 \param par
00201 is the parameter to be found or placed in the vector of parameters.
00202 
00203 \return
00204 is the index in the parameter vector corresponding to this parameter value.
00205 This value is not necessarily placed at the end of the vector
00206 (because values that are identically equal may be reused).
00207 */
00208 template <class Base>
00209 size_t recorder<Base>::PutPar(const Base &par)
00210 {    static size_t   hash_table[CPPAD_HASH_TABLE_SIZE * CPPAD_MAX_NUM_THREADS];
00211      size_t          i;
00212      size_t          code;
00213 
00214      CPPAD_ASSERT_UNKNOWN( 
00215           thread_offset_ / CPPAD_HASH_TABLE_SIZE
00216           == 
00217           thread_alloc::thread_num() 
00218      );
00219 
00220      // get hash code for this value
00221      code = static_cast<size_t>( hash_code(par) );
00222      CPPAD_ASSERT_UNKNOWN( code < CPPAD_HASH_TABLE_SIZE );
00223 
00224      // If we have a match, return the parameter index
00225      i = hash_table[code + thread_offset_];
00226      if( i < rec_par_.size() && IdenticalEqualPar(rec_par_[i], par) )
00227                return i;
00228      
00229      // place a new value in the table
00230      i           = rec_par_.extend(1);
00231      rec_par_[i] = par;
00232      CPPAD_ASSERT_UNKNOWN( rec_par_.size() == i + 1 );
00233 
00234      // make the hash code point to this new value
00235      hash_table[code + thread_offset_] = i;
00236 
00237      // return the parameter index
00238      return i;
00239 }
00240 // -------------------------- PutArg --------------------------------------
00241 /*!
00242 Prototype for putting operation argument indices in the recording.
00243 
00244 The following syntax
00245 \verbatim
00246      rec.PutArg(arg0)
00247      rec.PutArg(arg0, arg1)
00248      .
00249      .
00250      .
00251      rec.PutArg(arg0, arg1, ..., arg5)
00252 \endverbatim
00253 places the values passed to PutArg at the current end of the
00254 operation argument indices for the recording.
00255 \a arg0 comes before \a arg1, etc.
00256 The proper number of operation argument indices 
00257 corresponding to the operation code op is given by
00258 \verbatim
00259      NumArg(op)
00260 \endverbatim
00261 The number of the operation argument indices starts at zero
00262 after the default constructor and each call to Erase.
00263 It increases by the number of indices placed by each call to PutArg.
00264 */
00265 inline void prototype_put_arg(void)
00266 {    // This routine should not be called
00267      CPPAD_ASSERT_UNKNOWN(false);
00268 }
00269 /*!
00270 Put one operation argument index in the recording
00271 
00272 \param arg0
00273 The operation argument index
00274 
00275 \copydetails prototype_put_arg 
00276 */
00277 template <class Base>
00278 inline void recorder<Base>::PutArg(addr_t arg0)
00279 { 
00280      size_t i       = rec_op_arg_.extend(1);
00281      rec_op_arg_[i] =  static_cast<addr_t>( arg0 );
00282      CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
00283 }
00284 /*!
00285 Put two operation argument index in the recording
00286 
00287 \param arg0
00288 First operation argument index.
00289 
00290 \param arg1
00291 Second operation argument index.
00292 
00293 \copydetails prototype_put_arg 
00294 */
00295 template <class Base>
00296 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1)
00297 { 
00298      size_t i         = rec_op_arg_.extend(2);
00299      rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
00300      rec_op_arg_[i]   =  static_cast<addr_t>( arg1 );
00301      CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
00302 }
00303 /*!
00304 Put three operation argument index in the recording
00305 
00306 \param arg0
00307 First operation argument index.
00308 
00309 \param arg1
00310 Second operation argument index.
00311 
00312 \param arg2
00313 Third operation argument index.
00314 
00315 \copydetails prototype_put_arg 
00316 */
00317 template <class Base>
00318 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2)
00319 { 
00320      size_t i         = rec_op_arg_.extend(3);
00321      rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
00322      rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
00323      rec_op_arg_[i]   =  static_cast<addr_t>( arg2 );
00324      CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
00325 }
00326 /*!
00327 Put four operation argument index in the recording
00328 
00329 \param arg0
00330 First operation argument index.
00331 
00332 \param arg1
00333 Second operation argument index.
00334 
00335 \param arg2
00336 Third operation argument index.
00337 
00338 \param arg3
00339 Fourth operation argument index.
00340 
00341 \copydetails prototype_put_arg 
00342 */
00343 template <class Base>
00344 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
00345      addr_t arg3)
00346 { 
00347      size_t i         = rec_op_arg_.extend(4);
00348      rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
00349      rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
00350      rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
00351      rec_op_arg_[i]   =  static_cast<addr_t>( arg3 );
00352      CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
00353 
00354 }
00355 /*!
00356 Put five operation argument index in the recording
00357 
00358 \param arg0
00359 First operation argument index.
00360 
00361 \param arg1
00362 Second operation argument index.
00363 
00364 \param arg2
00365 Third operation argument index.
00366 
00367 \param arg3
00368 Fourth operation argument index.
00369 
00370 \param arg4
00371 Fifth operation argument index.
00372 
00373 \copydetails prototype_put_arg 
00374 */
00375 template <class Base>
00376 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
00377      addr_t arg3, addr_t arg4)
00378 { 
00379      size_t i         = rec_op_arg_.extend(5);
00380      rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
00381      rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
00382      rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
00383      rec_op_arg_[i++] =  static_cast<addr_t>( arg3 );
00384      rec_op_arg_[i]   =  static_cast<addr_t>( arg4 );
00385      CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
00386 
00387 }
00388 /*!
00389 Put six operation argument index in the recording
00390 
00391 \param arg0
00392 First operation argument index.
00393 
00394 \param arg1
00395 Second operation argument index.
00396 
00397 \param arg2
00398 Third operation argument index.
00399 
00400 \param arg3
00401 Fourth operation argument index.
00402 
00403 \param arg4
00404 Fifth operation argument index.
00405 
00406 \param arg5
00407 Sixth operation argument index.
00408 
00409 \copydetails prototype_put_arg 
00410 */
00411 template <class Base>
00412 inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, 
00413      addr_t arg3, addr_t arg4, addr_t arg5)
00414 { 
00415      size_t i         = rec_op_arg_.extend(6);
00416      rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
00417      rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
00418      rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
00419      rec_op_arg_[i++] =  static_cast<addr_t>( arg3 );
00420      rec_op_arg_[i++] =  static_cast<addr_t>( arg4 );
00421      rec_op_arg_[i]   =  static_cast<addr_t>( arg5 );
00422      CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
00423 }
00424 // --------------------------------------------------------------------------
00425 /*!
00426 Put a character string in the text for this recording.
00427 
00428 \param text
00429 is a '\\0' terminated character string that is to be put in the
00430 vector of characters corresponding to this recording.
00431 The terminator '\\0' will be included.
00432 
00433 \return
00434 is the offset with in the text vector for this recording at which
00435 the character string starts.
00436 */
00437 template <class Base>
00438 inline size_t recorder<Base>::PutTxt(const char *text)
00439 {
00440      // determine length of the text including terminating '\0'
00441      size_t n = 0;
00442      while( text[n] != '\0' )
00443           n++;
00444      CPPAD_ASSERT_UNKNOWN( n <= 1000 ); 
00445      n++;
00446      CPPAD_ASSERT_UNKNOWN( text[n-1] == '\0' );
00447 
00448      // copy text including terminating '\0'
00449      size_t i = rec_text_.extend(n); 
00450      size_t j;
00451      for(j = 0; j < n; j++)
00452           rec_text_[i + j] = text[j];
00453      CPPAD_ASSERT_UNKNOWN( rec_text_.size() == i + n );
00454 
00455      return i;
00456 }
00457 // -------------------------------------------------------------------------
00458 
00459 
00460 /*! \} */
00461 CPPAD_END_NAMESPACE
00462 # endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines