CppAD: A C++ Algorithmic Differentiation Package
20130918
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_FORWARD0SWEEP_INCLUDED 00003 # define CPPAD_FORWARD0SWEEP_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-14 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 namespace CppAD { // BEGIN_CPPAD_NAMESPACE 00017 /*! 00018 \file forward0sweep.hpp 00019 Compute zero order forward mode Taylor coefficients. 00020 */ 00021 00022 /* 00023 \def CPPAD_ATOMIC_CALL 00024 This avoids warnings when NDEBUG is defined and user_ok is not used. 00025 If NDEBUG is defined, this resolves to 00026 \code 00027 user_atom->forward 00028 \endcode 00029 otherwise, it respolves to 00030 \code 00031 user_ok = user_atom->forward 00032 \endcode 00033 This maco is undefined at the end of this file to facillitate is 00034 use with a different definition in other files. 00035 */ 00036 # ifdef NDEBUG 00037 # define CPPAD_ATOMIC_CALL user_atom->forward 00038 # else 00039 # define CPPAD_ATOMIC_CALL user_ok = user_atom->forward 00040 # endif 00041 00042 /*! 00043 \def CPPAD_FORWARD0SWEEP_TRACE 00044 This value is either zero or one. 00045 Zero is the normal operational value. 00046 If it is one, a trace of every forward0sweep computation is printed. 00047 (Note that forward0sweep is not used if CPPAD_USE_FORWARD0SWEEP is zero). 00048 */ 00049 # define CPPAD_FORWARD0SWEEP_TRACE 0 00050 00051 /*! 00052 Compute zero order forward mode Taylor coefficients. 00053 00054 <!-- define forward0sweep_doc_define --> 00055 \tparam Base 00056 The type used during the forward mode computations; i.e., the corresponding 00057 recording of operations used the type AD<Base>. 00058 00059 \param s_out 00060 Is the stream where output corresponding to PriOp operations will 00061 be written. 00062 00063 \param print 00064 If print is false, 00065 suppress the output that is otherwise generated by the c PriOp instructions. 00066 00067 \param n 00068 is the number of independent variables on the tape. 00069 00070 \param numvar 00071 is the total number of variables on the tape. 00072 This is also equal to the number of rows in the matrix taylor; i.e., 00073 play->num_var_rec(). 00074 00075 \param play 00076 The information stored in play 00077 is a recording of the operations corresponding to the function 00078 \f[ 00079 F : {\bf R}^n \rightarrow {\bf R}^m 00080 \f] 00081 where \f$ n \f$ is the number of independent variables and 00082 \f$ m \f$ is the number of dependent variables. 00083 \n 00084 \n 00085 The object play is effectly constant. 00086 The exception to this is that while palying back the tape 00087 the object play holds information about the current location 00088 with in the tape and this changes during palyback. 00089 00090 \param J 00091 Is the number of columns in the coefficient matrix taylor. 00092 This must be greater than or equal one. 00093 00094 <!-- end forward0sweep_doc_define --> 00095 00096 \param taylor 00097 \n 00098 \b Input: 00099 For i = 1 , ... , n, 00100 <code>taylor [i * J + 0]</code> 00101 variable with index j on the tape 00102 (these are the independent variables). 00103 \n 00104 \n 00105 \b Output: 00106 For i = n + 1, ... , numvar - 1, 00107 <code>taylor [i * J + 0]</code> 00108 is the zero order Taylor coefficient for the variable with 00109 index i on the tape. 00110 00111 \param cskip_op 00112 Is a vector with size play->num_op_rec(). 00113 The input value of the elements does not matter. 00114 Upon return, if cskip_op[i] is true, the operator index i 00115 does not affect any of the dependent variable 00116 (given the value of the independent variables). 00117 00118 \param var_by_load_op 00119 Is a vector with size play->num_load_op_rec(). 00120 The input value of the elements does not matter. 00121 Upon return, 00122 it is the variable index corresponding the result for each load operator. 00123 In the case where the index is zero, 00124 the load operator results in a parameter (not a variable). 00125 Note that the is no variable with index zero on the tape. 00126 00127 \return 00128 The return value is equal to the number of ComOp operations 00129 that have a different result from when the information in 00130 play was recorded. 00131 (Note that if NDEBUG is true, there are no ComOp operations 00132 in play and hence this return value is always zero.) 00133 */ 00134 00135 template <class Base> 00136 size_t forward0sweep( 00137 std::ostream& s_out, 00138 bool print, 00139 size_t n, 00140 size_t numvar, 00141 player<Base>* play, 00142 size_t J, 00143 Base* taylor, 00144 bool* cskip_op, 00145 pod_vector<addr_t>& var_by_load_op 00146 ) 00147 { CPPAD_ASSERT_UNKNOWN( J >= 1 ); 00148 CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); 00149 00150 // use p, q, r so other forward sweeps can use code defined here 00151 size_t p = 0; 00152 size_t q = 0; 00153 /* 00154 <!-- define forward0sweep_code_define --> 00155 */ 00156 // op code for current instruction 00157 OpCode op; 00158 00159 // index for current instruction 00160 size_t i_op; 00161 00162 // next variables 00163 size_t i_var; 00164 00165 // operation argument indices 00166 const addr_t* arg = CPPAD_NULL; 00167 00168 // initialize the comparision operator (ComOp) counter 00169 size_t compareCount = 0; 00170 00171 // If this includes a zero calculation, initialize this information 00172 pod_vector<bool> isvar_by_ind; 00173 pod_vector<size_t> index_by_ind; 00174 if( p == 0 ) 00175 { size_t i; 00176 00177 // this includes order zero calculation, initialize vector indices 00178 size_t num = play->num_vec_ind_rec(); 00179 if( num > 0 ) 00180 { isvar_by_ind.extend(num); 00181 index_by_ind.extend(num); 00182 for(i = 0; i < num; i++) 00183 { index_by_ind[i] = play->GetVecInd(i); 00184 isvar_by_ind[i] = false; 00185 } 00186 } 00187 // includes zero order, so initialize conditional skip flags 00188 num = play->num_op_rec(); 00189 for(i = 0; i < num; i++) 00190 cskip_op[i] = false; 00191 } 00192 00193 // work space used by UserOp. 00194 vector<bool> user_vx; // empty vecotor 00195 vector<bool> user_vy; // empty vecotor 00196 vector<Base> user_tx; // argument vector Taylor coefficients 00197 vector<Base> user_ty; // result vector Taylor coefficients 00198 size_t user_index = 0; // indentifier for this atomic operation 00199 size_t user_id = 0; // user identifier for this call to operator 00200 size_t user_i = 0; // index in result vector 00201 size_t user_j = 0; // index in argument vector 00202 size_t user_m = 0; // size of result vector 00203 size_t user_n = 0; // size of arugment vector 00204 // 00205 atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator 00206 # ifndef NDEBUG 00207 bool user_ok = false; // atomic op return value 00208 # endif 00209 // 00210 // next expected operator in a UserOp sequence 00211 enum { user_start, user_arg, user_ret, user_end } user_state = user_start; 00212 00213 // length of the parameter vector (used by CppAD assert macros) 00214 const size_t num_par = play->num_par_rec(); 00215 00216 // pointer to the beginning of the parameter vector 00217 const Base* parameter = CPPAD_NULL; 00218 if( num_par > 0 ) 00219 parameter = play->GetPar(); 00220 00221 // length of the text vector (used by CppAD assert macros) 00222 const size_t num_text = play->num_text_rec(); 00223 00224 // pointer to the beginning of the text vector 00225 const char* text = CPPAD_NULL; 00226 if( num_text > 0 ) 00227 text = play->GetTxt(0); 00228 /* 00229 <!-- end forward0sweep_code_define --> 00230 */ 00231 00232 // skip the BeginOp at the beginning of the recording 00233 play->forward_start(op, arg, i_op, i_var); 00234 CPPAD_ASSERT_UNKNOWN( op == BeginOp ); 00235 # if CPPAD_FORWARD0SWEEP_TRACE 00236 std::cout << std::endl; 00237 # endif 00238 bool more_operators = true; 00239 while(more_operators) 00240 { 00241 // this op 00242 play->forward_next(op, arg, i_op, i_var); 00243 CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) ); 00244 CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) ); 00245 CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() ); 00246 00247 // check if we are skipping this operation 00248 while( cskip_op[i_op] ) 00249 { if( op == CSumOp ) 00250 { // CSumOp has a variable number of arguments 00251 play->forward_csum(op, arg, i_op, i_var); 00252 } 00253 play->forward_next(op, arg, i_op, i_var); 00254 CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() ); 00255 } 00256 00257 // action to take depends on the case 00258 switch( op ) 00259 { 00260 case AbsOp: 00261 forward_abs_op_0(i_var, arg[0], J, taylor); 00262 break; 00263 // ------------------------------------------------- 00264 00265 case AddvvOp: 00266 forward_addvv_op_0(i_var, arg, parameter, J, taylor); 00267 break; 00268 // ------------------------------------------------- 00269 00270 case AddpvOp: 00271 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 00272 forward_addpv_op_0(i_var, arg, parameter, J, taylor); 00273 break; 00274 // ------------------------------------------------- 00275 00276 case AcosOp: 00277 // sqrt(1 - x * x), acos(x) 00278 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00279 forward_acos_op_0(i_var, arg[0], J, taylor); 00280 break; 00281 // ------------------------------------------------- 00282 00283 case AsinOp: 00284 // sqrt(1 - x * x), asin(x) 00285 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00286 forward_asin_op_0(i_var, arg[0], J, taylor); 00287 break; 00288 // ------------------------------------------------- 00289 00290 case AtanOp: 00291 // 1 + x * x, atan(x) 00292 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00293 forward_atan_op_0(i_var, arg[0], J, taylor); 00294 break; 00295 // ------------------------------------------------- 00296 00297 case CExpOp: 00298 // Use the general case with d == 0 00299 // (could create an optimzied verison for this case) 00300 forward_cond_op_0( 00301 i_var, arg, num_par, parameter, J, taylor 00302 ); 00303 break; 00304 // --------------------------------------------------- 00305 case ComOp: 00306 forward_comp_op_0( 00307 compareCount, arg, num_par, parameter, J, taylor 00308 ); 00309 break; 00310 // --------------------------------------------------- 00311 00312 case CosOp: 00313 // sin(x), cos(x) 00314 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00315 forward_cos_op_0(i_var, arg[0], J, taylor); 00316 break; 00317 // --------------------------------------------------- 00318 00319 case CoshOp: 00320 // sinh(x), cosh(x) 00321 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00322 forward_cosh_op_0(i_var, arg[0], J, taylor); 00323 break; 00324 // ------------------------------------------------- 00325 00326 case CSkipOp: 00327 // CSkipOp has a variable number of arguments and 00328 // forward_next thinks it has no arguments. 00329 // we must inform forward_next of this special case. 00330 forward_cskip_op_0( 00331 i_var, arg, num_par, parameter, J, taylor, cskip_op 00332 ); 00333 play->forward_cskip(op, arg, i_op, i_var); 00334 break; 00335 // ------------------------------------------------- 00336 00337 case CSumOp: 00338 // CSumOp has a variable number of arguments and 00339 // forward_next thinks it has no arguments. 00340 // we must inform forward_next of this special case. 00341 forward_csum_op( 00342 0, 0, i_var, arg, num_par, parameter, J, taylor 00343 ); 00344 play->forward_csum(op, arg, i_op, i_var); 00345 break; 00346 // ------------------------------------------------- 00347 00348 case DisOp: 00349 forward_dis_op_0(i_var, arg, J, taylor); 00350 break; 00351 // ------------------------------------------------- 00352 00353 case DivvvOp: 00354 forward_divvv_op_0(i_var, arg, parameter, J, taylor); 00355 break; 00356 // ------------------------------------------------- 00357 00358 case DivpvOp: 00359 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 00360 forward_divpv_op_0(i_var, arg, parameter, J, taylor); 00361 break; 00362 // ------------------------------------------------- 00363 00364 case DivvpOp: 00365 CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); 00366 forward_divvp_op_0(i_var, arg, parameter, J, taylor); 00367 break; 00368 // ------------------------------------------------- 00369 00370 case EndOp: 00371 CPPAD_ASSERT_NARG_NRES(op, 0, 0); 00372 more_operators = false; 00373 break; 00374 // ------------------------------------------------- 00375 00376 case ExpOp: 00377 forward_exp_op_0(i_var, arg[0], J, taylor); 00378 break; 00379 // ------------------------------------------------- 00380 00381 case InvOp: 00382 break; 00383 // ------------------------------------------------- 00384 00385 case LdpOp: 00386 forward_load_p_op_0( 00387 play, 00388 i_var, 00389 arg, 00390 parameter, 00391 J, 00392 taylor, 00393 isvar_by_ind.data(), 00394 index_by_ind.data(), 00395 var_by_load_op.data() 00396 ); 00397 break; 00398 // ------------------------------------------------- 00399 00400 case LdvOp: 00401 forward_load_v_op_0( 00402 play, 00403 i_var, 00404 arg, 00405 parameter, 00406 J, 00407 taylor, 00408 isvar_by_ind.data(), 00409 index_by_ind.data(), 00410 var_by_load_op.data() 00411 ); 00412 break; 00413 // ------------------------------------------------- 00414 00415 case LogOp: 00416 forward_log_op_0(i_var, arg[0], J, taylor); 00417 break; 00418 // ------------------------------------------------- 00419 00420 case MulvvOp: 00421 forward_mulvv_op_0(i_var, arg, parameter, J, taylor); 00422 break; 00423 // ------------------------------------------------- 00424 00425 case MulpvOp: 00426 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 00427 forward_mulpv_op_0(i_var, arg, parameter, J, taylor); 00428 break; 00429 // ------------------------------------------------- 00430 00431 case ParOp: 00432 forward_par_op_0( 00433 i_var, arg, num_par, parameter, J, taylor 00434 ); 00435 break; 00436 // ------------------------------------------------- 00437 00438 case PowvpOp: 00439 CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); 00440 forward_powvp_op_0(i_var, arg, parameter, J, taylor); 00441 break; 00442 // ------------------------------------------------- 00443 00444 case PowpvOp: 00445 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 00446 forward_powpv_op_0(i_var, arg, parameter, J, taylor); 00447 break; 00448 // ------------------------------------------------- 00449 00450 case PowvvOp: 00451 forward_powvv_op_0(i_var, arg, parameter, J, taylor); 00452 break; 00453 // ------------------------------------------------- 00454 00455 case PriOp: 00456 if( print ) forward_pri_0(s_out, 00457 i_var, arg, num_text, text, num_par, parameter, J, taylor 00458 ); 00459 break; 00460 // ------------------------------------------------- 00461 00462 case SignOp: 00463 // cos(x), sin(x) 00464 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00465 forward_sign_op_0(i_var, arg[0], J, taylor); 00466 break; 00467 // ------------------------------------------------- 00468 00469 case SinOp: 00470 // cos(x), sin(x) 00471 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00472 forward_sin_op_0(i_var, arg[0], J, taylor); 00473 break; 00474 // ------------------------------------------------- 00475 00476 case SinhOp: 00477 // cosh(x), sinh(x) 00478 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00479 forward_sinh_op_0(i_var, arg[0], J, taylor); 00480 break; 00481 // ------------------------------------------------- 00482 00483 case SqrtOp: 00484 forward_sqrt_op_0(i_var, arg[0], J, taylor); 00485 break; 00486 // ------------------------------------------------- 00487 00488 case StppOp: 00489 forward_store_pp_op_0( 00490 i_var, 00491 arg, 00492 num_par, 00493 J, 00494 taylor, 00495 isvar_by_ind.data(), 00496 index_by_ind.data() 00497 ); 00498 break; 00499 // ------------------------------------------------- 00500 00501 case StpvOp: 00502 forward_store_pv_op_0( 00503 i_var, 00504 arg, 00505 num_par, 00506 J, 00507 taylor, 00508 isvar_by_ind.data(), 00509 index_by_ind.data() 00510 ); 00511 break; 00512 // ------------------------------------------------- 00513 00514 case StvpOp: 00515 forward_store_vp_op_0( 00516 i_var, 00517 arg, 00518 num_par, 00519 J, 00520 taylor, 00521 isvar_by_ind.data(), 00522 index_by_ind.data() 00523 ); 00524 break; 00525 // ------------------------------------------------- 00526 00527 case StvvOp: 00528 forward_store_vv_op_0( 00529 i_var, 00530 arg, 00531 num_par, 00532 J, 00533 taylor, 00534 isvar_by_ind.data(), 00535 index_by_ind.data() 00536 ); 00537 break; 00538 // ------------------------------------------------- 00539 00540 case SubvvOp: 00541 forward_subvv_op_0(i_var, arg, parameter, J, taylor); 00542 break; 00543 // ------------------------------------------------- 00544 00545 case SubpvOp: 00546 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 00547 forward_subpv_op_0(i_var, arg, parameter, J, taylor); 00548 break; 00549 // ------------------------------------------------- 00550 00551 case SubvpOp: 00552 CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); 00553 forward_subvp_op_0(i_var, arg, parameter, J, taylor); 00554 break; 00555 // ------------------------------------------------- 00556 00557 case TanOp: 00558 // tan(x)^2, tan(x) 00559 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00560 forward_tan_op_0(i_var, arg[0], J, taylor); 00561 break; 00562 // ------------------------------------------------- 00563 00564 case TanhOp: 00565 // tanh(x)^2, tanh(x) 00566 CPPAD_ASSERT_UNKNOWN( i_var < numvar ); 00567 forward_tanh_op_0(i_var, arg[0], J, taylor); 00568 break; 00569 // ------------------------------------------------- 00570 00571 case UserOp: 00572 // start or end an atomic operation sequence 00573 CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); 00574 CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); 00575 if( user_state == user_start ) 00576 { user_index = arg[0]; 00577 user_id = arg[1]; 00578 user_n = arg[2]; 00579 user_m = arg[3]; 00580 user_atom = atomic_base<Base>::class_object(user_index); 00581 # ifndef NDEBUG 00582 if( user_atom == CPPAD_NULL ) 00583 { std::string msg = 00584 atomic_base<Base>::class_name(user_index) 00585 + ": atomic_base function has been deleted"; 00586 CPPAD_ASSERT_KNOWN(false, msg.c_str() ); 00587 } 00588 # endif 00589 if(user_tx.size() != user_n) 00590 user_tx.resize(user_n); 00591 if(user_ty.size() != user_m) 00592 user_ty.resize(user_m); 00593 user_j = 0; 00594 user_i = 0; 00595 user_state = user_arg; 00596 } 00597 else 00598 { CPPAD_ASSERT_UNKNOWN( user_state == user_end ); 00599 CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); 00600 CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); 00601 CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); 00602 CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); 00603 # ifndef NDEBUG 00604 if( ! user_ok ) 00605 { std::string msg = 00606 atomic_base<Base>::class_name(user_index) 00607 + ": atomic_base.forward: returned false"; 00608 CPPAD_ASSERT_KNOWN(false, msg.c_str() ); 00609 } 00610 # endif 00611 user_state = user_start; 00612 } 00613 break; 00614 00615 case UsrapOp: 00616 // parameter argument in an atomic operation sequence 00617 CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); 00618 CPPAD_ASSERT_UNKNOWN( user_j < user_n ); 00619 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 00620 user_tx[user_j++] = parameter[ arg[0] ]; 00621 if( user_j == user_n ) 00622 { // call users function for this operation 00623 user_atom->set_id(user_id); 00624 CPPAD_ATOMIC_CALL(p, q, 00625 user_vx, user_vy, user_tx, user_ty 00626 ); 00627 user_state = user_ret; 00628 } 00629 break; 00630 00631 case UsravOp: 00632 // variable argument in an atomic operation sequence 00633 CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); 00634 CPPAD_ASSERT_UNKNOWN( user_j < user_n ); 00635 CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); 00636 user_tx[user_j++] = taylor[ arg[0] * J + 0 ]; 00637 if( user_j == user_n ) 00638 { // call users function for this operation 00639 user_atom->set_id(user_id); 00640 CPPAD_ATOMIC_CALL(p, q, 00641 user_vx, user_vy, user_tx, user_ty 00642 ); 00643 user_state = user_ret; 00644 } 00645 break; 00646 00647 case UsrrpOp: 00648 // parameter result in an atomic operation sequence 00649 CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); 00650 CPPAD_ASSERT_UNKNOWN( user_i < user_m ); 00651 user_i++; 00652 if( user_i == user_m ) 00653 user_state = user_end; 00654 break; 00655 00656 case UsrrvOp: 00657 // variable result in an atomic operation sequence 00658 CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); 00659 CPPAD_ASSERT_UNKNOWN( user_i < user_m ); 00660 taylor[ i_var * J + 0 ] = user_ty[user_i++]; 00661 if( user_i == user_m ) 00662 user_state = user_end; 00663 break; 00664 // ------------------------------------------------- 00665 00666 default: 00667 CPPAD_ASSERT_UNKNOWN(false); 00668 } 00669 # if CPPAD_FORWARD0SWEEP_TRACE 00670 size_t d = 0; 00671 size_t i_tmp = i_var; 00672 Base* Z_tmp = taylor + i_var * J; 00673 00674 printOp( 00675 std::cout, 00676 play, 00677 i_op, 00678 i_tmp, 00679 op, 00680 arg, 00681 d + 1, 00682 Z_tmp, 00683 0, 00684 (Base *) CPPAD_NULL 00685 ); 00686 } 00687 std::cout << std::endl; 00688 # else 00689 } 00690 # endif 00691 CPPAD_ASSERT_UNKNOWN( user_state == user_start ); 00692 CPPAD_ASSERT_UNKNOWN( i_var + 1 == play->num_var_rec() ); 00693 00694 return compareCount; 00695 } 00696 00697 } // END_CPPAD_NAMESPACE 00698 00699 // preprocessor symbols that are local to this file 00700 # undef CPPAD_FORWARD0SWEEP_TRACE 00701 # undef CPPAD_ATOMIC_CALL 00702 00703 # endif