CppAD: A C++ Algorithmic Differentiation Package
20130102
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_PLAYER_INCLUDED 00003 # define CPPAD_PLAYER_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Eclipse Public License Version 1.0. 00011 00012 A copy of this license is included in the COPYING file of this distribution. 00013 Please visit http://www.coin-or.org/CppAD/ for information on other licenses. 00014 -------------------------------------------------------------------------- */ 00015 00016 CPPAD_BEGIN_NAMESPACE 00017 /*! 00018 \defgroup player_hpp player.hpp 00019 \{ 00020 \file player.hpp 00021 File used to define the player class. 00022 */ 00023 00024 00025 /*! 00026 Class used to store and play back an operation sequence recording. 00027 00028 \tparam Base 00029 These were AD< \a Base > operations when recorded. Operations during playback 00030 are done using the type \a Base . 00031 */ 00032 template <class Base> 00033 class player { 00034 00035 // -------------- Variables that define the recording ----------------------- 00036 private: 00037 /// Number of variables in the recording. 00038 size_t num_rec_var_; 00039 00040 /// The operators in the recording. 00041 pod_vector<CPPAD_OP_CODE_TYPE> rec_op_; 00042 00043 /// Number of VecAD vectors in the recording 00044 size_t num_rec_vecad_vec_; 00045 00046 /// The VecAD indices in the recording. 00047 pod_vector<addr_t> rec_vecad_ind_; 00048 00049 /// The operation argument indices in the recording 00050 pod_vector<addr_t> rec_op_arg_; 00051 00052 /// The parameters in the recording. 00053 /// Note that Base may not be plain old data, so use false in consructor. 00054 pod_vector<Base> rec_par_; 00055 00056 /// Character strings ('\\0' terminated) in the recording. 00057 pod_vector<char> rec_text_; 00058 00059 00060 // --------------- Functions used to create and maniplate a recording ------- 00061 public: 00062 /// Default constructor 00063 player(void) : 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 ~player(void) 00074 { } 00075 00076 // =============================================================== 00077 // Begin two functions with idential code but different argument types. 00078 /*! 00079 Moving an operation sequence from a recorder to a player 00080 00081 \param rec 00082 the object that was used to record the operation sequence. After this 00083 operation, the state of the recording is no longer defined. For example, 00084 the \c pod_vector member variables in \c this have been swapped with 00085 \c rec . 00086 */ 00087 void get(recorder<Base>& rec) 00088 { size_t i; 00089 00090 // Var 00091 num_rec_var_ = rec.num_rec_var_; 00092 00093 // Op 00094 rec_op_.swap(rec.rec_op_); 00095 00096 // VecInd 00097 rec_vecad_ind_.swap(rec.rec_vecad_ind_); 00098 00099 // Arg 00100 rec_op_arg_.swap(rec.rec_op_arg_); 00101 00102 // Par 00103 rec_par_.swap(rec.rec_par_); 00104 00105 // Txt 00106 rec_text_.swap(rec.rec_text_); 00107 00108 // set the number of VecAD vectors 00109 num_rec_vecad_vec_ = 0; 00110 for(i = 0; i < rec_vecad_ind_.size(); i += rec_vecad_ind_[i] + 1) 00111 num_rec_vecad_vec_++; 00112 // rec_vecad_ind_ contains size of each VecAD followed by 00113 // the parameter indices used to iniialize it. 00114 CPPAD_ASSERT_UNKNOWN( i == rec_vecad_ind_.size() ); 00115 } 00116 00117 /*! 00118 Copying an operation sequence from one player to another 00119 00120 \param play 00121 the object that contains the operatoion sequence to copy. 00122 */ 00123 void operator=(const player& play) 00124 { 00125 // Var 00126 num_rec_var_ = play.num_rec_var_; 00127 00128 // Op 00129 rec_op_ = play.rec_op_; 00130 00131 // VecInd 00132 num_rec_vecad_vec_ = play.num_rec_vecad_vec_; 00133 rec_vecad_ind_ = play.rec_vecad_ind_; 00134 00135 // Arg 00136 rec_op_arg_ = play.rec_op_arg_; 00137 00138 // Par 00139 rec_par_ = play.rec_par_; 00140 00141 // Txt 00142 rec_text_ = play.rec_text_; 00143 } 00144 // End two functions with idential code but different argument types. 00145 // =============================================================== 00146 00147 /// Erase all information in an operation sequence player. 00148 void Erase(void) 00149 { 00150 num_rec_var_ = 0; 00151 num_rec_vecad_vec_ = 0; 00152 00153 rec_op_.erase(); 00154 rec_vecad_ind_.erase(); 00155 rec_op_arg_.erase(); 00156 rec_par_.erase(); 00157 rec_text_.erase(); 00158 } 00159 00160 // ------------------ Old method of palying back a recording ----------------- 00161 public: 00162 /*! 00163 \brief 00164 Fetch an operator from the recording. 00165 00166 \return 00167 the i-th operator in the recording. 00168 00169 \param i 00170 the index of the operator in recording 00171 */ 00172 OpCode GetOp (size_t i) const 00173 { return OpCode(rec_op_[i]); } 00174 00175 /*! 00176 \brief 00177 Fetch a VecAD index from the recording. 00178 00179 \return 00180 the i-th VecAD index in the recording. 00181 00182 \param i 00183 the index of the VecAD index in recording 00184 */ 00185 size_t GetVecInd (size_t i) const 00186 { return rec_vecad_ind_[i]; } 00187 00188 /*! 00189 \brief 00190 Fetch a parameter from the recording. 00191 00192 \return 00193 the i-th parameter in the recording. 00194 00195 \param i 00196 the index of the parameter in recording 00197 */ 00198 Base GetPar(size_t i) const 00199 { return rec_par_[i]; } 00200 00201 /*! 00202 \brief 00203 Fetch entire parameter vector from the recording. 00204 00205 \return 00206 the entire parameter vector. 00207 00208 */ 00209 const Base* GetPar(void) const 00210 { return rec_par_.data(); } 00211 00212 /*! 00213 \brief 00214 Fetch a '\\0' terminated string from the recording. 00215 00216 \return 00217 the beginning of the string. 00218 00219 \param i 00220 the index where the string begins. 00221 */ 00222 const char *GetTxt(size_t i) const 00223 { CPPAD_ASSERT_UNKNOWN(i < rec_text_.size() ); 00224 return rec_text_.data() + i; 00225 } 00226 00227 /*! 00228 \brief 00229 Replace an argument index in the recording. 00230 00231 \param i 00232 is the index, in argument indices, that is to be replaced. 00233 00234 \param value 00235 is the new normal index value. 00236 */ 00237 void ReplaceInd(size_t i, size_t value) 00238 { rec_op_arg_[i] = static_cast<addr_t>( value ); } 00239 00240 /// Fetch number of variables in the recording. 00241 size_t num_rec_var(void) const 00242 { return num_rec_var_; } 00243 00244 /// Fetch number of operators in the recording. 00245 size_t num_rec_op(void) const 00246 { return rec_op_.size(); } 00247 00248 /// Fetch number of VecAD indices in the recording. 00249 size_t num_rec_vecad_ind(void) const 00250 { return rec_vecad_ind_.size(); } 00251 00252 /// Fetch number of VecAD vectors in the recording 00253 size_t num_rec_vecad_vec(void) const 00254 { return num_rec_vecad_vec_; } 00255 00256 /// Fetch number of argument indices in the recording. 00257 size_t num_rec_op_arg(void) const 00258 { return rec_op_arg_.size(); } 00259 00260 /// Fetch number of parameters in the recording. 00261 size_t num_rec_par(void) const 00262 { return rec_par_.size(); } 00263 00264 /// Fetch number of characters (representing strings) in the recording. 00265 size_t num_rec_text(void) const 00266 { return rec_text_.size(); } 00267 00268 /// Fetch a rough measure of amount of memory used to store recording 00269 /// (just lengths, not capacities). 00270 size_t Memory(void) const 00271 { return rec_op_.size() * sizeof(OpCode) 00272 + rec_op_arg_.size() * sizeof(addr_t) 00273 + rec_par_.size() * sizeof(Base) 00274 + rec_text_.size() * sizeof(char) 00275 + rec_vecad_ind_.size() * sizeof(addr_t) 00276 ; 00277 } 00278 00279 // ------------- Variables used for new methog of playing back a recording --- 00280 private: 00281 /// Current operator 00282 OpCode op_; 00283 00284 /// Index in recording corresponding to current operator 00285 size_t op_index_; 00286 00287 /// Current offset of the argument indices in rec_op_arg_ 00288 size_t op_arg_; 00289 00290 /// Index for primary (last) variable corresponding to current operator 00291 size_t var_index_; 00292 00293 // ----------- Functions used in new method for palying back a recording --- 00294 public: 00295 /*! 00296 Start a play back of the recording during a forward sweep. 00297 00298 Use repeated calls to next_forward to play back one operator at a time. 00299 00300 \param op 00301 The input value of op does not matter. Its output value is the 00302 first operator in the recording; i.e., BeginOp. 00303 00304 \param op_arg 00305 The input value of *op_arg does not matter. Its output value is the 00306 beginning of the vector of argument indices for the first operation; 00307 i.e., 0 00308 00309 \param op_index 00310 The input value of op_index does not matter. Its output value 00311 is the index of the next first operator in the recording; i.e., 0. 00312 00313 \param var_index 00314 The input value of var_index does not matter. Its output value is the 00315 index of the primary (last) result corresponding to the the first 00316 operator (which must be a BeginOp); i.e., 0. 00317 */ 00318 void start_forward( 00319 OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index) 00320 { 00321 op = op_ = OpCode( rec_op_[0] ); 00322 op_arg_ = 0; 00323 op_arg = rec_op_arg_.data(); 00324 op_index = op_index_ = 0; 00325 var_index = var_index_ = 0; 00326 00327 CPPAD_ASSERT_UNKNOWN( op_ == BeginOp ); 00328 CPPAD_ASSERT_NARG_NRES(op_, 0, 1); 00329 00330 return; 00331 } 00332 00333 /*! 00334 Fetch the next operator during a forward sweep. 00335 00336 Use start_forward to initialize to the first operator; i.e., 00337 the BeginOp at the beginning of the recording. 00338 00339 \param op 00340 The input value of op does not matter. Its output value is the 00341 next operator in the recording. 00342 For speed, \c next_forward does not check for the special case 00343 of <tt>op == CSumOp</tt>. In this case, the other return values 00344 from \c next_forward must be corrected by a call to \c forward_csum. 00345 00346 \param op_arg 00347 The input value of *op_arg does not matter. Its output value is the 00348 beginning of the vector of argument indices for this operation. 00349 00350 \param op_index 00351 The input value of op_index does not matter. Its output value 00352 is the index of the next operator in the recording. Thus the ouput 00353 value following the previous call to start_forward is one. In addition, 00354 the output value increases by one with each call to next_forward. 00355 00356 \param var_index 00357 The input value of var_index does not matter. Its output value is the 00358 index of the primary (last) result corresponding to the operator op. 00359 */ 00360 00361 void next_forward( 00362 OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index) 00363 { using CppAD::NumRes; 00364 using CppAD::NumArg; 00365 00366 // index for the next operator 00367 op_index = ++op_index_; 00368 00369 // first argument for next operator 00370 op_arg_ += NumArg(op_); // index 00371 op_arg = op_arg_ + rec_op_arg_.data(); // pointer 00372 00373 // next operator 00374 op = op_ = OpCode( rec_op_[ op_index_ ] ); 00375 00376 // index for last result for next operator 00377 var_index = var_index_ += NumRes(op); 00378 00379 CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() ); 00380 CPPAD_ASSERT_UNKNOWN( var_index_ < num_rec_var_ ); 00381 } 00382 /*! 00383 Correct \c next_forward return values when <tt>op == CSumOp</tt>. 00384 00385 \param op 00386 The input value of op must be the return value from the previous 00387 call to \c next_forward and must be \c CSumOp. 00388 00389 \param op_arg 00390 The input value of *op_arg must be the return value from the 00391 previous call to \c next_forward. Its output value is the 00392 beginning of the vector of argument indices for this operation. 00393 00394 \param op_index 00395 The input value of op_index does must be the return value from the 00396 previous call to \c next_forward. Its output value 00397 is the index of this operator in the recording. 00398 00399 \param var_index 00400 The input value of var_index must be the return value from the 00401 previous call to \c next_forward. Its output value is the 00402 index of the primary (last) result corresponding to this. 00403 */ 00404 void forward_csum( 00405 OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index) 00406 { using CppAD::NumRes; 00407 using CppAD::NumArg; 00408 CPPAD_ASSERT_UNKNOWN( op == CSumOp ); 00409 CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 ); 00410 CPPAD_ASSERT_UNKNOWN( 00411 op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ] 00412 ); 00413 /* 00414 The only thing that really needs fixing is op_arg_. 00415 Actual number of arugments for this operator is 00416 op_arg[0] + op_arg[1] + 4. 00417 We must change op_arg_ so that when you add NumArg(CSumOp) 00418 you get first argument for next operator in sequence. 00419 */ 00420 op_arg_ += op_arg[0] + op_arg[1] + 4; 00421 00422 CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() ); 00423 CPPAD_ASSERT_UNKNOWN( var_index_ < num_rec_var_ ); 00424 } 00425 /*! 00426 Get a non-constant version of op_arg returned by previous next_forward 00427 00428 \return 00429 The return value is equal to the return value of op_arg 00430 corresponding to the previous call to next_forward. 00431 */ 00432 addr_t* forward_non_const_arg(void) 00433 { return op_arg_ + rec_op_arg_.data(); } 00434 00435 /*! 00436 Start a play back of the recording during a reverse sweep. 00437 00438 Use repeated calls to next_reverse to play back one operator at a time. 00439 00440 \param op 00441 The input value of op does not matter. Its output value is the 00442 last operator in the recording; i.e., EndOp. 00443 00444 \param op_arg 00445 The input value of *op_arg does not matter. Its output value is the 00446 beginning of the vector of argument indices for the last operation; 00447 (there are no arguments for the last operation so \a op_arg is invalid). 00448 00449 \param op_index 00450 The input value of op_index does not matter. Its output value 00451 is the index of the last operator in the recording. 00452 00453 \param var_index 00454 The input value of var_index does not matter. Its output value is the 00455 index of the primary (last) result corresponding to the the last 00456 operator (which must be a EndOp). 00457 (there are no results for the last operation 00458 so \a var_index is invalid). 00459 */ 00460 00461 void start_reverse( 00462 OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index) 00463 { 00464 op_arg_ = rec_op_arg_.size(); // index 00465 op_arg = op_arg_ + rec_op_arg_.data(); // pointer 00466 00467 op_index = op_index_ = rec_op_.size() - 1; 00468 var_index = var_index_ = num_rec_var_ - 1; 00469 00470 op = op_ = OpCode( rec_op_[ op_index_ ] ); 00471 CPPAD_ASSERT_UNKNOWN( op_ == EndOp ); 00472 CPPAD_ASSERT_NARG_NRES(op, 0, 0); 00473 return; 00474 } 00475 00476 /*! 00477 Fetch the next operator during a reverse sweep. 00478 00479 Use start_reverse to initialize to reverse play back. 00480 The first call to next_reverse (after start_reverse) will give the 00481 last operator in the recording. 00482 00483 \param op 00484 The input value of op does not matter. Its output value is the 00485 next operator in the recording (in reverse order). 00486 The last operator sets op equal to EndOp. 00487 00488 \param op_arg 00489 The input value of *op_arg does not matter. Its output value is the 00490 beginning of the vector of argument indices for this operation. 00491 The last operator sets op_arg equal to the beginning of the 00492 argument indices for the entire recording. 00493 For speed, \c next_reverse does not check for the special case 00494 of <tt>op == CSumOp</tt>. In this case, the other return values 00495 from \c next_reverse must be corrected by a call to \c reverse_csum. 00496 00497 00498 \param op_index 00499 The input value of op_index does not matter. Its output value 00500 is the index of this operator in the recording. Thus the output 00501 value following the previous call to start_reverse is equal to 00502 the number of variables in the recording minus one. 00503 In addition, the output value decreases by one with each call to 00504 next_reverse. 00505 The last operator sets op_index equal to 0. 00506 00507 \param var_index 00508 The input value of var_index does not matter. Its output value is the 00509 index of the primary (last) result corresponding to the operator op. 00510 The last operator sets var_index equal to 0 (corresponding to BeginOp 00511 at beginning of operation sequence). 00512 */ 00513 00514 void next_reverse( 00515 OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index) 00516 { using CppAD::NumRes; 00517 using CppAD::NumArg; 00518 00519 // index of the last result for the next operator 00520 CPPAD_ASSERT_UNKNOWN( var_index_ >= NumRes(op_) ); 00521 var_index = var_index_ -= NumRes(op_); 00522 00523 // next operator 00524 CPPAD_ASSERT_UNKNOWN( op_index_ > 0 ); 00525 op_index = --op_index_; // index 00526 op = op_ = OpCode( rec_op_[ op_index_ ] ); // value 00527 00528 // first argument for next operator 00529 CPPAD_ASSERT_UNKNOWN( op_arg_ >= NumArg(op) ); 00530 op_arg_ -= NumArg(op); // index 00531 op_arg = op_arg_ + rec_op_arg_.data(); // pointer 00532 } 00533 /*! 00534 Correct \c next_reverse return values when <tt>op == CSumOp</tt>. 00535 00536 \param op 00537 The input value of op must be the return value from the previous 00538 call to \c next_reverse and must be \c CSumOp. 00539 00540 \param op_arg 00541 The input value of *op_arg must be the return value from the 00542 previous call to \c next_reverse. Its output value is the 00543 beginning of the vector of argument indices for this operation. 00544 00545 \param op_index 00546 The input value of op_index must be the return value from the 00547 previous call to \c next_reverse. Its output value 00548 is the index of the this operator in the recording. 00549 00550 \param var_index 00551 The input value of var_index must be the return value from the 00552 previous call to \c next_reverse. Its output value is the 00553 index of the primary (last) result corresponding to this operator. 00554 */ 00555 00556 void reverse_csum( 00557 OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index) 00558 { using CppAD::NumRes; 00559 using CppAD::NumArg; 00560 CPPAD_ASSERT_UNKNOWN( op == CSumOp ); 00561 CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 ); 00562 /* 00563 The things needs fixing are op_arg_ and op_arg. Currently, 00564 op_arg points first arugment for the previous operator. 00565 */ 00566 --op_arg; 00567 op_arg_ -= (op_arg[0] + 4); 00568 op_arg = op_arg_ + rec_op_arg_.data(); 00569 00570 CPPAD_ASSERT_UNKNOWN( 00571 op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ] 00572 ); 00573 CPPAD_ASSERT_UNKNOWN( op_index_ < rec_op_.size() ); 00574 CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() ); 00575 CPPAD_ASSERT_UNKNOWN( var_index_ < num_rec_var_ ); 00576 } 00577 00578 }; 00579 00580 /*! \} */ 00581 CPPAD_END_NAMESPACE 00582 # endif