1 # ifndef CPPAD_LOCAL_PLAY_PLAYER_HPP 2 # define CPPAD_LOCAL_PLAY_PLAYER_HPP 3 /* -------------------------------------------------------------------------- 4 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell 5 6 CppAD is distributed under the terms of the 7 Eclipse Public License Version 2.0. 8 9 This Source Code may also be made available under the following 10 Secondary License when the conditions for such availability set forth 11 in the Eclipse Public License, Version 2.0 are satisfied: 12 GNU General Public License, Version 2.0 or later. 13 ---------------------------------------------------------------------------- */ 14 15 # include <cppad/local/play/addr_enum.hpp> 16 # include <cppad/local/play/sequential_iterator.hpp> 17 # include <cppad/local/play/subgraph_iterator.hpp> 18 # include <cppad/local/play/random_setup.hpp> 19 # include <cppad/local/atom_state.hpp> 20 # include <cppad/local/is_pod.hpp> 21 22 namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE 23 /*! 24 \file player.hpp 25 File used to define the player class. 26 */ 27 28 /*! 29 Class used to store and play back an operation sequence recording. 30 31 \tparam Base 32 These were AD< Base > operations when recorded. Operations during playback 33 are done using the type Base . 34 */ 35 36 template <class Base> 37 class player { 38 // player<Base> must be a friend of player< AD<Base> > for base2ad to work 39 template <class AnotherBase> friend class player; 40 private: 41 // ---------------------------------------------------------------------- 42 // information that defines the recording 43 44 /// Number of independent dynamic parameters 45 size_t num_dynamic_ind_; 46 47 /// Number of variables in the recording. 48 size_t num_var_rec_; 49 50 /// number of vecad load opeations in the reconding 51 size_t num_var_load_rec_; 52 53 /// Number of VecAD vectors in the recording 54 size_t num_var_vecad_rec_; 55 56 /// The operators in the recording. 57 pod_vector<opcode_t> op_vec_; 58 59 /// The operation argument indices in the recording 60 pod_vector<addr_t> arg_vec_; 61 62 /// Character strings ('\\0' terminated) in the recording. 63 pod_vector<char> text_vec_; 64 65 /// The VecAD indices in the recording. 66 pod_vector<addr_t> all_var_vecad_ind_; 67 68 /// All of the parameters in the recording. 69 /// Use pod_maybe because Base may not be plain old data. 70 pod_vector_maybe<Base> all_par_vec_; 71 72 /// Which elements of all_par_vec_ are dynamic parameters 73 /// (size equal number of parametrers) 74 pod_vector<bool> dyn_par_is_; 75 76 /// mapping from dynamic parameter index to parameter index 77 /// 1: size equal to number of dynamic parameters 78 /// 2: dyn_ind2par_ind_[j] < dyn_ind2par_ind_[j+1] 79 pod_vector<addr_t> dyn_ind2par_ind_; 80 81 /// operators for just the dynamic parameters 82 /// (size equal number of dynamic parameters) 83 pod_vector<opcode_t> dyn_par_op_; 84 85 /// arguments for the dynamic parameter operators 86 pod_vector<addr_t> dyn_par_arg_; 87 88 // ---------------------------------------------------------------------- 89 // Information needed to use member functions that begin with random_ 90 // and for using const_subgraph_iterator. 91 92 /// index in arg_vec_ corresonding to the first argument for each operator 93 pod_vector<unsigned char> op2arg_vec_; 94 95 /*! 96 Index of the result variable for each operator. If the operator has 97 no results, this is not defined. The invalid index num_var_rec_ is used 98 when NDEBUG is not defined. If the operator has more than one result, this 99 is the primary result; i.e., the last result. Auxillary are only used by 100 the operator and not used by other operators. 101 */ 102 pod_vector<unsigned char> op2var_vec_; 103 104 /// Mapping from primary variable index to corresponding operator index. 105 /// This is used to traverse sub-graphs of the operation sequence. 106 /// This value is valid (invalid) for primary (auxillary) variables. 107 pod_vector<unsigned char> var2op_vec_; 108 109 public: 110 // ================================================================= 111 /// default constructor 112 // set all scalars to zero to avoid valgraind warning when ani assignment 113 // occures before values get set. player(void)114 player(void) : 115 num_dynamic_ind_(0) , 116 num_var_rec_(0) , 117 num_var_load_rec_(0) , 118 num_var_vecad_rec_(0) 119 { } 120 // move semantics constructor 121 // (none of the default constructor values matter to the destructor) player(player & play)122 player(player& play) 123 { swap(play); } 124 // ================================================================= 125 /// destructor ~player(void)126 ~player(void) 127 { } 128 // ====================================================================== 129 /// type used for addressing iterators for this player address_type(void) const130 play::addr_enum address_type(void) const 131 { 132 // required 133 size_t required = 0; 134 required = std::max(required, num_var_rec_ ); // number variables 135 required = std::max(required, op_vec_.size() ); // number operators 136 required = std::max(required, arg_vec_.size() ); // number arguments 137 // 138 // unsigned short 139 if( required <= std::numeric_limits<unsigned short>::max() ) 140 return play::unsigned_short_enum; 141 // 142 // unsigned int 143 if( required <= std::numeric_limits<unsigned int>::max() ) 144 return play::unsigned_int_enum; 145 // 146 // unsigned size_t 147 CPPAD_ASSERT_UNKNOWN( 148 required <= std::numeric_limits<size_t>::max() 149 ); 150 return play::size_t_enum; 151 } 152 // =============================================================== 153 /*! 154 Moving an operation sequence from a recorder to this player 155 156 \param rec 157 the object that was used to record the operation sequence. After this 158 operation, the state of the recording is no longer defined. For example, 159 the pod_vector member variables in this have been swapped with rec. 160 161 \param n_ind 162 the number of independent variables (only used for error checking 163 when NDEBUG is not defined). 164 165 \par 166 Use an assert to check that the length of the following vectors is 167 less than the maximum possible value for addr_t; i.e., that an index 168 in these vectors can be represented using the type addr_t: 169 op_vec_, all_var_vecad_ind_, arg_vec_, test_vec_, all_par_vec_, text_vec_, 170 dyn_par_arg_. 171 */ get_recording(recorder<Base> & rec,size_t n_ind)172 void get_recording(recorder<Base>& rec, size_t n_ind) 173 { 174 # ifndef NDEBUG 175 size_t addr_t_max = size_t( std::numeric_limits<addr_t>::max() ); 176 # endif 177 // just set size_t values 178 num_dynamic_ind_ = rec.num_dynamic_ind_; 179 num_var_rec_ = rec.num_var_rec_; 180 num_var_load_rec_ = rec.num_var_load_rec_; 181 182 // op_vec_ 183 op_vec_.swap(rec.op_vec_); 184 CPPAD_ASSERT_UNKNOWN(op_vec_.size() < addr_t_max ); 185 186 // op_arg_vec_ 187 arg_vec_.swap(rec.arg_vec_); 188 CPPAD_ASSERT_UNKNOWN(arg_vec_.size() < addr_t_max ); 189 190 // all_par_vec_ 191 all_par_vec_.swap(rec.all_par_vec_); 192 CPPAD_ASSERT_UNKNOWN(all_par_vec_.size() < addr_t_max ); 193 194 // dyn_par_is_, dyn_par_op_, dyn_par_arg_ 195 dyn_par_is_.swap( rec.dyn_par_is_ ); 196 dyn_par_op_.swap( rec.dyn_par_op_ ); 197 dyn_par_arg_.swap( rec.dyn_par_arg_ ); 198 CPPAD_ASSERT_UNKNOWN(dyn_par_arg_.size() < addr_t_max ); 199 200 // text_rec_ 201 text_vec_.swap(rec.text_vec_); 202 CPPAD_ASSERT_UNKNOWN(text_vec_.size() < addr_t_max ); 203 204 // all_var_vecad_ind_ 205 all_var_vecad_ind_.swap(rec.all_var_vecad_ind_); 206 CPPAD_ASSERT_UNKNOWN(all_var_vecad_ind_.size() < addr_t_max ); 207 208 // num_var_vecad_rec_ 209 num_var_vecad_rec_ = 0; 210 { // all_var_vecad_ind_ contains size of each VecAD followed by 211 // the parameter indices used to inialize it. 212 size_t i = 0; 213 while( i < all_var_vecad_ind_.size() ) 214 { num_var_vecad_rec_++; 215 i += size_t( all_var_vecad_ind_[i] ) + 1; 216 } 217 CPPAD_ASSERT_UNKNOWN( i == all_var_vecad_ind_.size() ); 218 } 219 220 // mapping from dynamic parameter index to parameter index 221 dyn_ind2par_ind_.resize( dyn_par_op_.size() ); 222 size_t i_dyn = 0; 223 for(size_t i_par = 0; i_par < all_par_vec_.size(); ++i_par) 224 { if( dyn_par_is_[i_par] ) 225 { dyn_ind2par_ind_[i_dyn] = addr_t( i_par ); 226 ++i_dyn; 227 } 228 } 229 CPPAD_ASSERT_UNKNOWN( i_dyn == dyn_ind2par_ind_.size() ); 230 231 // random access information 232 clear_random(); 233 234 // some checks 235 check_inv_op(n_ind); 236 check_variable_dag(); 237 check_dynamic_dag(); 238 } 239 // ---------------------------------------------------------------------- 240 /*! 241 Check that InvOp operators start with second operator and are contiguous, 242 and there are n_ind of them. 243 */ 244 # ifdef NDEBUG check_inv_op(size_t n_ind) const245 void check_inv_op(size_t n_ind) const 246 { return; } 247 # else check_inv_op(size_t n_ind) const248 void check_inv_op(size_t n_ind) const 249 { play::const_sequential_iterator itr = begin(); 250 OpCode op; 251 const addr_t* op_arg; 252 size_t var_index; 253 itr.op_info(op, op_arg, var_index); 254 CPPAD_ASSERT_UNKNOWN( op == BeginOp ); 255 size_t i_op = 0; 256 while( op != EndOp ) 257 { // start at second operator 258 (++itr).op_info(op, op_arg, var_index); 259 ++i_op; 260 CPPAD_ASSERT_UNKNOWN( (op == InvOp) == (i_op <= n_ind) ); 261 } 262 return; 263 } 264 # endif 265 // ---------------------------------------------------------------------- 266 /*! 267 Check variable graph to make sure arguments have value less 268 than or equal to the previously created variable. This is the directed 269 acyclic graph condition (DAG). 270 */ 271 # ifdef NDEBUG check_variable_dag(void) const272 void check_variable_dag(void) const 273 { return; } 274 # else check_variable_dag(void) const275 void check_variable_dag(void) const 276 { play::const_sequential_iterator itr = begin(); 277 OpCode op; 278 const addr_t* op_arg; 279 size_t var_index; 280 itr.op_info(op, op_arg, var_index); 281 CPPAD_ASSERT_UNKNOWN( op == BeginOp ); 282 // 283 addr_t arg_var_bound = 0; 284 while( op != EndOp ) 285 { (++itr).op_info(op, op_arg, var_index); 286 switch(op) 287 { 288 // cases where nothing to do 289 case BeginOp: 290 case EndOp: 291 case EqppOp: 292 case InvOp: 293 case LdpOp: 294 case LeppOp: 295 case LtppOp: 296 case NeppOp: 297 case ParOp: 298 case AFunOp: 299 case FunapOp: 300 case FunrpOp: 301 case FunrvOp: 302 case StppOp: 303 break; 304 305 // only first argument is a variable 306 case AbsOp: 307 case AcosOp: 308 case AcoshOp: 309 case AsinOp: 310 case AsinhOp: 311 case AtanOp: 312 case AtanhOp: 313 case CosOp: 314 case CoshOp: 315 case DivvpOp: 316 case ErfOp: 317 case ErfcOp: 318 case ExpOp: 319 case Expm1Op: 320 case LevpOp: 321 case LogOp: 322 case Log1pOp: 323 case LtvpOp: 324 case PowvpOp: 325 case SignOp: 326 case SinOp: 327 case SinhOp: 328 case SqrtOp: 329 case SubvpOp: 330 case TanOp: 331 case TanhOp: 332 case FunavOp: 333 case ZmulvpOp: 334 CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound ); 335 break; 336 337 // only second argument is a variable 338 case AddpvOp: 339 case DisOp: 340 case DivpvOp: 341 case EqpvOp: 342 case LdvOp: 343 case LepvOp: 344 case LtpvOp: 345 case MulpvOp: 346 case NepvOp: 347 case PowpvOp: 348 case StvpOp: 349 case SubpvOp: 350 case ZmulpvOp: 351 CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound ); 352 break; 353 354 // only first and second arguments are variables 355 case AddvvOp: 356 case DivvvOp: 357 case EqvvOp: 358 case LevvOp: 359 case LtvvOp: 360 case MulvvOp: 361 case NevvOp: 362 case PowvvOp: 363 case SubvvOp: 364 case ZmulvvOp: 365 CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound ); 366 CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound ); 367 break; 368 369 // StpvOp 370 case StpvOp: 371 CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound ); 372 break; 373 374 // StvvOp 375 case StvvOp: 376 CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound ); 377 CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound ); 378 break; 379 380 // CSumOp 381 case CSumOp: 382 { CPPAD_ASSERT_UNKNOWN( 5 < op_arg[2] ); 383 for(addr_t j = 5; j < op_arg[2]; j++) 384 CPPAD_ASSERT_UNKNOWN(op_arg[j] <= arg_var_bound); 385 } 386 itr.correct_before_increment(); 387 break; 388 389 // CExpOp 390 case CExpOp: 391 if( op_arg[1] & 1 ) 392 CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound); 393 if( op_arg[1] & 2 ) 394 CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound); 395 if( op_arg[1] & 4 ) 396 CPPAD_ASSERT_UNKNOWN( op_arg[4] <= arg_var_bound); 397 if( op_arg[1] & 8 ) 398 CPPAD_ASSERT_UNKNOWN( op_arg[5] <= arg_var_bound); 399 break; 400 401 // PriOp 402 case PriOp: 403 if( op_arg[0] & 1 ) 404 CPPAD_ASSERT_UNKNOWN( op_arg[1] <= arg_var_bound); 405 if( op_arg[0] & 2 ) 406 CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound); 407 break; 408 409 // CSkipOp 410 case CSkipOp: 411 if( op_arg[1] & 1 ) 412 CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound); 413 if( op_arg[1] & 2 ) 414 CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound); 415 itr.correct_before_increment(); 416 break; 417 418 default: 419 CPPAD_ASSERT_UNKNOWN(false); 420 break; 421 422 423 } 424 if( NumRes(op) > 0 ) 425 { if( var_index > 0 ) 426 { CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) < var_index); 427 } 428 else 429 { CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) == var_index); 430 } 431 // 432 arg_var_bound = addr_t(var_index); 433 } 434 } 435 return; 436 } 437 # endif 438 // ---------------------------------------------------------------------- 439 /*! 440 Check dynamic parameter graph to make sure arguments have value less 441 than or equal to the previously created dynamic parameter. 442 This is the directed acyclic graph condition (DAG). 443 */ 444 # ifdef NDEBUG check_dynamic_dag(void) const445 void check_dynamic_dag(void) const 446 { return; } 447 # else check_dynamic_dag(void) const448 void check_dynamic_dag(void) const 449 { // number of dynamic parameters 450 size_t num_dyn = dyn_par_op_.size(); 451 // 452 size_t i_arg = 0; // initialize dynamic parameter argument index 453 for(size_t i_dyn = 0; i_dyn < num_dyn; ++i_dyn) 454 { // i_par is parameter index 455 addr_t i_par = dyn_ind2par_ind_[i_dyn]; 456 CPPAD_ASSERT_UNKNOWN( dyn_par_is_[i_par] ); 457 // 458 // operator for this dynamic parameter 459 op_code_dyn op = op_code_dyn( dyn_par_op_[i_dyn] ); 460 // 461 // number of arguments for this dynamic parameter 462 size_t n_arg = num_arg_dyn(op); 463 if( op == atom_dyn ) 464 { size_t n = size_t( dyn_par_arg_[i_arg + 1] ); 465 size_t m = size_t( dyn_par_arg_[i_arg + 2] ); 466 n_arg = 5 + n + m; 467 CPPAD_ASSERT_UNKNOWN( 468 n_arg == size_t( dyn_par_arg_[i_arg + 4 + n + m] ) 469 ); 470 for(size_t i = 4; i < n - 1; ++i) 471 CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par ); 472 # ifndef NDEBUG 473 for(size_t i = 4+n; i < 4+n+m; ++i) 474 { addr_t j_par = dyn_par_arg_[i_arg + i]; 475 CPPAD_ASSERT_UNKNOWN( (j_par == 0) || (j_par >= i_par) ); 476 } 477 # endif 478 } 479 else 480 { size_t num_non_par = num_non_par_arg_dyn(op); 481 for(size_t i = num_non_par; i < n_arg; ++i) 482 CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par); 483 } 484 // 485 // next dynamic parameter 486 i_arg += n_arg; 487 } 488 return; 489 } 490 # endif 491 // =============================================================== 492 /*! 493 Copy a player<Base> to another player<Base> 494 495 \param play 496 object that contains the operatoion sequence to copy. 497 */ operator =(const player & play)498 void operator=(const player& play) 499 { 500 // size_t objects 501 num_dynamic_ind_ = play.num_dynamic_ind_; 502 num_var_rec_ = play.num_var_rec_; 503 num_var_load_rec_ = play.num_var_load_rec_; 504 num_var_vecad_rec_ = play.num_var_vecad_rec_; 505 // 506 // pod_vectors 507 op_vec_ = play.op_vec_; 508 arg_vec_ = play.arg_vec_; 509 text_vec_ = play.text_vec_; 510 all_var_vecad_ind_ = play.all_var_vecad_ind_; 511 dyn_par_is_ = play.dyn_par_is_; 512 dyn_ind2par_ind_ = play.dyn_ind2par_ind_; 513 dyn_par_op_ = play.dyn_par_op_; 514 dyn_par_arg_ = play.dyn_par_arg_; 515 op2arg_vec_ = play.op2arg_vec_; 516 op2var_vec_ = play.op2var_vec_; 517 var2op_vec_ = play.var2op_vec_; 518 // 519 // pod_maybe_vectors 520 all_par_vec_ = play.all_par_vec_; 521 } 522 // =============================================================== 523 /// Create a player< AD<Base> > from this player<Base> base2ad(void) const524 player< AD<Base> > base2ad(void) const 525 { player< AD<Base> > play; 526 // 527 // size_t objects 528 play.num_dynamic_ind_ = num_dynamic_ind_; 529 play.num_var_rec_ = num_var_rec_; 530 play.num_var_load_rec_ = num_var_load_rec_; 531 play.num_var_vecad_rec_ = num_var_vecad_rec_; 532 // 533 // pod_vectors 534 play.op_vec_ = op_vec_; 535 play.arg_vec_ = arg_vec_; 536 play.text_vec_ = text_vec_; 537 play.all_var_vecad_ind_ = all_var_vecad_ind_; 538 play.dyn_par_is_ = dyn_par_is_; 539 play.dyn_ind2par_ind_ = dyn_ind2par_ind_; 540 play.dyn_par_op_ = dyn_par_op_; 541 play.dyn_par_arg_ = dyn_par_arg_; 542 play.op2arg_vec_ = op2arg_vec_; 543 play.op2var_vec_ = op2var_vec_; 544 play.var2op_vec_ = var2op_vec_; 545 // 546 // pod_maybe_vector< AD<Base> > = pod_maybe_vector<Base> 547 play.all_par_vec_.resize( all_par_vec_.size() ); 548 for(size_t i = 0; i < all_par_vec_.size(); ++i) 549 play.all_par_vec_[i] = all_par_vec_[i]; 550 // 551 return play; 552 } 553 // =============================================================== 554 /// swap this recording with another recording 555 /// (used for move semantics version of ADFun assignment operation) swap(player & other)556 void swap(player& other) 557 { // size_t objects 558 std::swap(num_dynamic_ind_, other.num_dynamic_ind_); 559 std::swap(num_var_rec_, other.num_var_rec_); 560 std::swap(num_var_load_rec_, other.num_var_load_rec_); 561 std::swap(num_var_vecad_rec_, other.num_var_vecad_rec_); 562 // 563 // pod_vectors 564 op_vec_.swap( other.op_vec_); 565 arg_vec_.swap( other.arg_vec_); 566 text_vec_.swap( other.text_vec_); 567 all_var_vecad_ind_.swap( other.all_var_vecad_ind_); 568 dyn_par_is_.swap( other.dyn_par_is_); 569 dyn_ind2par_ind_.swap( other.dyn_ind2par_ind_); 570 dyn_par_op_.swap( other.dyn_par_op_); 571 dyn_par_arg_.swap( other.dyn_par_arg_); 572 op2arg_vec_.swap( other.op2arg_vec_); 573 op2var_vec_.swap( other.op2var_vec_); 574 var2op_vec_.swap( other.var2op_vec_); 575 // 576 // pod_maybe_vectors 577 all_par_vec_.swap( other.all_par_vec_); 578 } 579 // move semantics assignment operator =(player && play)580 void operator=(player&& play) 581 { swap(play); } 582 // ================================================================= 583 /// Enable use of const_subgraph_iterator and member functions that begin 584 // with random_(no work if already setup). 585 template <class Addr> setup_random(void)586 void setup_random(void) 587 { play::random_setup( 588 num_var_rec_ , 589 op_vec_ , 590 arg_vec_ , 591 op2arg_vec_.pod_vector_ptr<Addr>() , 592 op2var_vec_.pod_vector_ptr<Addr>() , 593 var2op_vec_.pod_vector_ptr<Addr>() 594 ); 595 } 596 /// Free memory used for functions that begin with random_ 597 /// and random iterators and subgraph iterators clear_random(void)598 void clear_random(void) 599 { 600 op2arg_vec_.clear(); 601 op2var_vec_.clear(); 602 var2op_vec_.clear(); 603 CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size() == 0 ); 604 CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 ); 605 CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 ); 606 } 607 /// get non-const version of all_par_vec all_par_vec(void)608 pod_vector_maybe<Base>& all_par_vec(void) 609 { return all_par_vec_; } 610 /// get non-const version of all_par_vec all_par_vec(void) const611 const pod_vector_maybe<Base>& all_par_vec(void) const 612 { return all_par_vec_; } 613 // ================================================================ 614 // const functions that retrieve infromation from this player 615 // ================================================================ 616 /// const version of dynamic parameter flag dyn_par_is(void) const617 const pod_vector<bool>& dyn_par_is(void) const 618 { return dyn_par_is_; } 619 /// const version of dynamic parameter index to parameter index dyn_ind2par_ind(void) const620 const pod_vector<addr_t>& dyn_ind2par_ind(void) const 621 { return dyn_ind2par_ind_; } 622 /// const version of dynamic parameter operator dyn_par_op(void) const623 const pod_vector<opcode_t>& dyn_par_op(void) const 624 { return dyn_par_op_; } 625 /// const version of dynamic parameter arguments dyn_par_arg(void) const626 const pod_vector<addr_t>& dyn_par_arg(void) const 627 { return dyn_par_arg_; } 628 /*! 629 \brief 630 fetch an operator from the recording. 631 632 \return 633 the i-th operator in the recording. 634 635 \param i 636 the index of the operator in recording 637 */ GetOp(size_t i) const638 OpCode GetOp (size_t i) const 639 { return OpCode(op_vec_[i]); } 640 641 /*! 642 \brief 643 Fetch a VecAD index from the recording. 644 645 \return 646 the i-th VecAD index in the recording. 647 648 \param i 649 the index of the VecAD index in recording 650 */ GetVecInd(size_t i) const651 size_t GetVecInd (size_t i) const 652 { return size_t( all_var_vecad_ind_[i] ); } 653 654 /*! 655 \brief 656 Fetch a parameter from the recording. 657 658 \return 659 the i-th parameter in the recording. 660 661 \param i 662 the index of the parameter in recording 663 */ GetPar(size_t i) const664 Base GetPar(size_t i) const 665 { return all_par_vec_[i]; } 666 667 /*! 668 \brief 669 Fetch entire parameter vector from the recording. 670 671 \return 672 the entire parameter vector. 673 674 */ GetPar(void) const675 const Base* GetPar(void) const 676 { return all_par_vec_.data(); } 677 678 /*! 679 \brief 680 Fetch a '\\0' terminated string from the recording. 681 682 \return 683 the beginning of the string. 684 685 \param i 686 the index where the string begins. 687 */ GetTxt(size_t i) const688 const char *GetTxt(size_t i) const 689 { CPPAD_ASSERT_UNKNOWN(i < text_vec_.size() ); 690 return text_vec_.data() + i; 691 } 692 693 /// Fetch number of independent dynamic parameters in the recording num_dynamic_ind(void) const694 size_t num_dynamic_ind(void) const 695 { return num_dynamic_ind_; } 696 697 /// Fetch number of dynamic parameters in the recording num_dynamic_par(void) const698 size_t num_dynamic_par(void) const 699 { return dyn_par_op_.size(); } 700 701 /// Fetch number of dynamic parameters operator arguments in the recording num_dynamic_arg(void) const702 size_t num_dynamic_arg(void) const 703 { return dyn_par_arg_.size(); } 704 705 /// Fetch number of variables in the recording. num_var_rec(void) const706 size_t num_var_rec(void) const 707 { return num_var_rec_; } 708 709 /// Fetch number of vecad load operations num_var_load_rec(void) const710 size_t num_var_load_rec(void) const 711 { return num_var_load_rec_; } 712 713 /// Fetch number of operators in the recording. num_op_rec(void) const714 size_t num_op_rec(void) const 715 { return op_vec_.size(); } 716 717 /// Fetch number of VecAD indices in the recording. num_var_vecad_ind_rec(void) const718 size_t num_var_vecad_ind_rec(void) const 719 { return all_var_vecad_ind_.size(); } 720 721 /// Fetch number of VecAD vectors in the recording num_var_vecad_rec(void) const722 size_t num_var_vecad_rec(void) const 723 { return num_var_vecad_rec_; } 724 725 /// Fetch number of argument indices in the recording. num_op_arg_rec(void) const726 size_t num_op_arg_rec(void) const 727 { return arg_vec_.size(); } 728 729 /// Fetch number of parameters in the recording. num_par_rec(void) const730 size_t num_par_rec(void) const 731 { return all_par_vec_.size(); } 732 733 /// Fetch number of characters (representing strings) in the recording. num_text_rec(void) const734 size_t num_text_rec(void) const 735 { return text_vec_.size(); } 736 737 /// A measure of amount of memory used to store 738 /// the operation sequence, just lengths, not capacities. 739 /// In user api as f.size_op_seq(); see the file seq_property.omh. size_op_seq(void) const740 size_t size_op_seq(void) const 741 { // check assumptions made by ad_fun<Base>::size_op_seq() 742 CPPAD_ASSERT_UNKNOWN( op_vec_.size() == num_op_rec() ); 743 CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == num_op_arg_rec() ); 744 CPPAD_ASSERT_UNKNOWN( all_par_vec_.size() == num_par_rec() ); 745 CPPAD_ASSERT_UNKNOWN( text_vec_.size() == num_text_rec() ); 746 CPPAD_ASSERT_UNKNOWN( all_var_vecad_ind_.size() == num_var_vecad_ind_rec() ); 747 return op_vec_.size() * sizeof(opcode_t) 748 + arg_vec_.size() * sizeof(addr_t) 749 + all_par_vec_.size() * sizeof(Base) 750 + dyn_par_is_.size() * sizeof(bool) 751 + dyn_ind2par_ind_.size() * sizeof(addr_t) 752 + dyn_par_op_.size() * sizeof(opcode_t) 753 + dyn_par_arg_.size() * sizeof(addr_t) 754 + text_vec_.size() * sizeof(char) 755 + all_var_vecad_ind_.size() * sizeof(addr_t) 756 ; 757 } 758 /// A measure of amount of memory used for random access routine 759 /// In user api as f.size_random(); see the file seq_property.omh. size_random(void) const760 size_t size_random(void) const 761 { 762 # ifndef NDEBUG 763 if( op2arg_vec_.size() == 0 ) 764 { CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 ); 765 CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 ); 766 } 767 else 768 { size_t size = 0; 769 switch( address_type() ) 770 { case play::unsigned_short_enum: 771 size = sizeof(unsigned short); 772 break; 773 // 774 case play::unsigned_int_enum: 775 size = sizeof(unsigned int); 776 break; 777 // 778 case play::size_t_enum: 779 size = sizeof(size_t); 780 break; 781 782 default: 783 CPPAD_ASSERT_UNKNOWN(false); 784 break; 785 } 786 CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size()/size == num_op_rec() ); 787 CPPAD_ASSERT_UNKNOWN( op2var_vec_.size()/size == num_op_rec() ); 788 CPPAD_ASSERT_UNKNOWN( var2op_vec_.size()/size == num_var_rec() ); 789 } 790 # endif 791 CPPAD_ASSERT_UNKNOWN( sizeof(unsigned char) == 1 ); 792 return op2arg_vec_.size() 793 + op2var_vec_.size() 794 + var2op_vec_.size() 795 ; 796 } 797 // ----------------------------------------------------------------------- 798 /// const sequential iterator begin begin(void) const799 play::const_sequential_iterator begin(void) const 800 { size_t op_index = 0; 801 size_t num_var = num_var_rec_; 802 return play::const_sequential_iterator( 803 num_var, &op_vec_, &arg_vec_, op_index 804 ); 805 } 806 /// const sequential iterator end end(void) const807 play::const_sequential_iterator end(void) const 808 { size_t op_index = op_vec_.size() - 1; 809 size_t num_var = num_var_rec_; 810 return play::const_sequential_iterator( 811 num_var, &op_vec_, &arg_vec_, op_index 812 ); 813 } 814 // ----------------------------------------------------------------------- 815 /// const subgraph iterator begin begin_subgraph(const play::const_random_iterator<addr_t> & random_itr,const pod_vector<addr_t> * subgraph) const816 play::const_subgraph_iterator<addr_t> begin_subgraph( 817 const play::const_random_iterator<addr_t>& random_itr , 818 const pod_vector<addr_t>* subgraph ) const 819 { size_t subgraph_index = 0; 820 return play::const_subgraph_iterator<addr_t>( 821 random_itr, 822 subgraph, 823 subgraph_index 824 ); 825 } 826 /// const subgraph iterator end 827 template <class Addr> end_subgraph(const play::const_random_iterator<Addr> & random_itr,const pod_vector<addr_t> * subgraph) const828 play::const_subgraph_iterator<Addr> end_subgraph( 829 const play::const_random_iterator<Addr>& random_itr , 830 const pod_vector<addr_t>* subgraph ) const 831 { size_t subgraph_index = subgraph->size() - 1; 832 return play::const_subgraph_iterator<Addr>( 833 random_itr, 834 subgraph, 835 subgraph_index 836 ); 837 } 838 // ----------------------------------------------------------------------- 839 /// const random iterator 840 template <class Addr> get_random(void) const841 play::const_random_iterator<Addr> get_random(void) const 842 { return play::const_random_iterator<Addr>( 843 op_vec_, 844 arg_vec_, 845 op2arg_vec_.pod_vector_ptr<Addr>(), 846 op2var_vec_.pod_vector_ptr<Addr>(), 847 var2op_vec_.pod_vector_ptr<Addr>() 848 ); 849 } 850 }; 851 852 } } // END_CPPAD_lOCAL_NAMESPACE 853 # endif 854