------------------------------------------------------- lines 8-234 of file: include/cppad/core/opt_val_hes.hpp ------------------------------------------------------- {xrst_begin opt_val_hes app} {xrst_spell signdet sy yy } Jacobian and Hessian of Optimal Values ###################################### Syntax ****** | *signdet* = ``opt_val_hes`` ( *x* , *y* , *fun* , *jac* , *hes* ) See Also ******** :ref:`BenderQuad-name` Reference ********* Algorithmic differentiation of implicit functions and optimal values, Bradley M. Bell and James V. Burke, Advances in Automatic Differentiation, 2008, Springer. Purpose ******* We are given a function :math:`S : \B{R}^n \times \B{R}^m \rightarrow \B{R}^\ell` and we define :math:`F : \B{R}^n \times \B{R}^m \rightarrow \B{R}` and :math:`V : \B{R}^n \rightarrow \B{R}` by .. math:: :nowrap: \begin{eqnarray} F(x, y) & = & \sum_{k=0}^{\ell-1} S_k ( x , y) \\ V(x) & = & F [ x , Y(x) ] \\ 0 & = & \partial_y F [x , Y(x) ] \end{eqnarray} We wish to compute the Jacobian and possibly also the Hessian, of :math:`V (x)`. BaseVector ********** The type *BaseVector* must be a :ref:`SimpleVector-name` class. We use *Base* to refer to the type of the elements of *BaseVector* ; i.e., *BaseVector* :: ``value_type`` x * The argument *x* has prototype ``const`` *BaseVector* & *x* and its size must be equal to *n* . It specifies the point at which we evaluating the Jacobian :math:`V^{(1)} (x)` (and possibly the Hessian :math:`V^{(2)} (x)`). y * The argument *y* has prototype ``const`` *BaseVector* & *y* and its size must be equal to *m* . It must be equal to :math:`Y(x)`; i.e., it must solve the implicit equation .. math:: 0 = \partial_y F ( x , y) Fun *** The argument *fun* is an object of type *Fun* which must support the member functions listed below. CppAD will may be recording operations of the type ``AD`` < *Base* > when these member functions are called. These member functions must not stop such a recording; e.g., they must not call :ref:`AD\::abort_recording` . Fun::ad_vector ============== The type *Fun* :: ``ad_vector`` must be a :ref:`SimpleVector-name` class with elements of type ``AD`` < *Base* > ; i.e. *Fun* :: ``ad_vector::value_type`` is equal to ``AD`` < *Base* > . fun.ell ======= The type *Fun* must support the syntax *ell* = *fun* . ``ell`` () where *ell* has prototype ``size_t`` *ell* and is the value of :math:`\ell`; i.e., the number of terms in the summation. One can choose *ell* equal to one, and have :math:`S(x,y)` the same as :math:`F(x, y)`. Each of the functions :math:`S_k (x , y)`, (in the summation defining :math:`F(x, y)`) is differentiated separately using AD. For very large problems, breaking :math:`F(x, y)` into the sum of separate simpler functions may reduce the amount of memory necessary for algorithmic differentiation and there by speed up the process. fun.s ===== The type *Fun* must support the syntax *s_k* = *fun* . ``s`` ( *k* , *x* , *y* ) The *fun* . ``s`` argument *k* has prototype ``size_t`` *k* and is between zero and *ell* ``- 1`` . The argument *x* to *fun* . ``s`` has prototype ``const`` *Fun* :: ``ad_vector&`` *x* and its size must be equal to *n* . The argument *y* to *fun* . ``s`` has prototype ``const`` *Fun* :: ``ad_vector&`` *y* and its size must be equal to *m* . The *fun* . ``s`` result *s_k* has prototype ``AD`` < *Base* > *s_k* and its value must be given by :math:`s_k = S_k ( x , y )`. fun.sy ====== The type *Fun* must support the syntax *sy_k* = *fun* . ``sy`` ( *k* , *x* , *y* ) The argument *k* to *fun* . ``sy`` has prototype ``size_t`` *k* The argument *x* to *fun* . ``sy`` has prototype ``const`` *Fun* :: ``ad_vector&`` *x* and its size must be equal to *n* . The argument *y* to *fun* . ``sy`` has prototype ``const`` *Fun* :: ``ad_vector&`` *y* and its size must be equal to *m* . The *fun* . ``sy`` result *sy_k* has prototype *Fun* :: ``ad_vector`` *sy_k* its size must be equal to *m* , and its value must be given by :math:`sy_k = \partial_y S_k ( x , y )`. jac *** The argument *jac* has prototype *BaseVector* & *jac* and has size *n* or zero. The input values of its elements do not matter. If it has size zero, it is not affected. Otherwise, on output it contains the Jacobian of :math:`V (x)`; i.e., for :math:`j = 0 , \ldots , n-1`, .. math:: jac[ j ] = V^{(1)} (x)_j where *x* is the first argument to ``opt_val_hes`` . hes *** The argument *hes* has prototype *BaseVector* & *hes* and has size *n* * *n* or zero. The input values of its elements do not matter. If it has size zero, it is not affected. Otherwise, on output it contains the Hessian of :math:`V (x)`; i.e., for :math:`i = 0 , \ldots , n-1`, and :math:`j = 0 , \ldots , n-1`, .. math:: hes[ i * n + j ] = V^{(2)} (x)_{i,j} signdet ******* If *hes* has size zero, *signdet* is not defined. Otherwise the return value *signdet* is the sign of the determinant for :math:`\partial_{yy}^2 F(x , y)`. If it is zero, then the matrix is singular and the Hessian is not computed ( *hes* is not changed). Example ******* {xrst_toc_hidden example/general/opt_val_hes.cpp } The file :ref:`opt_val_hes.cpp-name` contains an example and test of this operation. {xrst_end opt_val_hes}