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