Changeset 3809


Ignore:
Timestamp:
Mar 25, 2016 12:36:53 AM (4 years ago)
Author:
bradbell
Message:

merge to branch: trunk
from repository: https://github.com/coin-or/CppAD
start hash code: f8fc499c5720e9bead5d00b92db3d775c10e7043
end hash code: dd967ef41b8d6731d90ebb8b3e7e8b863565289c

commit dd967ef41b8d6731d90ebb8b3e7e8b863565289c
Author: Brad Bell <bradbell@…>
Date: Thu Mar 24 19:19:00 2016 -0700

eigen_mat_mul.hpp: add for_sparse_hes calculation.
atomic_base.hpp: edits to forward and reverse sparse hessian documentation.
for_hes_sweep.hpp: fix bug in ForSparseHes? calculation.
eigen_mat_mul.cpp: test for_sparse_hes calculation.

commit 99610d3bdda1162ec7e8884b3cc5811b5fc48c24
Author: Brad Bell <bradbell@…>
Date: Thu Mar 24 17:51:42 2016 -0700

eigen_mat_mul.cpp: test rev_sparse_hes.
eigen_mat_mul.hpp: fix heading -> subheading.

commit 19a0f5d8c3c1e8ea210f852f49adc290609fdf10
Author: Brad Bell <bradbell@…>
Date: Thu Mar 24 17:24:50 2016 -0700

eigen_mat_mul.hpp: add code for rev_sparse_hes.
atomic_base.hpp: in doc change some g(y) -> g[f(x)] (clearer).
eigen_mat_mul.cpp: test second order derivatives.

commit 4487cc1d4f5e598d690dba681b5c275281981bf0
Author: Brad Bell <bradbell@…>
Date: Thu Mar 24 15:14:17 2016 -0700

Add rev_sparse_jac to eigen_mat_mul.hpp.

commit 055fa95218ca47e30204796c887f33b5ca9f9788
Author: Brad Bell <bradbell@…>
Date: Thu Mar 24 07:40:49 2016 -0700

eigen_mat_mul.hpp: use subheadings to separate Public and Private.
eigen_mat_mul.cpp: test for_sparse_jac.

commit af8898d93493df4d1a088038abe926f9ab9f54d5
Author: Brad Bell <bradbell@…>
Date: Thu Mar 24 07:06:46 2016 -0700

eigen_mat_mul.hpp: add for_sparse_jac (not yet tested).
eigen_mat_mul.cpp: change to example with a non-zero Hessian.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/cppad/example/eigen_mat_mul.hpp

    r3808 r3809  
    3131
    3232/* %$$
    33 $head Publice Types$$
     33$head Publice$$
     34
     35$subhead Types$$
    3436$srccode%cpp% */
    3537namespace { // BEGIN_EMPTY_NAMESPACE
     
    5052                ad_scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > ad_matrix;
    5153/* %$$
    52 $head Public Constructor$$
     54$subhead Constructor$$
    5355$srccode%cpp% */
    5456        // constructor
     
    7274        { }
    7375/* %$$
    74 $head Public Pack$$
     76$subhead Pack$$
    7577$srccode%cpp% */
    7678        template <class Matrix, class Vector>
     
    9799        }
    98100/* %$$
    99 $head Public Unpack$$
     101$subhead Unpack$$
    100102$srccode%cpp% */
    101103        template <class Matrix, class Vector>
     
    116118        }
    117119/* %$$
    118 $head Private Variables$$
     120$head Private$$
     121
     122$subhead Variables$$
    119123$srccode%cpp% */
    120124private:
     
    137141        // -------------------------------------------------------------
    138142/* %$$
    139 $head Private rows$$
     143$subhead rows$$
    140144$srccode%cpp% */
    141145        // convert from int to size_t
     
    145149        {       return size_t( x.rows() ); }
    146150/* %$$
    147 $head Private cols$$
     151$subhead cols$$
    148152$srccode%cpp% */
    149153        // convert from int to size_t
     
    153157        {       return size_t( x.cols() ); }
    154158/* %$$
    155 $head Private forward$$
     159$subhead forward$$
    156160$srccode%cpp% */
    157161        // forward mode routine called by CppAD
     
    252256        }
    253257/* %$$
    254 $head Private reverse$$
     258$subhead reverse$$
    255259$srccode%cpp% */
    256260        // reverse mode routine called by CppAD
     
    343347        }
    344348/* %$$
     349$subhead for_sparse_jac$$
     350$srccode%cpp% */
     351        // forward Jacobian sparsity routine called by CppAD
     352        virtual bool for_sparse_jac(
     353                // number of columns in the matrix R
     354                size_t                                       q ,
     355                // sparsity pattern for the matrix R
     356                const CppAD::vector< std::set<size_t> >&     r ,
     357                // sparsity pattern for the matrix S = f'(x) * R
     358                CppAD::vector< std::set<size_t> >&           s )
     359        {       assert( nx_ == r.size() );
     360                assert( ny_ == s.size() );
     361                //
     362                size_t n_left = nr_left_ * n_middle_;
     363                for(size_t i = 0; i < nr_left_; i++)
     364                {       for(size_t j = 0; j < nc_right_; j++)
     365                        {       // pack index for entry (i, j) in result
     366                                size_t i_result = i * nc_right_ + j;
     367                                s[i_result].clear();
     368                                for(size_t ell = 0; ell < n_middle_; ell++)
     369                                {       // pack index for entry (i, ell) in left
     370                                        size_t i_left  = i * n_middle_ + ell;
     371                                        // pack index for entry (ell, j) in right
     372                                        size_t i_right = n_left + ell * nc_right_ + j;
     373                                        //
     374                                        s[i_result] = CppAD::set_union(s[i_result], r[i_left] );
     375                                        s[i_result] = CppAD::set_union(s[i_result], r[i_right] );
     376                                }
     377                        }
     378                }
     379                return true;
     380        }
     381/* %$$
     382$subhead rev_sparse_jac$$
     383$srccode%cpp% */
     384        // reverse Jacobian sparsity routine called by CppAD
     385        virtual bool rev_sparse_jac(
     386                // number of columns in the matrix R^T
     387                size_t                                      q  ,
     388                // sparsity pattern for the matrix R^T
     389                const CppAD::vector< std::set<size_t> >&    rt ,
     390                // sparsoity pattern for the matrix S^T = f'(x)^T * R^T
     391                CppAD::vector< std::set<size_t> >&          st )
     392        {       assert( nx_ == st.size() );
     393                assert( ny_ == rt.size() );
     394
     395                // initialize S^T as empty
     396                for(size_t i = 0; i < nx_; i++)
     397                        st[i].clear();
     398
     399                // sparsity for S(x)^T = f'(x)^T * R^T
     400                size_t n_left = nr_left_ * n_middle_;
     401                for(size_t i = 0; i < nr_left_; i++)
     402                {       for(size_t j = 0; j < nc_right_; j++)
     403                        {       // pack index for entry (i, j) in result
     404                                size_t i_result = i * nc_right_ + j;
     405                                st[i_result].clear();
     406                                for(size_t ell = 0; ell < n_middle_; ell++)
     407                                {       // pack index for entry (i, ell) in left
     408                                        size_t i_left  = i * n_middle_ + ell;
     409                                        // pack index for entry (ell, j) in right
     410                                        size_t i_right = n_left + ell * nc_right_ + j;
     411                                        //
     412                                        st[i_left]  = CppAD::set_union(st[i_left],  rt[i_result]);
     413                                        st[i_right] = CppAD::set_union(st[i_right], rt[i_result]);
     414                                }
     415                        }
     416                }
     417                return true;
     418        }
     419/* %$$
     420$subhead for_sparse_hes$$
     421$srccode%cpp% */
     422        virtual bool for_sparse_hes(
     423                // which components of x are variables for this call
     424                const CppAD::vector<bool>&                   vx,
     425                // sparsity pattern for the diagonal of R
     426                const CppAD::vector<bool>&                   r ,
     427                // sparsity pattern for the vector S
     428                const CppAD::vector<bool>&                   s ,
     429                // sparsity patternfor the Hessian H(x)
     430                CppAD::vector< std::set<size_t> >&           h )
     431        {       assert( vx.size() == nx_ );
     432                assert( r.size()  == nx_ );
     433                assert( s.size()  == ny_ );
     434                assert( h.size()  == nx_ );
     435                //
     436                // initilize h as empty
     437                for(size_t i = 0; i < nx_; i++)
     438                        h[i].clear();
     439                //
     440                size_t n_left = nr_left_ * n_middle_;
     441                for(size_t i = 0; i < nr_left_; i++)
     442                {       for(size_t j = 0; j < nc_right_; j++)
     443                        {       // pack index for entry (i, j) in result
     444                                size_t i_result = i * nc_right_ + j;
     445                                if( s[i_result] )
     446                                {       for(size_t ell = 0; ell < n_middle_; ell++)
     447                                        {       // pack index for entry (i, ell) in left
     448                                                size_t i_left  = i * n_middle_ + ell;
     449                                                // pack index for entry (ell, j) in right
     450                                                size_t i_right = n_left + ell * nc_right_ + j;
     451                                                if( r[i_left] & r[i_right] )
     452                                                {       h[i_left].insert(i_right);
     453                                                        h[i_right].insert(i_left);
     454                                                }
     455                                        }
     456                                }
     457                        }
     458                }
     459                return true;
     460        }
     461/* %$$
     462$subhead rev_sparse_hes$$
     463$srccode%cpp% */
     464        // reverse Hessian sparsity routine called by CppAD
     465        virtual bool rev_sparse_hes(
     466                // which components of x are variables for this call
     467                const CppAD::vector<bool>&                   vx,
     468                // sparsity pattern for S(x) = g'[f(x)]
     469                const CppAD::vector<bool>&                   s ,
     470                // sparsity pattern for d/dx g[f(x)] = S(x) * f'(x)
     471                CppAD::vector<bool>&                         t ,
     472                // number of columns in R, U(x), and V(x)
     473                size_t                                       q ,
     474                // sparsity pattern for R
     475                const CppAD::vector< std::set<size_t> >&     r ,
     476                // sparsity pattern for U(x) = g^{(2)} [ f(x) ] * f'(x) * R
     477                const CppAD::vector< std::set<size_t> >&     u ,
     478                // sparsity pattern for
     479                // V(x) = f'(x)^T * U(x) + sum_{i=0}^{m-1} S_i(x) f_i^{(2)} (x) * R
     480                CppAD::vector< std::set<size_t> >&           v )
     481        {       assert( vx.size() == nx_ );
     482                assert( s.size()  == ny_ );
     483                assert( t.size()  == nx_ );
     484                assert( r.size()  == nx_ );
     485                assert( v.size()  == nx_ );
     486                //
     487                // initilaize return sparsity patterns as false
     488                for(size_t j = 0; j < nx_; j++)
     489                {       t[j] = false;
     490                        v[j].clear();
     491                }
     492                //
     493                size_t n_left = nr_left_ * n_middle_;
     494                for(size_t i = 0; i < nr_left_; i++)
     495                {       for(size_t j = 0; j < nc_right_; j++)
     496                        {       // pack index for entry (i, j) in result
     497                                size_t i_result = i * nc_right_ + j;
     498                                for(size_t ell = 0; ell < n_middle_; ell++)
     499                                {       // pack index for entry (i, ell) in left
     500                                        size_t i_left  = i * n_middle_ + ell;
     501                                        // pack index for entry (ell, j) in right
     502                                        size_t i_right = n_left + ell * nc_right_ + j;
     503                                        //
     504                                        // back propagate T(x) = S(x) * f'(x).
     505                                        t[i_left]  |= bool( s[i_result] );
     506                                        t[i_right] |= bool( s[i_result] );
     507                                        //
     508                                        // V(x) = f'(x)^T * U(x) +  sum_i S_i(x) * f_i''(x) * R
     509                                        // U(x)   = g''[ f(x) ] * f'(x) * R
     510                                        // S_i(x) = g_i'[ f(x) ]
     511                                        //
     512                                        // back propagate f'(x)^T * U(x)
     513                                        v[i_left]  = CppAD::set_union(v[i_left],  u[i_result] );
     514                                        v[i_right] = CppAD::set_union(v[i_right], u[i_result] );
     515                                        //
     516                                        // back propagate S_i(x) * f_i''(x) * R
     517                                        // (here is where we use vx to check for cross terms)
     518                                        if( s[i_result] & vx[i_left] & vx[i_right] )
     519                                        {       v[i_left]  = CppAD::set_union(v[i_left],  r[i_right] );
     520                                                v[i_right] = CppAD::set_union(v[i_right], r[i_left]  );
     521                                        }
     522                                }
     523                        }
     524                }
     525                return true;
     526        }
     527/* %$$
    345528$head End Class Definition$$
    346529$srccode%cpp% */
  • trunk/cppad/local/atomic_base.hpp

    r3805 r3809  
    11401140Jacobian sparsity patterns.
    11411141For a fixed matrix $latex R \in B^{q \times m}$$,
    1142 the Jacobian of $latex R * f( x )$$ with respect to $latex x \in B^q$$ is
     1142the Jacobian of $latex R * f( x )$$ with respect to $latex x \in B^n$$ is
    11431143$latex \[
    11441144        S(x) = R * f^{(1)} (x)
     
    13031303The input value of its elements
    13041304are not specified (must not matter).
    1305 Upon return, $icode v$$ is a
     1305Upon return, $icode h$$ is a
    13061306$cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
    13071307$latex H(x) \in B^{n \times n}$$ which is defined above.
     
    14121412and its size is $icode m$$.
    14131413It is a sparsity pattern for
    1414 $latex S(x) = g^{(1)} (y) \in B^{1 \times m}$$.
     1414$latex S(x) = g^{(1)} [ f(x) ] \in B^{1 \times m}$$.
    14151415
    14161416$subhead t$$
     
    14581458U(x)
    14591459& = &
    1460 \partial_u \{ \partial_y g[ y + f^{(1)} (x) R u ] \}_{u=0}
     1460\{ \partial_u \{ \partial_y g[ y + f^{(1)} (x) R u ] \}_{y=f(x)} \}_{u=0}
    14611461\\
    14621462& = &
    1463 \partial_u \{ g^{(1)} [ y + f^{(1)} (x) R u ] \}_{u=0}
     1463\partial_u \{ g^{(1)} [ f(x) + f^{(1)} (x) R u ] \}_{u=0}
    14641464\\
    14651465& = &
    1466 g^{(2)} (y) f^{(1)} (x) R
     1466g^{(2)} [ f(x) ] f^{(1)} (x) R
    14671467\end{array}
    14681468\] $$
     
    14911491\\
    14921492& = &
    1493 f^{(1)} (x)^\R{T} g^{(2)} ( y ) f^{(1)} (x)  R
     1493f^{(1)} (x)^\R{T} g^{(2)} [ f(x) ] f^{(1)} (x)  R
    14941494+
    1495 \sum_{i=1}^m g_i^{(1)} (y) \; f_i^{(2)} (x) R
     1495\sum_{i=1}^m g_i^{(1)} [ f(x) ] \; f_i^{(2)} (x) R
    14961496\\
    14971497& = &
  • trunk/cppad/local/for_hes_sweep.hpp

    r3804 r3809  
    518518                        user_vx[user_j] = false;
    519519                        ++user_j;
    520                         if( user_j == n )
     520                        if( user_j == user_n )
    521521                                user_state = user_ret;
    522522                        break;
     
    536536                                user_r[user_j] = true;
    537537                        ++user_j;
    538                         if( user_j == n )
     538                        if( user_j == user_n )
    539539                                user_state = user_ret;
    540540                        break;
  • trunk/example/atomic/eigen_mat_mul.cpp

    r3808 r3809  
    2929f(x) =
    3030\left( \begin{array}{cc}
    31         0 & 0 \\
    32         1 & 2 \\
    33         2 & 4
     31        0   & 0 \\
     32        1   & 2 \\
     33        x_0 & x_1
    3434\end{array} \right)
    3535\left( \begin{array}{c}
     
    4141        0 \\
    4242        x_0 + 2 x_1 \\
    43         2 x_0 + 4 x_1 )
     43        x_0 x_0 + x_1 x_1 )
    4444\end{array} \right)
    4545\] $$
     
    110110        atomic_eigen_mat_mul<scalar> mat_mul(nr_left, n_middle, nc_right);
    111111        // -------------------------------------------------------------------
    112         //        [ 0  0 ]
    113         // left = [ 1  1 ]
    114         //        [ 2  2 ]
    115         ad_matrix ad_left(nr_left, n_middle);
    116         for(size_t i = 0; i < nr_left; i++)
    117         {       for(size_t j = 0; j < n_middle; j++)
    118                         ad_left(i, j) = scalar( (j + 1) * i );
    119         }
    120         // -------------------------------------------------------------------
    121112        // declare independent variable vector x
    122113        size_t n = 2;
     
    126117        CppAD::Independent(ad_x);
    127118        // -------------------------------------------------------------------
     119        //        [ 0     0    ]
     120        // left = [ 1     2    ]
     121        //        [ x[0]  x[1] ]
     122        ad_matrix ad_left(nr_left, n_middle);
     123        ad_left(0, 0) = ad_scalar(0.0);
     124        ad_left(0, 1) = ad_scalar(0.0);
     125        ad_left(1, 0) = ad_scalar(1.0);
     126        ad_left(1, 1) = ad_scalar(2.0);
     127        ad_left(2, 0) = ad_x[0];
     128        ad_left(2, 1) = ad_x[1];
     129        // -------------------------------------------------------------------
    128130        // right = [ x[0] , x[1] ]^T
    129131        ad_matrix ad_right(n_middle, nc_right);
    130         for(size_t i = 0; i < n_middle; i++)
    131         {       for(size_t j = 0; j < nc_right; j++)
    132                         ad_right(i, j) = ad_x[i];
    133         }
     132        ad_right(0, 0) = ad_x[0];
     133        ad_right(1, 0) = ad_x[1];
    134134        // -------------------------------------------------------------------
    135135        // use atomic operation to multiply left * right
     
    154154                x[i] = scalar(i + 2);
    155155        y   = f.Forward(0, x);
    156         ok &= NearEqual(y[0], 0.0,                     eps, eps);
    157         ok &= NearEqual(y[1], x[0] + 2.0 * x[1],       eps, eps);
    158         ok &= NearEqual(y[2], 2.0 * x[0] + 4.0 * x[1], eps, eps);
     156        ok &= NearEqual(y[0], 0.0,                       eps, eps);
     157        ok &= NearEqual(y[1], x[0] + 2.0 * x[1],         eps, eps);
     158        ok &= NearEqual(y[2], x[0] * x[0] + x[1] * x[1], eps, eps);
    159159        // -------------------------------------------------------------------
    160160        // check first order forward mode
     
    163163        x1[1] = 0.0;
    164164        y1    = f.Forward(1, x1);
    165         ok   &= NearEqual(y1[0], 0.0, eps, eps);
    166         ok   &= NearEqual(y1[1], 1.0, eps, eps);
    167         ok   &= NearEqual(y1[2], 2.0, eps, eps);
     165        ok   &= NearEqual(y1[0], 0.0,        eps, eps);
     166        ok   &= NearEqual(y1[1], 1.0,        eps, eps);
     167        ok   &= NearEqual(y1[2], 2.0 * x[0], eps, eps);
    168168        x1[0] = 0.0;
    169169        x1[1] = 1.0;
    170170        y1    = f.Forward(1, x1);
    171         ok   &= NearEqual(y1[0], 0.0, eps, eps);
    172         ok   &= NearEqual(y1[1], 2.0, eps, eps);
    173         ok   &= NearEqual(y1[2], 4.0, eps, eps);
     171        ok   &= NearEqual(y1[0], 0.0,        eps, eps);
     172        ok   &= NearEqual(y1[1], 2.0,        eps, eps);
     173        ok   &= NearEqual(y1[2], 2.0 * x[1], eps, eps);
     174        // -------------------------------------------------------------------
     175        // check second order forward mode
     176        CPPAD_TESTVECTOR(scalar) x2(n), y2(m);
     177        x2[0] = 0.0;
     178        x2[1] = 0.0;
     179        y2    = f.Forward(2, x2);
     180        ok   &= NearEqual(y2[0], 0.0, eps, eps);
     181        ok   &= NearEqual(y2[1], 0.0, eps, eps);
     182        ok   &= NearEqual(y2[2], 1.0, eps, eps); // 1/2 * f_1''(x)
    174183        // -------------------------------------------------------------------
    175184        // check first order reverse mode
    176         CPPAD_TESTVECTOR(scalar) w(m), dw(n);
     185        CPPAD_TESTVECTOR(scalar) w(m), d1w(n);
    177186        w[0]  = 0.0;
    178187        w[1]  = 1.0;
    179188        w[2]  = 0.0;
    180         dw    = f.Reverse(1, w);
    181         ok   &= NearEqual(dw[0], 1.0, eps, eps);
    182         ok   &= NearEqual(dw[1], 2.0, eps, eps);
     189        d1w   = f.Reverse(1, w);
     190        ok   &= NearEqual(d1w[0], 1.0, eps, eps);
     191        ok   &= NearEqual(d1w[1], 2.0, eps, eps);
    183192        w[0]  = 0.0;
    184193        w[1]  = 0.0;
    185194        w[2]  = 1.0;
    186         dw    = f.Reverse(1, w);
    187         ok   &= NearEqual(dw[0], 2.0, eps, eps);
    188         ok   &= NearEqual(dw[1], 4.0, eps, eps);
     195        d1w   = f.Reverse(1, w);
     196        ok   &= NearEqual(d1w[0], 2.0 * x[0], eps, eps);
     197        ok   &= NearEqual(d1w[1], 2.0 * x[1], eps, eps);
     198        // -------------------------------------------------------------------
     199        // check second order reverse mode
     200        CPPAD_TESTVECTOR(scalar) d2w(2 * n);
     201        d2w   = f.Reverse(2, w);
     202        ok   &= NearEqual(d2w[0 * 2 + 0], 2.0 * x[0], eps, eps);
     203        ok   &= NearEqual(d2w[1 * 2 + 0], 2.0 * x[1], eps, eps);
     204        // partial f_1 w.r.t x_1, x_0
     205        ok   &= NearEqual(d2w[0 * 2 + 1], 0.0,        eps, eps);
     206        // partial f_1 w.r.t x_1, x_1
     207        ok   &= NearEqual(d2w[1 * 2 + 1], 2.0,        eps, eps);
     208        // -------------------------------------------------------------------
     209        // check forward Jacobian sparsity
     210        CPPAD_TESTVECTOR( std::set<size_t> ) r(n), s(m);
     211        std::set<size_t> check_set;
     212        for(size_t j = 0; j < n; j++)
     213                r[j].insert(j);
     214        s      = f.ForSparseJac(n, r);
     215        check_set.clear();
     216        ok    &= s[0] == check_set;
     217        check_set.insert(0);
     218        check_set.insert(1);
     219        ok    &= s[1] == check_set;
     220        ok    &= s[2] == check_set;
     221        // -------------------------------------------------------------------
     222        // check reverse Jacobian sparsity
     223        r.resize(m);
     224        for(size_t i = 0; i < m; i++)
     225                r[i].insert(i);
     226        s  = f.RevSparseJac(m, r);
     227        check_set.clear();
     228        ok    &= s[0] == check_set;
     229        check_set.insert(0);
     230        check_set.insert(1);
     231        ok    &= s[1] == check_set;
     232        ok    &= s[2] == check_set;
     233        // -------------------------------------------------------------------
     234        // check forward Hessian sparsity for f_2 (x)
     235        CPPAD_TESTVECTOR( std::set<size_t> ) r2(1), s2(1), h(n);
     236        for(size_t j = 0; j < n; j++)
     237                r2[0].insert(j);
     238        s2[0].clear();
     239        s2[0].insert(2);
     240        h = f.ForSparseHes(r2, s2);
     241        check_set.clear();
     242        check_set.insert(0);
     243        ok &= h[0] == check_set;
     244        check_set.clear();
     245        check_set.insert(1);
     246        ok &= h[1] == check_set;
     247        // -------------------------------------------------------------------
     248        // check reverse Hessian sparsity for f_2 (x)
     249        CPPAD_TESTVECTOR( std::set<size_t> ) s3(1);
     250        s3[0].clear();
     251        s3[0].insert(2);
     252        h = f.RevSparseHes(n, s3);
     253        check_set.clear();
     254        check_set.insert(0);
     255        ok &= h[0] == check_set;
     256        check_set.clear();
     257        check_set.insert(1);
     258        ok &= h[1] == check_set;
     259        // -------------------------------------------------------------------
    189260        return ok;
    190261}
  • trunk/omh/whats_new/whats_new_16.omh

    r3808 r3809  
    4040
    4141$head 03-24$$
     42$list number$$
    4243Fix build of $code example/atomic.cpp$$ when
    4344$cref eigen_prefix$$ is not available
    4445(bug introduced when $cref atomic_eigen_mat_mul.cpp$$ was added).
     46$lnext
     47Extend $cref atomic_eigen_mat_mul.cpp$$ example to include
     48$cref/for_sparse_jac/atomic_eigen_mat_mul.hpp/Private/for_sparse_jac/$$,
     49$cref/rev_sparse_jac/atomic_eigen_mat_mul.hpp/Private/rev_sparse_jac/$$,
     50$cref/for_sparse_hes/atomic_eigen_mat_mul.hpp/Private/for_sparse_hes/$$,
     51$cref/rev_sparse_hes/atomic_eigen_mat_mul.hpp/Private/rev_sparse_hes/$$.
     52$lnext
     53Fix a bug in the $cref ForSparseHes$$ routine.
     54$lnext
     55Edit $cref atomic_rev_sparse_hes$$ documentation.
     56$lend
    4557
    4658$head 03-23$$
Note: See TracChangeset for help on using the changeset viewer.