Changeset 2991


Ignore:
Timestamp:
Oct 22, 2013 12:25:15 PM (6 years ago)
Author:
bradbell
Message:

merger in changes from branches/opt_cond_exp

Location:
trunk
Files:
28 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/bin/svn_merge.sh

    r2859 r2991  
    22# $Id$
    33# -----------------------------------------------------------------------------
    4 # CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     4# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    55#
    66# CppAD is distributed under multiple licenses. This distribution is under
     
    3333#
    3434# Name of the directory where the changes have been committed
    35 from_branch='branches/atomic'
     35from_branch='branches/opt_cond_exp'
    3636#
    3737# Version of the repository corresponding to from_branch just before changes
    38 Start=2797
     38Start=2952
    3939#
    4040# Version of the repository corresponding to from_branch after the changes
    41 End=2858
     41End=2990
    4242#
    4343# the svn merge command
  • trunk/cppad/local/ad_fun.hpp

    r2910 r2991  
    109109        pod_vector<Base> taylor_;
    110110
     111        /// which operations can be conditionally skipped
     112        /// Set during forward pass of order zero
     113        CppAD::vector<bool> cskip_op_;
     114
    111115        /// Packed results of the forward mode Jacobian sparsity calculations.
    112116        /// for_jac_sparse_pack_.n_set() != 0  implies other sparsity results
     
    428432        /// set number of coefficients currently allocated (per variable)
    429433        void capacity_taylor(size_t per_var);   
     434
     435        /// number of variables in conditional expressions that can be skipped
     436        size_t number_skip(void);   
    430437
    431438        /// number of independent variables
  • trunk/cppad/local/comp_op.hpp

    r2910 r2991  
    44
    55/* --------------------------------------------------------------------------
    6 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    77
    88CppAD is distributed under multiple licenses. This distribution is under
     
    2020\{
    2121\file comp_op.hpp
    22 Zero order forward mode check how man comparisons changed.
     22Zero order forward mode check how many comparisons changed.
    2323*/
    2424
  • trunk/cppad/local/dependent.hpp

    r2506 r2991  
    44
    55/* --------------------------------------------------------------------------
    6 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    77
    88CppAD is distributed under multiple licenses. This distribution is under
     
    270270        total_num_var_ = tape->Rec_.num_rec_var();
    271271
     272        // conditional skip vector
     273        cskip_op_.clear();
     274        cskip_op_.resize( tape->Rec_.num_rec_op() );
     275        for(i = 0; i < cskip_op_.size(); i++)
     276                cskip_op_[i] = false;
     277
    272278        // now that each dependent variable has a place in the tape,
    273279        // and there is a EndOp at the end of the tape, we can transfer the
  • trunk/cppad/local/for_jac_sweep.hpp

    r2910 r2991  
    189189        play->start_forward(op, arg, i_op, i_var);
    190190        CPPAD_ASSERT_UNKNOWN( op == BeginOp );
    191         while(op != EndOp)
     191        bool more_operators = true;
     192        while(more_operators)
    192193        {
    193194                // this op
     
    247248                                i_var, arg[0], var_sparsity
    248249                        );
     250                        break;
     251                        // -------------------------------------------------
     252
     253                        case CSkipOp:
     254                        // CSipOp has a variable number of arguments and
     255                        // next_forward thinks it one has one argument.
     256                        // we must inform next_forward of this special case.
     257                        play->forward_cskip(op, arg, i_op, i_var);
    249258                        break;
    250259                        // -------------------------------------------------
     
    324333                        case EndOp:
    325334                        CPPAD_ASSERT_NARG_NRES(op, 0, 0);
     335                        more_operators = false;
    326336                        break;
    327337                        // -------------------------------------------------
     
    698708                        std::cout,
    699709                        play,
     710                        i_op,
    700711                        i_var,
    701712                        op,
  • trunk/cppad/local/forward.hpp

    r2910 r2991  
    2222        omh/forward.omh%
    2323        cppad/local/cap_taylor.hpp%
     24        cppad/local/num_skip.hpp%
    2425        example/forward.cpp%
    2526        example/forward_mul.cpp
     
    3233// documened after Forward but included here so easy to see
    3334# include <cppad/local/cap_taylor.hpp>
     35# include <cppad/local/num_skip.hpp>
    3436
    3537namespace CppAD { // BEGIN_CPPAD_NAMESPACE
     
    122124# if CPPAD_USE_FORWARD0SWEEP
    123125                compare_change_ = forward0sweep(s, true,
    124                         n, total_num_var_, &play_, taylor_col_dim_, taylor_.data()
     126                        n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(),
     127                        cskip_op_
    125128                );
    126129# else
    127130                compare_change_ = forward_sweep(s, true, q,
    128                         p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data()
     131                        p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(),
     132                        cskip_op_
    129133                );
    130134# endif
     
    132136        else if( q == 0 )
    133137        {       compare_change_ = forward_sweep(s, true, q,
    134                         p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data()
     138                        p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(),
     139                        cskip_op_
    135140                );
    136141        }
    137142        else
    138143        {       forward_sweep(s, true, q,
    139                         p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data()
     144                        p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(),
     145                        cskip_op_
    140146                );
    141147        }
  • trunk/cppad/local/forward0sweep.hpp

    r2910 r2991  
    7575
    7676\param Rec
     772DO: change this name from Rec to play (becuase it is a player
     78and not a recorder).
    7779The information stored in \a Rec
    7880is a recording of the operations corresponding to the function
     
    111113index i on the tape.
    112114
     115\param cskip_op
     116Is a vector with size Rec->num_rec_op(),
     117the input value of the elements does not matter.
     118Upon return, if cskip_op[i] is true, the operator index i in the recording
     119does not affect any of the dependent variable (given the value
     120of the independent variables).
     121
    113122\a return
    114123The return value is equal to the number of ComOp operations
     
    127136        player<Base>         *Rec,
    128137        size_t                J,
    129         Base                 *Taylor
     138        Base                 *Taylor,
     139        CppAD::vector<bool>&  cskip_op
    130140)
    131141{       CPPAD_ASSERT_UNKNOWN( J >= 1 );
     
    159169                }
    160170        }
     171
     172        // zero order, so initialize conditional skip flags
     173        for(i = 0; i < Rec->num_rec_op(); i++)
     174                cskip_op[i] = false;
    161175
    162176        // work space used by UserOp.
     
    207221        std::cout << std::endl;
    208222# endif
    209         while(op != EndOp)
     223        bool more_operators = true;
     224        while(more_operators)
    210225        {
    211226                // this op
    212227                Rec->next_forward(op, arg, i_op, i_var);
    213 # ifndef NDEBUG
    214                 if( i_op <= n )
    215                 {       CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp));
     228                CPPAD_ASSERT_UNKNOWN( (i_op > n)  | (op == InvOp) ); 
     229                CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) ); 
     230
     231                // check if we are skipping this operation
     232                while( cskip_op[i_op] )
     233                {       if( op == CSumOp )
     234                        {       // CSumOp has a variable number of arguments
     235                                Rec->forward_csum(op, arg, i_op, i_var);
     236                        }
     237                        Rec->next_forward(op, arg, i_op, i_var);
    216238                }
    217                 else    CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
    218 # endif
    219239
    220240                // action to take depends on the case
     
    255275                        CPPAD_ASSERT_UNKNOWN( i_var < numvar  );
    256276                        forward_atan_op_0(i_var, arg[0], J, Taylor);
     277                        break;
     278                        // -------------------------------------------------
     279
     280                        case CExpOp:
     281                        // Use the general case with d == 0
     282                        // (could create an optimzied verison for this case)
     283                        forward_cond_op_0(
     284                                i_var, arg, num_par, parameter, J, Taylor
     285                        );
     286                        break;
     287                        // ---------------------------------------------------
     288                        case ComOp:
     289                        forward_comp_op_0(
     290                        compareCount, arg, num_par, parameter, J, Taylor
     291                        );
     292                        break;
     293                        // ---------------------------------------------------
     294
     295                        case CosOp:
     296                        // sin(x), cos(x)
     297                        CPPAD_ASSERT_UNKNOWN( i_var < numvar  );
     298                        forward_cos_op_0(i_var, arg[0], J, Taylor);
     299                        break;
     300                        // ---------------------------------------------------
     301
     302                        case CoshOp:
     303                        // sinh(x), cosh(x)
     304                        CPPAD_ASSERT_UNKNOWN( i_var < numvar  );
     305                        forward_cosh_op_0(i_var, arg[0], J, Taylor);
     306                        break;
     307                        // -------------------------------------------------
     308
     309                        case CSkipOp:
     310                        // CSkipOp has a variable number of arguments and
     311                        // next_forward thinks it one has one argument.
     312                        // we must inform next_forward of this special case.
     313                        Rec->forward_cskip(op, arg, i_op, i_var);
     314                        forward_cskip_op_0(
     315                                i_var, arg, num_par, parameter, J, Taylor, cskip_op
     316                        );
    257317                        break;
    258318                        // -------------------------------------------------
     
    267327                        );
    268328                        break;
    269 
    270                         // -------------------------------------------------
    271                         case CExpOp:
    272                         // Use the general case with d == 0
    273                         // (could create an optimzied verison for this case)
    274                         forward_cond_op_0(
    275                                 i_var, arg, num_par, parameter, J, Taylor
    276                         );
    277                         break;
    278                         // ---------------------------------------------------
    279                         case ComOp:
    280                         forward_comp_op_0(
    281                         compareCount, arg, num_par, parameter, J, Taylor
    282                         );
    283                         break;
    284                         // ---------------------------------------------------
    285 
    286                         case CosOp:
    287                         // sin(x), cos(x)
    288                         CPPAD_ASSERT_UNKNOWN( i_var < numvar  );
    289                         forward_cos_op_0(i_var, arg[0], J, Taylor);
    290                         break;
    291                         // ---------------------------------------------------
    292 
    293                         case CoshOp:
    294                         // sinh(x), cosh(x)
    295                         CPPAD_ASSERT_UNKNOWN( i_var < numvar  );
    296                         forward_cosh_op_0(i_var, arg[0], J, Taylor);
    297                         break;
    298329                        // -------------------------------------------------
    299330
     
    322353                        case EndOp:
    323354                        CPPAD_ASSERT_NARG_NRES(op, 0, 0);
     355                        more_operators = false;
    324356                        break;
    325357                        // -------------------------------------------------
     
    626658
    627659                        default:
    628                         CPPAD_ASSERT_UNKNOWN(0);
     660                        CPPAD_ASSERT_UNKNOWN(false);
    629661                }
    630662# if CPPAD_FORWARD0SWEEP_TRACE
     
    636668                        std::cout,
    637669                        Rec,
     670                        i_op,
    638671                        i_tmp,
    639672                        op,
  • trunk/cppad/local/forward_sweep.hpp

    r2910 r2991  
    8383
    8484\param Rec
     852DO: change this name from Rec to play (becuase it is a player
     86and not a recorder).
    8587The information stored in \a Rec
    8688is a recording of the operations corresponding to the function
     
    120122index i on the tape.
    121123
     124\param cskip_op
     125Is a vector with size \c numvar,
     126
     127\li <tt>q = 0</tt>
     128In this case,
     129the input value of the elements does not matter.
     130Upon return, if cskip_op[i] is true, the operator with index i
     131does not affect any of the dependent variable (given the value
     132of the independent variables).
     133
     134\li <tt>q > 0</tt>
     135The vector is not modified and
     136if cskip_op[i] is true, the operator with index i
     137does not affect any of the dependent variable (given the value
     138of the independent variables).
     139
    122140\a return
    123141If \a p is not zero, the return value is zero.
     
    139157        const size_t          numvar,
    140158        player<Base>         *Rec,
    141         const size_t         J,
    142         Base                 *Taylor
     159        const size_t          J,
     160        Base                 *Taylor,
     161        CppAD::vector<bool>&  cskip_op
    143162)
    144163{       CPPAD_ASSERT_UNKNOWN( J >= p + 1 );
     
    166185        size_t compareCount = 0;
    167186
    168         // if this is an order zero calculation, initialize vector indices
    169187        pod_vector<size_t> VectorInd;  // address for each element
    170188        pod_vector<bool>   VectorVar;  // is element a variable
    171         i = Rec->num_rec_vecad_ind();
    172         if( i > 0 )
    173         {       VectorInd.extend(i);
    174                 VectorVar.extend(i);
    175                 while(i--)
    176                 {       VectorInd[i] = Rec->GetVecInd(i);
    177                         VectorVar[i] = false;
     189        if( q == 0 )
     190        {
     191                // this includes order zero calculation, initialize vector indices
     192                i = Rec->num_rec_vecad_ind();
     193                if( i > 0 )
     194                {       VectorInd.extend(i);
     195                        VectorVar.extend(i);
     196                        while(i--)
     197                        {       VectorInd[i] = Rec->GetVecInd(i);
     198                                VectorVar[i] = false;
     199                        }
    178200                }
     201                // includes zero order, so initialize conditional skip flags
     202                for(i = 0; i < Rec->num_rec_op(); i++)
     203                        cskip_op[i] = false;
    179204        }
    180205
     
    226251        std::cout << std::endl;
    227252# endif
    228         while(op != EndOp)
     253        bool more_operators = true;
     254        while(more_operators)
    229255        {
    230256                // this op
     
    233259                CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) ); 
    234260
     261                // check if we are skipping this operation
     262                while( cskip_op[i_op] )
     263                {       if( op == CSumOp )
     264                        {       // CSumOp has a variable number of arguments
     265                                Rec->forward_csum(op, arg, i_op, i_var);
     266                        }
     267                        Rec->next_forward(op, arg, i_op, i_var);
     268                }
     269
    235270                // action depends on the operator
    236271                switch( op )
     
    298333                        CPPAD_ASSERT_UNKNOWN( i_var < numvar  );
    299334                        forward_cosh_op(q, p, i_var, arg[0], J, Taylor);
     335                        break;
     336                        // -------------------------------------------------
     337
     338                        case CSkipOp:
     339                        // CSkipOp has a variable number of arguments and
     340                        // next_forward thinks it one has one argument.
     341                        // we must inform next_forward of this special case.
     342                        Rec->forward_cskip(op, arg, i_op, i_var);
     343                        if( q == 0 )
     344                        {       forward_cskip_op_0(
     345                                        i_var, arg, num_par, parameter, J, Taylor, cskip_op
     346                                );
     347                        }
    300348                        break;
    301349                        // -------------------------------------------------
     
    344392                        case EndOp:
    345393                        CPPAD_ASSERT_NARG_NRES(op, 0, 0);
     394                        more_operators = false;
    346395                        break;
    347396                        // -------------------------------------------------
     
    697746                        std::cout,
    698747                        Rec,
     748                        i_op,
    699749                        i_tmp,
    700750                        op,
  • trunk/cppad/local/fun_construct.hpp

    r2910 r2991  
    325325                }
    326326        }
     327
     328        // allocate and copy the conditional skip information
     329        cskip_op_.clear();
     330        cskip_op_ = f.cskip_op_;
    327331
    328332        // allocate and copy the forward sparsity information
     
    452456# if CPPAD_USE_FORWARD0SWEEP
    453457        compare_change_ = forward0sweep(std::cout, false,
    454                 n, total_num_var_, &play_, taylor_col_dim_, taylor_.data()
     458                n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(),
     459                cskip_op_
    455460        );
    456461# else
    457462        size_t p = 0;
    458463        compare_change_ = forward_sweep(std::cout, false,
    459                 p, p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data()
     464                p, p, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(),
     465                cskip_op_
    460466        );
    461467# endif
  • trunk/cppad/local/independent.hpp

    r2506 r2991  
    44
    55/* --------------------------------------------------------------------------
    6 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    77
    88CppAD is distributed under multiple licenses. This distribution is under
     
    136136        // mark the beginning of the tape and skip the first variable index
    137137        // (zero) because parameters use taddr zero
    138         CPPAD_ASSERT_NARG_NRES(BeginOp, 0, 1);
     138        CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1);
    139139        Rec_.PutOp(BeginOp);
     140        Rec_.PutArg(0);
    140141
    141142        // place each of the independent variables in the tape
  • trunk/cppad/local/op.hpp

    r2506 r2991  
    44
    55/* --------------------------------------------------------------------------
    6 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    77
    88CppAD is distributed under multiple licenses. This distribution is under
     
    2828# include <cppad/local/cos_op.hpp>
    2929# include <cppad/local/cosh_op.hpp>
     30# include <cppad/local/cskip_op.hpp>
    3031# include <cppad/local/csum_op.hpp>
    3132# include <cppad/local/discrete_op.hpp>
  • trunk/cppad/local/op_code.hpp

    r2957 r2991  
    5656        AtanOp,   // atan(variable)
    5757        BeginOp,  // used to mark the beginning of the tape
    58         CExpOp,   // CondExp(cop, left, right, trueCase, falseCase)
     58        CExpOp,   // CondExpRel(left, right, trueCase, falseCase)
     59        // arg[0]     = the Rel operator: Lt, Le, Eq, Ge, Gt, or Ne
     60        // arg[1] & 1 = is left a variable
     61        // arg[1] & 2 = is right a variable
     62        // arg[1] & 4 = is trueCase a variable
     63        // arg[1] & 8 = is falseCase a variable
     64        // arg[2]     = index correspoding to left
     65        // arg[3]     = index correspoding to right
     66        // arg[4]     = index correspoding to trueCase
     67        // arg[5]     = index correspoding to falseCase
    5968        ComOp,    // Compare(cop, result, left, right)
    6069        CosOp,    //  cos(variable)
    6170        CoshOp,   // cosh(variable)
     71        CSkipOp,  // Conditional skip
     72        // arg[0]     = the Rel operator: Lt, Le, Eq, Ge, Gt, or Ne
     73        // arg[1] & 1 = is left a variable
     74        // arg[1] & 2 = is right a variable
     75        // arg[2]     = index correspoding to left
     76        // arg[3]     = index correspoding to right
     77        // arg[4] = number of operations to skip if CExpOp comparision is true
     78        // arg[5] = number of operations to skip if CExpOp comparision is false
     79        // arg[6] -> arg[5+arg[4]]               = skip operations if true
     80        // arg[6+arg[4]] -> arg[5+arg[4]+arg[5]] = skip operations if false
     81        // arg[6+arg[4]+arg[5]] = arg[4] + arg[5]
    6282        CSumOp,   // Cummulative summation
    6383        // arg[0] = number of addition variables in summation
     
    99119        // user atomic operation codes
    100120        UserOp,   //  start of a user atomic operaiton
     121        // arg[0] = index of the operation if atomic_base<Base> class
     122        // arg[1] = extra information passed trough by deprecated old atomic class
     123        // arg[2] = number of arguments to this atomic function
     124        // arg[3] = number of results for this atomic function
    101125        UsrapOp,  //  this user atomic argument is a parameter
    102126        UsravOp,  //  this user atomic argument is a variable
     
    129153        1, // AsinOp
    130154        1, // AtanOp
    131         0, // BeginOp
     155        1, // BeginOp  offset first real argument to have index 1
    132156        6, // CExpOp
    133157        4, // ComOp
    134158        1, // CosOp
    135159        1, // CoshOp
     160        0, // CSkipOp  (actually has a variable number of arguments, not zero)
    136161        0, // CSumOp   (actually has a variable number of arguments, not zero)
    137162        2, // DisOp
     
    232257        2, // CosOp
    233258        2, // CoshOp
     259        0, // CSkipOp
    234260        1, // CSumOp
    235261        1, // DisOp
     
    369395
    370396\param Rec
     3972DO: change this name from Rec to play (becuase it is a player
     398and not a recorder).
    371399Is the entire recording for the tape that this operator is in.
     400
     401\param i_op
     402is the index for the operator corresponding to this operation.
    372403
    373404\param i_var
     
    401432that correspond to this operation
    402433(ignored if NumRes(op) == 0).
     434
     435\par 2DO
     436print the operator index (in addition to the variables index).
    403437*/
    404438template <class Base, class Value>
     
    406440        std::ostream          &os     ,
    407441        const player<Base>   *Rec     ,
     442        size_t                 i_op   ,
    408443        size_t                 i_var  ,
    409444        OpCode                 op     ,
     
    433468                "Cos"   ,
    434469                "Cosh"  ,
     470                "CSkip" ,
    435471                "CSum"  ,
    436472                "Dis"   ,
     
    475511
    476512        // print operator
    477         printOpField(os,  "i=",      i_var, 5);
    478         if( op == CExpOp )
    479         {       printOpField(os, "op=", OpName[op], 4);
     513        printOpField(os,  "o=",      i_op,  5);
     514        printOpField(os,  "v=",      i_var, 5);
     515        if( op == CExpOp || op == CSkipOp || op == ComOp )
     516        {       printOpField(os, "", OpName[op], 5);
    480517                printOpField(os, "", CompareOpName[ ind[0] ], 3);
    481518        }
    482         else if( op == ComOp )
    483         {       printOpField(os, "op=", OpName[op], 3);
    484                 printOpField(os, "", CompareOpName[ ind[0] ], 4);
    485         }
    486         else    printOpField(os, "op=", OpName[op], 7);
     519        else    printOpField(os, "", OpName[op], 8);
    487520
    488521        // print other fields
     
    490523        switch( op )
    491524        {
     525                case CSkipOp:
     526                /*
     527                ind[0]     = the Rel operator: Lt, Le, Eq, Ge, Gt, or Ne
     528                ind[1] & 1 = is left a variable
     529                ind[1] & 2 = is right a variable
     530                ind[2]     = index correspoding to left
     531                ind[3]     = index correspoding to right
     532                ind[4] = number of operations to skip if CExpOp comparision is true
     533                ind[5] = number of operations to skip if CExpOp comparision is false
     534                ind[6] -> ind[5+ind[4]]               = skip operations if true
     535                ind[6+ind[4]] -> ind[5+ind[4]+ind[5]] = skip operations if false
     536                ind[6+ind[4]+ind[5]] = ind[4] + ind[5]
     537                */
     538                CPPAD_ASSERT_UNKNOWN( ind[6+ind[4]+ind[5]] == ind[4]+ind[5] );
     539                CPPAD_ASSERT_UNKNOWN(ind[1] != 0);
     540                if( ind[1] & 1 )
     541                        printOpField(os, " vl=", ind[2], ncol);
     542                else    printOpField(os, " pl=", Rec->GetPar(ind[2]), ncol);
     543                if( ind[1] & 2 )
     544                        printOpField(os, " vr=", ind[3], ncol);
     545                else    printOpField(os, " pr=", Rec->GetPar(ind[3]), ncol);
     546                if( size_t(ind[4]) < 3 )
     547                {       for(i = 0; i < size_t(ind[4]); i++)
     548                                printOpField(os, " ot=", ind[6+i], ncol);
     549                }
     550                else
     551                {       printOpField(os, "\n\tot=", ind[6+0], ncol);
     552                        for(i = 1; i < size_t(ind[4]); i++)
     553                                printOpField(os, " ot=", ind[6+i], ncol);
     554                }
     555                if( size_t(ind[5]) < 3 )
     556                {       for(i = 0; i < size_t(ind[5]); i++)
     557                                printOpField(os, " of=", ind[6+ind[4]+i], ncol);
     558                }
     559                else
     560                {       printOpField(os, "\n\tof=", ind[6+ind[4]+0], ncol);
     561                        {       for(i = 1; i < size_t(ind[5]); i++)
     562                                        printOpField(os, " of=", ind[6+ind[4]+i], ncol);
     563                        }
     564                }
     565                break;
     566
    492567                case CSumOp:
    493568                /*
  • trunk/cppad/local/optimize.hpp

    r2975 r2991  
    146146State for this variable set during reverse sweep.
    147147*/
    148 enum optimize_connection {
     148enum optimize_connection_type {
    149149        /// There is no operation that connects this variable to the
    150150        /// independent variables.
    151         not_connected     ,
     151        not_connected        ,
    152152
    153153        /// There is one or more operations that connects this variable to the
    154154        /// independent variables.
    155         yes_connected      ,
    156 
    157         /// There is only one parrent operation that connects this variable to
    158         /// the independent variables and it is one of the following:
    159         ///  AddvvOp, AddpvOp, SubpvOp, SubvpOp, or SubvvOp.
    160         sum_connected      ,
    161 
    162         /// Satisfies sum_connected and in addition
    163         /// the parrent operation is one of the following:
    164         ///  AddvvOp, AddpvOp, SubpvOp, SubvpOp, or SubvvOp.
    165         csum_connected
    166 
     155        yes_connected        ,
     156
     157        /// There is only one parrent that connects this variable to the
     158        /// independent variables and the parent is a summation operation; i.e.,
     159        /// AddvvOp, AddpvOp, SubpvOp, SubvpOp, or SubvvOp.
     160        sum_connected        ,
     161
     162        /// Satisfies the sum_connected assumptions above and in addition
     163        /// this variable is the result of summation operator.
     164        csum_connected       ,
     165
     166        /// This node is only connected in the case where the comparision is
     167        /// true for the conditional expression with index \c connect_index.
     168        cexp_true_connected  ,
     169
     170        /// This node is only connected in the case where the comparision is
     171        /// false for the conditional expression with index \c connect_index.
     172        cexp_false_connected
    167173};
    168174
     
    182188
    183189        /// How is this variable connected to the independent variables
    184         optimize_connection connect;
    185 
    186         /// Set during forward sweep to the index in the
    187         /// new operation sequence corresponding to this old varable.
     190        optimize_connection_type connect_type;
     191
     192        /*!
     193        The meaning of this index depends on \c connect_type as follows:
     194
     195        \par cexp_flag_connected
     196        For flag equal to ture or false, \c connect_index is the index of the
     197        conditional expression corresponding to this connection.
     198        */
     199        size_t connect_index;
     200
     201        /// New operation sequence corresponding to this old varable.
     202        /// Set during forward sweep to the index in the new tape
    188203        addr_t new_var;
     204
     205        /// New operator index for this varable.
     206        /// Set during forward sweep to the index in the new tape
     207        size_t new_op;
     208};
     209
     210struct optimize_size_pair {
     211        size_t i_op;  // an operator index
     212        size_t i_var; // a variable index
    189213};
    190214
     
    219243};
    220244
     245/*!
     246CExpOp information that is copied to corresponding CSkipOp
     247*/
     248struct optimize_cskip_info {
     249        /// comparision operator
     250        CompareOp cop;
     251        /// (flag & 1) is true if and only if left is a variable
     252        /// (flag & 2) is true if and only if right is a variable
     253        size_t flag;
     254        /// index for left comparison operand
     255        size_t left;
     256        /// index for right comparison operand
     257        size_t right;
     258        /// set of variables to skip on true
     259        CppAD::vector<size_t> skip_var_true;
     260        /// set of variables to skip on false
     261        CppAD::vector<size_t> skip_var_false;
     262        /// set of operations to skip on true
     263        CppAD::vector<size_t> skip_op_true;
     264        /// set of operations to skip on false
     265        CppAD::vector<size_t> skip_op_false;
     266        /// size of skip_op_true
     267        size_t n_op_true;
     268        /// size of skip_op_false
     269        size_t n_op_false;
     270        /// index in the argument recording of first argument for this CSkipOp
     271        size_t i_arg;
     272};
     273/*!
     274Connection information for a user atomic function
     275*/
     276struct optimize_user_info {
     277        /// type of connection for this atomic function
     278        optimize_connection_type connect_type;
     279        /// If this is an conditional connection, this is the index
     280        /// of the correpsonding CondExpOp
     281        size_t connect_index;
     282        /// If this is a conditional connection, this is the operator
     283        /// index of the beginning of the atomic call sequence; i.e.,
     284        /// the first UserOp.
     285        size_t op_begin;
     286        /// If this is a conditional connection, this is one more than the
     287        ///  operator index of the ending of the atomic call sequence; i.e.,
     288        /// the second UserOp.
     289        size_t op_end;
     290};
    221291
    222292/*!
     
    646716
    647717\return
    648 the result value is the index corresponding to the current
     718the result is the operaiton and variable index corresponding to the current
    649719operation in the new operation sequence.
    650720*/
    651721template <class Base>
    652 size_t optimize_record_pv(
     722optimize_size_pair optimize_record_pv(
    653723        const CppAD::vector<struct optimize_old_variable>& tape           ,
    654724        size_t                                             current        ,
     
    678748        new_arg[1]   = tape[ arg[1] ].new_var;
    679749        rec->PutArg( new_arg[0], new_arg[1] );
    680         size_t i     = rec->PutOp(op);
    681         CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < i );
    682         return i;
     750
     751        optimize_size_pair ret;
     752        ret.i_op  = rec->num_rec_op();
     753        ret.i_var = rec->PutOp(op);
     754        CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < ret.i_var );
     755        return ret;
    683756}
    684757
     
    745818
    746819\return
    747 the result value is the index corresponding to the current
     820the result operation and variable index corresponding to the current
    748821operation in the new operation sequence.
    749822*/
    750823template <class Base>
    751 size_t optimize_record_vp(
     824optimize_size_pair optimize_record_vp(
    752825        const CppAD::vector<struct optimize_old_variable>& tape           ,
    753826        size_t                                             current        ,
     
    775848        new_arg[1]   = rec->PutPar( par[arg[1]] );
    776849        rec->PutArg( new_arg[0], new_arg[1] );
    777         size_t i     = rec->PutOp(op);
    778         CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < i );
    779         return i;
     850
     851        optimize_size_pair ret;
     852        ret.i_op  = rec->num_rec_op();
     853        ret.i_var = rec->PutOp(op);
     854        CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < ret.i_var );
     855        return ret;
    780856}
    781857
     
    841917
    842918\return
    843 the result value is the index corresponding to the current
     919the result is the operation and variable index corresponding to the current
    844920operation in the new operation sequence.
    845921*/
    846922template <class Base>
    847 size_t optimize_record_vv(
     923optimize_size_pair optimize_record_vv(
    848924        const CppAD::vector<struct optimize_old_variable>& tape           ,
    849925        size_t                                             current        ,
     
    873949        new_arg[1]   = tape[ arg[1] ].new_var;
    874950        rec->PutArg( new_arg[0], new_arg[1] );
    875         size_t i     = rec->PutOp(op);
    876         CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < i );
    877         return i;
     951
     952        optimize_size_pair ret;
     953        ret.i_op  = rec->num_rec_op();
     954        ret.i_var = rec->PutOp(op);
     955        CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < ret.i_var );
     956        CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < ret.i_var );
     957        return ret;
    878958}
    879959
     
    9451025<tt>tape[i].new_var</tt>
    9461026is not yet defined for any node \c i that is \c csum_connected
    947 to the \a current node.
     1027to the \a current node
     1028(or that is \c sum_connected to a node that is \c csum_connected).
    9481029For example; suppose that index \c j corresponds to a variable
    9491030in the current operator,
    9501031<tt>i = tape[current].arg[j]</tt>,
    9511032and
    952 <tt>tape[arg[j]].connect == csum_connected</tt>.
     1033<tt>tape[arg[j]].connect_type == csum_connected</tt>.
    9531034It then follows that
    9541035<tt>tape[i].new_var == tape.size()</tt>.
     
    9581039must be one of <tt>AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp</tt>.
    9591040
    960 \li <tt>tape[current].connect</tt> must be \c yes_connected.
     1041\li <tt>tape[current].connect_type</tt> must be \c yes_connected.
     1042
     1043\li <tt>tape[j].connect_type == csum_connected</tt> for some index
     1044j that is a variable operand for the current operation.
    9611045*/
    9621046
    9631047
    9641048template <class Base>
    965 size_t optimize_record_csum(
     1049optimize_size_pair optimize_record_csum(
    9661050        const CppAD::vector<struct optimize_old_variable>& tape           ,
    9671051        size_t                                             current        ,
     
    9751059        CPPAD_ASSERT_UNKNOWN( work.add_stack.empty() );
    9761060        CPPAD_ASSERT_UNKNOWN( work.sub_stack.empty() );
    977         CPPAD_ASSERT_UNKNOWN( tape[current].connect == yes_connected );
     1061        CPPAD_ASSERT_UNKNOWN( tape[current].connect_type == yes_connected );
    9781062
    9791063        size_t                        i;
     
    9881072        work.op_stack.push( var );
    9891073        Base sum_par(0);
     1074
     1075# ifndef NDEBUG
     1076        bool ok = false;
     1077        if( var.op == SubvpOp )
     1078                ok = tape[ tape[current].arg[0] ].connect_type == csum_connected;
     1079        if( var.op == AddpvOp || var.op == SubpvOp )
     1080                ok = tape[ tape[current].arg[1] ].connect_type == csum_connected;
     1081        if( var.op == AddvvOp || var.op == SubvvOp )
     1082        {       ok  = tape[ tape[current].arg[0] ].connect_type == csum_connected;
     1083                ok |= tape[ tape[current].arg[1] ].connect_type == csum_connected;
     1084        }
     1085        CPPAD_ASSERT_UNKNOWN( ok );
     1086# endif
    9901087        while( ! work.op_stack.empty() )
    9911088        {       var     = work.op_stack.top();
     
    10071104                        case SubvpOp:
    10081105                        case SubvvOp:
    1009                         if( tape[arg[0]].connect == csum_connected )
     1106                        if( tape[arg[0]].connect_type == csum_connected )
    10101107                        {       CPPAD_ASSERT_UNKNOWN(
    10111108                                        size_t(tape[arg[0]].new_var) == tape.size()
     
    10401137                        case AddvvOp:
    10411138                        case AddpvOp:
    1042                         if( tape[arg[1]].connect == csum_connected )
     1139                        if( tape[arg[1]].connect_type == csum_connected )
    10431140                        {       CPPAD_ASSERT_UNKNOWN(
    10441141                                        size_t(tape[arg[1]].new_var) == tape.size()
     
    10831180        }
    10841181        rec->PutArg(n_add + n_sub);        // arg[3 + arg[0] + arg[1]]
    1085         i = rec->PutOp(CSumOp);
    1086         CPPAD_ASSERT_UNKNOWN(new_arg < tape.size());
    1087 
    1088         return i;
     1182
     1183
     1184        optimize_size_pair ret;
     1185        ret.i_op  = rec->num_rec_op();
     1186        ret.i_var = rec->PutOp(CSumOp);
     1187        CPPAD_ASSERT_UNKNOWN( new_arg < ret.i_var );
     1188        return ret;
    10891189}
    10901190// ==========================================================================
     
    11581258        // initialize all variables has having no connections
    11591259        for(i = 0; i < num_var; i++)
    1160                 tape[i].connect = not_connected;
     1260                tape[i].connect_type = not_connected;
    11611261
    11621262        for(j = 0; j < m; j++)
    11631263        {       // mark dependent variables as having one or more connections
    1164                 tape[ dep_taddr[j] ].connect = yes_connected;
     1264                tape[ dep_taddr[j] ].connect_type = yes_connected;
    11651265        }
    11661266
     
    11681268        // vecad maps a VecAD index (which corresponds to the beginning of the
    11691269        // VecAD object) to the vecad_connect falg for the VecAD object.
    1170         CppAD::vector<optimize_connection>   vecad_connect(num_vecad_vec);
     1270        CppAD::vector<optimize_connection_type>   vecad_connect(num_vecad_vec);
    11711271        CppAD::vector<size_t> vecad(num_vecad_ind);
    11721272        j = 0;
     
    11981298        enum { user_start, user_arg, user_ret, user_end } user_state;
    11991299
    1200         // During reverse mode, push true if user operation is connected,
    1201         // push false otherwise. During forward mode, use to determine if
    1202         // we are keeping this operation and then pop.
    1203         std::stack<bool> user_keep;
     1300        // During reverse mode, compute type of connection for each call to
     1301        // a user atomic function.
     1302        CppAD::vector<optimize_user_info>    user_info;
     1303        size_t                               user_curr = 0;
     1304
     1305        /// During reverse mode, information for each CSkip operation
     1306        CppAD::vector<optimize_cskip_info>   cskip_info;
    12041307
    12051308        // Initialize a reverse mode sweep through the operation sequence
     
    12121315        {       // next op
    12131316                play->next_reverse(op, arg, i_op, i_var);
    1214                 // This if is not necessary becasue last assignment
    1215                 // with this value of i_var will have NumRes(op) > 0
     1317
     1318                // Store the operator corresponding to each variable
    12161319                if( NumRes(op) > 0 )
    12171320                {       tape[i_var].op = op;
     
    12241327                else    CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
    12251328# endif
     1329                optimize_connection_type connect_type  = tape[i_var].connect_type;
     1330                size_t                  connect_index  = tape[i_var].connect_index;
     1331                bool flag;
    12261332                switch( op )
    12271333                {
     
    12421348                        case TanOp:
    12431349                        case TanhOp:
    1244                         if( tape[i_var].connect != not_connected )
    1245                                 tape[arg[0]].connect = yes_connected;
     1350                        switch( connect_type )
     1351                        {       case not_connected:
     1352                                break;
     1353       
     1354                                case yes_connected:
     1355                                case sum_connected:
     1356                                case csum_connected:
     1357                                tape[arg[0]].connect_type = yes_connected;
     1358                                break;
     1359
     1360                                case cexp_true_connected:
     1361                                case cexp_false_connected:
     1362                                if( tape[arg[0]].connect_type == not_connected )
     1363                                {       tape[arg[0]].connect_type  = connect_type;
     1364                                        tape[arg[0]].connect_index = connect_index;
     1365                                }
     1366                                flag  = tape[arg[0]].connect_type  != connect_type;
     1367                                flag |= tape[arg[0]].connect_index != connect_index;
     1368                                if( flag )
     1369                                        tape[arg[0]].connect_type = yes_connected;
     1370                                break;
     1371
     1372                                default:
     1373                                CPPAD_ASSERT_UNKNOWN(false);
     1374                        }
    12461375                        break; // --------------------------------------------
    12471376
     
    12511380                        case MulpvOp:
    12521381                        case PowpvOp:
    1253                         if( tape[i_var].connect != not_connected )
    1254                                 tape[arg[1]].connect = yes_connected;
     1382                        switch( connect_type )
     1383                        {       case not_connected:
     1384                                break;
     1385       
     1386                                case yes_connected:
     1387                                case sum_connected:
     1388                                case csum_connected:
     1389                                tape[arg[1]].connect_type = yes_connected;
     1390                                break;
     1391
     1392                                case cexp_true_connected:
     1393                                case cexp_false_connected:
     1394                                if( tape[arg[1]].connect_type == not_connected )
     1395                                {       tape[arg[1]].connect_type  = connect_type;
     1396                                        tape[arg[1]].connect_index = connect_index;
     1397                                }
     1398                                flag  = tape[arg[1]].connect_type  != connect_type;
     1399                                flag |= tape[arg[1]].connect_index != connect_index;
     1400                                if( flag )
     1401                                        tape[arg[1]].connect_type = yes_connected;
     1402                                break;
     1403
     1404                                default:
     1405                                CPPAD_ASSERT_UNKNOWN(false);
     1406                        }
    12551407                        break; // --------------------------------------------
    12561408               
    12571409                        // Special case for SubvpOp
    12581410                        case SubvpOp:
    1259                         if( tape[i_var].connect != not_connected )
    1260                         {
    1261                                 if( tape[arg[0]].connect == not_connected )
    1262                                         tape[arg[0]].connect = sum_connected;
    1263                                 else
    1264                                         tape[arg[0]].connect = yes_connected;
    1265                                 if( tape[i_var].connect == sum_connected )
    1266                                         tape[i_var].connect = csum_connected;
     1411                        switch( connect_type )
     1412                        {       case not_connected:
     1413                                break;
     1414       
     1415                                case yes_connected:
     1416                                case sum_connected:
     1417                                case csum_connected:
     1418                                if( tape[arg[0]].connect_type == not_connected )
     1419                                        tape[arg[0]].connect_type = sum_connected;
     1420                                else    tape[arg[0]].connect_type = yes_connected;
     1421                                break;
     1422
     1423                                case cexp_true_connected:
     1424                                case cexp_false_connected:
     1425                                if( tape[arg[0]].connect_type == not_connected )
     1426                                {       tape[arg[0]].connect_type  = connect_type;
     1427                                        tape[arg[0]].connect_index = connect_index;
     1428                                }
     1429                                flag  = tape[arg[0]].connect_type  != connect_type;
     1430                                flag |= tape[arg[0]].connect_index != connect_index;
     1431                                if( flag )
     1432                                        tape[arg[0]].connect_type = yes_connected;
     1433                                break;
     1434
     1435                                default:
     1436                                CPPAD_ASSERT_UNKNOWN(false);
     1437                        }
     1438                        if( connect_type == sum_connected )
     1439                        {       // convert sum to csum connection for this variable
     1440                                tape[i_var].connect_type = connect_type = csum_connected;
    12671441                        }
    12681442                        break; // --------------------------------------------
     
    12711445                        case AddpvOp:
    12721446                        case SubpvOp:
    1273                         if( tape[i_var].connect != not_connected )
    1274                         {
    1275                                 if( tape[arg[1]].connect == not_connected )
    1276                                         tape[arg[1]].connect = sum_connected;
    1277                                 else
    1278                                         tape[arg[1]].connect = yes_connected;
    1279                                 if( tape[i_var].connect == sum_connected )
    1280                                         tape[i_var].connect = csum_connected;
     1447                        switch( connect_type )
     1448                        {       case not_connected:
     1449                                break;
     1450       
     1451                                case yes_connected:
     1452                                case sum_connected:
     1453                                case csum_connected:
     1454                                if( tape[arg[1]].connect_type == not_connected )
     1455                                        tape[arg[1]].connect_type = sum_connected;
     1456                                else    tape[arg[1]].connect_type = yes_connected;
     1457                                break;
     1458
     1459                                case cexp_true_connected:
     1460                                case cexp_false_connected:
     1461                                if( tape[arg[1]].connect_type == not_connected )
     1462                                {       tape[arg[1]].connect_type  = connect_type;
     1463                                        tape[arg[1]].connect_index = connect_index;
     1464                                }
     1465                                flag  = tape[arg[1]].connect_type  != connect_type;
     1466                                flag |= tape[arg[1]].connect_index != connect_index;
     1467                                if( flag )
     1468                                        tape[arg[1]].connect_type = yes_connected;
     1469                                break;
     1470
     1471                                default:
     1472                                CPPAD_ASSERT_UNKNOWN(false);
     1473                        }
     1474                        if( connect_type == sum_connected )
     1475                        {       // convert sum to csum connection for this variable
     1476                                tape[i_var].connect_type = connect_type = csum_connected;
    12811477                        }
    12821478                        break; // --------------------------------------------
     
    12861482                        case AddvvOp:
    12871483                        case SubvvOp:
    1288                         if( tape[i_var].connect != not_connected )
    1289                         {
    1290                                 if( tape[arg[0]].connect == not_connected )
    1291                                         tape[arg[0]].connect = sum_connected;
    1292                                 else
    1293                                         tape[arg[0]].connect = yes_connected;
    1294 
    1295                                 if( tape[arg[1]].connect == not_connected )
    1296                                         tape[arg[1]].connect = sum_connected;
    1297                                 else
    1298                                         tape[arg[1]].connect = yes_connected;
    1299                                 if( tape[i_var].connect == sum_connected )
    1300                                         tape[i_var].connect = csum_connected;
     1484                        for(i = 0; i < 2; i++) switch( connect_type )
     1485                        {       case not_connected:
     1486                                break;
     1487
     1488                                case yes_connected:
     1489                                case sum_connected:
     1490                                case csum_connected:
     1491                                if( tape[arg[i]].connect_type == not_connected )
     1492                                        tape[arg[i]].connect_type = sum_connected;
     1493                                else    tape[arg[i]].connect_type = yes_connected;
     1494                                break;
     1495
     1496                                case cexp_true_connected:
     1497                                case cexp_false_connected:
     1498                                if( tape[arg[i]].connect_type == not_connected )
     1499                                {       tape[arg[i]].connect_type  = connect_type;
     1500                                        tape[arg[i]].connect_index = connect_index;
     1501                                }
     1502                                flag  = tape[arg[i]].connect_type  != connect_type;
     1503                                flag |= tape[arg[i]].connect_index != connect_index;
     1504                                if( flag )
     1505                                        tape[arg[i]].connect_type = yes_connected;
     1506                                break;
     1507
     1508                                default:
     1509                                CPPAD_ASSERT_UNKNOWN(false);
     1510                        }
     1511                        if( connect_type == sum_connected )
     1512                        {       // convert sum to csum connection for this variable
     1513                                tape[i_var].connect_type = connect_type = csum_connected;
    13011514                        }
    13021515                        break; // --------------------------------------------
     
    13071520                        case MulvvOp:
    13081521                        case PowvvOp:
    1309                         if( tape[i_var].connect != not_connected )
    1310                         {
    1311                                 tape[arg[0]].connect = yes_connected;
    1312                                 tape[arg[1]].connect = yes_connected;
     1522                        for(i = 0; i < 2; i++) switch( connect_type )
     1523                        {       case not_connected:
     1524                                break;
     1525
     1526                                case yes_connected:
     1527                                case sum_connected:
     1528                                case csum_connected:
     1529                                tape[arg[i]].connect_type = yes_connected;
     1530                                break;
     1531
     1532                                case cexp_true_connected:
     1533                                case cexp_false_connected:
     1534                                if( tape[arg[i]].connect_type == not_connected )
     1535                                {       tape[arg[i]].connect_type  = connect_type;
     1536                                        tape[arg[i]].connect_index = connect_index;
     1537                                }
     1538                                flag  = tape[arg[i]].connect_type  != connect_type;
     1539                                flag |= tape[arg[i]].connect_index != connect_index;
     1540                                if( flag )
     1541                                        tape[arg[i]].connect_type = yes_connected;
     1542                                break;
     1543
     1544                                default:
     1545                                CPPAD_ASSERT_UNKNOWN(false);
    13131546                        }
    13141547                        break; // --------------------------------------------
    13151548
    13161549                        // Conditional expression operators
     1550                        // 2DO: This does not handle nested conditional expressions;
     1551                        // i.e. Suppose i_var is connected to a conditional expression.
    13171552                        case CExpOp:
    13181553                        CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 );
    1319                         if( tape[i_var].connect != not_connected )
    1320                         {
     1554                        if( tape[i_var].connect_type != not_connected )
     1555                        {       optimize_cskip_info info;
     1556                                info.cop        = CompareOp( arg[0] );
     1557                                info.flag       = arg[1];
     1558                                info.left       = arg[2];
     1559                                info.right      = arg[3];
     1560                                info.n_op_true  = 0;
     1561                                info.n_op_false = 0;
     1562                                size_t index = cskip_info.size();
     1563                                cskip_info.push_back(info);
     1564
    13211565                                mask = 1;
    13221566                                for(i = 2; i < 6; i++)
    1323                                 {       if( arg[1] & mask )
    1324                                         {       CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_var );
    1325                                                 tape[arg[i]].connect = yes_connected;
     1567                                {       CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_var );
     1568                                        if( arg[1] & mask )
     1569                                        {       if( i == 2 || i == 3 )
     1570                                                        tape[arg[i]].connect_type = yes_connected;
     1571                                                else
     1572                                                {       tape[arg[i]].connect_index = index;
     1573                                                        if( i == 4 )
     1574                                                                tape[arg[i]].connect_type =
     1575                                                                                cexp_true_connected;
     1576                                                        else
     1577                                                        {       // i == 5
     1578                                                                tape[arg[i]].connect_type =
     1579                                                                                cexp_false_connected;
     1580                                                        }
     1581                                                }
    13261582                                        }
    13271583                                        mask = mask << 1;
     
    13311587
    13321588                        // Operations where there is noting to do
    1333                         case BeginOp:
    13341589                        case ComOp:
    13351590                        case EndOp:
    1336                         case InvOp:
    13371591                        case ParOp:
    13381592                        case PriOp:
    13391593                        break;  // --------------------------------------------
    13401594
     1595                        // Operators that never get removed
     1596                        case BeginOp:
     1597                        case InvOp:
     1598                        tape[i_var].connect_type = yes_connected;
     1599                        break;
     1600
    13411601                        // Load using a parameter index
    13421602                        case LdpOp:
    1343                         if( tape[i_var].connect != not_connected )
     1603                        if( tape[i_var].connect_type != not_connected )
    13441604                        {
    13451605                                i                = vecad[ arg[0] - 1 ];
     
    13501610                        // Load using a variable index
    13511611                        case LdvOp:
    1352                         if( tape[i_var].connect != not_connected )
     1612                        if( tape[i_var].connect_type != not_connected )
    13531613                        {
    13541614                                i                    = vecad[ arg[0] - 1 ];
    13551615                                vecad_connect[i]     = yes_connected;
    1356                                 tape[arg[1]].connect = yes_connected;
     1616                                tape[arg[1]].connect_type = yes_connected;
    13571617                        }
    13581618                        break; // --------------------------------------------
     
    13621622                        i = vecad[ arg[0] - 1 ];
    13631623                        if( vecad_connect[i] != not_connected )
    1364                                 tape[arg[2]].connect = yes_connected;
     1624                                tape[arg[2]].connect_type = yes_connected;
    13651625                        break; // --------------------------------------------
    13661626
     
    13691629                        i = vecad[ arg[0] - 1 ];
    13701630                        if( vecad_connect[i] )
    1371                         {       tape[arg[1]].connect = yes_connected;
    1372                                 tape[arg[2]].connect = yes_connected;
     1631                        {       tape[arg[1]].connect_type = yes_connected;
     1632                                tape[arg[2]].connect_type = yes_connected;
    13731633                        }
    13741634                        break;
     
    13911651                                user_i     = user_m;
    13921652                                user_state = user_ret;
    1393                                 user_keep.push(false);
     1653                                //
     1654                                optimize_user_info info;
     1655                                info.connect_type = not_connected;
     1656                                info.op_end       = i_op + 1;
     1657                                user_info.push_back(info);
     1658                               
    13941659                        }
    13951660                        else
     
    14001665                                CPPAD_ASSERT_UNKNOWN( user_m     == size_t(arg[3]) );
    14011666                                user_state = user_end;
     1667                                //
     1668                                CPPAD_ASSERT_UNKNOWN( user_curr + 1 == user_info.size() );
     1669                                user_info[user_curr].op_begin = i_op;
     1670                                user_curr                     = user_info.size();
    14021671               }
    14031672                        break;
     
    14231692                        --user_j;
    14241693                        if( ! user_s[user_j].empty() )
    1425                         {       tape[arg[0]].connect = yes_connected;
    1426                                 user_keep.top() = true;
    1427                         }
     1694                                tape[arg[0]].connect_type =
     1695                                        user_info[user_curr].connect_type;
    14281696                        if( user_j == 0 )
    14291697                                user_state = user_start;
     
    14561724                        --user_i;
    14571725                        user_r[user_i].clear();
    1458                         if( tape[i_var].connect != not_connected )
     1726                        switch( connect_type )
     1727                        {       case not_connected:
     1728                                break;
     1729
     1730                                case yes_connected:
     1731                                case sum_connected:
     1732                                case csum_connected:
     1733                                user_info[user_curr].connect_type = yes_connected;
    14591734                                user_r[user_i].insert(0);
     1735                                break;
     1736
     1737                                case cexp_true_connected:
     1738                                case cexp_false_connected:
     1739                                if( user_info[user_curr].connect_type == not_connected )
     1740                                {       user_info[user_curr].connect_type  = connect_type;
     1741                                        user_info[user_curr].connect_index = connect_index;
     1742                                }
     1743                                flag  = user_info[user_curr].connect_type != connect_type;
     1744                                flag |= user_info[user_curr].connect_index!=connect_index;
     1745                                if( flag )
     1746                                        user_info[user_curr].connect_type = yes_connected;
     1747                                user_r[user_i].insert(0);
     1748                                break;
     1749
     1750                                default:
     1751                                CPPAD_ASSERT_UNKNOWN(false);
     1752                        }
    14601753                        if( user_i == 0 )
    14611754                        {       // call users function for this operation
     
    14811774        // -------------------------------------------------------------
    14821775
    1483         // Erase all information in the recording
    1484         rec->free();
     1776        // Determine which variables can be conditionally skipped
     1777        for(i = 0; i < num_var; i++)
     1778        {       if( tape[i].connect_type == cexp_true_connected )
     1779                {       j = tape[i].connect_index;
     1780                        cskip_info[j].skip_var_false.push_back(i);
     1781                }
     1782                if( tape[i].connect_type == cexp_false_connected )
     1783                {       j = tape[i].connect_index;
     1784                        cskip_info[j].skip_var_true.push_back(i);
     1785                }
     1786        }
     1787        // Move skip information from user_info to cskip_info
     1788        for(i = 0; i < user_info.size(); i++)
     1789        {       if( user_info[i].connect_type == cexp_true_connected )
     1790                {       j = user_info[i].connect_index;
     1791                        cskip_info[j].n_op_false =
     1792                                user_info[i].op_end - user_info[i].op_begin;
     1793                }
     1794                if( user_info[i].connect_type == cexp_false_connected )
     1795                {       j = user_info[i].connect_index;
     1796                        cskip_info[j].n_op_true =
     1797                                user_info[i].op_end - user_info[i].op_begin;
     1798                }
     1799        }
     1800
     1801        // Sort the conditional skip information by the maximum of the
     1802        // index for the left and right comparision operands
     1803        CppAD::vector<size_t> cskip_info_order( cskip_info.size() );
     1804        {       CppAD::vector<size_t> keys( cskip_info.size() );
     1805                for(i = 0; i < cskip_info.size(); i++)
     1806                        keys[i] = std::max( cskip_info[i].left, cskip_info[i].right );
     1807                CppAD::index_sort(keys, cskip_info_order);
     1808        }
     1809        size_t cskip_info_next = 0;
     1810
    14851811
    14861812        // Initilaize table mapping hash code to variable index in tape
     
    14911817        CPPAD_ASSERT_UNKNOWN( tape[0].op == BeginOp );
    14921818
    1493         // initialize mapping from old variable index to new variable index
     1819        // initialize mapping from old variable index to new
     1820        // operator and variable index
    14941821        for(i = 0; i < num_var; i++)
     1822        {       tape[i].new_op  = 0;       // invalid index (except for BeginOp)
    14951823                tape[i].new_var = num_var; // invalid index
    1496        
     1824        }
     1825
     1826        // Erase all information in the old recording
     1827        rec->free();
    14971828
    14981829        // initialize mapping from old VecAD index to new VecAD index
     
    15231854        // start playing the operations in the forward direction
    15241855        play->start_forward(op, arg, i_op, i_var);
     1856        CPPAD_ASSERT_UNKNOWN( user_curr == user_info.size() );
    15251857
    15261858        // playing forward skips BeginOp at the beginning, but not EndOp at
    15271859        // the end.  Put BeginOp at beginning of recording
    15281860        CPPAD_ASSERT_UNKNOWN( op == BeginOp );
    1529         CPPAD_ASSERT_NARG_NRES(BeginOp, 0, 1);
     1861        CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1);
     1862        tape[i_var].new_op  = rec->num_rec_op();
    15301863        tape[i_var].new_var = rec->PutOp(BeginOp);
     1864        rec->PutArg(0);
     1865
    15311866
    15321867        // temporary buffer for new argument values
     
    15361871        // (decalared here to avoid realloaction of memory)
    15371872        optimize_csum_stacks csum_work;
     1873
     1874        // tempory used to hold a size_pair
     1875        optimize_size_pair size_pair;
    15381876
    15391877        user_state = user_start;
     
    15431881                CPPAD_ASSERT_UNKNOWN( (i_op > n)  | (op == InvOp) );
    15441882                CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) );
     1883
     1884                // determine if we should insert a conditional skip here
     1885                bool skip = cskip_info_next < cskip_info.size();
     1886                skip     &= (op != BeginOp) & (op != InvOp);
     1887                if( skip )
     1888                {       j     = cskip_info_order[cskip_info_next];
     1889                        if( NumRes(op) > 0 )
     1890                        {       skip &= cskip_info[j].left < i_var;
     1891                                skip &= cskip_info[j].right < i_var;
     1892                        }
     1893                        else
     1894                        {       skip &= cskip_info[j].left <= i_var;
     1895                                skip &= cskip_info[j].right <= i_var;
     1896                        }
     1897                }
     1898                if( skip )
     1899                {       cskip_info_next++;
     1900                        skip &= cskip_info[j].skip_var_true.size() > 0 ||
     1901                                        cskip_info[j].skip_var_false.size() > 0;
     1902                        if( skip )
     1903                        {       optimize_cskip_info info = cskip_info[j];
     1904                                CPPAD_ASSERT_UNKNOWN( NumRes(CSkipOp) == 0 );
     1905                                size_t n_true  =
     1906                                        info.skip_var_true.size() + info.n_op_true;
     1907                                size_t n_false =
     1908                                        info.skip_var_false.size() + info.n_op_false;
     1909                                size_t n_arg   = 7 + n_true + n_false;
     1910                                // reserve space for the arguments to this operator but
     1911                                // delay setting them until we have all the new addresses
     1912                                cskip_info[j].i_arg = rec->ReserveArg(n_arg);
     1913                                CPPAD_ASSERT_UNKNOWN( cskip_info[i].i_arg > 0 );
     1914                                rec->PutOp(CSkipOp);
     1915                        }
     1916                        else    cskip_info[j].i_arg = 0;
     1917                }
    15451918
    15461919                // determine if we should keep this operation in the new
     
    15721945                        case SubvpOp:
    15731946                        case SubvvOp:
    1574                         keep  = tape[i_var].connect != not_connected;
    1575                         keep &= tape[i_var].connect != csum_connected;
     1947                        keep  = tape[i_var].connect_type != not_connected;
     1948                        keep &= tape[i_var].connect_type != csum_connected;
    15761949                        break;
    15771950
     
    15811954                        case UsrrpOp:
    15821955                        case UsrrvOp:
    1583                         keep = user_keep.top();
     1956                        keep = true;
    15841957                        break;
    15851958
    15861959                        default:
    1587                         keep = tape[i_var].connect != not_connected;
     1960                        keep = tape[i_var].connect_type != not_connected;
    15881961                        break;
    15891962                }
     
    16231996                                new_arg[0]   = tape[ arg[0] ].new_var;
    16241997                                rec->PutArg( new_arg[0] );
    1625                                 i                   = rec->PutOp(op);
    1626                                 tape[i_var].new_var = i;
     1998                                tape[i_var].new_op  = rec->num_rec_op();
     1999                                tape[i_var].new_var = i = rec->PutOp(op);
    16272000                                CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < i );
    16282001                        }
     
    16322005                        // left is a variable and right is a parameter
    16332006                        case SubvpOp:
    1634                         if( tape[arg[0]].connect == csum_connected )
     2007                        if( tape[arg[0]].connect_type == csum_connected )
    16352008                        {
    16362009                                // convert to a sequence of summation operators
    1637                                 tape[i_var].new_var = optimize_record_csum(
     2010                                size_pair = optimize_record_csum(
    16382011                                        tape                , // inputs
    16392012                                        i_var               ,
     
    16432016                                        csum_work
    16442017                                );
     2018                                tape[i_var].new_op  = size_pair.i_op;
     2019                                tape[i_var].new_var = size_pair.i_var;
    16452020                                // abort rest of this case
    16462021                                break;
     
    16592034                                tape[i_var].new_var = match_var;
    16602035                        else
    1661                         {       tape[i_var].new_var = optimize_record_vp(
     2036                        {       size_pair = optimize_record_vp(
    16622037                                        tape                , // inputs
    16632038                                        i_var               ,
     
    16682043                                        arg
    16692044                                );
     2045                                tape[i_var].new_op  = size_pair.i_op;
     2046                                tape[i_var].new_var = size_pair.i_var;
    16702047                                replace_hash = true;
    16712048                        }
     
    16762053                        case SubpvOp:
    16772054                        case AddpvOp:
    1678                         if( tape[arg[1]].connect == csum_connected )
     2055                        if( tape[arg[1]].connect_type == csum_connected )
    16792056                        {
    16802057                                // convert to a sequence of summation operators
    1681                                 tape[i_var].new_var = optimize_record_csum(
     2058                                size_pair = optimize_record_csum(
    16822059                                        tape                , // inputs
    16832060                                        i_var               ,
     
    16872064                                        csum_work
    16882065                                );
     2066                                tape[i_var].new_op  = size_pair.i_op;
     2067                                tape[i_var].new_var = size_pair.i_var;
    16892068                                // abort rest of this case
    16902069                                break;
     
    17042083                                tape[i_var].new_var = match_var;
    17052084                        else
    1706                         {       tape[i_var].new_var = optimize_record_pv(
     2085                        {       size_pair = optimize_record_pv(
    17072086                                        tape                , // inputs
    17082087                                        i_var               ,
     
    17132092                                        arg
    17142093                                );
     2094                                tape[i_var].new_op  = size_pair.i_op;
     2095                                tape[i_var].new_var = size_pair.i_var;
    17152096                                replace_hash = true;
    17162097                        }
     
    17212102                        case AddvvOp:
    17222103                        case SubvvOp:
    1723                         if( (tape[arg[0]].connect == csum_connected) |
    1724                             (tape[arg[1]].connect == csum_connected)
     2104                        if( (tape[arg[0]].connect_type == csum_connected) |
     2105                            (tape[arg[1]].connect_type == csum_connected)
    17252106                        )
    17262107                        {
    17272108                                // convert to a sequence of summation operators
    1728                                 tape[i_var].new_var = optimize_record_csum(
     2109                                size_pair = optimize_record_csum(
    17292110                                        tape                , // inputs
    17302111                                        i_var               ,
     
    17342115                                        csum_work
    17352116                                );
     2117                                tape[i_var].new_op  = size_pair.i_op;
     2118                                tape[i_var].new_var = size_pair.i_var;
    17362119                                // abort rest of this case
    17372120                                break;
     
    17512134                                tape[i_var].new_var = match_var;
    17522135                        else
    1753                         {       tape[i_var].new_var = optimize_record_vv(
     2136                        {       size_pair = optimize_record_vv(
    17542137                                        tape                , // inputs
    17552138                                        i_var               ,
     
    17602143                                        arg
    17612144                                );
     2145                                tape[i_var].new_op  = size_pair.i_op;
     2146                                tape[i_var].new_var = size_pair.i_var;
    17622147                                replace_hash = true;
    17632148                        }
     
    17902175                                new_arg[5]
    17912176                        );
     2177                        tape[i_var].new_op  = rec->num_rec_op();
    17922178                        tape[i_var].new_var = rec->PutOp(op);
    17932179                        break;
     
    18022188                        case InvOp:
    18032189                        CPPAD_ASSERT_NARG_NRES(op, 0, 1);
     2190                        tape[i_var].new_op  = rec->num_rec_op();
    18042191                        tape[i_var].new_var = rec->PutOp(op);
    18052192                        break;
     
    18112198
    18122199                        rec->PutArg( new_arg[0] );
     2200                        tape[i_var].new_op  = rec->num_rec_op();
    18132201                        tape[i_var].new_var = rec->PutOp(op);
    18142202                        break;
     
    18252213                                0
    18262214                        );
     2215                        tape[i_var].new_op  = rec->num_rec_op();
    18272216                        tape[i_var].new_var = rec->PutOp(op);
    18282217                        break;
     
    18402229                                0
    18412230                        );
     2231                        tape[i_var].new_var = rec->num_rec_op();
    18422232                        tape[i_var].new_var = rec->PutOp(op);
    18432233                        break;
     
    19122302                        CPPAD_ASSERT_NARG_NRES(op, 4, 0);
    19132303                        if( user_state == user_start )
    1914                                 user_state = user_arg;
     2304                        {       user_state = user_arg;
     2305                                CPPAD_ASSERT_UNKNOWN( user_curr > 0 );
     2306                                user_curr--;
     2307                                user_info[user_curr].op_begin = rec->num_rec_op();
     2308                        }
    19152309                        else
    19162310                        {       user_state = user_start;
    1917                                 user_keep.pop();       
     2311                                user_info[user_curr].op_end = rec->num_rec_op() + 1;
    19182312                        }
    19192313                        // user_index, user_id, user_n, user_m
    1920                         rec->PutArg(arg[0], arg[1], arg[2], arg[3]);
    1921                         rec->PutOp(UserOp);
     2314                        if( user_info[user_curr].connect_type != not_connected )
     2315                        {       rec->PutArg(arg[0], arg[1], arg[2], arg[3]);
     2316                                rec->PutOp(UserOp);
     2317                        }
    19222318                        break;
    19232319
    19242320                        case UsrapOp:
    19252321                        CPPAD_ASSERT_NARG_NRES(op, 1, 0);
    1926                         new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
    1927                         rec->PutArg(new_arg[0]);
    1928                         rec->PutOp(UsrapOp);
     2322                        if( user_info[user_curr].connect_type != not_connected )
     2323                        {       new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
     2324                                rec->PutArg(new_arg[0]);
     2325                                rec->PutOp(UsrapOp);
     2326                        }
    19292327                        break;
    19302328
    19312329                        case UsravOp:
    19322330                        CPPAD_ASSERT_NARG_NRES(op, 1, 0);
    1933                         new_arg[0] = tape[arg[0]].new_var;
    1934                         if( size_t(new_arg[0]) < num_var )
    1935                         {       rec->PutArg(new_arg[0]);
    1936                                 rec->PutOp(UsravOp);
    1937                         }
    1938                         else
    1939                         {       // This argument does not affect the result and
    1940                                 // has been optimized out so use nan in its place.
    1941                                 new_arg[0] = rec->PutPar( nan(Base(0)) );
    1942                                 rec->PutArg(new_arg[0]);
    1943                                 rec->PutOp(UsrapOp);
     2331                        if( user_info[user_curr].connect_type != not_connected )
     2332                        {       new_arg[0] = tape[arg[0]].new_var;
     2333                                if( size_t(new_arg[0]) < num_var )
     2334                                {       rec->PutArg(new_arg[0]);
     2335                                        rec->PutOp(UsravOp);
     2336                                }
     2337                                else
     2338                                {       // This argument does not affect the result and
     2339                                        // has been optimized out so use nan in its place.
     2340                                        new_arg[0] = rec->PutPar( nan(Base(0)) );
     2341                                        rec->PutArg(new_arg[0]);
     2342                                        rec->PutOp(UsrapOp);
     2343                                }
    19442344                        }
    19452345                        break;
     
    19472347                        case UsrrpOp:
    19482348                        CPPAD_ASSERT_NARG_NRES(op, 1, 0);
    1949                         new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
    1950                         rec->PutArg(new_arg[0]);
    1951                         rec->PutOp(UsrrpOp);
     2349                        if( user_info[user_curr].connect_type != not_connected )
     2350                        {       new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
     2351                                rec->PutArg(new_arg[0]);
     2352                                rec->PutOp(UsrrpOp);
     2353                        }
    19522354                        break;
    19532355                       
    19542356                        case UsrrvOp:
    19552357                        CPPAD_ASSERT_NARG_NRES(op, 0, 1);
    1956                         tape[i_var].new_var = rec->PutOp(UsrrvOp);
     2358                        if( user_info[user_curr].connect_type != not_connected )
     2359                        {       tape[i_var].new_op  = rec->num_rec_op();
     2360                                tape[i_var].new_var = rec->PutOp(UsrrvOp);
     2361                        }
    19572362                        break;
    19582363                        // ---------------------------------------------------
     
    19732378        // modify the dependent variable vector to new indices
    19742379        for(i = 0; i < dep_taddr.size(); i++ )
    1975         {       CPPAD_ASSERT_UNKNOWN( size_t(tape[ dep_taddr[i] ].new_var) < num_var );
     2380        {       CPPAD_ASSERT_UNKNOWN( size_t(tape[dep_taddr[i]].new_var) < num_var );
    19762381                dep_taddr[i] = tape[ dep_taddr[i] ].new_var;
     2382        }
     2383
     2384# ifndef NDEBUG
     2385        size_t num_new_op = rec->num_rec_op();
     2386        for(i_var = 0; i_var < tape.size(); i_var++)
     2387                CPPAD_ASSERT_UNKNOWN( tape[i_var].new_op < num_new_op );
     2388# endif
     2389
     2390        // Move skip information from user_info to cskip_info
     2391        for(i = 0; i < user_info.size(); i++)
     2392        {       if( user_info[i].connect_type == cexp_true_connected )
     2393                {       j = user_info[i].connect_index;
     2394                        k = user_info[i].op_begin;
     2395                        while(k < user_info[i].op_end)
     2396                                cskip_info[j].skip_op_false.push_back(k++);
     2397                }
     2398                if( user_info[i].connect_type == cexp_false_connected )
     2399                {       j = user_info[i].connect_index;
     2400                        k = user_info[i].op_begin;
     2401                        while(k < user_info[i].op_end)
     2402                                cskip_info[j].skip_op_true.push_back(k++);
     2403                }
     2404        }
     2405
     2406        // fill in the arguments for the CSkip operations
     2407        CPPAD_ASSERT_UNKNOWN( cskip_info_next == cskip_info.size() );
     2408        for(i = 0; i < cskip_info.size(); i++)
     2409        {       optimize_cskip_info info = cskip_info[i];
     2410                if( info.i_arg > 0 )
     2411                {       CPPAD_ASSERT_UNKNOWN( info.n_op_true==info.skip_op_true.size() );
     2412                        CPPAD_ASSERT_UNKNOWN(info.n_op_false==info.skip_op_false.size());
     2413                        size_t n_true  =
     2414                                info.skip_var_true.size() + info.skip_op_true.size();
     2415                        size_t n_false =
     2416                                info.skip_var_false.size() + info.skip_op_false.size();
     2417                        size_t i_arg   = info.i_arg;
     2418                        rec->ReplaceArg(i_arg++, info.cop   );
     2419                        rec->ReplaceArg(i_arg++, info.flag  );
     2420                        rec->ReplaceArg(i_arg++, info.left  );
     2421                        rec->ReplaceArg(i_arg++, info.right );
     2422                        rec->ReplaceArg(i_arg++, n_true     );
     2423                        rec->ReplaceArg(i_arg++, n_false    );
     2424                        for(j = 0; j < info.skip_var_true.size(); j++)
     2425                        {       i_var = info.skip_var_true[j];
     2426                                CPPAD_ASSERT_UNKNOWN( tape[i_var].new_op > 0 );
     2427                                rec->ReplaceArg(i_arg++, tape[i_var].new_op );
     2428                        }
     2429                        for(j = 0; j < info.skip_op_true.size(); j++)
     2430                        {       i_op = info.skip_op_true[j];
     2431                                rec->ReplaceArg(i_arg++, i_op);
     2432                        }
     2433                        for(j = 0; j < info.skip_var_false.size(); j++)
     2434                        {       i_var = info.skip_var_false[j];
     2435                                CPPAD_ASSERT_UNKNOWN( tape[i_var].new_op > 0 );
     2436                                rec->ReplaceArg(i_arg++, tape[i_var].new_op );
     2437                        }
     2438                        for(j = 0; j < info.skip_op_false.size(); j++)
     2439                        {       i_op = info.skip_op_false[j];
     2440                                rec->ReplaceArg(i_arg++, i_op);
     2441                        }
     2442                        rec->ReplaceArg(i_arg++, n_true + n_false);
     2443# ifndef NDEBUG
     2444                        size_t n_arg   = 7 + n_true + n_false;
     2445                        CPPAD_ASSERT_UNKNOWN( info.i_arg + n_arg == i_arg );
     2446# endif
     2447                }
    19772448        }
    19782449}
     
    19982469        size_t n = ind_taddr_.size();
    19992470
     2471        size_t i;
    20002472# ifndef NDEBUG
    2001         size_t i, j, m = dep_taddr_.size();
     2473        size_t j, m = dep_taddr_.size();
    20022474        CppAD::vector<Base> x(n), y(m), check(m);
    20032475        bool check_zero_order = taylor_per_var_ > 0;
     
    20432515        taylor_col_dim_ = 0;
    20442516
     2517        // resize and initilaize conditional skip vector
     2518        // (must use player size because it now has the recoreder information)
     2519        cskip_op_.resize( play_.num_rec_op() );
     2520        for(i = 0; i < cskip_op_.size(); i++)
     2521                cskip_op_[i] = false;
     2522
    20452523# ifndef NDEBUG
    20462524        if( check_zero_order )
  • trunk/cppad/local/player.hpp

    r2910 r2991  
    44
    55/* --------------------------------------------------------------------------
    6 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    77
    88CppAD is distributed under multiple licenses. This distribution is under
     
    227227        /*!
    228228        \brief
    229         Replace an argument index in the recording.
     229        Replace an argument value in the recording.
     230        2DO: change name of this routine to ReplaceArg.
    230231
    231232        \param i
    232         is the index, in argument indices, that is to be replaced.
     233        is the index, in the recording argument vector,
     234        of the value that is to be replaced.
    233235
    234236        \param value
    235         is the new normal index value.
     237        is the new argument value.
    236238        */
    237239        void ReplaceInd(size_t i, size_t value)
     
    326328
    327329                CPPAD_ASSERT_UNKNOWN( op_  == BeginOp );
    328                 CPPAD_ASSERT_NARG_NRES(op_, 0, 1);
     330                CPPAD_ASSERT_NARG_NRES(op_, 1, 1);
    329331
    330332                return;
     
    340342        The input value of op does not matter. Its output value is the
    341343        next operator in the recording.
    342         For speed, \c next_forward does not check for the special case
    343         of <tt>op == CSumOp</tt>. In this case, the other return values
    344         from \c next_forward must be corrected by a call to \c forward_csum.
     344        For speed, \c next_forward does not check for the special cases
     345        where  <tt>op == CSumOp</tt> or <tt>op == CSkipOp</tt>. In these cases,
     346        the other return values from \c next_forward must be corrected by a call
     347        to \c forward_csum or \c forward_cskip respectively.
    345348
    346349        \param op_arg
     
    424427        }
    425428        /*!
     429        Correct \c next_forward return values when <tt>op == CSkipOp</tt>.
     430
     431        \param op
     432        The input value of op must be the return value from the previous
     433        call to \c next_forward and must be \c CSkipOp.
     434
     435        \param op_arg
     436        The input value of *op_arg must be the return value from the
     437        previous call to \c next_forward. Its output value is the
     438        beginning of the vector of argument indices for this operation.
     439
     440        \param op_index
     441        The input value of op_index does must be the return value from the
     442        previous call to \c next_forward. Its output value
     443        is the index of this operator in the recording.
     444
     445        \param var_index
     446        The input value of var_index must be the return value from the
     447        previous call to \c next_forward. Its output value is the
     448        index of the primary (last) result corresponding to this.
     449        */
     450        void forward_cskip(
     451        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
     452        {       using CppAD::NumRes;
     453                using CppAD::NumArg;
     454                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
     455                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
     456                CPPAD_ASSERT_UNKNOWN(
     457                op_arg[4] + op_arg[5] == op_arg[ 6 + op_arg[4] + op_arg[5] ]
     458                );
     459                /*
     460                The only thing that really needs fixing is op_arg_.
     461                Actual number of arugments for this operator is
     462                        7 + op_arg[4] + op_arg[5]
     463                We must change op_arg_ so that when you add NumArg(CSkipOp)
     464                you get first argument for next operator in sequence.
     465                */
     466                op_arg_    += 7 + op_arg[4] + op_arg[5];
     467
     468                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
     469                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
     470        }
     471        /*!
    426472        Get a non-constant version of op_arg returned by previous next_forward
    427473
     
    491537        The last operator sets op_arg equal to the beginning of the
    492538        argument indices for the entire recording.
    493         For speed, \c next_reverse does not check for the special case
    494         of <tt>op == CSumOp</tt>. In this case, the other return values
    495         from \c next_reverse must be corrected by a call to \c reverse_csum.
     539        For speed, \c next_reverse does not check for the special cases
     540        <tt>op == CSumOp</tt> or <tt>op == CSkipOp</tt>. In these cases, the other
     541        return values from \c next_reverse must be corrected by a call to
     542        \c reverse_csum or \c reverse_cskip respectively.
    496543
    497544
     
    575622                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
    576623        }
     624        /*!
     625        Correct \c next_reverse return values when <tt>op == CSkipOp</tt>.
     626
     627        \param op
     628        The input value of op must be the return value from the previous
     629        call to \c next_reverse and must be \c CSkipOp.
     630
     631        \param op_arg
     632        The input value of *op_arg must be the return value from the
     633        previous call to \c next_reverse. Its output value is the
     634        beginning of the vector of argument indices for this operation.
     635
     636        \param op_index
     637        The input value of op_index must be the return value from the
     638        previous call to \c next_reverse. Its output value
     639        is the index of the this operator in the recording.
     640
     641        \param var_index
     642        The input value of var_index must be the return value from the
     643        previous call to \c next_reverse. Its output value is the
     644        index of the primary (last) result corresponding to this operator.
     645        */
     646
     647        void reverse_cskip(
     648        OpCode& op, const addr_t*& op_arg, size_t& op_index, size_t& var_index)
     649        {       using CppAD::NumRes;
     650                using CppAD::NumArg;
     651                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
     652                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
     653                /*
     654                The things needs fixing are op_arg_ and op_arg. Currently,
     655                op_arg points first arugment for the previous operator.
     656                */
     657                --op_arg;
     658                op_arg_    -= (op_arg[0] + 4);
     659                op_arg      = op_arg_ + rec_op_arg_.data();
     660
     661                CPPAD_ASSERT_UNKNOWN(
     662                op_arg[1] + op_arg[2] == op_arg[ 3 + op_arg[1] + op_arg[2] ]
     663                );
     664                CPPAD_ASSERT_UNKNOWN( op_index_  < rec_op_.size() );
     665                CPPAD_ASSERT_UNKNOWN( op_arg_ + NumArg(op) <= rec_op_arg_.size() );
     666                CPPAD_ASSERT_UNKNOWN( var_index_  < num_rec_var_ );
     667        }
    577668
    578669};
  • trunk/cppad/local/recorder.hpp

    r2910 r2991  
    33# define CPPAD_RECORDER_INCLUDED
    44/* --------------------------------------------------------------------------
    5 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     5CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    66
    77CppAD is distributed under multiple licenses. This distribution is under
     
    111111                addr_t arg4, addr_t arg5);
    112112
     113        // Reserve space for a specified number of arguments
     114        inline size_t ReserveArg(size_t n_arg);
     115
     116        // Replace an argument value
     117        void ReplaceArg(size_t i_arg, size_t value);
     118
    113119        /// Put a character string in the text for this recording.
    114120        inline size_t PutTxt(const char *text);
     
    117123        size_t num_rec_var(void) const
    118124        {       return num_rec_var_; }
     125
     126        /// Number of operators currently stored in the recording.
     127        size_t num_rec_op(void) const
     128        {       return  rec_op_.size(); }
    119129
    120130        /// Approximate amount of memory used by the recording
     
    424434// --------------------------------------------------------------------------
    425435/*!
     436Reserve space for arguments, but delay placing values there.
     437
     438\param n_arg
     439number of arguements to reserve space for
     440
     441\return
     442is the index in the argument vector corresponding to the
     443first of the arguments being reserved.
     444*/
     445template <class Base>
     446inline size_t recorder<Base>::ReserveArg(size_t n_arg)
     447{
     448        size_t i = rec_op_arg_.extend(n_arg);
     449        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + n_arg );
     450        return i;
     451}
     452
     453/*!
     454\brief
     455Replace an argument value in the recording
     456(intended to fill in reserved values).
     457
     458\param i_arg
     459is the index, in argument vector, for the value that is replaced.
     460
     461\param value
     462is the new value for the argument with the specified index.
     463*/
     464template <class Base>
     465inline void recorder<Base>::ReplaceArg(size_t i_arg, size_t value)
     466{       rec_op_arg_[i_arg] =  static_cast<addr_t>( value ); }
     467// --------------------------------------------------------------------------
     468/*!
    426469Put a character string in the text for this recording.
    427470
  • trunk/cppad/local/rev_hes_sweep.hpp

    r2910 r2991  
    208208        CppAD::vectorBool zh_value(limit);
    209209# endif
    210         while(op != BeginOp)
     210        bool more_operators = true;
     211        while(more_operators)
    211212        {
    212213                // next op
     
    274275
    275276                        case BeginOp:
    276                         CPPAD_ASSERT_NARG_NRES(op, 0, 1)
     277                        CPPAD_ASSERT_NARG_NRES(op, 1, 1)
     278                        more_operators = false;
     279                        break;
     280                        // -------------------------------------------------
     281
     282                        case CSkipOp:
     283                        // CSkipOp has a variable number of arguments and
     284                        // next_reverse thinks it one has one argument.
     285                        // We must inform next_reverse of this special case.
     286                        play->reverse_cskip(op, arg, i_op, i_var);
    277287                        break;
    278288                        // -------------------------------------------------
     
    783793                        std::cout,
    784794                        play,
     795                        i_op,
    785796                        i_var,
    786797                        op,
  • trunk/cppad/local/rev_jac_sweep.hpp

    r2910 r2991  
    188188        CppAD::vector<bool> z_value(limit);
    189189# endif
    190         while(op != BeginOp )
     190        bool more_operators = true;
     191        while(more_operators)
    191192        {
    192193                // next op
     
    254255
    255256                        case BeginOp:
    256                         CPPAD_ASSERT_NARG_NRES(op, 0, 1);
     257                        CPPAD_ASSERT_NARG_NRES(op, 1, 1);
     258                        more_operators = false;
     259                        break;
     260                        // -------------------------------------------------
     261
     262                        case CSkipOp:
     263                        // CSkipOp has a variable number of arguments and
     264                        // next_reverse thinks it one has one argument.
     265                        // We must inform next_reverse of this special case.
     266                        play->reverse_cskip(op, arg, i_op, i_var);
    257267                        break;
    258268                        // -------------------------------------------------
     
    698708                        std::cout,
    699709                        play,
     710                        i_op,
    700711                        i_var,
    701712                        op,
  • trunk/cppad/local/reverse.hpp

    r2910 r2991  
    182182                taylor_.data(),
    183183                p,
    184                 Partial.data()
     184                Partial.data(),
     185                cskip_op_
    185186        );
    186187
  • trunk/cppad/local/reverse_sweep.hpp

    r2910 r2991  
    7272
    7373\param Rec
     742DO: change this name from Rec to play (becuase it is a player
     75and not a recorder).
    7476The information stored in \a Rec
    7577is a recording of the operations corresponding to the function
     
    145147respect to \f$ u_j^{(k)} \f$.
    146148
     149\param cskip_op
     150Is a vector with size Rec->num_rec_op().
     151If cskip_op[i] is true, the operator index i in the recording
     152does not affect any of the dependent variable (given the value
     153of the independent variables).
     154
    147155\par Assumptions
    148156The first operator on the tape is a BeginOp,
     
    152160template <class Base>
    153161void ReverseSweep(
    154         size_t                d,
    155         size_t                n,
    156         size_t                numvar,
    157         player<Base>*         Rec,
    158         size_t                J,
    159         const Base*           Taylor,
    160         size_t                K,
    161         Base*                 Partial
     162        size_t                      d,
     163        size_t                      n,
     164        size_t                      numvar,
     165        player<Base>*               Rec,
     166        size_t                      J,
     167        const Base*                 Taylor,
     168        size_t                      K,
     169        Base*                       Partial,
     170        const CppAD::vector<bool>&  cskip_op
    162171)
    163172{
     
    212221        std::cout << std::endl;
    213222# endif
    214         while(op != BeginOp )
     223        bool more_operators = true;
     224        while(more_operators)
    215225        {       // next op
    216226                Rec->next_reverse(op, arg, i_op, i_var);
    217 # ifndef NDEBUG
    218                 if( i_op <= n )
    219                 {       CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp));
     227                CPPAD_ASSERT_UNKNOWN((i_op >  n) | (op == InvOp) | (op == BeginOp));
     228                CPPAD_ASSERT_UNKNOWN((i_op <= n) | (op != InvOp) | (op != BeginOp));
     229
     230                // check if we are skipping this operation
     231                while( cskip_op[i_op] )
     232                {       if( op == CSumOp )
     233                        {       // CSumOp has a variable number of arguments
     234                                Rec->reverse_csum(op, arg, i_op, i_var);
     235                        }
     236                        Rec->next_reverse(op, arg, i_op, i_var);
    220237                }
    221                 else    CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
    222 # endif
    223238
    224239                // rest of informaiton depends on the case
     
    231246                        std::cout,
    232247                        Rec,
     248                        i_op,
    233249                        i_tmp,
    234250                        op,
     
    294310
    295311                        case BeginOp:
    296                         CPPAD_ASSERT_NARG_NRES(op, 0, 1);
    297                         break;
    298                         // --------------------------------------------------
     312                        CPPAD_ASSERT_NARG_NRES(op, 1, 1);
     313                        more_operators = false;
     314                        break;
     315                        // --------------------------------------------------
     316
     317                        case CSkipOp:
     318                        // CSkipOp has a variable number of arguments and
     319                        // next_forward thinks it one has one argument.
     320                        // we must inform next_forward of this special case.
     321                        Rec->reverse_cskip(op, arg, i_op, i_var);
     322                        break;
     323                        // -------------------------------------------------
    299324
    300325                        case CSumOp:
  • trunk/example/CMakeLists.txt

    r2892 r2991  
    150150        near_equal_ext.cpp
    151151        not_complex_ad.cpp
     152        number_skip.cpp
    152153        numeric_type.cpp
    153154        ode_err_control.cpp
  • trunk/example/example.cpp

    r2892 r2991  
    122122extern bool NearEqualExt(void);
    123123extern bool not_complex_ad(void);
     124extern bool number_skip(void);
    124125extern bool NumericType(void);
    125126extern bool OdeErrControl(void);
     
    276277        ok &= Run( NearEqualExt,      "NearEqualExt"     );
    277278        ok &= Run( not_complex_ad,    "not_complex_ad"   );
     279        ok &= Run( number_skip,       "number_skip"      );
    278280        ok &= Run( NumericType,       "NumericType"      );
    279281        ok &= Run( OdeErrControl,     "OdeErrControl"    );
  • trunk/example/makefile.am

    r2940 r2991  
    145145        near_equal_ext.cpp \
    146146        not_complex_ad.cpp \
     147        number_skip.cpp \
    147148        numeric_type.cpp \
    148149        ode_err_control.cpp \
  • trunk/example/seq_property.cpp

    r2506 r2991  
    11/* $Id$ */
    22/* --------------------------------------------------------------------------
    3 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     3CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    44
    55CppAD is distributed under multiple licenses. This distribution is under
     
    7474        size_t nop  = 1;
    7575
    76         // Use narg to track the number of operator arguments
    77         size_t narg = 0;
     76        // Start with one for operator corresponding to phantom argument
     77        size_t narg = 1;
    7878
    7979        // Use ntext to track the number of characters used to label
  • trunk/makefile.am

    r2859 r2991  
    161161        cppad/local/cos_op.hpp \
    162162        cppad/local/cppad_assert.hpp \
     163        cppad/local/cskip_op.hpp \
    163164        cppad/local/csum_op.hpp \
    164165        cppad/local/declare_ad.hpp \
     
    200201        cppad/local/mul_op.hpp \
    201202        cppad/local/near_equal_ext.hpp \
     203        cppad/local/num_skip.hpp \
    202204        cppad/local/omp_max_thread.hpp \
    203205        cppad/local/op_code.hpp \
  • trunk/omh/example_list.omh

    r2897 r2991  
    181181$rref near_equal_ext.cpp$$
    182182$rref not_complex_ad.cpp$$
     183$rref number_skip.cpp$$
    183184$rref numeric_type.cpp$$
    184185$rref ode_err_control.cpp$$
  • trunk/omh/seq_property.omh

    r2683 r2991  
    11$Id$
    22/* --------------------------------------------------------------------------
    3 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell
     3CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
    44
    55CppAD is distributed under multiple licenses. This distribution is under
     
    186186Note that one integer index is stored in the operation sequence
    187187for each argument.
     188Also note that, as of 2013-10-20, there is an extra
     189phantom argument with index 0 that is not used.
    188190
    189191$head size_text$$
  • trunk/test_more/optimize.cpp

    r2976 r2991  
    1818namespace {
    1919        // -------------------------------------------------------------------
     20        // Test conditional optimizing out call to an atomic function call
     21        void k_algo(
     22                const CppAD::vector< CppAD::AD<double> >& x ,
     23                      CppAD::vector< CppAD::AD<double> >& y )
     24        {       y[0] = x[0] + x[1]; }
     25
     26        void h_algo(
     27                const CppAD::vector< CppAD::AD<double> >& x ,
     28                      CppAD::vector< CppAD::AD<double> >& y )
     29        {       y[0] = x[0] - x[1]; }
     30
     31        bool atomic_cond_exp(void)
     32        {       bool ok = true;
     33                typedef CppAD::vector< CppAD::AD<double> > ADVector;
     34
     35                // Create a checkpoint version of the function g
     36                ADVector ax(2), ag(1), ah(1), ay(1);
     37                ax[0] = 0.;
     38                ax[1] = 1.;
     39                CppAD::checkpoint<double> k_check("k_check", k_algo, ax, ag);
     40                CppAD::checkpoint<double> h_check("h_check", h_algo, ax, ah);
     41
     42                // independent variable vector
     43                Independent(ax);
     44
     45                // atomic function calls that get conditionally used
     46                k_check(ax, ag);
     47                h_check(ax, ah);
     48
     49                // conditional expression
     50                ay[0] = CondExpLt(ax[0], ax[1], ag[0], ah[0]);
     51       
     52                // create function object f : ax -> ay
     53                CppAD::ADFun<double> f;
     54                f.Dependent(ax, ay);
     55       
     56                // use zero order to evaluate when condition is true
     57                CppAD::vector<double>  x(2), dx(2);
     58                CppAD::vector<double>  y(1), dy(1), w(1);
     59                x[0] = 3.;
     60                x[1] = 4.;
     61                y    = f.Forward(0, x);
     62                ok  &= y[0] == x[0] + x[1];
     63
     64                // before optimize
     65                ok  &= f.number_skip() == 0;
     66
     67                // now optimize the operation sequence
     68                f.optimize();
     69
     70                // optimized zero order forward when condition is false
     71                x[0] = 4.;
     72                x[1] = 3.;
     73                y    = f.Forward(0, x);
     74                ok   = y[0] == x[0] - x[1];
     75
     76                // after optimize can skip either call to g or call to h
     77                ok  &= f.number_skip() == 1;
     78
     79                // optimized first order forward
     80                dx[0] = 2.;
     81                dx[1] = 1.;
     82                dy    = f.Forward(1, dx);
     83                ok   &= dy[0] == dx[0] - dx[1];
     84
     85                // optimized first order reverse
     86                w[0]  = 1.;
     87                dx    = f.Reverse(1, w);
     88                ok   &= dx[0] == 1.;
     89                ok   &= dx[1] == -1.;
     90       
     91                return ok;
     92        }
     93        // -------------------------------------------------------------------
    2094        // Test of optimizing out arguments to an atomic function
    21         void algo(
     95        void g_algo(
    2296                const CppAD::vector< CppAD::AD<double> >& ax ,
    2397                      CppAD::vector< CppAD::AD<double> >& ay )
    2498        {       ay = ax; }
    2599
     100        bool atomic_no_used(void)
     101        {       bool ok = true;
     102                using CppAD::AD;
     103                using CppAD::vector;
     104       
     105                // Create a checkpoint version of the function g
     106                vector< AD<double> > ax(2), ay(1), az(1);
     107                ax[0] = 0.;
     108                ax[1] = 1.;
     109                CppAD::checkpoint<double> g_check("g_check", g_algo, ax, ay);
     110       
     111                // independent variable vector
     112                Independent(ax);
     113       
     114                // call atomic function that does not get used
     115                g_check(ax, ay);
     116       
     117                // conditional expression
     118                az[0] = CondExpLt(ax[0], ax[1], ax[0] + ax[1], ax[0] - ax[1]);
     119               
     120                // create function object f : ax -> az
     121                CppAD::ADFun<double> f;
     122                f.Dependent(ax, az);
     123
     124                // number of variables before optimization
     125                size_t n_before = f.size_var();
     126               
     127                // now optimize the operation sequence
     128                f.optimize();
     129
     130                // number of variables before optimization
     131                size_t n_after = f.size_var();
     132                ok            &= n_after + 1 == n_before;
     133       
     134                // check optimization works ok
     135                vector<double> x(2), z(1);
     136                x[0] = 4.;
     137                x[1] = 3.;
     138                z    = f.Forward(0, x);
     139                ok   = z[0] == x[0] - x[1];
     140               
     141                return ok;
     142        }
    26143        bool atomic_arguments(void)
    27144        {       bool ok = true;
     
    30147                vector< AD<double> > au(2), aw(2), ax(2), ay(1);
    31148
    32                 // create atomic function corresponding to algo
     149                // create atomic function corresponding to g_algo
    33150                au[0] = 1.0;
    34151                au[1] = 2.0;
    35                 CppAD::checkpoint<double> algo_check("algo", algo, au, ax);
     152                CppAD::checkpoint<double> g_check("g_algo", g_algo, au, ax);
    36153
    37154                // start recording a new function
    38155                CppAD::Independent(ax);
    39156
    40                 // now use algo_check during the recording
     157                // now use g_check during the recording
    41158                au[0] = ax[0] + ax[1]; // this argument requires a new variable
    42159                au[1] = ax[0] - ax[1]; // this argument also requires a new variable
    43                 algo_check(au, aw);
     160                g_check(au, aw);
    44161
    45162                // now create f(x) = x_0 - x_1
     
    765882                return ok;
    766883        }
    767         bool forward_sparse_jacobian_csum()
     884        bool forward_sparse_jacobian()
    768885        {       bool ok = true;
    769886                using namespace CppAD;
     
    773890       
    774891                // dimension of the range space
    775                 size_t m = 2;
     892                size_t m = 3;
    776893       
    777894                // independent variable vector
     
    779896                X[0] = 2.;
    780897                X[1] = 3.;
     898                X[2] = 4.;
    781899                Independent(X);
    782900       
     
    800918                Y[index]             = Y[0] - (X[1] + X[2]);
    801919                Check[index * n + 0] = true;
     920                Check[index * n + 1] = true;
     921                Check[index * n + 2] = true;
     922                index++;
     923
     924                // Y[2]
     925                // 2DO: There is a subtitle issue that has to do with using reverse
     926                // jacobian sparsity patterns during the optimization process.
     927                // We need an option to include X[0] in the sparsity pattern
     928                // so the optimizer can know it affects the results.
     929                Y[index]             = CondExpLe(X[0], X[1], X[1]+X[1], X[2]-X[2]);
     930                Check[index * n + 0] = false;
    802931                Check[index * n + 1] = true;
    803932                Check[index * n + 2] = true;
     
    835964                return ok;
    836965        }
    837         bool reverse_sparse_jacobian_csum()
     966        bool reverse_sparse_jacobian()
    838967        {       bool ok = true;
    839968                using namespace CppAD;
     
    843972       
    844973                // dimension of the range space
    845                 size_t m = 2;
     974                size_t m = 3;
    846975       
    847976                // independent variable vector
     
    849978                X[0] = 2.;
    850979                X[1] = 3.;
     980                X[2] = 4.;
    851981                Independent(X);
    852982       
     
    8731003                Check[index * n + 2] = true;
    8741004                index++;
     1005
     1006                // Y[2]
     1007                // 2DO: There is a subtitle issue that has to do with using reverse
     1008                // jacobian sparsity patterns during the optimization process.
     1009                // We need an option to include X[0] in the sparsity pattern
     1010                // so the optimizer can know it affects the results.
     1011                Y[index]             = CondExpLe(X[0], X[1], X[1]+X[1], X[2]-X[2]);
     1012                Check[index * n + 0] = false;
     1013                Check[index * n + 1] = true;
     1014                Check[index * n + 2] = true;
     1015                index++;
    8751016       
    8761017                // check final index
     
    9021043                return ok;
    9031044        }
    904         bool reverse_sparse_hessian_csum(void)
     1045        bool reverse_sparse_hessian(void)
    9051046        {       bool ok = true;
    9061047                using CppAD::AD;
    9071048                size_t i, j;
    9081049       
    909                 size_t n = 2;
     1050                size_t n = 3;
    9101051                CppAD::vector< AD<double> > X(n);
    9111052                X[0] = 1.;
    9121053                X[1] = 2.;
     1054                X[2] = 3.;
    9131055                CppAD::Independent(X);
    9141056       
    9151057                size_t m = 1;
    9161058                CppAD::vector< AD<double> > Y(m);
    917                 Y[0] = (2. + X[0] + X[1] + 3.) * X[0];
     1059                Y[0] = CondExpGe( X[0], X[1],
     1060                        X[0] + (2. + X[1] + 3.) * X[1],
     1061                        X[0] + (2. + X[2] + 3.) * X[1]
     1062                );
    9181063       
    9191064                CppAD::vector<bool> check(n * n);
    920                 check[0 * n + 0] = true;  // partial w.r.t. x[0], x[0]
    921                 check[0 * n + 1] = true;  //                x[0], x[1]
    922                 check[1 * n + 0] = true;  //                x[1], x[0]
    923                 check[1 * n + 1] = false; //                x[1], x[1]
     1065                check[0 * n + 0] = false; // partial w.r.t. x[0], x[0]
     1066                check[0 * n + 1] = false; //                x[0], x[1]
     1067                check[0 * n + 2] = false; //                x[0], x[2]
     1068
     1069                check[1 * n + 0] = false; // partial w.r.t. x[1], x[0]
     1070                check[1 * n + 1] = true;  //                x[1], x[1]
     1071                check[1 * n + 2] = true;  //                x[1], x[2]
     1072
     1073                check[2 * n + 0] = false; // partial w.r.t. x[2], x[0]
     1074                check[2 * n + 1] = true;  //                x[2], x[1]
     1075                check[2 * n + 2] = false; //                x[2], x[2]
    9241076       
    9251077                // create function object F : X -> Y
     
    11661318bool optimize(void)
    11671319{       bool ok = true;
     1320        // check optimizing out entire atomic function
     1321        ok     &= atomic_cond_exp();
    11681322        // check optimizing out atomic arguments
    11691323        ok     &= atomic_arguments();
     
    11811335        ok     &= forward_csum();
    11821336        ok     &= reverse_csum();
    1183         ok     &= forward_sparse_jacobian_csum();
    1184         ok     &= reverse_sparse_jacobian_csum();
    1185         ok     &= reverse_sparse_hessian_csum();
     1337        // sparsity patterns
     1338        ok     &= forward_sparse_jacobian();
     1339        ok     &= reverse_sparse_jacobian();
     1340        ok     &= reverse_sparse_hessian();
    11861341        // check that CondExp properly detects dependencies
    11871342        ok     &= cond_exp_depend();
Note: See TracChangeset for help on using the changeset viewer.