CppAD: A C++ Algorithmic Differentiation Package 20110419
op_code.hpp
Go to the documentation of this file.
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