we need an autodiff library at some point (or we need to roll our own but I do not think that makes sense). CppAD is well tested and header only and easy to include. It is also Liscene compatible with GPL v3.0. Here we bring it in as a dependency
490 lines
14 KiB
C++
490 lines
14 KiB
C++
# ifndef CPPAD_LOCAL_STORE_OP_HPP
|
|
# define CPPAD_LOCAL_STORE_OP_HPP
|
|
/* --------------------------------------------------------------------------
|
|
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
|
|
|
|
CppAD is distributed under the terms of the
|
|
Eclipse Public License Version 2.0.
|
|
|
|
This Source Code may also be made available under the following
|
|
Secondary License when the conditions for such availability set forth
|
|
in the Eclipse Public License, Version 2.0 are satisfied:
|
|
GNU General Public License, Version 2.0 or later.
|
|
---------------------------------------------------------------------------- */
|
|
|
|
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
|
|
/*
|
|
$begin store_op_var$$
|
|
$spell
|
|
pv
|
|
vp
|
|
vv
|
|
Vec
|
|
op
|
|
var
|
|
isvar
|
|
ind
|
|
Taylor
|
|
arg
|
|
num
|
|
Addr
|
|
$$
|
|
$section Changing an Element in a Variable VecAD Vector$$
|
|
|
|
$head See Also$$
|
|
$cref/op_code_var store/op_code_var/Store/$$.
|
|
|
|
$head Syntax$$
|
|
$codei%forward_store_%IV%_op_0(
|
|
%i_z%,
|
|
%arg%,
|
|
%num_par%,
|
|
%parameter%,
|
|
%cap_order%,
|
|
%taylor%,
|
|
%vec_ad2isvar%,
|
|
%vec_ad2index%
|
|
)
|
|
%$$
|
|
where the index type $icode I$$ and the value being stored type $icode V$$
|
|
are $code p$$ (for parameter) or $code v$$ (for variable).
|
|
|
|
$head Prototype$$
|
|
$srcthisfile%
|
|
0%// BEGIN_FORWARD_STORE_PP_OP_0%// END_FORWARD_STORE_PP_OP_0%1
|
|
%$$
|
|
The prototype for
|
|
$code forward_store_pv_op_0$$,
|
|
$code forward_store_vp_op_0$$, and
|
|
$code forward_store_vv_op_0$$,
|
|
are the same except for the function name.
|
|
|
|
$head Notation$$
|
|
|
|
$subhead v$$
|
|
We use $icode v$$ to denote the $cref VecAD$$ vector for this operation.
|
|
|
|
$subhead x$$
|
|
We use $icode x$$ to denote the $codei%AD%<%Base%>%$$
|
|
index for this operation.
|
|
|
|
$subhead i_vec$$
|
|
We use $icode i_vec$$ to denote the $code size_t$$ value
|
|
corresponding to $icode x$$.
|
|
|
|
$subhead n_load$$
|
|
This is the number of load instructions in this recording.
|
|
|
|
$subhead n_all$$
|
|
This is the number of values in the single array that includes
|
|
all the vectors together with the size of each vector.
|
|
|
|
$head Base$$
|
|
base type for the operator; i.e., this operation was recorded
|
|
using AD<Base> and computations by this routine are done using type Base.
|
|
|
|
$head i_z$$
|
|
is the AD variable index corresponding to the result of this load operation.
|
|
|
|
$head arg$$
|
|
|
|
$subhead arg[0]$$
|
|
is the offset of this VecAD vector relative to the beginning
|
|
of the $icode vec_ad2isvar$$ and $icode vec_ad2index$$ arrays.
|
|
|
|
$subhead arg[1]$$
|
|
If this is
|
|
$code forward_load_p_op_0$$ ($code forward_load_v_op_0$$)
|
|
$icode%arg%[%1%]%$$ is the parameter index (variable index)
|
|
corresponding to $cref/i_vec/load_op_var/Notation/i_vec/$$.
|
|
|
|
$subhead arg[2]$$
|
|
Is the index of this VecAD load instruction in the
|
|
$icode load_op2var$$ array.
|
|
|
|
$head num_par$$
|
|
is the number of parameters in this recording.
|
|
|
|
$head parameter$$
|
|
This is the vector of parameters for this recording which has size
|
|
$icode num_par$$.
|
|
|
|
$head cap_order$$
|
|
number of columns in the matrix containing the Taylor coefficients.
|
|
|
|
$head taylor$$
|
|
Is the matrix of Taylor coefficients for all the variables.
|
|
|
|
$head vec_ad2isvar$$
|
|
This vector has size $icode n_all$$ and
|
|
the input values of its elements does not matter.
|
|
If the value being stored is a parameter (variable),
|
|
$icode%vec_ad2isvar%[ %arg%[0] + %i_vec% ]%$$
|
|
is set to false (true).
|
|
|
|
$head vec_ad2index$$
|
|
This array has size $icode n_all$$
|
|
and the input value of its elements does not matter.
|
|
If the value being stored is a parameter (variable),
|
|
$icode%vec_ad2index%[ %arg%[0] + %i_vec% ]%$$
|
|
is set to the parameter (variable) index
|
|
corresponding to the value being stored.
|
|
|
|
$end
|
|
*/
|
|
// BEGIN_FORWARD_STORE_PP_OP_0
|
|
template <class Base>
|
|
void forward_store_pp_op_0(
|
|
size_t i_z ,
|
|
const addr_t* arg ,
|
|
size_t num_par ,
|
|
const Base* parameter ,
|
|
size_t cap_order ,
|
|
const Base* taylor ,
|
|
bool* vec_ad2isvar ,
|
|
size_t* vec_ad2index )
|
|
// END_FORWARD_STORE_PP_OP_0
|
|
{ addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) );
|
|
CPPAD_ASSERT_KNOWN(
|
|
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
|
|
"VecAD: zero order forward dynamic parameter index out of range"
|
|
);
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(StppOp) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(StppOp) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par );
|
|
|
|
vec_ad2isvar[ arg[0] + i_vec ] = false;
|
|
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
|
|
}
|
|
template <class Base>
|
|
void forward_store_pv_op_0(
|
|
size_t i_z ,
|
|
const addr_t* arg ,
|
|
size_t num_par ,
|
|
const Base* parameter ,
|
|
size_t cap_order ,
|
|
const Base* taylor ,
|
|
bool* vec_ad2isvar ,
|
|
size_t* vec_ad2index )
|
|
{ addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) );
|
|
CPPAD_ASSERT_KNOWN(
|
|
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
|
|
"VecAD: zero order forward dynamic parameter index out of range"
|
|
);
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(StpvOp) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(StpvOp) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
|
|
vec_ad2isvar[ arg[0] + i_vec ] = true;
|
|
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
|
|
}
|
|
template <class Base>
|
|
void forward_store_vp_op_0(
|
|
size_t i_z ,
|
|
const addr_t* arg ,
|
|
size_t num_par ,
|
|
size_t cap_order ,
|
|
const Base* taylor ,
|
|
bool* vec_ad2isvar ,
|
|
size_t* vec_ad2index )
|
|
{
|
|
addr_t i_vec = addr_t(Integer( taylor[ size_t(arg[1]) * cap_order + 0 ] ));
|
|
CPPAD_ASSERT_KNOWN(
|
|
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
|
|
"VecAD: zero order forward variable index out of range"
|
|
);
|
|
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(StvpOp) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(StvpOp) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par );
|
|
|
|
vec_ad2isvar[ arg[0] + i_vec ] = false;
|
|
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
|
|
}
|
|
template <class Base>
|
|
void forward_store_vv_op_0(
|
|
size_t i_z ,
|
|
const addr_t* arg ,
|
|
size_t num_par ,
|
|
size_t cap_order ,
|
|
const Base* taylor ,
|
|
bool* vec_ad2isvar ,
|
|
size_t* vec_ad2index )
|
|
{
|
|
addr_t i_vec = addr_t(Integer( taylor[ size_t(arg[1]) * cap_order + 0 ] ));
|
|
CPPAD_ASSERT_KNOWN(
|
|
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
|
|
"VecAD: index during zero order forward sweep is out of range"
|
|
);
|
|
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(StvpOp) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(StvpOp) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
|
|
vec_ad2isvar[ arg[0] + i_vec ] = true;
|
|
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
/*
|
|
==============================================================================
|
|
<!-- define preamble -->
|
|
The C++ source code corresponding to this operation is
|
|
\verbatim
|
|
v[x] = y
|
|
\endverbatim
|
|
where v is a VecAD<Base> vector, x is an AD<Base> object,
|
|
and y is AD<Base> or Base objects.
|
|
We define the index corresponding to v[x] by
|
|
\verbatim
|
|
i_v_x = vec_ad2index[ arg[0] + i_vec ]
|
|
\endverbatim
|
|
where i_vec is defined under the heading arg[1] below:
|
|
<!-- end preamble -->
|
|
==============================================================================
|
|
*/
|
|
/*!
|
|
Shared documnetation for sparsity operations corresponding to
|
|
op = StpvOp or StvvOp (not called).
|
|
|
|
\tparam Vector_set
|
|
is the type used for vectors of sets. It can be either
|
|
sparse::pack_setvec or sparse::list_setvec.
|
|
|
|
\param op
|
|
is the code corresponding to this operator;
|
|
i.e., StpvOp, StvpOp, or StvvOp.
|
|
|
|
\param arg
|
|
\n
|
|
arg[0]
|
|
is the offset corresponding to this VecAD vector in the combined array.
|
|
\n
|
|
\n
|
|
arg[2]
|
|
\n
|
|
The set with index arg[2] in var_sparsity
|
|
is the sparsity pattern corresponding to y.
|
|
(Note that arg[2] > 0 because y is a variable.)
|
|
|
|
\param num_combined
|
|
is the total number of elements in the VecAD address array.
|
|
|
|
\param combined
|
|
combined [ arg[0] - 1 ]
|
|
is the index of the set in vecad_sparsity corresponding
|
|
to the sparsity pattern for the vector v.
|
|
We use the notation i_v below which is defined by
|
|
\verbatim
|
|
i_v = combined[ arg[0] - 1 ]
|
|
\endverbatim
|
|
|
|
\param var_sparsity
|
|
The set with index arg[2] in var_sparsity
|
|
is the sparsity pattern for y.
|
|
This is an input for forward mode operations.
|
|
For reverse mode operations:
|
|
The sparsity pattern for v is added to the spartisy pattern for y.
|
|
|
|
\param vecad_sparsity
|
|
The set with index i_v in vecad_sparsity
|
|
is the sparsity pattern for v.
|
|
This is an input for reverse mode operations.
|
|
For forward mode operations, the sparsity pattern for y is added
|
|
to the sparsity pattern for the vector v.
|
|
|
|
\par Checked Assertions
|
|
\li NumArg(op) == 3
|
|
\li NumRes(op) == 0
|
|
\li 0 < arg[0]
|
|
\li arg[0] < num_combined
|
|
\li arg[2] < var_sparsity.n_set()
|
|
\li i_v < vecad_sparsity.n_set()
|
|
*/
|
|
template <class Vector_set>
|
|
void sparse_store_op(
|
|
OpCode op ,
|
|
const addr_t* arg ,
|
|
size_t num_combined ,
|
|
const size_t* combined ,
|
|
Vector_set& var_sparsity ,
|
|
Vector_set& vecad_sparsity )
|
|
{
|
|
// This routine is only for documentaiton, it should not be used
|
|
CPPAD_ASSERT_UNKNOWN( false );
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
Forward mode sparsity operations for StpvOp and StvvOp
|
|
|
|
<!-- replace preamble -->
|
|
The C++ source code corresponding to this operation is
|
|
\verbatim
|
|
v[x] = y
|
|
\endverbatim
|
|
where v is a VecAD<Base> vector, x is an AD<Base> object,
|
|
and y is AD<Base> or Base objects.
|
|
We define the index corresponding to v[x] by
|
|
\verbatim
|
|
i_v_x = vec_ad2index[ arg[0] + i_vec ]
|
|
\endverbatim
|
|
where i_vec is defined under the heading arg[1] below:
|
|
<!-- end preamble -->
|
|
|
|
\param dependency
|
|
is this a dependency (or sparsity) calculation.
|
|
|
|
\copydetails CppAD::local::sparse_store_op
|
|
*/
|
|
template <class Vector_set>
|
|
void forward_sparse_store_op(
|
|
bool dependency ,
|
|
OpCode op ,
|
|
const addr_t* arg ,
|
|
size_t num_combined ,
|
|
const size_t* combined ,
|
|
Vector_set& var_sparsity ,
|
|
Vector_set& vecad_sparsity )
|
|
{
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
|
|
size_t i_v = combined[ arg[0] - 1 ];
|
|
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() );
|
|
|
|
if( dependency & ( (op == StvvOp) | (op == StvpOp) ) )
|
|
vecad_sparsity.binary_union(i_v, i_v, size_t(arg[1]), var_sparsity);
|
|
|
|
if( (op == StpvOp) | (op == StvvOp ) )
|
|
vecad_sparsity.binary_union(i_v, i_v, size_t(arg[2]), var_sparsity);
|
|
|
|
return;
|
|
}
|
|
|
|
/*!
|
|
Reverse mode sparsity operations for StpvOp, StvpOp, and StvvOp
|
|
|
|
<!-- replace preamble -->
|
|
The C++ source code corresponding to this operation is
|
|
\verbatim
|
|
v[x] = y
|
|
\endverbatim
|
|
where v is a VecAD<Base> vector, x is an AD<Base> object,
|
|
and y is AD<Base> or Base objects.
|
|
We define the index corresponding to v[x] by
|
|
\verbatim
|
|
i_v_x = vec_ad2index[ arg[0] + i_vec ]
|
|
\endverbatim
|
|
where i_vec is defined under the heading arg[1] below:
|
|
<!-- end preamble -->
|
|
|
|
This routine is given the sparsity patterns for
|
|
G(v[x], y , w , u ... ) and it uses them to compute the
|
|
sparsity patterns for
|
|
\verbatim
|
|
H(y , w , u , ... ) = G[ v[x], y , w , u , ... ]
|
|
\endverbatim
|
|
|
|
\param dependency
|
|
is this a dependency (or sparsity) calculation.
|
|
|
|
\copydetails CppAD::local::sparse_store_op
|
|
*/
|
|
template <class Vector_set>
|
|
void reverse_sparse_jacobian_store_op(
|
|
bool dependency ,
|
|
OpCode op ,
|
|
const addr_t* arg ,
|
|
size_t num_combined ,
|
|
const size_t* combined ,
|
|
Vector_set& var_sparsity ,
|
|
Vector_set& vecad_sparsity )
|
|
{
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
|
|
size_t i_v = combined[ arg[0] - 1 ];
|
|
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() );
|
|
|
|
if( dependency & ( (op == StvpOp) | (op == StvvOp) ) )
|
|
var_sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_v, vecad_sparsity);
|
|
if( (op == StpvOp) | (op == StvvOp) )
|
|
var_sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_v, vecad_sparsity);
|
|
|
|
return;
|
|
}
|
|
|
|
/*!
|
|
Reverse mode sparsity operations for StpvOp and StvvOp
|
|
|
|
<!-- replace preamble -->
|
|
The C++ source code corresponding to this operation is
|
|
\verbatim
|
|
v[x] = y
|
|
\endverbatim
|
|
where v is a VecAD<Base> vector, x is an AD<Base> object,
|
|
and y is AD<Base> or Base objects.
|
|
We define the index corresponding to v[x] by
|
|
\verbatim
|
|
i_v_x = vec_ad2index[ arg[0] + i_vec ]
|
|
\endverbatim
|
|
where i_vec is defined under the heading arg[1] below:
|
|
<!-- end preamble -->
|
|
|
|
This routine is given the sparsity patterns for
|
|
G(v[x], y , w , u ... )
|
|
and it uses them to compute the sparsity patterns for
|
|
\verbatim
|
|
H(y , w , u , ... ) = G[ v[x], y , w , u , ... ]
|
|
\endverbatim
|
|
|
|
\copydetails CppAD::local::sparse_store_op
|
|
|
|
\param var_jacobian
|
|
var_jacobian[ arg[2] ]
|
|
is false (true) if the Jacobian of G with respect to y is always zero
|
|
(may be non-zero).
|
|
|
|
\param vecad_jacobian
|
|
vecad_jacobian[i_v]
|
|
is false (true) if the Jacobian with respect to x is always zero
|
|
(may be non-zero).
|
|
On input, it corresponds to the function G,
|
|
and on output it corresponds to the function H.
|
|
*/
|
|
template <class Vector_set>
|
|
void reverse_sparse_hessian_store_op(
|
|
OpCode op ,
|
|
const addr_t* arg ,
|
|
size_t num_combined ,
|
|
const size_t* combined ,
|
|
Vector_set& var_sparsity ,
|
|
Vector_set& vecad_sparsity ,
|
|
bool* var_jacobian ,
|
|
bool* vecad_jacobian )
|
|
{
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
|
|
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
|
|
size_t i_v = combined[ arg[0] - 1 ];
|
|
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
|
|
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() );
|
|
|
|
var_sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_v, vecad_sparsity);
|
|
|
|
var_jacobian[ arg[2] ] |= vecad_jacobian[i_v];
|
|
|
|
return;
|
|
}
|
|
|
|
} } // END_CPPAD_LOCAL_NAMESPACE
|
|
# endif
|