openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

783 lines
21 KiB

# ifndef CPPAD_LOCAL_REV_HES_SWEEP_HPP
# define CPPAD_LOCAL_REV_HES_SWEEP_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.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file rev_hes_sweep.hpp
Compute Reverse mode Hessian sparsity patterns.
*/
/*!
\def CPPAD_REV_HES_SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every rev_hes_sweep computation is printed.
*/
# define CPPAD_REV_HES_SWEEP_TRACE 0
/*!
Given the forward Jacobian sparsity pattern for all the variables,
and the reverse Jacobian sparsity pattern for the dependent variables,
RevHesSweep computes the Hessian sparsity pattern for all the independent
variables.
\tparam Base
base type for the operator; i.e., this operation sequence was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse_pack or sparse_list.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape; i.e.,
\a play->num_var_rec().
This is also the number of rows in the entire sparsity pattern
\a rev_hes_sparse.
\param play
The information stored in \a play
is a recording of the operations corresponding to a function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables
and \f$ m \f$ is the number of dependent variables.
The object \a play is effectly constant.
It is not declared const because while playing back the tape
the object \a play holds information about the current location
with in the tape and this changes during playback.
\param for_jac_sparse
For i = 0 , ... , \a numvar - 1,
(for all the variables on the tape),
the forward Jacobian sparsity pattern for the variable with index i
corresponds to the set with index i in \a for_jac_sparse.
\param RevJac
\b Input:
For i = 0, ... , \a numvar - 1
the if the variable with index i on the tape is an dependent variable and
included in the Hessian, \a RevJac[ i ] is equal to true,
otherwise it is equal to false.
\n
\n
\b Output: The values in \a RevJac upon return are not specified; i.e.,
it is used for temporary work space.
\param rev_hes_sparse
The reverse Hessian sparsity pattern for the variable with index i
corresponds to the set with index i in \a rev_hes_sparse.
\n
\n
\b Input: For i = 0 , ... , \a numvar - 1
the reverse Hessian sparsity pattern for the variable with index i is empty.
\n
\n
\b Output: For j = 1 , ... , \a n,
the reverse Hessian sparsity pattern for the independent dependent variable
with index (j-1) is given by the set with index j
in \a rev_hes_sparse.
The values in the rest of \a rev_hes_sparse are not specified; i.e.,
they are used for temporary work space.
*/
template <class Base, class Vector_set>
void RevHesSweep(
size_t n,
size_t numvar,
local::player<Base>* play,
const Vector_set& for_jac_sparse,
bool* RevJac,
Vector_set& rev_hes_sparse
)
{
OpCode op;
size_t i_op;
size_t i_var;
const addr_t* arg = CPPAD_NULL;
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
size_t i, j, k;
// check numvar argument
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
CPPAD_ASSERT_UNKNOWN( for_jac_sparse.n_set() == numvar );
CPPAD_ASSERT_UNKNOWN( rev_hes_sparse.n_set() == numvar );
CPPAD_ASSERT_UNKNOWN( numvar > 0 );
// upper limit exclusive for set elements
size_t limit = rev_hes_sparse.end();
CPPAD_ASSERT_UNKNOWN( for_jac_sparse.end() == limit );
// check number of sets match
CPPAD_ASSERT_UNKNOWN(
for_jac_sparse.n_set() == rev_hes_sparse.n_set()
);
// vecad_sparsity contains a sparsity pattern for each VecAD object.
// vecad_ind maps a VecAD index (beginning of the VecAD object)
// to the index for the corresponding set in vecad_sparsity.
size_t num_vecad_ind = play->num_vec_ind_rec();
size_t num_vecad_vec = play->num_vecad_vec_rec();
Vector_set vecad_sparse;
vecad_sparse.resize(num_vecad_vec, limit);
pod_vector<size_t> vecad_ind;
pod_vector<bool> vecad_jac;
if( num_vecad_vec > 0 )
{ size_t length;
vecad_ind.extend(num_vecad_ind);
vecad_jac.extend(num_vecad_vec);
j = 0;
for(i = 0; i < num_vecad_vec; i++)
{ // length of this VecAD
length = play->GetVecInd(j);
// set vecad_ind to proper index for this VecAD
vecad_ind[j] = i;
// make all other values for this vector invalid
for(k = 1; k <= length; k++)
vecad_ind[j+k] = num_vecad_vec;
// start of next VecAD
j += length + 1;
// initialize this vector's reverse jacobian value
vecad_jac[i] = false;
}
CPPAD_ASSERT_UNKNOWN( j == play->num_vec_ind_rec() );
}
// ----------------------------------------------------------------------
// user's atomic op calculator
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
//
// work space used by UserOp.
vector<Base> user_x; // parameters in x as integers
vector<size_t> user_ix; // variable indices for argument vector
vector<size_t> user_iy; // variable indices for result vector
//
// information set by forward_user (initialization to avoid warnings)
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
// information set by forward_user (necessary initialization)
enum_user_state user_state = end_user; // proper initialization
// ----------------------------------------------------------------------
//
// pointer to the beginning of the parameter vector
// (used by atomic functions
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
//
// Initialize
play->reverse_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == EndOp );
# if CPPAD_REV_HES_SWEEP_TRACE
std::cout << std::endl;
CppAD::vectorBool zf_value(limit);
CppAD::vectorBool zh_value(limit);
# endif
bool more_operators = true;
while(more_operators)
{ bool flag; // temporary for use in switch cases
//
// next op
play->reverse_next(op, arg, i_op, i_var);
# ifndef NDEBUG
if( i_op <= n )
{ CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp));
}
else CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
# endif
// rest of information depends on the case
switch( op )
{
case AbsOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case AddvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_addsub_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case BeginOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
more_operators = false;
break;
// -------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->reverse_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->reverse_csum(op, arg, i_op, i_var);
reverse_sparse_hessian_csum_op(
i_var, arg, RevJac, rev_hes_sparse
);
break;
// -------------------------------------------------
case CExpOp:
reverse_sparse_hessian_cond_op(
i_var, arg, num_par, RevJac, rev_hes_sparse
);
break;
// ---------------------------------------------------
case CosOp:
// sin(x), cos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// ---------------------------------------------------
case CoshOp:
// sinh(x), cosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case DisOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
// derivativve is identically zero
break;
// -------------------------------------------------
case DivvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_div_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ErfOp:
// arg[1] is always the parameter 0
// arg[2] is always the parameter 2 / sqrt(pi)
CPPAD_ASSERT_NARG_NRES(op, 3, 5);
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ExpOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1)
// Z is already defined
break;
// -------------------------------------------------
case LdpOp:
reverse_sparse_hessian_load_op(
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case LdvOp:
reverse_sparse_hessian_load_op(
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
break;
// -------------------------------------------------
case LogOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case MulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_mul_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ParOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case PowvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
reverse_sparse_hessian_pow_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
break;
// -------------------------------------------------
case SignOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
// Derivative is identiaclly zero
break;
// -------------------------------------------------
case SinOp:
// cos(x), sin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SinhOp:
// cosh(x), sinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SqrtOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case StppOp:
// sparsity cannot propagate through a parameter
CPPAD_ASSERT_NARG_NRES(op, 3, 0)
break;
// -------------------------------------------------
case StpvOp:
reverse_sparse_hessian_store_op(
op,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case StvpOp:
// sparsity cannot propagate through a parameter
CPPAD_ASSERT_NARG_NRES(op, 3, 0)
break;
// -------------------------------------------------
case StvvOp:
reverse_sparse_hessian_store_op(
op,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case SubvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_addsub_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case TanOp:
// tan(x)^2, tan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case TanhOp:
// tanh(x)^2, tanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case UserOp:
CPPAD_ASSERT_UNKNOWN(
user_state == start_user || user_state == end_user
);
flag = user_state == end_user;
user_atom = play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ user_x.resize(user_n);
user_ix.resize(user_n);
user_iy.resize(user_m);
}
else
{ // call users function for this operation
user_atom->set_old(user_old);
user_atom->rev_sparse_hes(
user_x, user_ix, user_iy,
for_jac_sparse, RevJac, rev_hes_sparse
);
}
break;
case UsrapOp:
// parameter argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// argument parameter value
user_x[user_j] = parameter[arg[0]];
// special variable index used for parameters
user_ix[user_j] = 0;
break;
case UsravOp:
// variable argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// argument variables not available during sparsity calculations
user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN();
// variable index for this argument
user_ix[user_j] = arg[0];
break;
case UsrrpOp:
// parameter result in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// special variable index used for parameters
user_iy[user_i] = 0;
break;
case UsrrvOp:
// variable result in an atomic operation sequence
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// variable index for this result
user_iy[user_i] = i_var;
break;
// -------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ZmulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_mul_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(0);
}
# if CPPAD_REV_HES_SWEEP_TRACE
for(j = 0; j < limit; j++)
{ zf_value[j] = false;
zh_value[j] = false;
}
typename Vector_set::const_iterator itr_jac(for_jac_sparse, i_var);
j = *itr_jac;
while( j < limit )
{ zf_value[j] = true;
j = *(++itr_jac);
}
typename Vector_set::const_iterator itr_hes(rev_hes_sparse, i_var);
j = *itr_hes;
while( j < limit )
{ zh_value[j] = true;
j = *(++itr_hes);
}
printOp(
std::cout,
play,
i_op,
i_var,
op,
arg
);
// should also print RevJac[i_var], but printOpResult does not
// yet allow for this
if( NumRes(op) > 0 && op != BeginOp ) printOpResult(
std::cout,
1,
&zf_value,
1,
&zh_value
);
std::cout << std::endl;
}
std::cout << std::endl;
# else
}
# endif
// values corresponding to BeginOp
CPPAD_ASSERT_UNKNOWN( i_op == 0 );
CPPAD_ASSERT_UNKNOWN( i_var == 0 );
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_REV_HES_SWEEP_TRACE
# endif