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