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