# ifndef CPPAD_CORE_REV_SPARSE_HES_HPP # define CPPAD_CORE_REV_SPARSE_HES_HPP /* -------------------------------------------------------------------------- CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell CppAD is distributed under multiple licenses. This distribution is under the terms of the Eclipse Public License Version 1.0. A copy of this license is included in the COPYING file of this distribution. Please visit http://www.coin-or.org/CppAD/ for information on other licenses. -------------------------------------------------------------------------- */ /* $begin RevSparseHes$$ $spell std VecAD Jacobian Jac Hessian Hes const Bool Dep proportional var cpp $$ $section Hessian Sparsity Pattern: Reverse Mode$$ $head Syntax$$ $icode%h% = %f%.RevSparseHes(%q%, %s%) %$$ $icode%h% = %f%.RevSparseHes(%q%, %s%, %transpose%)%$$ $head Purpose$$ We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the $cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. For a fixed matrix $latex R \in \B{R}^{n \times q}$$ and a fixed vector $latex S \in \B{R}^{1 \times m}$$, we define $latex \[ \begin{array}{rcl} H(x) & = & \partial_x \left[ \partial_u S * F[ x + R * u ] \right]_{u=0} \\ & = & R^\R{T} * (S * F)^{(2)} ( x ) \\ H(x)^\R{T} & = & (S * F)^{(2)} ( x ) * R \end{array} \] $$ Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for the matrix $latex R$$ and the vector $latex S$$, $code RevSparseHes$$ returns a sparsity pattern for the $latex H(x)$$. $head f$$ The object $icode f$$ has prototype $codei% const ADFun<%Base%> %f% %$$ $head x$$ If the operation sequence in $icode f$$ is $cref/independent/glossary/Operation/Independent/$$ of the independent variables in $latex x \in B^n$$, the sparsity pattern is valid for all values of (even if it has $cref CondExp$$ or $cref VecAD$$ operations). $head q$$ The argument $icode q$$ has prototype $codei% size_t %q% %$$ It specifies the number of columns in $latex R \in \B{R}^{n \times q}$$ and the number of rows in $latex H(x) \in \B{R}^{q \times n}$$. It must be the same value as in the previous $cref ForSparseJac$$ call $codei% %f%.ForSparseJac(%q%, %r%, %r_transpose%) %$$ Note that if $icode r_transpose$$ is true, $icode r$$ in the call above corresponding to $latex R^\R{T} \in \B{R}^{q \times n}$$ $head transpose$$ The argument $icode transpose$$ has prototype $codei% bool %transpose% %$$ The default value $code false$$ is used when $icode transpose$$ is not present. $head r$$ The matrix $latex R$$ is specified by the previous call $codei% %f%.ForSparseJac(%q%, %r%, %transpose%) %$$ see $cref/r/ForSparseJac/r/$$. The type of the elements of $cref/VectorSet/RevSparseHes/VectorSet/$$ must be the same as the type of the elements of $icode r$$. $head s$$ The argument $icode s$$ has prototype $codei% const %VectorSet%& %s% %$$ (see $cref/VectorSet/RevSparseHes/VectorSet/$$ below) If it has elements of type $code bool$$, its size is $latex m$$. If it has elements of type $code std::set$$, its size is one and all the elements of $icode%s%[0]%$$ are between zero and $latex m - 1$$. It specifies a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for the vector $icode S$$. $head h$$ The result $icode h$$ has prototype $codei% %VectorSet%& %h% %$$ (see $cref/VectorSet/RevSparseHes/VectorSet/$$ below). $subhead transpose false$$ If $icode h$$ has elements of type $code bool$$, its size is $latex q * n$$. If it has elements of type $code std::set$$, its size is $latex q$$ and all the set elements are between zero and $icode%n%-1%$$ inclusive. It specifies a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for the matrix $latex H(x)$$. $subhead transpose true$$ If $icode h$$ has elements of type $code bool$$, its size is $latex n * q$$. If it has elements of type $code std::set$$, its size is $latex n$$ and all the set elements are between zero and $icode%q%-1%$$ inclusive. It specifies a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for the matrix $latex H(x)^\R{T}$$. $head VectorSet$$ The type $icode VectorSet$$ must be a $cref SimpleVector$$ class with $cref/elements of type/SimpleVector/Elements of Specified Type/$$ $code bool$$ or $code std::set$$; see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion of the difference. The type of the elements of $cref/VectorSet/RevSparseHes/VectorSet/$$ must be the same as the type of the elements of $icode r$$. $head Entire Sparsity Pattern$$ Suppose that $latex q = n$$ and $latex R \in \B{R}^{n \times n}$$ is the $latex n \times n$$ identity matrix. Further suppose that the $latex S$$ is the $th k$$ $cref/elementary vector/glossary/Elementary Vector/$$; i.e. $latex \[ S_j = \left\{ \begin{array}{ll} 1 & {\rm if} \; j = k \\ 0 & {\rm otherwise} \end{array} \right. \] $$ In this case, the corresponding value $icode h$$ is a sparsity pattern for the Hessian matrix $latex F_k^{(2)} (x) \in \B{R}^{n \times n}$$. $head Example$$ $children% example/sparse/rev_sparse_hes.cpp %example/sparse/sparsity_sub.cpp %$$ The file $cref rev_sparse_hes.cpp$$ contains an example and test of this operation. It returns true if it succeeds and false otherwise. The file $cref/sparsity_sub.cpp/sparsity_sub.cpp/RevSparseHes/$$ contains an example and test of using $code RevSparseHes$$ to compute the sparsity pattern for a subset of the Hessian. $end ----------------------------------------------------------------------------- */ # include # include # include namespace CppAD { // BEGIN_CPPAD_NAMESPACE /*! \file rev_sparse_hes.hpp Reverse mode Hessian sparsity patterns. */ // =========================================================================== // RevSparseHesCase /*! Private helper function for RevSparseHes(q, s) bool sparsity. All of the description in the public member function RevSparseHes(q, s) applies. \param set_type is a \c bool value. This argument is used to dispatch to the proper source code depending on the vlaue of \c VectorSet::value_type. \param transpose See \c RevSparseHes(q, s). \param q See \c RevSparseHes(q, s). \param s See \c RevSparseHes(q, s). \param h is the return value for the corresponging call to \c RevSparseJac(q, s). */ template template void ADFun::RevSparseHesCase( bool set_type , bool transpose , size_t q , const VectorSet& s , VectorSet& h ) { size_t n = Domain(); size_t m = Range(); // h.resize(q * n ); CPPAD_ASSERT_KNOWN( for_jac_sparse_pack_.n_set() > 0, "RevSparseHes: previous stored call to ForSparseJac did not " "use bool for the elements of r." ); CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == 0 ); CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == num_var_tape_ ); // // temporary indices size_t i, j; // check Vector is Simple VectorSet class with bool elements CheckSimpleVector(); CPPAD_ASSERT_KNOWN( q == for_jac_sparse_pack_.end(), "RevSparseHes: q is not equal to its value\n" "in the previous call to ForSparseJac with this ADFun object." ); CPPAD_ASSERT_KNOWN( size_t(s.size()) == m, "RevSparseHes: size of s is not equal to\n" "range dimension for ADFun object." ); // Array that will hold reverse Jacobian dependency flag. // Initialize as true for the dependent variables. local::pod_vector RevJac; RevJac.extend(num_var_tape_); for(i = 0; i < num_var_tape_; i++) RevJac[i] = false; for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); RevJac[ dep_taddr_[i] ] = s[i]; } // vector of sets that will hold reverse Hessain values local::sparse_pack rev_hes_pattern; rev_hes_pattern.resize(num_var_tape_, q); // compute the Hessian sparsity patterns local::RevHesSweep( n, num_var_tape_, &play_, for_jac_sparse_pack_, RevJac.data(), rev_hes_pattern ); // return values corresponding to independent variables CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == n * q ); for(j = 0; j < n; j++) { for(i = 0; i < q; i++) { if( transpose ) h[ j * q + i ] = false; else h[ i * n + j ] = false; } } // j is index corresponding to reverse mode partial for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // ind_taddr_[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); // extract the result from rev_hes_pattern CPPAD_ASSERT_UNKNOWN( rev_hes_pattern.end() == q ); local::sparse_pack::const_iterator itr(rev_hes_pattern, j + 1); i = *itr; while( i < q ) { if( transpose ) h[ j * q + i ] = true; else h[ i * n + j ] = true; i = *(++itr); } } } /*! Private helper function for RevSparseHes(q, s) set sparsity. All of the description in the public member function RevSparseHes(q, s) applies. \param set_type is a \c std::set value. This argument is used to dispatch to the proper source code depending on the vlaue of \c VectorSet::value_type. \param transpose See \c RevSparseHes(q, s). \param q See \c RevSparseHes(q, s). \param s See \c RevSparseHes(q, s). \param h is the return value for the corresponging call to \c RevSparseJac(q, s). */ template template void ADFun::RevSparseHesCase( const std::set& set_type , bool transpose , size_t q , const VectorSet& s , VectorSet& h ) { size_t n = Domain(); # ifndef NDEBUG size_t m = Range(); # endif // if( transpose ) h.resize(n); else h.resize(q); CPPAD_ASSERT_KNOWN( for_jac_sparse_set_.n_set() > 0, "RevSparseHes: previous stored call to ForSparseJac did not " "use std::set for the elements of r." ); CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == 0 ); CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == num_var_tape_ ); // // temporary indices size_t i, j; std::set::const_iterator itr_1; // check VectorSet is Simple Vector class with sets for elements CheckSimpleVector, VectorSet>( local::one_element_std_set(), local::two_element_std_set() ); CPPAD_ASSERT_KNOWN( q == for_jac_sparse_set_.end(), "RevSparseHes: q is not equal to its value\n" "in the previous call to ForSparseJac with this ADFun object." ); CPPAD_ASSERT_KNOWN( s.size() == 1, "RevSparseHes: size of s is not equal to one." ); // Array that will hold reverse Jacobian dependency flag. // Initialize as true for the dependent variables. local::pod_vector RevJac; RevJac.extend(num_var_tape_); for(i = 0; i < num_var_tape_; i++) RevJac[i] = false; itr_1 = s[0].begin(); while( itr_1 != s[0].end() ) { i = *itr_1++; CPPAD_ASSERT_KNOWN( i < m, "RevSparseHes: an element of the set s[0] has value " "greater than or equal m" ); CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); RevJac[ dep_taddr_[i] ] = true; } // vector of sets that will hold reverse Hessain values local::sparse_list rev_hes_pattern; rev_hes_pattern.resize(num_var_tape_, q); // compute the Hessian sparsity patterns local::RevHesSweep( n, num_var_tape_, &play_, for_jac_sparse_set_, RevJac.data(), rev_hes_pattern ); // return values corresponding to independent variables // j is index corresponding to reverse mode partial CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == q || transpose ); CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == n || ! transpose ); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); // extract the result from rev_hes_pattern // and add corresponding elements to result sets in h CPPAD_ASSERT_UNKNOWN( rev_hes_pattern.end() == q ); local::sparse_list::const_iterator itr_2(rev_hes_pattern, j+1); i = *itr_2; while( i < q ) { if( transpose ) h[j].insert(i); else h[i].insert(j); i = *(++itr_2); } } } // =========================================================================== // RevSparseHes /*! User API for Hessian sparsity patterns using reverse mode. The C++ source code corresponding to this operation is \verbatim h = f.RevSparseHes(q, r) \endverbatim \tparam Base is the base type for this recording. \tparam VectorSet is a simple vector with elements of type \c bool or \c std::set. \param transpose is true (false) if \c is is equal to \f$ H(x) \f$ (\f$ H(x)^T \f$) where \f[ H(x) = R^T (S * F)^{(2)} (x) \f] where \f$ F \f$ is the function corresponding to the operation sequence and \a x is any argument value. \param q is the value of \a q in the by the previous call of the form \verbatim f.ForSparseJac(q, r, packed) \endverbatim The value \c r in this call is a sparsity pattern for the matrix \f$ R \f$. The type of the element of \c r for the previous call to \c ForSparseJac must be the same as the type of the elements of \c s. \param s is a vector with size \c m that specifies the sparsity pattern for the vector \f$ S \f$, where \c m is the number of dependent variables corresponding to the operation sequence stored in \a play. \return If \c transpose is false (true), the return vector is a sparsity pattern for \f$ H(x) \f$ (\f$ H(x)^T \f$). \f[ H(x) = R^T ( S * F)^{(2)} (x) \f] where \f$ F \f$ is the function corresponding to the operation sequence and \a x is any argument value. */ template template VectorSet ADFun::RevSparseHes( size_t q, const VectorSet& s, bool transpose ) { VectorSet h; typedef typename VectorSet::value_type Set_type; // Should check to make sure q is same as in previous call to // forward sparse Jacobian. RevSparseHesCase( Set_type() , transpose , q , s , h ); return h; } // =========================================================================== // RevSparseHesCheckpoint /*! Hessian sparsity patterns calculation used by checkpoint functions. \tparam Base is the base type for this recording. \param transpose is true (false) h is equal to \f$ H(x) \f$ (\f$ H(x)^T \f$) where \f[ H(x) = R^T (S * F)^{(2)} (x) \f] where \f$ F \f$ is the function corresponding to the operation sequence and \f$ x \f$ is any argument value. \param q is the value of q in the by the previous call of the form \verbatim f.ForSparseJac(q, r) \endverbatim The value r in this call is a sparsity pattern for the matrix \f$ R \f$. \param s is a vector with size m that specifies the sparsity pattern for the vector \f$ S \f$, where m is the number of dependent variables corresponding to the operation sequence stored in play_. \param h The input size and elements of h do not matter. On output, h is the sparsity pattern for the matrix \f$ H(x) \f$ or \f$ H(x)^T \f$ depending on transpose. \par Assumptions The forward jacobian sparsity pattern must be currently stored in this ADFUN object. */ template void ADFun::RevSparseHesCheckpoint( size_t q , vector& s , bool transpose , local::sparse_list& h ) { size_t n = Domain(); size_t m = Range(); // checkpoint functions should get this right CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == 0 ); CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == num_var_tape_ ); CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.end() == q ); CPPAD_ASSERT_UNKNOWN( s.size() == m ); // Array that holds the reverse Jacobiain dependcy flags. // Initialize as true for dependent variables, flase for others. local::pod_vector RevJac; RevJac.extend(num_var_tape_); for(size_t i = 0; i < num_var_tape_; i++) RevJac[i] = false; for(size_t i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ) RevJac[ dep_taddr_[i] ] = s[i]; } // holds reverse Hessian sparsity pattern for all variables local::sparse_list rev_hes_pattern; rev_hes_pattern.resize(num_var_tape_, q); // compute Hessian sparsity pattern for all variables local::RevHesSweep( n, num_var_tape_, &play_, for_jac_sparse_set_, RevJac.data(), rev_hes_pattern ); // dimension the return value if( transpose ) h.resize(n, q); else h.resize(q, n); // j is index corresponding to reverse mode partial for(size_t j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // ind_taddr_[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); // extract the result from rev_hes_pattern CPPAD_ASSERT_UNKNOWN( rev_hes_pattern.end() == q ); local::sparse_list::const_iterator itr(rev_hes_pattern, j + 1); size_t i = *itr; while( i < q ) { if( transpose ) h.add_element(j, i); else h.add_element(i, j); i = *(++itr); } } } } // END_CPPAD_NAMESPACE # endif