CppAD: A C++ Algorithmic Differentiation Package 20110419
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_OP_CODE_INCLUDED 00003 # define CPPAD_OP_CODE_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-11 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Common 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 # include <string> 00016 # include <sstream> 00017 # include <iomanip> 00018 00019 # include <cppad/local/define.hpp> 00020 00021 CPPAD_BEGIN_NAMESPACE 00022 /*! 00023 \file op_code.hpp 00024 Defines the OpCode enum type and functions related to it. 00025 00026 */ 00027 00028 00029 /*! 00030 Type used to distinguish different AD< \a Base > atomic operations. 00031 00032 Each of the operators ends with the characters Op. Ignoring the Op at the end, 00033 the operators appear in alphabetical order. Binary operation where both 00034 operands have type AD< \a Base > use the following convention for thier endings: 00035 \verbatim 00036 Ending Left-Operand Right-Operand 00037 pvOp parameter variable 00038 vpOp variable parameter 00039 vvOp variable variable 00040 \endverbatim 00041 For example, AddpvOp represents the addition operator where the left 00042 operand is a parameter and the right operand is a variable. 00043 */ 00044 enum OpCode { 00045 AbsOp, // abs(variable) 00046 AcosOp, // asin(variable) 00047 AddpvOp, // parameter + variable 00048 AddvvOp, // variable + variable 00049 AsinOp, // asin(variable) 00050 AtanOp, // atan(variable) 00051 BeginOp, // used to mark the beginning of the tape 00052 CExpOp, // CondExp(cop, left, right, trueCase, falseCase) 00053 ComOp, // Compare(cop, result, left, right) 00054 CosOp, // cos(variable) 00055 CoshOp, // cosh(variable) 00056 CSumOp, // Cummulative summation (has variable number of arguments) 00057 DisOp, // discrete::eval(index, variable) 00058 DivpvOp, // parameter / variable 00059 DivvpOp, // variable / parameter 00060 DivvvOp, // variable / variable 00061 EndOp, // used to mark the end of the tape 00062 ExpOp, // exp(variable) 00063 LdpOp, // z[parameter] 00064 LdvOp, // z[variable] 00065 InvOp, // independent variable 00066 LogOp, // log(variable) 00067 MulpvOp, // parameter * variable 00068 MulvvOp, // variable * variable 00069 ParOp, // parameter 00070 PowvpOp, // pow(variable, parameter) 00071 PowpvOp, // pow(parameter, variable) 00072 PowvvOp, // pow(variable, variable) 00073 PripOp, // text parameter 00074 PrivOp, // text parameter 00075 SinOp, // sin(variable) 00076 SinhOp, // sinh(variable) 00077 SqrtOp, // sqrt(variable) 00078 StppOp, // z[parameter] = parameter 00079 StvpOp, // z[variable] = parameter 00080 StpvOp, // z[parameter] = variable 00081 StvvOp, // z[variable] = variable 00082 SubpvOp, // parameter - variable 00083 SubvpOp, // variable - parameter 00084 SubvvOp, // variable - variable 00085 // user atomic operation codes (note yet implemented) 00086 UsrapOp, // this user atomic argument is a parameter 00087 UsravOp, // this user atomic argument is a variable 00088 UserOp, // start of a user atomic operaiton 00089 UsrrpOp, // this user atomic result is a parameter 00090 UsrrvOp // this user atomic result is a variable 00091 }; 00092 00093 /*! 00094 Table containing number of arguments for the corresponding operator. 00095 00096 The i-th element in this table specifes the number of arguments stored for each 00097 occurance of the operator that is the i-th value in the OpCode enum type. 00098 For example, for the first three OpCode enum values we have 00099 \verbatim 00100 OpCode j NumArgTable[j] Meaning 00101 AbsOp 0 1 index of variable we are taking absolute value of 00102 AcosOp 1 1 index of variable we are taking cosine of 00103 AddpvOp 1 2 indices of parameter and variable we are adding 00104 \endverbatim 00105 Note that the meaning of the arguments depends on the operator. 00106 */ 00107 const size_t NumArgTable[] = { 00108 1, // AbsOp 00109 1, // AcosOp 00110 2, // AddpvOp 00111 2, // AddvvOp 00112 1, // AsinOp 00113 1, // AtanOp 00114 0, // BeginOp 00115 6, // CExpOp 00116 4, // ComOp 00117 1, // CosOp 00118 1, // CoshOp 00119 0, // CSumOp (actually has a variable number of arguments, not zero) 00120 2, // DisOp 00121 2, // DivpvOp 00122 2, // DivvpOp 00123 2, // DivvvOp 00124 0, // EndOp 00125 1, // ExpOp 00126 3, // LdpOp 00127 3, // LdvOp 00128 0, // InvOp 00129 1, // LogOp 00130 2, // MulvvOp 00131 2, // MulpvOp 00132 1, // ParOp 00133 2, // PowvpOp 00134 2, // PowpvOp 00135 2, // PowvvOp 00136 2, // PripOp 00137 2, // PrivOp 00138 1, // SinOp 00139 1, // SinhOp 00140 1, // SqrtOp 00141 3, // StppOp 00142 3, // StvpOp 00143 3, // StpvOp 00144 3, // StvvOp 00145 2, // SubpvOp 00146 2, // SubvpOp 00147 2, // SubvvOp 00148 1, // UsrapOp 00149 1, // UsravOp 00150 4, // UserOp 00151 1, // UsrrpOp 00152 0 // UsrrvOp 00153 }; 00154 00155 /*! 00156 Fetch the number of arguments for a specified operator. 00157 00158 \return 00159 Number of arguments corresponding to the specified operator. 00160 00161 \param op 00162 Operator for which we are fetching the number of arugments. 00163 */ 00164 inline size_t NumArg( OpCode op) 00165 { 00166 CPPAD_ASSERT_UNKNOWN( size_t(UsrrvOp) == 00167 sizeof(NumArgTable) / sizeof(NumArgTable[0]) - 1 00168 ); 00169 CPPAD_ASSERT_UNKNOWN( size_t(op) <= size_t(UsrrvOp) ); 00170 00171 return NumArgTable[(size_t) op]; 00172 } 00173 00174 /*! 00175 Number of variables resulting from the corresponding operation. 00176 00177 The i-th element in this table specifes the number of varibles for each 00178 occurance of the operator that is the i-th value in the OpCode enum type. 00179 For example, for the first three OpCode enum values we have 00180 \verbatim 00181 OpCode j NumResTable[j] Meaning 00182 AbsOp 0 1 variable that is the result of the absolute value 00183 AcosOp 1 2 acos(x) and sqrt(1-x*x) are required for this op 00184 AddpvOp 1 1 variable that is the result of the addition 00185 \endverbatim 00186 */ 00187 // alphabetical order (ignoring the Op at the end) 00188 const size_t NumResTable[] = { 00189 1, // AbsOp 00190 2, // AcosOp 00191 1, // AddpvOp 00192 1, // AddvvOp 00193 2, // AsinOp 00194 2, // AtanOp 00195 1, // BeginOp offsets first variable to have index one (not zero) 00196 1, // CExpOp 00197 0, // ComOp 00198 2, // CosOp 00199 2, // CoshOp 00200 1, // CSumOp 00201 1, // DisOp 00202 1, // DivpvOp 00203 1, // DivvpOp 00204 1, // DivvvOp 00205 0, // EndOp 00206 1, // ExpOp 00207 1, // LdpOp 00208 1, // LdvOp 00209 1, // InvOp 00210 1, // LogOp 00211 1, // MulvvOp 00212 1, // MulpvOp 00213 1, // ParOp 00214 3, // PowvpOp 00215 3, // PowpvOp 00216 3, // PowvvOp 00217 0, // PripOp 00218 0, // PrivOp 00219 2, // SinOp 00220 2, // SinhOp 00221 1, // SqrtOp 00222 0, // StppOp 00223 0, // StvpOp 00224 0, // StpvOp 00225 0, // StvvOp 00226 1, // SubpvOp 00227 1, // SubvpOp 00228 1, // SubvvOp 00229 0, // UsrapOp 00230 0, // UsravOp 00231 0, // UserOp 00232 0, // UsrrpOp 00233 1, // UsrrvOp 00234 0 // Not used: avoids warning by g++ 4.3.2 when pycppad builds 00235 }; 00236 00237 /*! 00238 Fetch the number of variables resulting from the specified operation. 00239 00240 \return 00241 number of variables resulting from the specified operator. 00242 00243 \param op 00244 Operator for which we are fetching the number of result variables. 00245 */ 00246 inline size_t NumRes(OpCode op) 00247 { // check ensuring conversion to size_t is as expected 00248 CPPAD_ASSERT_UNKNOWN( size_t(UsrrvOp) == 00249 sizeof(NumResTable) / sizeof(NumResTable[0]) - 2 00250 ); 00251 // this test ensures that all indices are within the table 00252 CPPAD_ASSERT_UNKNOWN( size_t(op) <= size_t(UsrrvOp) ); 00253 00254 return NumResTable[(size_t) op]; 00255 } 00256 00257 /*! 00258 Prints a single field corresponding to an operator. 00259 00260 A specified leader is printed in front of the value 00261 and then the value is left justified in the following width character. 00262 00263 \tparam Type 00264 is the type of the value we are printing. 00265 00266 \param os 00267 is the stream that we are printing to. 00268 00269 \param leader 00270 are characters printed before the value. 00271 00272 \param value 00273 is the value being printed. 00274 00275 \param width 00276 is the number of character to print the value in. 00277 If the value does not fit in the width, the value is replace 00278 by width '*' characters. 00279 */ 00280 template <class Type> 00281 void printOpField( 00282 std::ostream &os , 00283 const char * leader , 00284 const Type &value , 00285 size_t width ) 00286 { 00287 std::ostringstream buffer; 00288 std::string str; 00289 00290 // first print the leader 00291 os << leader; 00292 00293 // print the value into an internal buffer 00294 buffer << std::setw(width) << value; 00295 str = buffer.str(); 00296 00297 // length of the string 00298 size_t len = str.size(); 00299 if( len > width ) 00300 { size_t i; 00301 for(i = 0; i < width-1; i++) 00302 os << str[i]; 00303 os << "*"; 00304 return; 00305 } 00306 00307 // count number of spaces at begining 00308 size_t nspace = 0; 00309 while(str[nspace] == ' ' && nspace < len) 00310 nspace++; 00311 00312 // left justify the string 00313 size_t i = nspace; 00314 while( i < len ) 00315 os << str[i++]; 00316 00317 i = width - len + nspace; 00318 while(i--) 00319 os << " "; 00320 } 00321 00322 /*! 00323 Prints a single operator, its operands, and the corresponding result values. 00324 00325 \tparam Base 00326 Is the base type for these AD< \a Base > operations. 00327 00328 \tparam Value 00329 Determines the type of the values that we are printing. 00330 00331 \param os 00332 is the output stream that the information is printed on. 00333 00334 \param Rec 00335 Is the entire recording for the tape that this operator is in. 00336 00337 \param i_var 00338 is the index for the variable corresponding to the result of this operation 00339 (ignored if NumRes(op) == 0). 00340 00341 \param op 00342 The operator code (OpCode) for this operation. 00343 00344 \param ind 00345 is the vector of argument indices for this operation 00346 (must have NumArg(op) elements). 00347 00348 \param nfz 00349 is the number of forward sweep calculated values of type Value 00350 that correspond to this operation 00351 (ignored if NumRes(op) == 0). 00352 00353 \param fz 00354 points to the first forward calculated value 00355 that correspond to this operation 00356 (ignored if NumRes(op) == 0). 00357 00358 \param nrz 00359 is the number of reverse sweep calculated values of type Value 00360 that correspond to this operation 00361 (ignored if NumRes(op) == 0). 00362 00363 \param rz 00364 points to the first reverse calculated value 00365 that correspond to this operation 00366 (ignored if NumRes(op) == 0). 00367 */ 00368 template <class Base, class Value> 00369 void printOp( 00370 std::ostream &os , 00371 const player<Base> *Rec , 00372 size_t i_var , 00373 OpCode op , 00374 const size_t *ind , 00375 size_t nfz , 00376 const Value *fz , 00377 size_t nrz , 00378 const Value *rz ) 00379 { size_t i; 00380 00381 static const char *CompareOpName[] = 00382 { "Lt", "Le", "Eq", "Ge", "Gt", "Ne" }; 00383 static const char *OpName[] = { 00384 "Abs" , 00385 "Acos" , 00386 "Addpv" , 00387 "Addvv" , 00388 "Asin" , 00389 "Atan" , 00390 "Begin" , 00391 "CExp" , 00392 "Com" , 00393 "Cos" , 00394 "Cosh" , 00395 "CSum" , 00396 "DisOp" , 00397 "Divpv" , 00398 "Divvp" , 00399 "Divvv" , 00400 "End" , 00401 "Exp" , 00402 "Ldp" , 00403 "Ldv" , 00404 "Inv" , 00405 "Log" , 00406 "Mulpv" , 00407 "Mulvv" , 00408 "Par" , 00409 "Powvp" , 00410 "Powpv" , 00411 "Powvv" , 00412 "Prip" , 00413 "Priv" , 00414 "Sin" , 00415 "Sinh" , 00416 "Sqrt" , 00417 "Stpp" , 00418 "Stvp" , 00419 "Stpv" , 00420 "Stvv" , 00421 "Subpv" , 00422 "Subvp" , 00423 "Subvv" , 00424 "Usrap" , 00425 "Usrav" , 00426 "User" , 00427 "Usrrp" , 00428 "Usrrv" 00429 }; 00430 CPPAD_ASSERT_UNKNOWN( 00431 size_t(UsrrvOp) == sizeof(OpName) / sizeof(OpName[0]) - 1 00432 ); 00433 00434 // print operator 00435 printOpField(os, "i=", i_var, 5); 00436 if( op == CExpOp ) 00437 { printOpField(os, "op=", OpName[op], 4); 00438 printOpField(os, "", CompareOpName[ ind[0] ], 3); 00439 } 00440 else if( op == ComOp ) 00441 { printOpField(os, "op=", OpName[op], 3); 00442 printOpField(os, "", CompareOpName[ ind[0] ], 4); 00443 } 00444 else printOpField(os, "op=", OpName[op], 7); 00445 00446 // print other fields 00447 size_t ncol = 5; 00448 switch( op ) 00449 { 00450 case CSumOp: 00451 /* 00452 ind[0] = number of addition variables in summation 00453 ind[1] = number of subtraction variables in summation 00454 ind[2] = index of parameter that initializes summation 00455 ind[3], ... , ind[2+ind[0]] = index for positive variables 00456 ind[3+ind[0]], ..., ind[2+ind[0]+ind[1]] = negative variables 00457 ind[3+ind[0]+ind[1]] = ind[0] + ind[1] 00458 */ 00459 CPPAD_ASSERT_UNKNOWN( ind[3+ind[0]+ind[1]] == ind[0]+ind[1] ); 00460 printOpField(os, " pr=", Rec->GetPar(ind[2]), ncol); 00461 for(i = 0; i < ind[0]; i++) 00462 printOpField(os, " +v=", ind[3+i], ncol); 00463 for(i = 0; i < ind[1]; i++) 00464 printOpField(os, " -v=", ind[3+ind[0]+i], ncol); 00465 break; 00466 00467 case LdpOp: 00468 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); 00469 printOpField(os, "off=", ind[0], ncol); 00470 printOpField(os, "idx=", ind[1], ncol); 00471 break; 00472 00473 case LdvOp: 00474 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); 00475 printOpField(os, "off=", ind[0], ncol); 00476 printOpField(os, " v=", ind[1], ncol); 00477 break; 00478 00479 case StppOp: 00480 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); 00481 printOpField(os, "off=", ind[0], ncol); 00482 printOpField(os, "idx=", ind[1], ncol); 00483 printOpField(os, " pr=", Rec->GetPar(ind[2]), ncol); 00484 break; 00485 00486 case StpvOp: 00487 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); 00488 printOpField(os, "off=", ind[0], ncol); 00489 printOpField(os, "idx=", ind[1], ncol); 00490 printOpField(os, " vr=", ind[2], ncol); 00491 break; 00492 00493 case StvpOp: 00494 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); 00495 printOpField(os, "off=", ind[0], ncol); 00496 printOpField(os, " vl=", ind[1], ncol); 00497 printOpField(os, " pr=", Rec->GetPar(ind[2]), ncol); 00498 break; 00499 00500 case StvvOp: 00501 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); 00502 printOpField(os, "off=", ind[0], ncol); 00503 printOpField(os, " vl=", ind[1], ncol); 00504 printOpField(os, " vr=", ind[2], ncol); 00505 break; 00506 00507 case AddvvOp: 00508 case DivvvOp: 00509 case MulvvOp: 00510 case PowvvOp: 00511 case SubvvOp: 00512 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); 00513 printOpField(os, " vl=", ind[0], ncol); 00514 printOpField(os, " vr=", ind[1], ncol); 00515 break; 00516 00517 case AddpvOp: 00518 case SubpvOp: 00519 case MulpvOp: 00520 case PowpvOp: 00521 case DivpvOp: 00522 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); 00523 printOpField(os, " pl=", Rec->GetPar(ind[0]), ncol); 00524 printOpField(os, " vr=", ind[1], ncol); 00525 break; 00526 00527 case DivvpOp: 00528 case PowvpOp: 00529 case SubvpOp: 00530 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); 00531 printOpField(os, " vl=", ind[0], ncol); 00532 printOpField(os, " pr=", Rec->GetPar(ind[1]), ncol); 00533 break; 00534 00535 case AbsOp: 00536 case AcosOp: 00537 case AsinOp: 00538 case AtanOp: 00539 case CosOp: 00540 case CoshOp: 00541 case ExpOp: 00542 case LogOp: 00543 case SinOp: 00544 case SinhOp: 00545 case SqrtOp: 00546 case UsravOp: 00547 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); 00548 printOpField(os, " v=", ind[0], ncol); 00549 break; 00550 00551 case ParOp: 00552 case UsrapOp: 00553 case UsrrpOp: 00554 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); 00555 printOpField(os, " p=", Rec->GetPar(ind[0]), ncol); 00556 break; 00557 00558 case UserOp: 00559 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); 00560 { const char* name = user_atomic<Base>::name(ind[0]); 00561 printOpField(os, " f=", name, ncol); 00562 printOpField(os, " i=", ind[1], ncol); 00563 printOpField(os, " n=", ind[2], ncol); 00564 printOpField(os, " m=", ind[3], ncol); 00565 } 00566 break; 00567 00568 case PripOp: 00569 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); 00570 os << "txt=\"" << Rec->GetTxt(ind[0]); 00571 os << "\" p=" << Rec->GetPar(ind[1]); 00572 break; 00573 00574 case PrivOp: 00575 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); 00576 os << "txt=\"" << Rec->GetTxt(ind[0]); 00577 os << "\" v=" << ind[1]; 00578 break; 00579 00580 case BeginOp: 00581 case EndOp: 00582 case InvOp: 00583 case UsrrvOp: 00584 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); 00585 break; 00586 00587 case DisOp: 00588 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); 00589 { const char* name = discrete<Base>::name(ind[0]); 00590 printOpField(os, " f=", name, ncol); 00591 printOpField(os, " x=", ind[1], ncol); 00592 } 00593 break; 00594 00595 00596 case CExpOp: 00597 CPPAD_ASSERT_UNKNOWN(ind[1] != 0); 00598 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 6 ); 00599 if( ind[1] & 1 ) 00600 printOpField(os, " vl=", ind[2], ncol); 00601 else printOpField(os, " pl=", Rec->GetPar(ind[2]), ncol); 00602 if( ind[1] & 2 ) 00603 printOpField(os, " vr=", ind[3], ncol); 00604 else printOpField(os, " pr=", Rec->GetPar(ind[3]), ncol); 00605 if( ind[1] & 4 ) 00606 printOpField(os, " vt=", ind[4], ncol); 00607 else printOpField(os, " pt=", Rec->GetPar(ind[4]), ncol); 00608 if( ind[1] & 8 ) 00609 printOpField(os, " vf=", ind[5], ncol); 00610 else printOpField(os, " pf=", Rec->GetPar(ind[5]), ncol); 00611 break; 00612 00613 case ComOp: 00614 CPPAD_ASSERT_UNKNOWN(ind[1] != 0); 00615 CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); 00616 if( ind[1] & 1 ) 00617 printOpField(os, "res=", 1, ncol); 00618 else printOpField(os, "res=", 0, ncol); 00619 if( ind[1] & 2 ) 00620 printOpField(os, " vl=", ind[2], ncol); 00621 else printOpField(os, " pl=", Rec->GetPar(ind[2]), ncol); 00622 if( ind[1] & 4 ) 00623 printOpField(os, " vr=", ind[3], ncol); 00624 else printOpField(os, " pr=", Rec->GetPar(ind[3]), ncol); 00625 break; 00626 00627 default: 00628 CPPAD_ASSERT_UNKNOWN(0); 00629 } 00630 size_t k; 00631 if( NumRes(op) > 0 && (op != BeginOp) ) 00632 { 00633 for(k = 0; k < nfz; k++) 00634 std::cout << "| fz[" << k << "]=" << fz[k]; 00635 for(k = 0; k < nrz; k++) 00636 std::cout << "| rz[" << k << "]=" << rz[k]; 00637 } 00638 std::cout << std::endl; 00639 } 00640 00641 CPPAD_END_NAMESPACE 00642 # endif