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
131 lines
4.7 KiB
C++
131 lines
4.7 KiB
C++
# ifndef CPPAD_CORE_DIV_HPP
|
|
# define CPPAD_CORE_DIV_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.
|
|
---------------------------------------------------------------------------- */
|
|
|
|
// BEGIN CppAD namespace
|
|
namespace CppAD {
|
|
|
|
template <class Base>
|
|
AD<Base> operator / (const AD<Base> &left , const AD<Base> &right)
|
|
{
|
|
// compute the Base part
|
|
AD<Base> result;
|
|
result.value_ = left.value_ / right.value_;
|
|
CPPAD_ASSERT_UNKNOWN( Parameter(result) );
|
|
|
|
// check if there is a recording in progress
|
|
local::ADTape<Base>* tape = AD<Base>::tape_ptr();
|
|
if( tape == nullptr )
|
|
return result;
|
|
tape_id_t tape_id = tape->id_;
|
|
// tape_id cannot match the default value for tape_id_; i.e., 0
|
|
CPPAD_ASSERT_UNKNOWN( tape_id > 0 );
|
|
|
|
// check if left and right tapes match
|
|
bool match_left = left.tape_id_ == tape_id;
|
|
bool match_right = right.tape_id_ == tape_id;
|
|
|
|
// check if left and right are dynamic parameters
|
|
bool dyn_left = match_left & (left.ad_type_ == dynamic_enum);
|
|
bool dyn_right = match_right & (right.ad_type_ == dynamic_enum);
|
|
|
|
// check if left and right are variables
|
|
bool var_left = match_left & (left.ad_type_ != dynamic_enum);
|
|
bool var_right = match_right & (right.ad_type_ != dynamic_enum);
|
|
|
|
CPPAD_ASSERT_KNOWN(
|
|
left.tape_id_ == right.tape_id_ || ! match_left || ! match_right ,
|
|
"Divide: AD variables or dynamic parameters on different threads."
|
|
);
|
|
if( var_left )
|
|
{ if( var_right )
|
|
{ // result = variable / variable
|
|
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvvOp) == 1 );
|
|
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvvOp) == 2 );
|
|
|
|
// put operand addresses in tape
|
|
tape->Rec_.PutArg(left.taddr_, right.taddr_);
|
|
// put operator in the tape
|
|
result.taddr_ = tape->Rec_.PutOp(local::DivvvOp);
|
|
// make result a variable
|
|
result.tape_id_ = tape_id;
|
|
result.ad_type_ = variable_enum;
|
|
}
|
|
else if( (! dyn_right) & IdenticalOne(right.value_) )
|
|
{ // result = variable / 1
|
|
result.make_variable(left.tape_id_, left.taddr_);
|
|
}
|
|
else
|
|
{ // result = variable / parameter
|
|
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvpOp) == 1 );
|
|
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvpOp) == 2 );
|
|
|
|
// put operand addresses in tape
|
|
addr_t p = right.taddr_;
|
|
if( ! dyn_right )
|
|
p = tape->Rec_.put_con_par(right.value_);
|
|
tape->Rec_.PutArg(left.taddr_, p);
|
|
// put operator in the tape
|
|
result.taddr_ = tape->Rec_.PutOp(local::DivvpOp);
|
|
// make result a variable
|
|
result.tape_id_ = tape_id;
|
|
result.ad_type_ = variable_enum;
|
|
}
|
|
}
|
|
else if( var_right )
|
|
{ if( (! dyn_left) & IdenticalZero(left.value_) )
|
|
{ // result = 0 / variable
|
|
}
|
|
else
|
|
{ // result = parameter / variable
|
|
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivpvOp) == 1 );
|
|
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivpvOp) == 2 );
|
|
|
|
// put operand addresses in tape
|
|
addr_t p = left.taddr_;
|
|
if( ! dyn_left )
|
|
p = tape->Rec_.put_con_par(left.value_);
|
|
tape->Rec_.PutArg(p, right.taddr_);
|
|
// put operator in the tape
|
|
result.taddr_ = tape->Rec_.PutOp(local::DivpvOp);
|
|
// make result a variable
|
|
result.tape_id_ = tape_id;
|
|
result.ad_type_ = variable_enum;
|
|
}
|
|
}
|
|
else if( dyn_left | dyn_right )
|
|
{ addr_t arg0 = left.taddr_;
|
|
addr_t arg1 = right.taddr_;
|
|
if( ! dyn_left )
|
|
arg0 = tape->Rec_.put_con_par(left.value_);
|
|
if( ! dyn_right )
|
|
arg1 = tape->Rec_.put_con_par(right.value_);
|
|
//
|
|
// parameters with a dynamic parameter result
|
|
result.taddr_ = tape->Rec_.put_dyn_par(
|
|
result.value_, local::div_dyn, arg0, arg1
|
|
);
|
|
result.tape_id_ = tape_id;
|
|
result.ad_type_ = dynamic_enum;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// convert other cases into the case above
|
|
CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(/)
|
|
|
|
|
|
} // END CppAD namespace
|
|
|
|
# endif
|