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