CppAD: A C++ Algorithmic Differentiation Package 20110419
|
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