build(CppAD): brought in CppAD for autodiff

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
This commit is contained in:
2025-06-19 14:51:02 -04:00
parent 76662db03e
commit 856ab51b4c
367 changed files with 108392 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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.
-----------------------------------------------------------------------------

View File

@@ -0,0 +1,184 @@
# -----------------------------------------------------------------------------
# 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.
# -----------------------------------------------------------------------------
# Configure the CppAD include file directory
# -----------------------------------------------------------------------------
# check_match
MACRO(check_match match_variable match_constant output_variable)
STRING(COMPARE EQUAL ${${match_variable}} ${match_constant} match_flag )
IF( match_flag )
SET(${output_variable} 1)
ELSE( match_flag )
SET(${output_variable} 0)
ENDIF( match_flag )
print_variable(${output_variable})
ENDMACRO(check_match)
# -----------------------------------------------------------------------------
# compiler_has_conversion_warn
SET( clang_or_gnu 0 )
IF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
SET(clang_or_gnu 1)
ENDIF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
IF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" )
SET(clang_or_gnu 1)
ENDIF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" )
IF( clang_or_gnu )
SET(backup "${cppad_cxx_flags}")
SET(cppad_cxx_flags "${backup} -Wfloat-conversion -Wconversion -Werror")
#
SET(source "int main(void) { return 0; }")
run_source_test("${source}" compiler_has_conversion_warn )
#
SET(cppad_cxx_flags "${backup}")
ELSE( clang_or_gnu )
SET( compiler_has_conversion_warn 0 )
ENDIF( clang_or_gnu )
# -----------------------------------------------------------------------------
# cppad_boostvector, cppad_cppadvector, cppad_eigenvector, cppad_stdvector
#
check_match(cppad_testvector boost cppad_boostvector)
check_match(cppad_testvector cppad cppad_cppadvector)
check_match(cppad_testvector eigen cppad_eigenvector)
check_match(cppad_testvector std cppad_stdvector)
IF( NOT cppad_boostvector )
IF( NOT cppad_cppadvector )
IF( NOT cppad_eigenvector )
IF( NOT cppad_stdvector )
MESSAGE(FATAL_ERROR
"cppad_testvector not one of following: boost, cppad, eigen, std."
"This should have been found earlier, please report this as a bug."
)
ENDIF( NOT cppad_stdvector )
ENDIF( NOT cppad_eigenvector )
ENDIF( NOT cppad_cppadvector )
ENDIF( NOT cppad_boostvector )
IF( cppad_boostvector )
# FIND_PACKAGE(Boost) done by ../CMakeLists.txt
IF( NOT Boost_FOUND )
MESSAGE(FATAL_ERROR
"cppad_testvector == boost but cannot find boost include files"
)
ENDIF( NOT Boost_FOUND )
ENDIF( cppad_boostvector )
#
IF( cppad_eigenvector )
IF( NOT include_eigen )
MESSAGE(FATAL_ERROR
"cppad_testvector == eigen but eigen_prefix is not specified"
)
ENDIF( NOT include_eigen )
ENDIF( cppad_eigenvector )
#
print_variable(cppad_cplusplus_201100_ok)
# -----------------------------------------------------------------------------
# cppad_has_gettimeofday
#
SET(source "
# include<sys/time.h>
int main(void)
{ struct timeval time;
gettimeofday(&time, 0);
return 0;
}"
)
run_source_test("${source}" cppad_has_gettimeofday)
# -----------------------------------------------------------------------------
# cppad_tape_addr_type, cppad_tape_id_type
#
FOREACH(cmake_var cppad_tape_id_type cppad_tape_addr_type )
SET(source "
# include <limits>
int main(void)
{ bool is_unsigned = ! std::numeric_limits<${${cmake_var}}>::is_signed;
return int(! is_unsigned);
}
"
)
run_source_test("${source}" ${cmake_var}_is_unsigned)
IF( ${cmake_var}_is_unsigned STREQUAL 0 )
MESSAGE(STATUS
"Warning: using a signed ${cmake_var} is for CppAD developers only !"
)
ENDIF( ${cmake_var}_is_unsigned STREQUAL 0 )
ENDFOREACH( cmake_var )
# -----------------------------------------------------------------------------
# check that cppad_max_num_threads is >= 4
#
SET(CMAKE_REQUIRED_DERINITIONS "")
SET(CMAKE_REQUIRED_INCLUDES "")
SET(CMAKE_REQUIRED_LIBRARIES "")
SET(CMAKE_REQUIRED_FLAGS "")
SET(source "
int main(void)
{ const char* number = \"${cppad_max_num_threads}\";
int value = 0;
while( *number == ' ' )
number++;
while( '0' <= *number && *number <= '9' )
{ value = 10 * value + (int)(*number - '0');
number++;
}
while( *number == ' ' )
number++;
if( *number != char(0) )
return 1;
if( value < 4 )
return 1;
return 0;
}
" )
# Using CHECK_CXX_SOURCE_RUNS directly (instead of run_source_test).
IF( DEFINED cppad_max_num_threads_is_integer_ge_4 )
MESSAGE( ERROR
"cppad_max_num_threads_is_integer_ge_4 is defined before expected"
)
ENDIF( DEFINED cppad_max_num_threads_is_integer_ge_4 )
CHECK_CXX_SOURCE_RUNS("${source}" cppad_max_num_threads_is_integer_ge_4 )
IF( NOT cppad_max_num_threads_is_integer_ge_4 )
MESSAGE(FATAL_ERROR
"cppad_max_num_threads is not an integer greater than or equal 4"
)
ENDIF( NOT cppad_max_num_threads_is_integer_ge_4 )
# -----------------------------------------------------------------------------
# cppad_has_mkstemp
#
SET(source "
# include <stdlib.h>
# include <unistd.h>
int main(void)
{
char pattern[] = \"/tmp/fileXXXXXX\";
int fd = mkstemp(pattern);
return 0;
}
" )
run_source_test("${source}" cppad_has_mkstemp )
# -----------------------------------------------------------------------------
# cppad_has_tmpname_s
#
SET(source "
# include <stdio.h>
int main(void)
{ char filename[L_tmpnam_s ];
if( tmpnam_s(filename, L_tmpnam_s ) != 0 )
return 1;
return 0;
}
" )
run_source_test("${source}" cppad_has_tmpnam_s )
# -----------------------------------------------------------------------------
# configure.hpp
CONFIGURE_FILE(
${CMAKE_CURRENT_SOURCE_DIR}/configure.hpp.in
${CMAKE_CURRENT_SOURCE_DIR}/configure.hpp
)
# -----------------------------------------------------------------------------

View File

@@ -0,0 +1,177 @@
# ifndef CPPAD_BASE_REQUIRE_HPP
# define CPPAD_BASE_REQUIRE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 base_require$$
$spell
azmul
ostream
alloc
eps
std
cppad.hpp
namespace
bool
const
CppAD
enum
inline
Op
std
CondExp
$$
$section AD<Base> Requirements for a CppAD Base Type$$
$head Syntax$$
$code # include <cppad/base_require.hpp>$$
$head Purpose$$
This section lists the requirements for the type
$icode Base$$ so that the type $codei%AD<%Base%>%$$ can be used.
$head API Warning$$
Defining a CppAD $icode Base$$ type is an advanced use of CppAD.
This part of the CppAD API changes with time. The most common change
is adding more requirements.
Search for $code base_require$$ in the
current $cref whats_new$$ section for these changes.
$head Standard Base Types$$
In the case where $icode Base$$ is
$code float$$,
$code double$$,
$code std::complex<float>$$,
$code std::complex<double>$$,
or $codei%AD<%Other%>%$$,
these requirements are provided by including the file
$code cppad/cppad.hpp$$.
In the documentation, The notation $latex \B{R}$$ denotes
the field corresponding to the base type.
Multiplication must be commutative for this field,
but it need not be the reals; e.g., the complex numbers.
$head Include Order$$
If you are linking a non-standard base type to CppAD,
you must first include the file $code cppad/base_require.hpp$$,
then provide the specifications below,
and then include the file $code cppad/cppad.hpp$$.
$head Numeric Type$$
The type $icode Base$$ must support all the operations for a
$cref NumericType$$.
$head Output Operator$$
The type $icode Base$$ must support the syntax
$codei%
%os% << %x%
%$$
where $icode os$$ is an $code std::ostream&$$
and $icode x$$ is a $code const base_alloc&$$.
For example, see
$cref/base_alloc/base_alloc.hpp/Output Operator/$$.
$head Integer$$
The type $icode Base$$ must support the syntax
$codei%
%i% = CppAD::Integer(%x%)
%$$
which converts $icode x$$ to an $code int$$.
The argument $icode x$$ has prototype
$codei%
const %Base%& %x%
%$$
and the return value $icode i$$ has prototype
$codei%
int %i%
%$$
$subhead Suggestion$$
In many cases, the $icode Base$$ version of the $code Integer$$ function
can be defined by
$codei%
namespace CppAD {
inline int Integer(const %Base%& x)
{ return static_cast<int>(x); }
}
%$$
For example, see
$cref/base_float/base_float.hpp/Integer/$$ and
$cref/base_alloc/base_alloc.hpp/Integer/$$.
$head Absolute Zero, azmul$$
The type $icode Base$$ must support the syntax
$codei%
%z% = azmul(%x%, %y%)
%$$
see; $cref azmul$$.
The following preprocessor macro invocation suffices
(for most $icode Base$$ types):
$codei%
namespace CppAD {
CPPAD_AZMUL(%Base%)
}
%$$
where the macro is defined by
$srccode%cpp% */
# define CPPAD_AZMUL(Base) \
inline Base azmul(const Base& x, const Base& y) \
{ Base zero(0.0); \
if( x == zero ) \
return zero; \
return x * y; \
}
/* %$$
$childtable%
omh/base_require/base_member.omh%
include/cppad/core/base_cond_exp.hpp%
omh/base_require/base_identical.omh%
omh/base_require/base_ordered.omh%
include/cppad/core/base_std_math.hpp%
include/cppad/core/base_limits.hpp%
include/cppad/core/base_to_string.hpp%
include/cppad/core/base_hash.hpp%
omh/base_require/base_example.omh
%$$
$end
*/
// definitions that must come before base implementations
# include <cppad/utility/error_handler.hpp>
# include <cppad/local/define.hpp>
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/declare_ad.hpp>
// grouping documentation by feature
# include <cppad/core/base_cond_exp.hpp>
# include <cppad/core/base_std_math.hpp>
# include <cppad/core/base_limits.hpp>
# include <cppad/core/base_to_string.hpp>
# include <cppad/core/base_hash.hpp>
// must define template class numeric_limits before the base cases
# include <cppad/core/numeric_limits.hpp>
# include <cppad/core/epsilon.hpp> // deprecated
// base cases that come with CppAD
# include <cppad/core/base_float.hpp>
# include <cppad/core/base_double.hpp>
# include <cppad/core/base_complex.hpp>
// deprecated base type
# include <cppad/core/zdouble.hpp>
# endif

View File

@@ -0,0 +1,238 @@
# ifndef CPPAD_CONFIGURE_HPP
# define CPPAD_CONFIGURE_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 configure.hpp$$
$spell
noexcept
pragmas
unreferenced
CppAD
cppad
yyyymmdd
yyyy
mm
dd
adolc
cmake
colpack
eigen
ipopt
gettimeofday
namespace
mkstemp
tmpnam
nullptr
sizeof
std
hpp
addr
$$
$section Preprocessor Symbols Set By CMake Command$$
$head CPPAD_COMPILER_HAS_CONVERSION_WARN$$
is the compiler a variant of g++ and has conversion warnings
$srccode%hpp% */
# define CPPAD_COMPILER_HAS_CONVERSION_WARN 0
/* %$$
$head CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS$$
This macro is only used to document the pragmas that disables the
follow warnings:
$subhead C4100$$
unreferenced formal parameter.
$subhead C4127$$
conditional expression is constant.
$srccode%hpp% */
# define CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS 1
# if _MSC_VER
# pragma warning( disable : 4100 )
# pragma warning( disable : 4127 )
# endif
# undef CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS
/* %$$
$head CPPAD_USE_CPLUSPLUS_2011$$
Deprecated 2020-12-03:
Should CppAD use C++11 features. This is always 1 (for true).
$srccode%hpp% */
# define CPPAD_USE_CPLUSPLUS_2011 1
/* %$$
$head CPPAD_PACKAGE_STRING$$
cppad-yyyymmdd as a C string where yyyy is year, mm is month, and dd is day.
$srccode%hpp% */
# define CPPAD_PACKAGE_STRING "cppad-20210000.8"
/* %$$
$head CPPAD_HAS_ADOLC$$
Was include_adolc=true on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_ADOLC 0
/* %$$
$head CPPAD_HAS_COLPACK$$
Was a colpack_prefix specified on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_COLPACK 0
/* %$$
$head CPPAD_HAS_EIGEN$$
Was include_eigen=true on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_EIGEN 0
/* %$$
$head CPPAD_HAS_IPOPT$$
Was include_ipopt=true on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_IPOPT 0
/* %$$
$head CPPAD_DEPRECATED$$
This symbol is not currently being used.
$srccode%hpp% */
# define CPPAD_DEPRECATED
/* %$$
$head CPPAD_BOOSTVECTOR$$
If this symbol is one, and _MSC_VER is not defined,
we are using boost vector for CPPAD_TESTVECTOR.
It this symbol is zero,
we are not using boost vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_BOOSTVECTOR 0
/* %$$
$head CPPAD_CPPADVECTOR$$
If this symbol is one,
we are using CppAD vector for CPPAD_TESTVECTOR.
It this symbol is zero,
we are not using CppAD vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_CPPADVECTOR 1
/* %$$
$head CPPAD_STDVECTOR$$
If this symbol is one,
we are using standard vector for CPPAD_TESTVECTOR.
It this symbol is zero,
we are not using standard vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_STDVECTOR 0
/* %$$
$head CPPAD_EIGENVECTOR$$
If this symbol is one,
we are using Eigen vector for CPPAD_TESTVECTOR.
If this symbol is zero,
we are not using Eigen vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_EIGENVECTOR 0
/* %$$
$head CPPAD_HAS_GETTIMEOFDAY$$
If this symbol is one, and _MSC_VER is not defined,
this system supports the gettimeofday function.
Otherwise, this symbol should be zero.
$srccode%hpp% */
# define CPPAD_HAS_GETTIMEOFDAY 1
/* %$$
$head CPPAD_TAPE_ADDR_TYPE$$
Is the type used to store address on the tape. If not size_t, then
<code>sizeof(CPPAD_TAPE_ADDR_TYPE) <= sizeof( size_t )</code>
to conserve memory.
This type must support std::numeric_limits,
the <= operator,
and conversion to size_t.
Make sure that the type chosen returns true for is_pod<CPPAD_TAPE_ADDR_TYPE>
in pod_vector.hpp.
This type is later defined as addr_t in the CppAD namespace.
$srccode%hpp% */
# define CPPAD_TAPE_ADDR_TYPE unsigned int
/* %$$
$head CPPAD_TAPE_ID_TYPE$$
Is the type used to store tape identifiers. If not size_t, then
<code>sizeof(CPPAD_TAPE_ID_TYPE) <= sizeof( size_t )</code>
to conserve memory.
This type must support std::numeric_limits,
the <= operator,
and conversion to size_t.
Make sure that the type chosen returns true for is_pod<CPPAD_TAPE_ID_TYPE>
in pod_vector.hpp.
This type is later defined as tape_id_t in the CppAD namespace.
$srccode%hpp% */
# define CPPAD_TAPE_ID_TYPE unsigned int
/* %$$
$head CPPAD_MAX_NUM_THREADS$$
Specifies the maximum number of threads that CppAD can support
(must be greater than or equal four).
The user may define CPPAD_MAX_NUM_THREADS before including any of the CppAD
header files. If it is not yet defined,
$srccode%hpp% */
# ifndef CPPAD_MAX_NUM_THREADS
# define CPPAD_MAX_NUM_THREADS 48
# endif
/* %$$
$head CPPAD_HAS_MKSTEMP$$
It true, mkstemp works in C++ on this system.
$srccode%hpp% */
# define CPPAD_HAS_MKSTEMP 1
/* %$$
$head CPPAD_HAS_TMPNAM_S$$
It true, tmpnam_s works in C++ on this system.
$srccode%hpp% */
# define CPPAD_HAS_TMPNAM_S 0
/* %$$
$head CPPAD_NULL$$
Deprecated 2020-12-03:
This preprocessor symbol was used for a null pointer before c++11.
Replace it by $code nullptr$$.
$head CPPAD_NOEXCEPT$$
Deprecated 2020-12-03:
This preprocessor symbol was used for no exception before c++11,
replace it by $code noexcept$$.
$subhead CPPAD_NDEBUG_NOEXCEPT$$
This preprocessor symbol is
$code noexcept$$ when C++11 is available and $code NDEBUG$$ is defined.
Otherwise it is empty.
$end
*/
// -------------------------------------------------
# define CPPAD_NULL nullptr
# define CPPAD_NOEXCEPT noexcept
//
# ifdef NDEBUG
# define CPPAD_NDEBUG_NOEXCEPT noexcept
# else
# define CPPAD_NDEBUG_NOEXCEPT
# endif
// -------------------------------------------------
# endif

View File

@@ -0,0 +1,238 @@
# ifndef CPPAD_CONFIGURE_HPP
# define CPPAD_CONFIGURE_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 configure.hpp$$
$spell
noexcept
pragmas
unreferenced
CppAD
cppad
yyyymmdd
yyyy
mm
dd
adolc
cmake
colpack
eigen
ipopt
gettimeofday
namespace
mkstemp
tmpnam
nullptr
sizeof
std
hpp
addr
$$
$section Preprocessor Symbols Set By CMake Command$$
$head CPPAD_COMPILER_HAS_CONVERSION_WARN$$
is the compiler a variant of g++ and has conversion warnings
$srccode%hpp% */
# define CPPAD_COMPILER_HAS_CONVERSION_WARN @compiler_has_conversion_warn@
/* %$$
$head CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS$$
This macro is only used to document the pragmas that disables the
follow warnings:
$subhead C4100$$
unreferenced formal parameter.
$subhead C4127$$
conditional expression is constant.
$srccode%hpp% */
# define CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS 1
# if _MSC_VER
# pragma warning( disable : 4100 )
# pragma warning( disable : 4127 )
# endif
# undef CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS
/* %$$
$head CPPAD_USE_CPLUSPLUS_2011$$
Deprecated 2020-12-03:
Should CppAD use C++11 features. This is always 1 (for true).
$srccode%hpp% */
# define CPPAD_USE_CPLUSPLUS_2011 1
/* %$$
$head CPPAD_PACKAGE_STRING$$
cppad-yyyymmdd as a C string where yyyy is year, mm is month, and dd is day.
$srccode%hpp% */
# define CPPAD_PACKAGE_STRING "cppad-@cppad_version@"
/* %$$
$head CPPAD_HAS_ADOLC$$
Was include_adolc=true on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_ADOLC @cppad_has_adolc@
/* %$$
$head CPPAD_HAS_COLPACK$$
Was a colpack_prefix specified on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_COLPACK @cppad_has_colpack@
/* %$$
$head CPPAD_HAS_EIGEN$$
Was include_eigen=true on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_EIGEN @cppad_has_eigen@
/* %$$
$head CPPAD_HAS_IPOPT$$
Was include_ipopt=true on the cmake command line.
$srccode%hpp% */
# define CPPAD_HAS_IPOPT @cppad_has_ipopt@
/* %$$
$head CPPAD_DEPRECATED$$
This symbol is not currently being used.
$srccode%hpp% */
# define CPPAD_DEPRECATED @cppad_deprecated_01@
/* %$$
$head CPPAD_BOOSTVECTOR$$
If this symbol is one, and _MSC_VER is not defined,
we are using boost vector for CPPAD_TESTVECTOR.
It this symbol is zero,
we are not using boost vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_BOOSTVECTOR @cppad_boostvector@
/* %$$
$head CPPAD_CPPADVECTOR$$
If this symbol is one,
we are using CppAD vector for CPPAD_TESTVECTOR.
It this symbol is zero,
we are not using CppAD vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_CPPADVECTOR @cppad_cppadvector@
/* %$$
$head CPPAD_STDVECTOR$$
If this symbol is one,
we are using standard vector for CPPAD_TESTVECTOR.
It this symbol is zero,
we are not using standard vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_STDVECTOR @cppad_stdvector@
/* %$$
$head CPPAD_EIGENVECTOR$$
If this symbol is one,
we are using Eigen vector for CPPAD_TESTVECTOR.
If this symbol is zero,
we are not using Eigen vector for CPPAD_TESTVECTOR.
$srccode%hpp% */
# define CPPAD_EIGENVECTOR @cppad_eigenvector@
/* %$$
$head CPPAD_HAS_GETTIMEOFDAY$$
If this symbol is one, and _MSC_VER is not defined,
this system supports the gettimeofday function.
Otherwise, this symbol should be zero.
$srccode%hpp% */
# define CPPAD_HAS_GETTIMEOFDAY @cppad_has_gettimeofday@
/* %$$
$head CPPAD_TAPE_ADDR_TYPE$$
Is the type used to store address on the tape. If not size_t, then
<code>sizeof(CPPAD_TAPE_ADDR_TYPE) <= sizeof( size_t )</code>
to conserve memory.
This type must support std::numeric_limits,
the <= operator,
and conversion to size_t.
Make sure that the type chosen returns true for is_pod<CPPAD_TAPE_ADDR_TYPE>
in pod_vector.hpp.
This type is later defined as addr_t in the CppAD namespace.
$srccode%hpp% */
# define CPPAD_TAPE_ADDR_TYPE @cppad_tape_addr_type@
/* %$$
$head CPPAD_TAPE_ID_TYPE$$
Is the type used to store tape identifiers. If not size_t, then
<code>sizeof(CPPAD_TAPE_ID_TYPE) <= sizeof( size_t )</code>
to conserve memory.
This type must support std::numeric_limits,
the <= operator,
and conversion to size_t.
Make sure that the type chosen returns true for is_pod<CPPAD_TAPE_ID_TYPE>
in pod_vector.hpp.
This type is later defined as tape_id_t in the CppAD namespace.
$srccode%hpp% */
# define CPPAD_TAPE_ID_TYPE @cppad_tape_id_type@
/* %$$
$head CPPAD_MAX_NUM_THREADS$$
Specifies the maximum number of threads that CppAD can support
(must be greater than or equal four).
The user may define CPPAD_MAX_NUM_THREADS before including any of the CppAD
header files. If it is not yet defined,
$srccode%hpp% */
# ifndef CPPAD_MAX_NUM_THREADS
# define CPPAD_MAX_NUM_THREADS @cppad_max_num_threads@
# endif
/* %$$
$head CPPAD_HAS_MKSTEMP$$
It true, mkstemp works in C++ on this system.
$srccode%hpp% */
# define CPPAD_HAS_MKSTEMP @cppad_has_mkstemp@
/* %$$
$head CPPAD_HAS_TMPNAM_S$$
It true, tmpnam_s works in C++ on this system.
$srccode%hpp% */
# define CPPAD_HAS_TMPNAM_S @cppad_has_tmpnam_s@
/* %$$
$head CPPAD_NULL$$
Deprecated 2020-12-03:
This preprocessor symbol was used for a null pointer before c++11.
Replace it by $code nullptr$$.
$head CPPAD_NOEXCEPT$$
Deprecated 2020-12-03:
This preprocessor symbol was used for no exception before c++11,
replace it by $code noexcept$$.
$subhead CPPAD_NDEBUG_NOEXCEPT$$
This preprocessor symbol is
$code noexcept$$ when C++11 is available and $code NDEBUG$$ is defined.
Otherwise it is empty.
$end
*/
// -------------------------------------------------
# define CPPAD_NULL nullptr
# define CPPAD_NOEXCEPT noexcept
//
# ifdef NDEBUG
# define CPPAD_NDEBUG_NOEXCEPT noexcept
# else
# define CPPAD_NDEBUG_NOEXCEPT
# endif
// -------------------------------------------------
# endif

View File

@@ -0,0 +1,58 @@
# ifndef CPPAD_CORE_ABORT_RECORDING_HPP
# define CPPAD_CORE_ABORT_RECORDING_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 abort_recording$$
$spell
$$
$section Abort Recording of an Operation Sequence$$
$head Syntax$$
$codei%AD<%Base%>::abort_recording()%$$
$head Purpose$$
Sometimes it is necessary to abort the recording of an operation sequence
that started with a call of the form
$codei%
Independent(%x%)
%$$
If such a recording is currently in progress,
$code abort_recording$$ will stop the recording and delete the
corresponding information.
Otherwise, $code abort_recording$$ has no effect.
$children%
example/general/abort_recording.cpp
%$$
$head Example$$
The file
$cref abort_recording.cpp$$
contains an example and test of this operation.
$end
----------------------------------------------------------------------------
*/
namespace CppAD {
template <class Base>
void AD<Base>::abort_recording(void)
{ local::ADTape<Base>* tape = AD<Base>::tape_ptr();
if( tape != nullptr )
AD<Base>::tape_manage(delete_tape_manage);
}
}
# endif

View File

@@ -0,0 +1,132 @@
# ifndef CPPAD_CORE_ABS_HPP
# define CPPAD_CORE_ABS_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 abs$$
$spell
fabs
Vec
std
faq
Taylor
Cpp
namespace
const
abs
$$
$section AD Absolute Value Functions: abs, fabs$$
$head Syntax$$
$icode%y% = abs(%x%)
%$$
$icode%y% = fabs(%x%)%$$
$head x, y$$
See the $cref/possible types/unary_standard_math/Possible Types/$$
for a unary standard math function.
$head Atomic$$
In the case where $icode x$$ is an AD type,
this is an $cref/atomic operation/glossary/Operation/Atomic/$$.
$head Complex Types$$
The functions $code abs$$ and $icode fabs$$
are not defined for the base types
$code std::complex<float>$$ or $code std::complex<double>$$
because the complex $code abs$$ function is not complex differentiable
(see $cref/complex types faq/Faq/Complex Types/$$).
$head Derivative$$
CppAD defines the derivative of the $code abs$$ function is
the $cref sign$$ function; i.e.,
$latex \[
{\rm abs}^{(1)} ( x ) = {\rm sign} (x ) =
\left\{ \begin{array}{rl}
+1 & {\rm if} \; x > 0 \\
0 & {\rm if} \; x = 0 \\
-1 & {\rm if} \; x < 0
\end{array} \right.
\] $$
The result for $icode%x% == 0%$$ used to be a directional derivative.
$head Example$$
$children%
example/general/fabs.cpp
%$$
The file
$cref fabs.cpp$$
contains an example and test of this function.
$end
-------------------------------------------------------------------------------
*/
// BEGIN CppAD namespace
namespace CppAD {
template <class Base>
AD<Base> AD<Base>::abs_me (void) const
{
AD<Base> result;
result.value_ = abs(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;
// check if operand is a constant parameter
if( tape_id_ != tape->id_ )
return result;
if(ad_type_ == dynamic_enum)
{ // dynamic paramter argument
result.taddr_ = tape->Rec_.put_dyn_par(
result.value_, local::abs_dyn, taddr_
);
result.tape_id_ = tape_id_;
result.ad_type_ = dynamic_enum;
}
else
{ // variable argument
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AbsOp) == 1 );
// corresponding operand address
tape->Rec_.PutArg(taddr_);
// put operator in the tape
result.taddr_ = tape->Rec_.PutOp(local::AbsOp);
// make result a variable
result.tape_id_ = tape_id_;
result.ad_type_ = variable_enum;
}
return result;
}
template <class Base>
AD<Base> abs(const AD<Base> &x)
{ return x.abs_me(); }
template <class Base>
AD<Base> abs(const VecAD_reference<Base> &x)
{ return x.ADBase().abs_me(); }
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,959 @@
# ifndef CPPAD_CORE_ABS_NORMAL_FUN_HPP
# define CPPAD_CORE_ABS_NORMAL_FUN_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 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 abs_normal_fun$$
$spell
const
$$
$section Create An Abs-normal Representation of a Function$$
$head Syntax$$
$icode%f%.abs_normal_fun(%g%, %a%)%$$
$head f$$
The object $icode f$$ has prototype
$codei%
const ADFun<%Base%>& %f%
%$$
It represents a function $latex f : \B{R}^n \rightarrow \B{R}^m$$.
We assume that the only non-smooth terms in the representation are
absolute value functions and use $latex s \in \B{Z}_+$$
to represent the number of these terms.
$subhead n$$
We use $icode n$$ to denote the dimension of the domain space for $icode f$$.
$subhead m$$
We use $icode m$$ to denote the dimension of the range space for $icode f$$.
$subhead s$$
We use $icode s$$ to denote the number of absolute value terms in $icode f$$.
$head a$$
The object $icode a$$ has prototype
$codei%
ADFun<%Base%> %a%
%$$
The initial function representation in $icode a$$ is lost.
Upon return it represents the result of the absolute terms
$latex a : \B{R}^n \rightarrow \B{R}^s$$; see $latex a(x)$$ defined below.
Note that $icode a$$ is constructed by copying $icode f$$
and then changing the dependent variables. There may
be many calculations in this representation that are not necessary
and can be removed using
$codei%
%a%.optimize()
%$$
This optimization is not done automatically by $code abs_normal_fun$$
because it may take a significant amount of time.
$subhead zeta$$
Let $latex \zeta_0 ( x )$$
denote the argument for the first absolute value term in $latex f(x)$$,
$latex \zeta_1 ( x , |\zeta_0 (x)| )$$ for the second term, and so on.
$subhead a(x)$$
For $latex i = 0 , \ldots , {s-1}$$ define
$latex \[
a_i (x)
=
| \zeta_i ( x , a_0 (x) , \ldots , a_{i-1} (x ) ) |
\] $$
This defines $latex a : \B{R}^n \rightarrow \B{R}^s$$.
$head g$$
The object $icode g$$ has prototype
$codei%
ADFun<%Base%> %g%
%$$
The initial function representation in $icode g$$ is lost.
Upon return it represents the smooth function
$latex g : \B{R}^{n + s} \rightarrow \B{R}^{m + s}$$ is defined by
$latex \[
g( x , u )
=
\left[ \begin{array}{c} y(x, u) \\ z(x, u) \end{array} \right]
\] $$
were $latex y(x, u)$$ and $latex z(x, u)$$ are defined below.
$subhead z(x, u)$$
Define the smooth function
$latex z : \B{R}^{n + s} \rightarrow \B{R}^s$$ by
$latex \[
z_i ( x , u ) = \zeta_i ( x , u_0 , \ldots , u_{i-1} )
\] $$
Note that the partial of $latex z_i$$ with respect to $latex u_j$$ is zero
for $latex j \geq i$$.
$subhead y(x, u)$$
There is a smooth function
$latex y : \B{R}^{n + s} \rightarrow \B{R}^m$$
such that $latex y( x , u ) = f(x)$$ whenever $latex u = a(x)$$.
$head Affine Approximation$$
We define the affine approximations
$latex \[
\begin{array}{rcl}
y[ \hat{x} ]( x , u )
& = &
y ( \hat{x}, a( \hat{x} ) )
+ \partial_x y ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} )
+ \partial_u y ( \hat{x}, a( \hat{x} ) ) ( u - a( \hat{x} ) )
\\
z[ \hat{x} ]( x , u )
& = &
z ( \hat{x}, a( \hat{x} ) )
+ \partial_x z ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} )
+ \partial_u z ( \hat{x}, a( \hat{x} ) ) ( u - a( \hat{x} ) )
\end{array}
\] $$
It follows that
$latex \[
\begin{array}{rcl}
y( x , u )
& = &
y[ \hat{x} ]( x , u ) + o ( x - \hat{x}, u - a( \hat{x} ) )
\\
z( x , u )
& = &
z[ \hat{x} ]( x , u ) + o ( x - \hat{x}, u - a( \hat{x} ) )
\end{array}
\] $$
$head Abs-normal Approximation$$
$subhead Approximating a(x)$$
The function $latex a(x)$$ is not smooth, but it is equal to
$latex | z(x, u) |$$ when $latex u = a(x)$$.
Furthermore
$latex \[
z[ \hat{x} ]( x , u )
=
z ( \hat{x}, a( \hat{x} ) )
+ \partial_x z ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} )
+ \partial_u z ( \hat{x}, a( \hat{x} ) ) ( u - a( \hat{x} ) )
\] $$
The partial of $latex z_i$$ with respect to $latex u_j$$ is zero
for $latex j \geq i$$. It follows that
$latex \[
z_i [ \hat{x} ]( x , u )
=
z_i ( \hat{x}, a( \hat{x} ) )
+ \partial_x z_i ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} )
+ \sum_{j < i} \partial_{u(j)}
z_i ( \hat{x}, a( \hat{x} ) ) ( u_j - a_j ( \hat{x} ) )
\] $$
Considering the case $latex i = 0$$ we define
$latex \[
a_0 [ \hat{x} ]( x )
=
| z_0 [ \hat{x} ]( x , u ) |
=
\left|
z_0 ( \hat{x}, a( \hat{x} ) )
+ \partial_x z_0 ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} )
\right|
\] $$
It follows that
$latex \[
a_0 (x) = a_0 [ \hat{x} ]( x ) + o ( x - \hat{x} )
\] $$
In general, we define $latex a_i [ \hat{x} ]$$ using
$latex a_j [ \hat{x} ]$$ for $latex j < i$$ as follows:
$latex \[
a_i [ \hat{x} ]( x )
=
\left |
z_i ( \hat{x}, a( \hat{x} ) )
+ \partial_x z_i ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} )
+ \sum_{j < i} \partial_{u(j)}
z_i ( \hat{x}, a( \hat{x} ) )
( a_j [ \hat{x} ] ( x ) - a_j ( \hat{x} ) )
\right|
\] $$
It follows that
$latex \[
a (x) = a[ \hat{x} ]( x ) + o ( x - \hat{x} )
\] $$
Note that in the case where $latex z(x, u)$$ and $latex y(x, u)$$ are
affine,
$latex \[
a[ \hat{x} ]( x ) = a( x )
\] $$
$subhead Approximating f(x)$$
$latex \[
f(x)
=
y ( x , a(x ) )
=
y [ \hat{x} ] ( x , a[ \hat{x} ] ( x ) )
+ o( x - \hat{x} )
\] $$
$head Correspondence to Literature$$
Using the notation
$latex Z = \partial_x z(\hat{x}, \hat{u})$$,
$latex L = \partial_u z(\hat{x}, \hat{u})$$,
$latex J = \partial_x y(\hat{x}, \hat{u})$$,
$latex Y = \partial_u y(\hat{x}, \hat{u})$$,
the approximation for $latex z$$ and $latex y$$ are
$latex \[
\begin{array}{rcl}
z[ \hat{x} ]( x , u )
& = &
z ( \hat{x}, a( \hat{x} ) ) + Z ( x - \hat{x} ) + L ( u - a( \hat{x} ) )
\\
y[ \hat{x} ]( x , u )
& = &
y ( \hat{x}, a( \hat{x} ) ) + J ( x - \hat{x} ) + Y ( u - a( \hat{x} ) )
\end{array}
\] $$
Moving the terms with $latex \hat{x}$$ together, we have
$latex \[
\begin{array}{rcl}
z[ \hat{x} ]( x , u )
& = &
z ( \hat{x}, a( \hat{x} ) ) - Z \hat{x} - L a( \hat{x} ) + Z x + L u
\\
y[ \hat{x} ]( x , u )
& = &
y ( \hat{x}, a( \hat{x} ) ) - J \hat{x} - Y a( \hat{x} ) + J x + Y u
\end{array}
\] $$
Using the notation
$latex c = z ( \hat{x}, \hat{u} ) - Z \hat{x} - L \hat{u}$$,
$latex b = y ( \hat{x}, \hat{u} ) - J \hat{x} - Y \hat{u}$$,
we have
$latex \[
\begin{array}{rcl}
z[ \hat{x} ]( x , u ) & = & c + Z x + L u
\\
y[ \hat{x} ]( x , u ) & = & b + J x + Y u
\end{array}
\] $$
Considering the affine case, where the approximations are exact,
and choosing $latex u = a(x) = |z(x, u)|$$, we obtain
$latex \[
\begin{array}{rcl}
z( x , a(x ) ) & = & c + Z x + L |z( x , a(x ) )|
\\
y( x , a(x ) ) & = & b + J x + Y |z( x , a(x ) )|
\end{array}
\] $$
This is Equation (2) of the
$cref/reference/example_abs_normal/Reference/$$.
$children%example/abs_normal/abs_normal.omh
%$$
$head Example$$
The file $cref abs_get_started.cpp$$ contains
an example and test using this operation.
The section $cref example_abs_normal$$
has a links to all the abs normal examples.
$end
-------------------------------------------------------------------------------
*/
/*!
file abs_normal_fun.hpp
Create an abs-normal representation of a function
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
Create an abs-normal representation of an ADFun object.
\tparam Base
base type for this abs-normal form and for the function beging represented;
i.e., f.
\param f
is the function that this object will represent in abs-normal form.
This is effectively const except that the play back state play_
is used.
*/
# ifndef NDEBUG
# define CPPAD_J_PAR_EQUAL_REC j_par = (size_t) rec
# else
# define CPPAD_J_PAR_EQUAL_REC rec
# endif
template <class Base, class RecBase>
void ADFun<Base,RecBase>::abs_normal_fun(ADFun& g, ADFun& a) const
{ using namespace local;
// -----------------------------------------------------------------------
// Forward sweep to determine number of absolute value operations in f
// -----------------------------------------------------------------------
// The argument and result index in f for each absolute value operator
CppAD::vector<addr_t> f_abs_arg;
CppAD::vector<size_t> f_abs_res;
//
OpCode op; // this operator
const addr_t* arg = nullptr; // arguments for this operator
size_t i_var; // variable index for this operator
local::play::const_sequential_iterator itr = play_.begin();
itr.op_info(op, arg, i_var);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
//
bool more_operators = true;
while( op != EndOp )
{
// next op
(++itr).op_info(op, arg, i_var);
switch( op )
{ // absolute value operator
case AbsOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
f_abs_arg.push_back( arg[0] );
f_abs_res.push_back( i_var );
break;
default:
break;
}
}
// ------------------------------------------------------------------------
// Forward sweep to create new recording
// ------------------------------------------------------------------------
// dynamic parameter information in player
const pod_vector<bool>& dyn_par_is( play_.dyn_par_is() );
const pod_vector<opcode_t>& dyn_par_op( play_.dyn_par_op() );
const pod_vector<addr_t>& dyn_par_arg( play_.dyn_par_arg() );
//
// recorder for new operation sequence
recorder<Base> rec;
//
// number of parameters in both operation sequences
size_t num_par = play_.num_par_rec();
//
// number of independent dynamic parameters
size_t num_dynamic_ind = play_.num_dynamic_par();
rec.set_num_dynamic_ind(num_dynamic_ind);
//
// set all parameter to be exactly the same in rec as in play
size_t i_dyn = 0; // dynamic parameter index
size_t i_arg = 0; // dynamic parameter operator argument index
for(size_t i_par = 0; i_par < num_par; ++i_par)
{
# ifndef NDEBUG
size_t j_par = 0;
# endif
// value of this parameter
Base par = play_.GetPar(i_par);
if( ! dyn_par_is[i_par] )
CPPAD_J_PAR_EQUAL_REC.put_con_par(par);
else
{ // operator for this dynamic parameter
op_code_dyn op_dyn = op_code_dyn( dyn_par_op[i_dyn] );
CPPAD_ASSERT_KNOWN(
op_dyn != local::atom_dyn,
"abs_normal_fun: not yet implemented for "
"atomic dynamic parameter functions"
);
//
// number of arguments for this dynamic parameter
size_t n_arg = num_arg_dyn(op_dyn);
//
switch(n_arg)
{ case 0:
CPPAD_J_PAR_EQUAL_REC.put_dyn_par(par, op_dyn);
break;
case 1:
CPPAD_J_PAR_EQUAL_REC.put_dyn_par(par, op_dyn,
dyn_par_arg[i_arg + 0]
);
break;
case 2:
CPPAD_J_PAR_EQUAL_REC.put_dyn_par(par, op_dyn,
dyn_par_arg[i_arg + 0] ,
dyn_par_arg[i_arg + 1]
);
break;
case 5:
CPPAD_J_PAR_EQUAL_REC.put_dyn_cond_exp(par,
CompareOp( dyn_par_arg[i_arg + 0] ) ,
dyn_par_arg[i_arg + 1] ,
dyn_par_arg[i_arg + 2] ,
dyn_par_arg[i_arg + 3] ,
dyn_par_arg[i_arg + 4]
);
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
++i_dyn;
i_arg += n_arg;
}
CPPAD_ASSERT_UNKNOWN( j_par == i_par );
}
//
// number of variables in both operation sequences
// (the AbsOp operators are replace by InvOp operators)
const size_t num_var = play_.num_var_rec();
//
// mapping from old variable index to new variable index
CPPAD_ASSERT_UNKNOWN(
size_t( (std::numeric_limits<addr_t>::max)() ) >= num_var
);
CppAD::vector<addr_t> f2g_var(num_var);
for(i_var = 0; i_var < num_var; i_var++)
f2g_var[i_var] = addr_t( num_var ); // invalid (should not be used)
//
// record the independent variables in f
itr = play_.begin();
itr.op_info(op, arg, i_var);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
more_operators = true;
while( more_operators )
{ switch( op )
{
// phantom variable
case BeginOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
CPPAD_ASSERT_UNKNOWN( arg[0] == 0 );
rec.PutArg(0);
f2g_var[i_var] = rec.PutOp(op);
break;
// independent variables
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
f2g_var[i_var] = rec.PutOp(op);
break;
// end of independent variables
default:
more_operators = false;
break;
}
if( more_operators )
(++itr).op_info(op, arg, i_var);
}
// add one for the phantom variable
CPPAD_ASSERT_UNKNOWN( 1 + Domain() == i_var );
//
// record the independent variables corresponding AbsOp results
size_t index_abs;
for(index_abs = 0; index_abs < f_abs_res.size(); index_abs++)
f2g_var[ f_abs_res[index_abs] ] = rec.PutOp(InvOp);
//
// used to hold new argument vector
addr_t new_arg[6];
//
// now loop through the rest of the
more_operators = true;
index_abs = 0;
while( more_operators )
{ addr_t mask; // temporary used in some switch cases
switch( op )
{
// check setting of f_abs_arg and f_abs_res;
case AbsOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
CPPAD_ASSERT_UNKNOWN( f_abs_arg[index_abs] == arg[0] );
CPPAD_ASSERT_UNKNOWN( f_abs_res[index_abs] == i_var );
CPPAD_ASSERT_UNKNOWN( f2g_var[i_var] > 0 );
++index_abs;
break;
// These operators come at beginning of take and are handled above
case InvOp:
CPPAD_ASSERT_UNKNOWN(false);
break;
// ---------------------------------------------------------------
// Unary operators, argument a parameter, one result
case ParOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
new_arg[0] = arg[0]; // parameter
rec.PutArg( new_arg[0] );
f2g_var[i_var] = rec.PutOp(op);
break;
// --------------------------------------------------------------
// Unary operators, argument a variable, one result
// (excluding the absolute value operator AbsOp)
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case ExpOp:
case Expm1Op:
case LogOp:
case Log1pOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case TanOp:
case TanhOp:
// some of these operators have an auxillary result; e.g.,
// sine and cosine are computed togeather.
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 || NumRes(op) == 2 );
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var );
new_arg[0] = f2g_var[ arg[0] ];
rec.PutArg( new_arg[0] );
f2g_var[i_var] = rec.PutOp( op );
break;
case ErfOp:
case ErfcOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 5);
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var );
// Error function is a special case
// second argument is always the parameter 0
// third argument is always the parameter 2 / sqrt(pi)
rec.PutArg( arg[1] ); // parameter
rec.PutArg( arg[2] ); // parameter
f2g_var[i_var] = rec.PutOp(op);
break;
// --------------------------------------------------------------
// Binary operators, left variable, right parameter, one result
case SubvpOp:
case DivvpOp:
case PowvpOp:
case ZmulvpOp:
# ifndef NDEBUG
if( op == PowvpOp )
{ CPPAD_ASSERT_NARG_NRES(op, 2, 3);
}
else
{ CPPAD_ASSERT_NARG_NRES(op, 2, 1);
}
# endif
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var );
new_arg[0] = f2g_var[ arg[0] ];
new_arg[1] = arg[1]; // parameter
rec.PutArg( new_arg[0], new_arg[1] );
f2g_var[i_var] = rec.PutOp(op);
break;
// ---------------------------------------------------
// Binary operators, left index, right variable, one result
case DisOp:
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
new_arg[0] = arg[0];
new_arg[1] = f2g_var[ arg[1] ];
rec.PutArg( new_arg[0], new_arg[1] );
f2g_var[i_var] = rec.PutOp(op);
break;
// --------------------------------------------------------------
// Binary operators, left parameter, right variable, one result
case AddpvOp:
case SubpvOp:
case MulpvOp:
case DivpvOp:
case PowpvOp:
case ZmulpvOp:
# ifndef NDEBUG
if( op == PowpvOp )
{ CPPAD_ASSERT_NARG_NRES(op, 2, 3);
}
else
{ CPPAD_ASSERT_NARG_NRES(op, 2, 1);
}
# endif
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
new_arg[0] = arg[0]; // parameter
new_arg[1] = f2g_var[ arg[1] ];
rec.PutArg( new_arg[0], new_arg[1] );
f2g_var[i_var] = rec.PutOp(op);
break;
// --------------------------------------------------------------
// Binary operators, left and right variables, one result
case AddvvOp:
case SubvvOp:
case MulvvOp:
case DivvvOp:
case PowvvOp:
case ZmulvvOp:
# ifndef NDEBUG
if( op == PowvvOp )
{ CPPAD_ASSERT_NARG_NRES(op, 2, 3);
}
else
{ CPPAD_ASSERT_NARG_NRES(op, 2, 1);
}
# endif
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var );
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
new_arg[0] = f2g_var[ arg[0] ];
new_arg[1] = f2g_var[ arg[1] ];
rec.PutArg( new_arg[0], new_arg[1] );
f2g_var[i_var] = rec.PutOp(op);
break;
// ---------------------------------------------------
// Conditional expression operators
case CExpOp:
CPPAD_ASSERT_NARG_NRES(op, 6, 1);
new_arg[0] = arg[0];
new_arg[1] = arg[1];
mask = 1;
for(size_t i = 2; i < 6; i++)
{ if( arg[1] & mask )
{ CPPAD_ASSERT_UNKNOWN( size_t(f2g_var[arg[i]]) < num_var );
new_arg[i] = f2g_var[ arg[i] ];
}
else
new_arg[i] = arg[i]; // parameter
mask = mask << 1;
}
rec.PutArg(
new_arg[0] ,
new_arg[1] ,
new_arg[2] ,
new_arg[3] ,
new_arg[4] ,
new_arg[5]
);
f2g_var[i_var] = rec.PutOp(op);
break;
// --------------------------------------------------
// Operators with no arguments and no results
case EndOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 0);
rec.PutOp(op);
more_operators = false;
break;
// ---------------------------------------------------
// Operations with two arguments and no results
case LepvOp:
case LtpvOp:
case EqpvOp:
case NepvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
new_arg[0] = arg[0]; // parameter
new_arg[1] = f2g_var[ arg[1] ];
rec.PutArg(new_arg[0], new_arg[1]);
rec.PutOp(op);
break;
//
case LevpOp:
case LtvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
new_arg[0] = f2g_var[ arg[0] ];
new_arg[1] = arg[1]; // parameter
rec.PutArg(new_arg[0], new_arg[1]);
rec.PutOp(op);
break;
//
case LevvOp:
case LtvvOp:
case EqvvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
new_arg[0] = f2g_var[ arg[0] ];
new_arg[1] = f2g_var[ arg[1] ];
rec.PutArg(new_arg[0], new_arg[1]);
rec.PutOp(op);
break;
// ---------------------------------------------------
// print forward operator
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
//
// arg[0]
new_arg[0] = arg[0];
//
// arg[1]
if( arg[0] & 1 )
{
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
new_arg[1] = f2g_var[ arg[1] ];
}
else
{ new_arg[1] = arg[1]; // parameter
}
//
// arg[3]
if( arg[0] & 2 )
{
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[3] ] ) < num_var );
new_arg[3] = f2g_var[ arg[3] ];
}
else
{ new_arg[3] = arg[3]; // parameter
}
new_arg[2] = rec.PutTxt( play_.GetTxt(size_t(arg[2])) );
new_arg[4] = rec.PutTxt( play_.GetTxt(size_t(arg[4])) );
//
rec.PutArg(
new_arg[0] ,
new_arg[1] ,
new_arg[2] ,
new_arg[3] ,
new_arg[4]
);
// no result
rec.PutOp(op);
break;
// ---------------------------------------------------
// VecAD operators
// Load using a parameter index
case LdpOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 1);
new_arg[0] = arg[0];
new_arg[1] = arg[1]; // parameter
new_arg[2] = arg[2];
rec.PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
f2g_var[i_var] = rec.PutLoadOp(op);
break;
// Load using a variable index
case LdvOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 1);
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
new_arg[0] = arg[0];
new_arg[1] = f2g_var[ arg[1] ];
new_arg[2] = arg[2];
rec.PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
f2g_var[i_var] = rec.PutLoadOp(op);
break;
// Store a parameter using a parameter index
case StppOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
new_arg[0] = arg[0];
new_arg[1] = arg[1]; // parameter
new_arg[2] = arg[2]; // parameter
rec.PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
rec.PutOp(op);
break;
// Store a parameter using a variable index
case StvpOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
new_arg[0] = arg[0];
new_arg[1] = f2g_var[ arg[1] ];
new_arg[2] = arg[2]; // parameter
rec.PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
rec.PutOp(op);
break;
// Store a variable using a parameter index
case StpvOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[2] ] ) < num_var );
new_arg[0] = arg[0];
new_arg[1] = arg[1]; // parameter
new_arg[2] = f2g_var[ arg[2] ];
rec.PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
rec.PutOp(op);
break;
// Store a variable using a variable index
case StvvOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var );
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[2] ] ) < num_var );
new_arg[0] = arg[0];
new_arg[1] = f2g_var[ arg[1] ];
new_arg[2] = f2g_var[ arg[2] ];
rec.PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
break;
// -----------------------------------------------------------
// atomic function call operators
case AFunOp:
CPPAD_ASSERT_NARG_NRES(op, 4, 0);
// atom_index, atom_old, atom_n, atom_m
rec.PutArg(arg[0], arg[1], arg[2], arg[3]);
rec.PutOp(AFunOp);
break;
case FunapOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
new_arg[0] = arg[0]; // parameter
rec.PutArg(new_arg[0]);
rec.PutOp(FunapOp);
break;
case FunavOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[arg[0]] ) < num_var );
new_arg[0] = f2g_var[ arg[0] ];
rec.PutArg(new_arg[0]);
rec.PutOp(FunavOp);
break;
case FunrpOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
new_arg[0] = arg[0]; // parameter
rec.PutArg(new_arg[0]);
rec.PutOp(FunrpOp);
break;
case FunrvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
f2g_var[i_var] = rec.PutOp(FunrvOp);
break;
// ---------------------------------------------------
// all cases should be handled above
default:
CPPAD_ASSERT_UNKNOWN(false);
}
if( more_operators )
(++itr).op_info(op, arg, i_var);
}
// Check a few expected results
CPPAD_ASSERT_UNKNOWN( rec.num_op_rec() == play_.num_op_rec() );
CPPAD_ASSERT_UNKNOWN( rec.num_var_rec() == play_.num_var_rec() );
CPPAD_ASSERT_UNKNOWN( rec.num_var_load_rec() == play_.num_var_load_rec() );
// -----------------------------------------------------------------------
// Use rec to create the function g
// -----------------------------------------------------------------------
// number of variables in the recording
g.num_var_tape_ = rec.num_var_rec();
// dimension cskip_op vector to number of operators
g.cskip_op_.resize( rec.num_op_rec() );
// independent variables in g: (x, u)
size_t s = f_abs_res.size();
size_t n = Domain();
g.ind_taddr_.resize(n + s);
// (x, u)
for(size_t j = 0; j < n; j++)
{ g.ind_taddr_[j] = size_t( f2g_var[ ind_taddr_[j] ] );
CPPAD_ASSERT_UNKNOWN( g.ind_taddr_[j] == j + 1 );
}
for(size_t j = 0; j < s; j++)
{ g.ind_taddr_[n + j] = size_t( f2g_var[ f_abs_res[j] ] );
CPPAD_ASSERT_UNKNOWN( g.ind_taddr_[n + j] == n + j + 1 );
}
// dependent variable in g: (y, z)
CPPAD_ASSERT_UNKNOWN( s == f_abs_arg.size() );
size_t m = Range();
g.dep_taddr_.resize(m + s);
for(size_t i = 0; i < m; i++)
{ g.dep_taddr_[i] = size_t( f2g_var[ dep_taddr_[i] ] );
CPPAD_ASSERT_UNKNOWN( g.dep_taddr_[i] < num_var );
}
for(size_t i = 0; i < s; i++)
{ g.dep_taddr_[m + i] = size_t( f2g_var[ f_abs_arg[i] ] );
CPPAD_ASSERT_UNKNOWN( g.dep_taddr_[m + i] < num_var );
}
// which dependent variables are parameters
g.dep_parameter_.resize(m + s);
for(size_t i = 0; i < m; i++)
g.dep_parameter_[i] = dep_parameter_[i];
for(size_t i = 0; i < s; i++)
g.dep_parameter_[m + i] = false;
// free memory allocated for sparse Jacobian calculation
// (the resutls are no longer valid)
g.for_jac_sparse_pack_.resize(0, 0);
g.for_jac_sparse_set_.resize(0, 0);
// free taylor coefficient memory
g.taylor_.clear();
g.num_order_taylor_ = 0;
g.cap_order_taylor_ = 0;
// Transferring the recording swaps its vectors so do this last
// replace the recording in g (this ADFun object)
g.play_.get_recording(rec, n + s);
// resize subgraph_info_
g.subgraph_info_.resize(
g.ind_taddr_.size(), // n_ind
g.dep_taddr_.size(), // n_dep
g.play_.num_op_rec(), // n_op
g.play_.num_var_rec() // n_var
);
// ------------------------------------------------------------------------
// Create the function a
// ------------------------------------------------------------------------
// start with a copy of f
a = *this;
// dependent variables in a(x)
CPPAD_ASSERT_UNKNOWN( s == f_abs_arg.size() );
a.dep_taddr_.resize(s);
for(size_t i = 0; i < s; i++)
{ a.dep_taddr_[i] = f_abs_res[i];
CPPAD_ASSERT_UNKNOWN( a.dep_taddr_[i] < num_var );
}
// free memory allocated for sparse Jacobian calculation
// (the resutls are no longer valid)
a.for_jac_sparse_pack_.resize(0, 0);
a.for_jac_sparse_set_.resize(0, 0);
// free taylor coefficient memory
a.taylor_.clear();
a.num_order_taylor_ = 0;
a.cap_order_taylor_ = 0;
}
// preprocessor symbols that are local to this file
# undef CPPAD_J_PAR_EQUAL_REC
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,311 @@
# ifndef CPPAD_CORE_AD_HPP
# define CPPAD_CORE_AD_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.
---------------------------------------------------------------------------- */
// simple AD operations that must be defined for AD as well as base class
# include <cppad/core/ordered.hpp>
# include <cppad/core/identical.hpp>
// define the template classes that are used by the AD template class
# include <cppad/local/op_code_dyn.hpp>
# include <cppad/local/op_code_var.hpp>
# include <cppad/core/ad_type.hpp>
# include <cppad/local/record/recorder.hpp>
# include <cppad/local/play/player.hpp>
# include <cppad/local/ad_tape.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
// tape_manage_enum
typedef enum {
new_tape_manage,
delete_tape_manage
}
tape_manage_enum;
template <class Base>
class AD {
private :
// -----------------------------------------------------------------------
// Base type value for this object
Base value_;
//
// tape for this object
tape_id_t tape_id_;
//
// tape address for this object
// (when tape_id is current tape for AD<Base>)
addr_t taddr_;
//
// sub-type for this object
// (when tape_id is current tape for AD<Base>)
ad_type_enum ad_type_;
// -----------------------------------------------------------------------
// enable use of AD<Base> in parallel mode
template <class Type>
friend void parallel_ad(void);
// template friend functions where template parameter is not bound
template <class ADVector>
friend void Independent(
ADVector& x ,
size_t abort_op_index ,
bool record_compare ,
ADVector& dynamic
);
// one argument functions
friend bool Constant <Base> (const AD<Base> &u);
friend bool Constant <Base> (const VecAD<Base> &u);
//
friend bool Dynamic <Base> (const AD<Base> &u);
friend bool Dynamic <Base> (const VecAD<Base> &u);
//
friend bool Parameter <Base> (const AD<Base> &u);
friend bool Parameter <Base> (const VecAD<Base> &u);
//
friend bool Variable <Base> (const AD<Base> &u);
friend bool Variable <Base> (const VecAD<Base> &u);
//
friend int Integer <Base> (const AD<Base> &u);
friend AD Var2Par <Base> (const AD<Base> &u);
//
friend unsigned short hash_code <Base> (const AD<Base> &u);
//
// power function
friend AD pow <Base>
(const AD<Base> &x, const AD<Base> &y);
// azmul function
friend AD azmul <Base>
(const AD<Base> &x, const AD<Base> &y);
// order determining functions, see ordered.hpp
friend bool GreaterThanZero <Base> (const AD<Base> &x);
friend bool GreaterThanOrZero <Base> (const AD<Base> &x);
friend bool LessThanZero <Base> (const AD<Base> &x);
friend bool LessThanOrZero <Base> (const AD<Base> &x);
friend bool abs_geq <Base>
(const AD<Base>& x, const AD<Base>& y);
// The identical property functions, see identical.hpp
friend bool IdenticalCon <Base> (const AD<Base> &x);
friend bool IdenticalZero <Base> (const AD<Base> &x);
friend bool IdenticalOne <Base> (const AD<Base> &x);
friend bool IdenticalEqualCon <Base>
(const AD<Base> &x, const AD<Base> &y);
// EqualOpSeq function
friend bool EqualOpSeq <Base>
(const AD<Base> &u, const AD<Base> &v);
// NearEqual function
friend bool NearEqual <Base> (
const AD<Base> &x, const AD<Base> &y, const Base &r, const Base &a);
friend bool NearEqual <Base> (
const Base &x, const AD<Base> &y, const Base &r, const Base &a);
friend bool NearEqual <Base> (
const AD<Base> &x, const Base &y, const Base &r, const Base &a);
// CondExp function
friend AD<Base> CondExpOp <Base> (
enum CompareOp cop ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &trueCase ,
const AD<Base> &falseCase
);
// classes
friend class local::ADTape<Base>;
friend class local::recorder<Base>;
friend class ADFun<Base>;
friend class atomic_base<Base>;
friend class atomic_three<Base>;
friend class discrete<Base>;
friend class VecAD<Base>;
friend class VecAD_reference<Base>;
// arithematic binary operators
friend AD<Base> operator + <Base>
(const AD<Base> &left, const AD<Base> &right);
friend AD<Base> operator - <Base>
(const AD<Base> &left, const AD<Base> &right);
friend AD<Base> operator * <Base>
(const AD<Base> &left, const AD<Base> &right);
friend AD<Base> operator / <Base>
(const AD<Base> &left, const AD<Base> &right);
// comparison operators
friend bool operator < <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool operator <= <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool operator > <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool operator >= <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool operator == <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool operator != <Base>
(const AD<Base> &left, const AD<Base> &right);
// input operator
friend std::istream& operator >> <Base>
(std::istream &is, AD<Base> &x);
// output operations
friend std::ostream& operator << <Base>
(std::ostream &os, const AD<Base> &x);
friend void PrintFor <Base> (
const AD<Base>& flag ,
const char* before ,
const AD<Base>& var ,
const char* after
);
public:
// type of value
typedef Base value_type;
// implicit default constructor
AD(void);
// destructor
~AD(void) { }
// use default implicit copy constructor
// AD(const AD &x);
# ifdef CPPAD_FOR_TMB
// TMB would rather have implicit construction from double,
// CppAD uses default constructor and assignment to double instead.
AD(const double &d);
# else
// implicit construction from base type
AD(const Base &b);
# endif
// implicit contructor from VecAD<Base>::reference
AD(const VecAD_reference<Base> &x);
// explicit construction from some other type (depricated)
template <class T> explicit AD(const T &t);
// conversion from AD to Base type
friend Base Value <Base> (const AD<Base> &x);
// use default assignment operator
// AD& operator=(const AD &x);
// assingment from base type
AD& operator=(const Base &b);
// assignment from VecAD<Base>::reference
AD& operator=(const VecAD_reference<Base> &x);
// assignment from some other type
template <class T> AD& operator=(const T &right);
// compound assignment operators
AD& operator += (const AD &right);
AD& operator -= (const AD &right);
AD& operator *= (const AD &right);
AD& operator /= (const AD &right);
// unary operators
AD operator +(void) const;
AD operator -(void) const;
// interface so these functions need not be friends
AD abs_me(void) const;
AD acos_me(void) const;
AD asin_me(void) const;
AD atan_me(void) const;
AD cos_me(void) const;
AD cosh_me(void) const;
AD exp_me(void) const;
AD fabs_me(void) const;
AD log_me(void) const;
AD sin_me(void) const;
AD sign_me(void) const;
AD sinh_me(void) const;
AD sqrt_me(void) const;
AD tan_me(void) const;
AD tanh_me(void) const;
AD asinh_me(void) const;
AD acosh_me(void) const;
AD atanh_me(void) const;
AD erf_me(bool complemnet) const;
AD expm1_me(void) const;
AD log1p_me(void) const;
// ----------------------------------------------------------
// static public member functions
// abort current AD<Base> recording
static void abort_recording(void);
// set the maximum number of OpenMP threads (deprecated)
static void omp_max_thread(size_t number);
// These functions declared public so can be accessed by user through
// a macro interface and are not intended for direct use.
// The macro interface is documented in bool_fun.hpp.
// Developer documentation for these fucntions is in bool_fun.hpp
static bool UnaryBool(
bool FunName(const Base &x),
const AD<Base> &x
);
static bool BinaryBool(
bool FunName(const Base &x, const Base &y),
const AD<Base> &x , const AD<Base> &y
);
private:
// -----------------------------------------------------------------
// Make this parameter a new variable
void make_variable(tape_id_t id, addr_t taddr)
{ CPPAD_ASSERT_UNKNOWN( Parameter(*this) ); // currently a par
CPPAD_ASSERT_UNKNOWN( taddr > 0 ); // sure valid taddr
tape_id_ = id;
taddr_ = taddr;
ad_type_ = variable_enum;
}
// ---------------------------------------------------------------
// tape linking functions
//
// not static
local::ADTape<Base>* tape_this(void) const;
//
// static
static tape_id_t* tape_id_ptr(size_t thread);
static local::ADTape<Base>** tape_handle(size_t thread);
static local::ADTape<Base>* tape_manage(tape_manage_enum job);
static local::ADTape<Base>* tape_ptr(void);
static local::ADTape<Base>* tape_ptr(tape_id_t tape_id);
};
// ---------------------------------------------------------------------------
} // END_CPPAD_NAMESPACE
// tape linking private functions
# include <cppad/core/tape_link.hpp>
// operations that expect the AD template class to be defined
# endif

View File

@@ -0,0 +1,144 @@
# ifndef CPPAD_CORE_AD_ASSIGN_HPP
# define CPPAD_CORE_AD_ASSIGN_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 ad_assign$$
$spell
Vec
const
$$
$section AD Assignment Operator$$
$head Syntax$$
$icode%y% = %x%$$
$head Purpose$$
Assigns the value in $icode x$$ to the object $icode y$$.
In either case,
$head x$$
The argument $icode x$$ has prototype
$codei%
const %Type% &%x%
%$$
where $icode Type$$ is
$codei%VecAD<%Base%>::reference%$$,
$codei%AD<%Base%>%$$,
$icode Base$$,
or any type that has an implicit constructor of the form
$icode%Base%(%x%)%$$.
$head y$$
The target $icode y$$ has prototype
$codei%
AD<%Base%> %y%
%$$
$head Example$$
$children%
example/general/ad_assign.cpp
%$$
The file $cref ad_assign.cpp$$ contain examples and tests of these operations.
It test returns true if it succeeds and false otherwise.
$end
------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file ad_assign.hpp
AD<Base> constructors and and copy operations.
*/
/*!
\page AD_default_assign
Use default assignment operator
because they may be optimized better than the code below:
\code
template <class Base>
AD<Base>& AD<Base>::operator=(const AD<Base> &right)
{ value_ = right.value_;
tape_id_ = right.tape_id_;
taddr_ = right.taddr_;
ad_type_ = right.ad_type_;
return *this;
}
\endcode
*/
/*!
Assignment to Base type value.
\tparam Base
Base type for this AD object.
\param b
is the Base type value being assignment to this AD object.
The tape identifier will be an invalid tape identifier,
so this object is initially a parameter.
*/
template <class Base>
AD<Base>& AD<Base>::operator=(const Base &b)
{ value_ = b;
tape_id_ = 0;
//
CPPAD_ASSERT_UNKNOWN( ! ( Variable(*this) | Dynamic(*this) ) );
return *this;
}
/*!
Assignment to an ADVec<Base> element drops the vector information.
\tparam Base
Base type for this AD object.
*/
template <class Base>
AD<Base>& AD<Base>::operator=(const VecAD_reference<Base> &x)
{ *this = x.ADBase();
CPPAD_ASSERT_UNKNOWN( ! Dynamic(*this) );
return *this;
}
/*!
Assignment from any other type, converts to Base type, and then uses assignment
from Base type.
\tparam Base
Base type for this AD object.
\tparam T
is the the type that is being assigned to AD<Base>.
There must be an assignment for Base from Type.
\param t
is the object that is being assigned to an AD<Base> object.
*/
template <class Base>
template <class T>
AD<Base>& AD<Base>::operator=(const T &t)
{ *this = Base(t);
CPPAD_ASSERT_UNKNOWN( ! ( Variable(*this) | Dynamic(*this) ) );
return *this;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,143 @@
# ifndef CPPAD_CORE_AD_BINARY_HPP
# define CPPAD_CORE_AD_BINARY_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 ad_binary$$
$spell
Op
VecAD
const
$$
$section AD Binary Arithmetic Operators$$
$head Syntax$$
$icode%z% = %x% %Op% %y%$$
$head Purpose$$
Performs arithmetic operations where either $icode x$$ or $icode y$$
has type
$codei%AD<%Base%>%$$ or
$cref%VecAD<Base>::reference%VecAD%VecAD<Base>::reference%$$.
$head Op$$
The operator $icode Op$$ is one of the following
$table
$bold Op$$ $cnext $bold Meaning$$ $rnext
$code +$$ $cnext $icode z$$ is $icode x$$ plus $icode y$$ $rnext
$code -$$ $cnext $icode z$$ is $icode x$$ minus $icode y$$ $rnext
$code *$$ $cnext $icode z$$ is $icode x$$ times $icode y$$ $rnext
$code /$$ $cnext $icode z$$ is $icode x$$ divided by $icode y$$
$tend
$head Base$$
The type $icode Base$$ is determined by the operand that
has type $codei%AD<%Base%>%$$ or $codei%VecAD<%Base%>::reference%$$.
$head x$$
The operand $icode x$$ has the following prototype
$codei%
const %Type% &%x%
%$$
where $icode Type$$ is
$codei%VecAD<%Base%>::reference%$$,
$codei%AD<%Base%>%$$,
$icode Base$$, or
$code double$$.
$head y$$
The operand $icode y$$ has the following prototype
$codei%
const %Type% &%y%
%$$
where $icode Type$$ is
$codei%VecAD<%Base%>::reference%$$,
$codei%AD<%Base%>%$$,
$icode Base$$, or
$code double$$.
$head z$$
The result $icode z$$ has the following prototype
$codei%
%Type% %z%
%$$
where $icode Type$$ is
$codei%AD<%Base%>%$$.
$head Operation Sequence$$
This is an $cref/atomic_base/glossary/Operation/Atomic/$$
$cref/AD of Base/glossary/AD of Base/$$ operation
and hence it is part of the current
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$children%
example/general/add.cpp%
example/general/sub.cpp%
example/general/mul.cpp%
example/general/div.cpp
%$$
$head Example$$
The following files contain examples and tests of these functions.
Each test returns true if it succeeds and false otherwise.
$table
$rref add.cpp$$
$rref sub.cpp$$
$rref mul.cpp$$
$rref div.cpp$$
$tend
$head Derivative$$
If $latex f$$ and $latex g$$ are
$cref/Base functions/glossary/Base Function/$$
$subhead Addition$$
$latex \[
\D{[ f(x) + g(x) ]}{x} = \D{f(x)}{x} + \D{g(x)}{x}
\] $$
$subhead Subtraction$$
$latex \[
\D{[ f(x) - g(x) ]}{x} = \D{f(x)}{x} - \D{g(x)}{x}
\] $$
$subhead Multiplication$$
$latex \[
\D{[ f(x) * g(x) ]}{x} = g(x) * \D{f(x)}{x} + f(x) * \D{g(x)}{x}
\] $$
$subhead Division$$
$latex \[
\D{[ f(x) / g(x) ]}{x} =
[1/g(x)] * \D{f(x)}{x} - [f(x)/g(x)^2] * \D{g(x)}{x}
\] $$
$end
-----------------------------------------------------------------------------
*/
# include <cppad/core/add.hpp>
# include <cppad/core/sub.hpp>
# include <cppad/core/mul.hpp>
# include <cppad/core/div.hpp>
# endif

View File

@@ -0,0 +1,199 @@
# ifndef CPPAD_CORE_AD_CTOR_HPP
# define CPPAD_CORE_AD_CTOR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 ad_ctor$$
$spell
cppad
ctor
initializes
Vec
const
$$
$section AD Constructors $$
$head Syntax$$
$codei%AD<%Base%> %y%()
%$$
$codei%AD<%Base%> %y%(%x%)
%$$
$head Purpose$$
creates a new $codei%AD<%Base%>%$$ object $icode y$$
and initializes its value as equal to $icode x$$.
$head x$$
$subhead implicit$$
There is an implicit constructor where $icode x$$ has one of the following
prototypes:
$codei%
const %Base%& %x%
const VecAD<%Base%>& %x%
%$$
$subhead explicit$$
There is an explicit constructor where $icode x$$ has prototype
$codei%
const %Type%& %x%
%$$
for any type that has an explicit constructor of the form
$icode%Base%(%x%)%$$.
$head y$$
The target $icode y$$ has prototype
$codei%
AD<%Base%> %y%
%$$
$head Example$$
$children%
example/general/ad_ctor.cpp
%$$
The files $cref ad_ctor.cpp$$ contain examples and tests of these operations.
It test returns true if it succeeds and false otherwise.
$end
------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file ad_ctor.hpp
AD<Base> constructors and and copy operations.
*/
/*!
\page AD_default_ctor
Use default copy constructor
because they may be optimized better than the code below:
\code
template <class Base>
AD<Base>::AD(const AD &x)
{
value_ = x.value_;
tape_id_ = x.tape_id_;
taddr_ = x.taddr_;
ad_type_ = x.ad_type_;
return;
}
\endcode
*/
/*!
Default Constructor.
\tparam Base
Base type for this AD object.
*/
template <class Base>
AD<Base>::AD(void)
: value_()
, tape_id_(0)
, taddr_(0)
, ad_type_(constant_enum)
{ }
// --------------------------------------------------------------------------
# ifdef CPPAD_FOR_TMB
/*!
Constructor from double.
\param d
is value corresponding to this AD object.
The tape identifier will be an invalid tape identifier,
so this object is initially a parameter.
\par CPPAD_FOR_TMB
This constructor is defined when CPPAD_FOR_TMB is defined.
*/
template <class Base>
AD<Base>::AD(const double &d)
: value_( Base(d) )
, tape_id_(0)
, taddr_(0)
, ad_type_(constant_enum)
{ // check that this is a parameter
CPPAD_ASSERT_UNKNOWN( Parameter(*this) );
}
// --------------------------------------------------------------------------
# else
// --------------------------------------------------------------------------
/*!
Constructor from Base type.
\tparam Base
Base type for this AD object.
\param b
is the Base type value corresponding to this AD object.
The tape identifier will be an invalid tape identifier,
so this object is initially a parameter.
\par CPPAD_FOR_TMB
This constructor is defined when CPPAD_FOR_TMB is not defined.
*/
template <class Base>
AD<Base>::AD(const Base &b)
: value_(b)
, tape_id_(0)
, taddr_(0)
, ad_type_(constant_enum)
{ // check that this is a parameter
CPPAD_ASSERT_UNKNOWN( Parameter(*this) );
}
# endif
// --------------------------------------------------------------------------
/*!
Constructor from an ADVec<Base> element drops the vector information.
\tparam Base
Base type for this AD object.
*/
template <class Base>
AD<Base>::AD(const VecAD_reference<Base> &x)
{ *this = x.ADBase(); }
/*!
Constructor from any other type, converts to Base type, and uses constructor
from Base type.
\tparam Base
Base type for this AD object.
\tparam T
is the the type that is being converted to AD<Base>.
There must be a constructor for Base from Type.
\param t
is the object that is being converted from T to AD<Base>.
*/
template <class Base>
template <class T>
AD<Base>::AD(const T &t)
: value_(Base(t))
, tape_id_(0)
, taddr_(0)
, ad_type_(constant_enum)
{ }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,876 @@
# ifndef CPPAD_CORE_AD_FUN_HPP
# define CPPAD_CORE_AD_FUN_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 ADFun$$
$spell
xk
Ind
bool
taylor_
sizeof
const
std
ind_taddr_
dep_taddr_
$$
$spell
$$
$section ADFun Objects$$
$head Purpose$$
An AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$
is stored in an $code ADFun$$ object by its $cref FunConstruct$$.
The $code ADFun$$ object can then be used to calculate function values,
derivative values, and other values related to the corresponding function.
$childtable%
omh/adfun.omh%
include/cppad/core/optimize.hpp%
include/cppad/core/fun_check.hpp%
include/cppad/core/check_for_nan.hpp
%$$
$end
*/
# include <cppad/core/graph/cpp_graph.hpp>
# include <cppad/local/subgraph/info.hpp>
# include <cppad/local/graph/cpp_graph_op.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file ad_fun.hpp
File used to define the ADFun<Base> class.
*/
/*!
Class used to hold function objects
\tparam Base
A function object has a recording of <tt>AD<Base></tt> operations.
It does it calculations using Base operations.
*/
template <class Base, class RecBase>
class ADFun {
// ADFun<Base> must be a friend of ADFun< AD<Base> > for base2ad to work.
template <class Base2, class RecBase2> friend class ADFun;
private:
// ------------------------------------------------------------
// Private member variables
// ------------------------------------------------------------
/// name of this function (so far only json operations use this value)
std::string function_name_;
/// Did the previous optimzation exceed the collision limit
bool exceed_collision_limit_;
/// Has this ADFun object been optmized
bool has_been_optimized_;
/// Check for nan's and report message to user (default value is true).
bool check_for_nan_;
/// If zero, ignoring comparison operators. Otherwise is the
/// compare change count at which to store the operator index.
size_t compare_change_count_;
/// If compare_change_count_ is zero, compare_change_number_ is also zero.
/// Otherwise, it is set to the number of comparison operations that had a
/// different result during the subsequent zero order forward.
size_t compare_change_number_;
/// If compare_change_count is zero, compare_change_op_index_ is also
/// zero. Otherwise it is the operator index for the comparison operator
//// that corresponded to the number changing from count-1 to count.
size_t compare_change_op_index_;
/// number of orders stored in taylor_
size_t num_order_taylor_;
/// maximum number of orders that will fit in taylor_
size_t cap_order_taylor_;
/// number of directions stored in taylor_
size_t num_direction_taylor_;
/// number of variables in the recording (play_)
size_t num_var_tape_;
/// tape address for the independent variables
local::pod_vector<size_t> ind_taddr_;
/// tape address and parameter flag for the dependent variables
local::pod_vector<size_t> dep_taddr_;
/// which dependent variables are actually parameters
local::pod_vector<bool> dep_parameter_;
/// which operations can be conditionally skipped
/// Set during forward pass of order zero
local::pod_vector<bool> cskip_op_;
/// Variable on the tape corresponding to each vecad load operation
/// (if zero, the operation corresponds to a parameter).
local::pod_vector<addr_t> load_op2var_;
/// results of the forward mode calculations
local::pod_vector_maybe<Base> taylor_;
/// used for subgraph reverse mode calculations.
/// Declared here to avoid reallocation for each call to subgraph_reverse.
/// Not in subgraph_info_ because it depends on Base.
local::pod_vector_maybe<Base> subgraph_partial_;
/// the operation sequence corresponding to this object
local::player<Base> play_;
/// subgraph information for this object
local::subgraph::subgraph_info subgraph_info_;
/// Packed results of the forward mode Jacobian sparsity calculations.
/// for_jac_sparse_pack_.n_set() != 0 implies other sparsity results
/// are empty
local::sparse::pack_setvec for_jac_sparse_pack_;
/// Set results of the forward mode Jacobian sparsity calculations
/// for_jac_sparse_set_.n_set() != 0 implies for_sparse_pack_ is empty.
local::sparse::list_setvec for_jac_sparse_set_;
// ------------------------------------------------------------
// Private member functions
// ------------------------------------------------------------
/// change the operation sequence corresponding to this object
template <class ADvector>
void Dependent(local::ADTape<Base> *tape, const ADvector &y);
// vector of bool version of ForSparseJac
// (doxygen in cppad/core/for_sparse_jac.hpp)
template <class SetVector>
void ForSparseJacCase(
bool set_type ,
bool transpose ,
bool dependency,
size_t q ,
const SetVector& r ,
SetVector& s
);
// vector of std::set<size_t> version of ForSparseJac
// (doxygen in cppad/core/for_sparse_jac.hpp)
template <class SetVector>
void ForSparseJacCase(
const std::set<size_t>& set_type ,
bool transpose ,
bool dependency,
size_t q ,
const SetVector& r ,
SetVector& s
);
// vector of bool version of RevSparseJac
// (doxygen in cppad/core/rev_sparse_jac.hpp)
template <class SetVector>
void RevSparseJacCase(
bool set_type ,
bool transpose ,
bool dependency,
size_t p ,
const SetVector& s ,
SetVector& r
);
// vector of std::set<size_t> version of RevSparseJac
// (doxygen in cppad/core/rev_sparse_jac.hpp)
template <class SetVector>
void RevSparseJacCase(
const std::set<size_t>& set_type ,
bool transpose ,
bool dependency,
size_t p ,
const SetVector& s ,
SetVector& r
);
// vector of bool version of ForSparseHes
// (doxygen in cppad/core/for_sparse_hes.hpp)
template <class SetVector>
void ForSparseHesCase(
bool set_type ,
const SetVector& r ,
const SetVector& s ,
SetVector& h
);
// vector of std::set<size_t> version of ForSparseHes
// (doxygen in cppad/core/for_sparse_hes.hpp)
template <class SetVector>
void ForSparseHesCase(
const std::set<size_t>& set_type ,
const SetVector& r ,
const SetVector& s ,
SetVector& h
);
// vector of bool version of RevSparseHes
// (doxygen in cppad/core/rev_sparse_hes.hpp)
template <class SetVector>
void RevSparseHesCase(
bool set_type ,
bool transpose ,
size_t q ,
const SetVector& s ,
SetVector& h
);
// vector of std::set<size_t> version of RevSparseHes
// (doxygen in cppad/core/rev_sparse_hes.hpp)
template <class SetVector>
void RevSparseHesCase(
const std::set<size_t>& set_type ,
bool transpose ,
size_t q ,
const SetVector& s ,
SetVector& h
);
// Forward mode version of SparseJacobian
// (doxygen in cppad/core/sparse_jacobian.hpp)
template <class BaseVector, class SetVector, class SizeVector>
size_t SparseJacobianFor(
const BaseVector& x ,
SetVector& p_transpose ,
const SizeVector& row ,
const SizeVector& col ,
BaseVector& jac ,
sparse_jacobian_work& work
);
// Reverse mode version of SparseJacobian
// (doxygen in cppad/core/sparse_jacobian.hpp)
template <class BaseVector, class SetVector, class SizeVector>
size_t SparseJacobianRev(
const BaseVector& x ,
SetVector& p ,
const SizeVector& row ,
const SizeVector& col ,
BaseVector& jac ,
sparse_jacobian_work& work
);
// combined sparse_list and sparse_pack version of SparseHessian
// (doxygen in cppad/core/sparse_hessian.hpp)
template <class BaseVector, class SetVector, class SizeVector>
size_t SparseHessianCompute(
const BaseVector& x ,
const BaseVector& w ,
SetVector& sparsity ,
const SizeVector& row ,
const SizeVector& col ,
BaseVector& hes ,
sparse_hessian_work& work
);
public:
/// default constructor
ADFun(void);
/// copy constructor
ADFun(const ADFun& g) = delete;
// assignment operator
// (doxygen in cppad/core/fun_construct.hpp)
void operator=(const ADFun& f);
// swap
void swap(ADFun& f);
// move semenatics copy
ADFun(ADFun&& f);
// move semantics assignment
void operator=(ADFun&& f);
// create from Json or C++ AD graph
void from_json(const std::string& json);
void from_graph(const cpp_graph& graph_obj);
void from_graph(
const cpp_graph& graph_obj ,
const vector<bool>& dyn2var ,
const vector<bool>& var2dyn
);
// create a Json or C++ AD graph
std::string to_json(void);
void to_graph(cpp_graph& graph_obj);
// create ADFun< AD<Base> > from this ADFun<Base>
// (doxygen in cppad/core/base2ad.hpp)
ADFun< AD<Base>, RecBase > base2ad(void) const;
/// sequence constructor
template <class ADvector>
ADFun(const ADvector &x, const ADvector &y);
/// destructor
~ADFun(void);
/// set check_for_nan
void check_for_nan(bool value);
/// get check_for_nan
bool check_for_nan(void) const;
/// assign a new operation sequence
template <class ADvector>
void Dependent(const ADvector &x, const ADvector &y);
/// new_dynamic user API
template <class BaseVector>
void new_dynamic(const BaseVector& dynamic);
/// forward mode user API, one order multiple directions.
template <class BaseVector>
BaseVector Forward(size_t q, size_t r, const BaseVector& x);
/// forward mode user API, multiple orders one direction.
template <class BaseVector>
BaseVector Forward(
size_t q, const BaseVector& xq, std::ostream& s = std::cout
);
/// reverse mode sweep
template <class BaseVector>
BaseVector Reverse(size_t p, const BaseVector &v);
// forward Jacobian sparsity pattern
// (doxygen in cppad/core/for_sparse_jac.hpp)
template <class SetVector>
SetVector ForSparseJac(
size_t q, const SetVector &r, bool transpose = false,
bool dependency = false
);
// reverse Jacobian sparsity pattern
// (doxygen in cppad/core/rev_sparse_jac.hpp)
template <class SetVector>
SetVector RevSparseJac(
size_t q, const SetVector &s, bool transpose = false,
bool dependency = false
);
// subgraph_reverse: select domain
// (doxygen in cppad/core/subgraph_reverse.hpp)
template <class BoolVector>
void subgraph_reverse(
const BoolVector& select_domain
);
// subgraph_reverse: compute derivative
// (doxygen in cppad/core/subgraph_reverse.hpp)
template <class Addr, class BaseVector, class SizeVector>
void subgraph_reverse_helper(
size_t q ,
size_t ell ,
SizeVector& col ,
BaseVector& dw
);
// subgraph_reverse: compute derivative
// (doxygen in cppad/core/subgraph_reverse.hpp)
template <class BaseVector, class SizeVector>
void subgraph_reverse(
size_t q ,
size_t ell ,
SizeVector& col ,
BaseVector& dw
);
// subgraph_jac_rev: compute Jacobian
// (doxygen in cppad/core/subgraph_jac_rev.hpp)
template <class SizeVector, class BaseVector>
void subgraph_jac_rev(
const BaseVector& x ,
sparse_rcv<SizeVector, BaseVector>& subset
);
// subgraph_jac_rev: compute Jacobian
// (doxygen missing in cppad/core/subgraph_jac_rev.hpp)
template <class BoolVector, class SizeVector, class BaseVector>
void subgraph_jac_rev(
const BoolVector& select_domain ,
const BoolVector& select_range ,
const BaseVector& x ,
sparse_rcv<SizeVector, BaseVector>& matrix_out
);
// compute sparse Jacobian using forward mode
// (doxygen in cppad/core/sparse_jac.hpp)
template <class SizeVector, class BaseVector>
size_t sparse_jac_for(
size_t group_max ,
const BaseVector& x ,
sparse_rcv<SizeVector, BaseVector>& subset ,
const sparse_rc<SizeVector>& pattern ,
const std::string& coloring ,
sparse_jac_work& work
);
// compute sparse Jacobian using reverse mode
// (doxygen in cppad/core/sparse_jac.hpp)
template <class SizeVector, class BaseVector>
size_t sparse_jac_rev(
const BaseVector& x ,
sparse_rcv<SizeVector, BaseVector>& subset ,
const sparse_rc<SizeVector>& pattern ,
const std::string& coloring ,
sparse_jac_work& work
);
// compute sparse Hessian
// (doxygen in cppad/core/sparse_hes.hpp)
template <class SizeVector, class BaseVector>
size_t sparse_hes(
const BaseVector& x ,
const BaseVector& w ,
sparse_rcv<SizeVector, BaseVector>& subset ,
const sparse_rc<SizeVector>& pattern ,
const std::string& coloring ,
sparse_hes_work& work
);
// compute sparsity pattern using subgraphs
// (doxygen in cppad/core/subgraph_sparsity.hpp)
template <class BoolVector, class SizeVector>
void subgraph_sparsity(
const BoolVector& select_domain ,
const BoolVector& select_range ,
bool transpose ,
sparse_rc<SizeVector>& pattern_out
);
// forward mode Jacobian sparsity pattern
// (doxygen in cppad/core/for_jac_sparsity.hpp)
template <class SizeVector>
void for_jac_sparsity(
const sparse_rc<SizeVector>& pattern_in ,
bool transpose ,
bool dependency ,
bool internal_bool ,
sparse_rc<SizeVector>& pattern_out
);
// reverse mode Jacobian sparsity pattern
// (doxygen in cppad/core/for_jac_sparsity.hpp)
template <class SizeVector>
void rev_jac_sparsity(
const sparse_rc<SizeVector>& pattern_in ,
bool transpose ,
bool dependency ,
bool internal_bool ,
sparse_rc<SizeVector>& pattern_out
);
// reverse mode Hessian sparsity pattern
// (doxygen in cppad/core/rev_hes_sparsity.hpp)
template <class BoolVector, class SizeVector>
void rev_hes_sparsity(
const BoolVector& select_range ,
bool transpose ,
bool internal_bool ,
sparse_rc<SizeVector>& pattern_out
);
// forward mode Hessian sparsity pattern
// (doxygen in cppad/core/for_hes_sparsity.hpp)
template <class BoolVector, class SizeVector>
void for_hes_sparsity(
const BoolVector& select_domain ,
const BoolVector& select_range ,
bool internal_bool ,
sparse_rc<SizeVector>& pattern_out
);
// forward mode Hessian sparsity pattern
// (see doxygen in cppad/core/for_sparse_hes.hpp)
template <class SetVector>
SetVector ForSparseHes(
const SetVector &r, const SetVector &s
);
// internal set sparsity version of ForSparseHes
// (used by checkpoint functions only)
void ForSparseHesCheckpoint(
vector<bool>& r ,
vector<bool>& s ,
local::sparse::list_setvec& h
);
// reverse mode Hessian sparsity pattern
// (see doxygen in cppad/core/rev_sparse_hes.hpp)
template <class SetVector>
SetVector RevSparseHes(
size_t q, const SetVector &s, bool transpose = false
);
// internal set sparsity version of RevSparseHes
// (doxygen in cppad/core/rev_sparse_hes.hpp)
// (used by checkpoint functions only)
void RevSparseHesCheckpoint(
size_t q ,
vector<bool>& s ,
bool transpose ,
local::sparse::list_setvec& h
);
// internal set sparsity version of RevSparseJac
// (doxygen in cppad/core/rev_sparse_jac.hpp)
// (used by checkpoint functions only)
void RevSparseJacCheckpoint(
size_t q ,
const local::sparse::list_setvec& r ,
bool transpose ,
bool dependency ,
local::sparse::list_setvec& s
);
// internal set sparsity version of RevSparseJac
// (doxygen in cppad/core/for_sparse_jac.hpp)
// (used by checkpoint functions only)
void ForSparseJacCheckpoint(
size_t q ,
const local::sparse::list_setvec& r ,
bool transpose ,
bool dependency ,
local::sparse::list_setvec& s
);
/// did previous optimization exceed the collision limit
bool exceed_collision_limit(void) const
{ return exceed_collision_limit_; }
/// amount of memory used for boolean Jacobain sparsity pattern
size_t size_forward_bool(void) const
{ return for_jac_sparse_pack_.memory(); }
/// free memory used for Jacobain sparsity pattern
void size_forward_bool(size_t zero)
{ CPPAD_ASSERT_KNOWN(
zero == 0,
"size_forward_bool: argument not equal to zero"
);
for_jac_sparse_pack_.resize(0, 0);
}
/// amount of memory used for vector of set Jacobain sparsity pattern
size_t size_forward_set(void) const
{ return for_jac_sparse_set_.memory(); }
/// free memory used for Jacobain sparsity pattern
void size_forward_set(size_t zero)
{ CPPAD_ASSERT_KNOWN(
zero == 0,
"size_forward_bool: argument not equal to zero"
);
for_jac_sparse_set_.resize(0, 0);
}
/// number of operators in the operation sequence
size_t size_op(void) const
{ return play_.num_op_rec(); }
/// number of operator arguments in the operation sequence
size_t size_op_arg(void) const
{ return play_.num_op_arg_rec(); }
/// amount of memory required for the operation sequence
size_t size_op_seq(void) const
{ return play_.size_op_seq(); }
/// amount of memory currently allocated for random access
/// of the operation sequence
size_t size_random(void) const
{ return play_.size_random(); }
/// number of parameters in the operation sequence
size_t size_par(void) const
{ return play_.num_par_rec(); }
/// number of independent dynamic parameters
size_t size_dyn_ind(void) const
{ return play_.num_dynamic_ind(); }
/// number of dynamic parameters
size_t size_dyn_par(void) const
{ return play_.num_dynamic_par(); }
/// number of dynamic parameters arguments
size_t size_dyn_arg(void) const
{ return play_.num_dynamic_arg(); }
/// number taylor coefficient orders calculated
size_t size_order(void) const
{ return num_order_taylor_; }
/// number taylor coefficient directions calculated
size_t size_direction(void) const
{ return num_direction_taylor_; }
/// number of characters in the operation sequence
size_t size_text(void) const
{ return play_.num_text_rec(); }
/// number of variables in opertion sequence
size_t size_var(void) const
{ return num_var_tape_; }
/// number of VecAD indices in the operation sequence
size_t size_VecAD(void) const
{ return play_.num_var_vecad_ind_rec(); }
/// set number of orders currently allocated (user API)
void capacity_order(size_t c);
/// set number of orders and directions currently allocated
void capacity_order(size_t c, size_t r);
/// number of variables in conditional expressions that can be skipped
size_t number_skip(void);
/// number of independent variables
size_t Domain(void) const
{ return ind_taddr_.size(); }
/// number of dependent variables
size_t Range(void) const
{ return dep_taddr_.size(); }
/// is variable a parameter
bool Parameter(size_t i)
{ CPPAD_ASSERT_KNOWN(
i < dep_taddr_.size(),
"Argument to Parameter is >= dimension of range space"
);
return dep_parameter_[i];
}
/// Deprecated: number of comparison operations that changed
/// for the previous zero order forward (than when function was recorded)
size_t CompareChange(void) const
{ return compare_change_number_; }
/// count as which to store operator index
void compare_change_count(size_t count)
{ compare_change_count_ = count;
compare_change_number_ = 0;
compare_change_op_index_ = 0;
}
/// number of comparison operations that changed
size_t compare_change_number(void) const
{ return compare_change_number_; }
/// operator index for the count-th comparison change
size_t compare_change_op_index(void) const
{ if( has_been_optimized_ )
return 0;
return compare_change_op_index_;
}
/// calculate entire Jacobian
template <class BaseVector>
BaseVector Jacobian(const BaseVector &x);
/// calculate Hessian for one component of f
template <class BaseVector>
BaseVector Hessian(const BaseVector &x, const BaseVector &w);
template <class BaseVector>
BaseVector Hessian(const BaseVector &x, size_t i);
/// forward mode calculation of partial w.r.t one domain component
template <class BaseVector>
BaseVector ForOne(
const BaseVector &x ,
size_t j );
/// reverse mode calculation of derivative of one range component
template <class BaseVector>
BaseVector RevOne(
const BaseVector &x ,
size_t i );
/// forward mode calculation of a subset of second order partials
template <class BaseVector, class SizeVector_t>
BaseVector ForTwo(
const BaseVector &x ,
const SizeVector_t &J ,
const SizeVector_t &K );
/// reverse mode calculation of a subset of second order partials
template <class BaseVector, class SizeVector_t>
BaseVector RevTwo(
const BaseVector &x ,
const SizeVector_t &I ,
const SizeVector_t &J );
/// calculate sparse Jacobians
template <class BaseVector>
BaseVector SparseJacobian(
const BaseVector &x
);
template <class BaseVector, class SetVector>
BaseVector SparseJacobian(
const BaseVector &x ,
const SetVector &p
);
template <class BaseVector, class SetVector, class SizeVector>
size_t SparseJacobianForward(
const BaseVector& x ,
const SetVector& p ,
const SizeVector& r ,
const SizeVector& c ,
BaseVector& jac ,
sparse_jacobian_work& work
);
template <class BaseVector, class SetVector, class SizeVector>
size_t SparseJacobianReverse(
const BaseVector& x ,
const SetVector& p ,
const SizeVector& r ,
const SizeVector& c ,
BaseVector& jac ,
sparse_jacobian_work& work
);
/// calculate sparse Hessians
template <class BaseVector>
BaseVector SparseHessian(
const BaseVector& x ,
const BaseVector& w
);
template <class BaseVector, class BoolVector>
BaseVector SparseHessian(
const BaseVector& x ,
const BaseVector& w ,
const BoolVector& p
);
template <class BaseVector, class SetVector, class SizeVector>
size_t SparseHessian(
const BaseVector& x ,
const BaseVector& w ,
const SetVector& p ,
const SizeVector& r ,
const SizeVector& c ,
BaseVector& hes ,
sparse_hessian_work& work
);
// Optimize the tape
// (see doxygen documentation in optimize.hpp)
void optimize( const std::string& options = "" );
// create abs-normal representation of the function f(x)
void abs_normal_fun( ADFun& g, ADFun& a ) const;
// clear all subgraph information
void clear_subgraph(void);
// ------------------- Deprecated -----------------------------
/// deprecated: assign a new operation sequence
template <class ADvector>
void Dependent(const ADvector &y);
/// Deprecated: number of variables in opertion sequence
size_t Size(void) const
{ return num_var_tape_; }
/// Deprecated: # taylor_ coefficients currently stored
/// (per variable,direction)
size_t Order(void) const
{ return num_order_taylor_ - 1; }
/// Deprecated: amount of memory for this object
/// Note that an approximation is used for the std::set<size_t> memory
size_t Memory(void) const
{ size_t pervar = cap_order_taylor_ * sizeof(Base)
+ for_jac_sparse_pack_.memory()
+ for_jac_sparse_set_.memory();
size_t total = num_var_tape_ * pervar;
total += play_.size_op_seq();
total += play_.size_random();
total += subgraph_info_.memory();
return total;
}
/// Deprecated: # taylor_ coefficient orderss stored
/// (per variable,direction)
size_t taylor_size(void) const
{ return num_order_taylor_; }
/// Deprecated: Does this AD operation sequence use
/// VecAD<Base>::reference operands
bool use_VecAD(void) const
{ return play_.num_var_vecad_ind_rec() > 0; }
/// Deprecated: # taylor_ coefficient orders calculated
/// (per variable,direction)
size_t size_taylor(void) const
{ return num_order_taylor_; }
/// Deprecated: set number of orders currently allocated
/// (per variable,direction)
void capacity_taylor(size_t per_var);
};
// ---------------------------------------------------------------------------
} // END_CPPAD_NAMESPACE
// non-user interfaces
# include <cppad/local/sweep/forward0.hpp>
# include <cppad/local/sweep/forward1.hpp>
# include <cppad/local/sweep/forward2.hpp>
# include <cppad/local/sweep/reverse.hpp>
# include <cppad/local/sweep/for_jac.hpp>
# include <cppad/local/sweep/rev_jac.hpp>
# include <cppad/local/sweep/rev_hes.hpp>
# include <cppad/local/sweep/for_hes.hpp>
# include <cppad/core/graph/from_graph.hpp>
# include <cppad/core/graph/to_graph.hpp>
// user interfaces
# include <cppad/core/parallel_ad.hpp>
# include <cppad/core/independent/independent.hpp>
# include <cppad/core/dependent.hpp>
# include <cppad/core/fun_construct.hpp>
# include <cppad/core/base2ad.hpp>
# include <cppad/core/abort_recording.hpp>
# include <cppad/core/fun_eval.hpp>
# include <cppad/core/drivers.hpp>
# include <cppad/core/fun_check.hpp>
# include <cppad/core/omp_max_thread.hpp>
# include <cppad/core/optimize.hpp>
# include <cppad/core/abs_normal_fun.hpp>
# include <cppad/core/graph/from_json.hpp>
# include <cppad/core/graph/to_json.hpp>
# endif

View File

@@ -0,0 +1,220 @@
# ifndef CPPAD_CORE_AD_IO_HPP
# define CPPAD_CORE_AD_IO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 ad_input$$
$spell
VecAD
std
istream
const
$$
$section AD Input Stream Operator$$
$head Syntax$$
$icode%is% >> %x%$$
$head Purpose$$
Sets $icode x$$ to a $cref/parameter/glossary/Parameter/$$
with value $icode b$$ corresponding to
$codei%
%is% >> %b%
%$$
where $icode b$$ is a $icode Base$$ object.
It is assumed that this $icode Base$$ input operation returns
a reference to $icode is$$.
$head is$$
The operand $icode is$$ has prototype
$codei%
std::istream& %is%
%$$
$head x$$
The operand $icode x$$ has one of the following prototypes
$codei%
AD<%Base%>& %x%
%$$
$head Result$$
The result of this operation can be used as a reference to $icode is$$.
For example, if the operand $icode y$$ has prototype
$codei%
AD<%Base%> %y%
%$$
then the syntax
$codei%
%is% >> %x% >> %y%
%$$
will first read the $icode Base$$ value of $icode x$$ from $icode is$$,
and then read the $icode Base$$ value to $icode y$$.
$head Operation Sequence$$
The result of this operation is not an
$cref/AD of Base/glossary/AD of Base/$$ object.
Thus it will not be recorded as part of an
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Example$$
$children%
example/general/ad_input.cpp
%$$
The file
$cref ad_input.cpp$$
contains an example and test of this operation.
$end
------------------------------------------------------------------------------
$begin ad_output$$
$spell
VecAD
std
ostream
const
$$
$section AD Output Stream Operator$$
$head Syntax$$
$icode%os% << %x%$$
$head See Also$$
$cref PrintFor$$
$head Purpose$$
Writes the $icode Base$$ value, corresponding to $icode x$$,
to the output stream $icode os$$.
$head Assumption$$
If $icode b$$ is a $icode Base$$ object,
$codei%
%os% << %b%
%$$
returns a reference to $icode os$$.
$head os$$
The operand $icode os$$ has prototype
$codei%
std::ostream& %os%
%$$
$head x$$
The operand $icode x$$ has one of the following prototypes
$codei%
const AD<%Base%>& %x%
const VecAD<%Base%>::reference& %x%
%$$
$head Result$$
The result of this operation can be used as a reference to $icode os$$.
For example, if the operand $icode y$$ has prototype
$codei%
AD<%Base%> %y%
%$$
then the syntax
$codei%
%os% << %x% << %y%
%$$
will output the value corresponding to $icode x$$
followed by the value corresponding to $icode y$$.
$head Operation Sequence$$
The result of this operation is not an
$cref/AD of Base/glossary/AD of Base/$$ object.
Thus it will not be recorded as part of an
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Example$$
$children%
example/general/ad_output.cpp
%$$
The file
$cref ad_output.cpp$$
contains an example and test of this operation.
$end
------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file ad_io.hpp
AD<Base> input and ouput stream operators.
*/
// ---------------------------------------------------------------------------
/*!
Read an AD<Base> object from an input stream.
\tparam Base
Base type for the AD object.
\param is [in,out]
Is the input stream from which that value is read.
\param x [out]
is the object that is being set to a value.
Upone return, x.value_ is read from the input stream
and x.tape_is_ is zero; i.e., x is a parameter.
*/
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
std::istream& operator >> (std::istream& is, AD<Base>& x)
{ // like assignment to a base type value
x.tape_id_ = 0;
CPPAD_ASSERT_UNKNOWN( Parameter(x) );
return (is >> x.value_);
}
// ---------------------------------------------------------------------------
/*!
Write an AD<Base> object to an output stream.
\tparam Base
Base type for the AD object.
\param os [in,out]
Is the output stream to which that value is written.
\param x
is the object that is being written to the output stream.
This is equivalent to writing x.value_ to the output stream.
*/
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
std::ostream& operator << (std::ostream &os, const AD<Base> &x)
{ return (os << x.value_); }
// ---------------------------------------------------------------------------
/*!
Write a VecAD_reference<Base> object to an output stream.
\tparam Base
Base type for the VecAD_reference object.
\param os [in,out]
Is the output stream to which that value is written.
\param x
is the element of the VecAD object that is being written to the output stream.
This is equivalent to writing the corresponing Base value to the stream.
*/
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
std::ostream& operator << (std::ostream &os, const VecAD_reference<Base> &x)
{ return (os << x.ADBase()); }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,70 @@
# ifndef CPPAD_CORE_AD_TO_STRING_HPP
# define CPPAD_CORE_AD_TO_STRING_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 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 ad_to_string$$
$spell
const
std
$$
$section Convert An AD or Base Type to String$$
$head Syntax$$
$icode%s% = to_string(%value%)%$$.
$head See Also$$
$cref to_string$$, $cref base_to_string$$
$head value$$
The argument $icode value$$ has prototype
$codei%
const AD<%Base%>& %value%
const %Base%& %value%
%$$
where $icode Base$$ is a type that supports the
$cref base_to_string$$ type requirement.
$head s$$
The return value has prototype
$codei%
std::string %s%
%$$
and contains a representation of the specified $icode value$$.
If $icode value$$ is an AD type,
the result has the same precision as for the $icode Base$$ type.
$head Example$$
The file $cref to_string.cpp$$
includes an example and test of $code to_string$$ with AD types.
$end
*/
# include <cppad/utility/to_string.hpp>
# include <cppad/core/ad.hpp>
namespace CppAD {
// Template definition is in cppad/utility/to_string.hpp.
// Partial specialzation for AD<Base> types
template<class Base>
struct to_string_struct< CppAD::AD<Base> >
{ std::string operator()(const CppAD::AD<Base>& value)
{ to_string_struct<Base> ts;
return ts( Value( Var2Par( value ) ) ); }
};
}
# endif

View File

@@ -0,0 +1,59 @@
# ifndef CPPAD_CORE_AD_TYPE_HPP
# define CPPAD_CORE_AD_TYPE_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.
---------------------------------------------------------------------------- */
# include <cppad/local/is_pod.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*
$begin ad_type_enum$$
$spell
enum
typedef
CppAD
namespace
$$
$section Type of AD an Object$$
$head User API$$
The values $code constant_enum$$, $code dynamic_enum$$ and
$code variable_enum$$ are in the user API; see
$cref/ad_type/atomic_three/ad_type/$$ for $code atomic_three$$ functions.
$head typedef$$
This typedef is in the $code CppAD$$ namespace:
$srccode%hpp% */
typedef enum {
constant_enum, // constant parameter
dynamic_enum, // dynamic parameter
variable_enum, // variable
number_ad_type_enum // number of valid values for type_ad_enum
} ad_type_enum;
/* %$$
$head is_pod$$
The following informs $cref is_pod$$ that this is plain old data.
$srccode%hpp% */
namespace local {
template <> inline bool
is_pod<ad_type_enum>(void) { return true; }
}
/* %$$
$end
*/
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,50 @@
# ifndef CPPAD_CORE_AD_VALUED_HPP
# define CPPAD_CORE_AD_VALUED_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 ADValued$$
$spell
$$
$section AD Valued Operations and Functions$$
$comment atomic.omh includes atomic_two.hpp$$
$childtable%
include/cppad/core/arithmetic.hpp%
include/cppad/core/standard_math.hpp%
include/cppad/core/cond_exp.hpp%
include/cppad/core/discrete/user.omh%
include/cppad/core/numeric_limits.hpp%
include/cppad/core/atomic/atomic.omh
%$$
$end
*/
// include MathOther.h after CondExp.h because some MathOther.h routines use
// CondExp.h and CondExp.h is not sufficently declared in Declare.h
# include <cppad/core/arithmetic.hpp>
# include <cppad/core/standard_math.hpp>
# include <cppad/core/azmul.hpp>
# include <cppad/core/cond_exp.hpp>
# include <cppad/core/discrete/discrete.hpp>
# include <cppad/core/atomic/atomic_three.hpp>
# include <cppad/core/chkpoint_two/chkpoint_two.hpp>
# include <cppad/core/atomic/atomic_two.hpp>
# include <cppad/core/atomic/atomic_one.hpp>
# include <cppad/core/chkpoint_one/chkpoint_one.hpp>
# endif

View File

@@ -0,0 +1,131 @@
# ifndef CPPAD_CORE_ADD_HPP
# define CPPAD_CORE_ADD_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 of this AD object
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 ,
"Add: AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // result = variable + variable
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddvvOp) == 2 );
// put operand addresses in tape
tape->Rec_.PutArg(left.taddr_, right.taddr_);
// put operator in the tape
result.taddr_ = tape->Rec_.PutOp(local::AddvvOp);
// make result a variable
result.tape_id_ = tape_id;
result.ad_type_ = variable_enum;
}
else if( (! dyn_right) & IdenticalZero(right.value_) )
{ // result = variable + 0
result.make_variable(left.tape_id_, left.taddr_);
}
else
{ // result = variable + parameter
// = parameter + variable
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 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(p, left.taddr_);
// put operator in the tape
result.taddr_ = tape->Rec_.PutOp(local::AddpvOp);
// 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
result.make_variable(right.tape_id_, right.taddr_);
}
else
{ // result = parameter + variable
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 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::AddpvOp);
// 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::add_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

View File

@@ -0,0 +1,128 @@
# ifndef CPPAD_CORE_ADD_EQ_HPP
# define CPPAD_CORE_ADD_EQ_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>& AD<Base>::operator += (const AD<Base> &right)
{
// compute the Base part
Base left;
left = value_;
value_ += right.value_;
// check if there is a recording in progress
local::ADTape<Base>* tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return *this;
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 = 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 & (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 & (ad_type_ != dynamic_enum);
bool var_right = match_right & (right.ad_type_ != dynamic_enum);
CPPAD_ASSERT_KNOWN(
tape_id_ == right.tape_id_ || ! match_left || ! match_right ,
"+= : AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // this = variable + variable
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddvvOp) == 2 );
// put operand addresses in tape
tape->Rec_.PutArg(taddr_, right.taddr_);
// put operator in the tape
taddr_ = tape->Rec_.PutOp(local::AddvvOp);
// check that this is a variable
CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id );
CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum);
}
else if( dyn_right | (! IdenticalZero(right.value_) ) )
{ // this = variable + parameter
// = parameter + variable
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 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(p, taddr_);
// put operator in the tape
taddr_ = tape->Rec_.PutOp(local::AddpvOp);
// check that this is a variable
CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id );
CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum);
}
}
else if( var_right )
{ if( (! dyn_left) & IdenticalZero(left) )
{ // this = 0 + right
make_variable(right.tape_id_, right.taddr_);
}
else
{ // this = parameter + variable
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 2 );
// put operand addresses in tape
addr_t p = taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left);
tape->Rec_.PutArg(p, right.taddr_);
// put operator in the tape
taddr_ = tape->Rec_.PutOp(local::AddpvOp);
// make this a variable
tape_id_ = tape_id;
ad_type_ = variable_enum;
}
}
else if( dyn_left | dyn_right )
{ addr_t arg0 = taddr_;
addr_t arg1 = right.taddr_;
if( ! dyn_left )
arg0 = tape->Rec_.put_con_par(left);
if( ! dyn_right )
arg1 = tape->Rec_.put_con_par(right.value_);
//
// parameters with a dynamic parameter results
taddr_ = tape->Rec_.put_dyn_par(
value_, local::add_dyn, arg0, arg1
);
tape_id_ = tape_id;
ad_type_ = dynamic_enum;
}
return *this;
}
CPPAD_FOLD_ASSIGNMENT_OPERATOR(+=)
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,42 @@
# ifndef CPPAD_CORE_ARITHMETIC_HPP
# define CPPAD_CORE_ARITHMETIC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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 Arithmetic$$
$spell
Op
const
$$
$section AD Arithmetic Operators and Compound Assignments$$
$childtable%
include/cppad/core/unary_plus.hpp%
include/cppad/core/unary_minus.hpp%
include/cppad/core/ad_binary.hpp%
include/cppad/core/compound_assign.hpp
%$$
$end
-------------------------------------------------------------------------------
*/
# include <cppad/core/unary_plus.hpp>
# include <cppad/core/unary_minus.hpp>
# include <cppad/core/ad_binary.hpp>
# include <cppad/core/compound_assign.hpp>
# endif

View File

@@ -0,0 +1,152 @@
# ifndef CPPAD_CORE_ATAN2_HPP
# define CPPAD_CORE_ATAN2_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 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 atan2$$
$spell
Vec
CppAD
namespace
std
atan
const
$$
$section AD Two Argument Inverse Tangent Function$$
$head Syntax$$
$icode%theta% = atan2(%y%, %x%)%$$
$head Purpose$$
Determines an angle $latex \theta \in [ - \pi , + \pi ]$$
such that
$latex \[
\begin{array}{rcl}
\sin ( \theta ) & = & y / \sqrt{ x^2 + y^2 } \\
\cos ( \theta ) & = & x / \sqrt{ x^2 + y^2 }
\end{array}
\] $$
$head y$$
The argument $icode y$$ has one of the following prototypes
$codei%
const AD<%Base%> &%y%
const VecAD<%Base%>::reference &%y%
%$$
$head x$$
The argument $icode x$$ has one of the following prototypes
$codei%
const AD<%Base%> &%x%
const VecAD<%Base%>::reference &%x%
%$$
$head theta$$
The result $icode theta$$ has prototype
$codei%
AD<%Base%> %theta%
%$$
$head Operation Sequence$$
The AD of $icode Base$$
operation sequence used to calculate $icode theta$$ is
$cref/independent/glossary/Operation/Independent/$$
of $icode x$$ and $icode y$$.
$head Example$$
$children%
example/general/atan2.cpp
%$$
The file
$cref atan2.cpp$$
contains an example and test of this function.
$end
-------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN CppAD namespace
inline float atan2(float x, float y)
{ return std::atan2(x, y); }
inline double atan2(double x, double y)
{ return std::atan2(x, y); }
// The code below is used as an example by the CondExp documentation.
// BEGIN CondExp
template <class Base>
AD<Base> atan2 (const AD<Base> &y, const AD<Base> &x)
{ //
// zero, pi2, pi
AD<Base> zero(0.);
AD<Base> pi2(2. * atan(1.));
AD<Base> pi(2. * pi2);
//
// abs_x, abs_y
// Not using fabs because its derivative is zero at zero
AD<Base> abs_x = CondExpGe(x, zero, x, -x);
AD<Base> abs_y = CondExpGe(y, zero, y, -y);
//
// first
// This is the result for first quadrant: x >= 0 , y >= 0
AD<Base> alpha = atan(abs_y / abs_x);
AD<Base> beta = pi2 - atan(abs_x / abs_y);
AD<Base> first = CondExpGt(abs_x, abs_y, alpha, beta);
//
// second
// This is the result for second quadrant: x <= 0 , y >= 0
AD<Base> second = pi - first;
//
// third
// This is the result for third quadrant: x <= 0 , y <= 0
AD<Base> third = - pi + first;
//
// fourth
// This is the result for fourth quadrant: x >= 0 , y <= 0
AD<Base> fourth = - first;
//
// alpha
// This is the result for x >= 0
alpha = CondExpGe(y, zero, first, fourth);
//
// beta
// This is the result for x <= 0
beta = CondExpGe(y, zero, second, third);
//
//
AD<Base> result = CondExpGe(x, zero, alpha, beta);
return result;
}
// END CondExp
template <class Base>
AD<Base> atan2 (const VecAD_reference<Base> &y, const AD<Base> &x)
{ return atan2( y.ADBase() , x ); }
template <class Base>
AD<Base> atan2 (const AD<Base> &y, const VecAD_reference<Base> &x)
{ return atan2( y , x.ADBase() ); }
template <class Base>
AD<Base> atan2
(const VecAD_reference<Base> &y, const VecAD_reference<Base> &x)
{ return atan2( y.ADBase() , x.ADBase() ); }
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,26 @@
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 atomic$$
$section Atomic AD Functions$$
$childtable%
include/cppad/core/atomic/atomic_three.hpp%
include/cppad/core/chkpoint_two/chkpoint_two.hpp
%$$
$head Deprecated Atomic Function$$
$cref atomic_one$$,
$cref atomic_two$$,
$cref chkpoint_one$$.
$end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,486 @@
# ifndef CPPAD_CORE_ATOMIC_ATOMIC_THREE_HPP
# define CPPAD_CORE_ATOMIC_ATOMIC_THREE_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 atomic_three$$
$spell
taylor
ctor
afun
arg
jac
hes
CppAD
enum
mul
hpp
const
$$
$section Defining Atomic Functions: Third Generation$$
$head Syntax$$
$subhead Define Class$$
$codei%class %atomic_user% : public CppAD::atomic_three<%Base%> {
%...%
};%$$
$subhead Construct Atomic Function$$
$icode%atomic_user% %afun%(%ctor_arg_list%)%$$
$subhead Use Atomic Function$$
$icode%afun%(%ax%, %ay%)%$$
$subhead Class Member Callbacks$$
$icode%ok% = %afun%.for_type(
%parameter_x%, %type_x%, %type_y%
)
%ok% = %afun%.forward(
%parameter_x%, %type_x%,
%need_y%, %order_low%, %order_up%, %taylor_x%, %taylor_y%
)
%ok% = %afun%.reverse(
%parameter_x%, %type_x%,
%order_up%, %taylor_x%, %taylor_y%, %partial_x%, %partial_y%
)
%ok% = %afun%.jac_sparsity(
%parameter_x%, %type_x%, %dependency%, %select_x% %select_y%, %pattern_out%
)
%ok% = %afun%.hes_sparsity(
%parameter_x%, %type_x%, %select_x% %select_y%, %pattern_out%
)
%ok% = %afun%.rev_depend(
%parameter_x%, %type_x%, %depend_x%, %depend_y%
)%$$
$head See Also$$
$cref chkpoint_two$$, $cref atomic_two$$
$head Purpose$$
$subhead Speed$$
In some cases, it is possible to compute derivatives of a function
$latex \[
y = g(x) \; {\rm where} \; g : \B{R}^n \rightarrow \B{R}^m
\] $$
more efficiently than by coding it using $codei%AD<%Base%>%$$
$cref/atomic/glossary/Operation/Atomic/$$ operations
and letting CppAD do the rest.
The class $codei%atomic_three%<%Base%>%$$ is used to
create a new atomic operation corresponding to a function $latex g(x)$$
where the user specifies how to compute the derivatives
and sparsity patterns for $latex g(x)$$.
$subhead Reduce Memory$$
If the function $latex g(x)$$ is many times during the recording
of an $cref ADFun$$ object,
using an atomic version of $latex g(x)$$ removed the need for repeated
copies of the corresponding $codei%AD<%Base%>%$$ operations and variables
in the recording.
$head ad_type$$
The type $code CppAD::ad_type_enum$$
is used to specify if an AD object is a
$cref/constant parameter/glossary/Parameter/Constant/$$
$cref/dynamic parameter/glossary/Parameter/Dynamic/$$
or $cref/variable/glossary/Variable/$$.
It has the following possible values:
$center
$table
$icode ad_type_enum$$ $pre $$ $cnext Meaning $rnext
$code constant_enum$$ $pre $$ $cnext constant parameter $rnext
$code dynamic_enum$$ $pre $$ $cnext dynamic parameter $rnext
$code variable_enum$$ $pre $$ $cnext variable
$tend
$$
In addition,
$code constant_enum < dynamic_enum < variable_enum$$.
$head Virtual Functions$$
The $cref/callback functions/atomic_three/Syntax/Class Member Callbacks/$$
are implemented by defining the virtual functions in the
$icode atomic_user$$ class.
These functions compute derivatives,
sparsity patterns, and dependency relations.
Each virtual function has a default implementation
that returns $icode%ok% == false%$$.
The $cref/for_type/atomic_three_for_type/$$
and $cref/forward/atomic_three_forward/$$ function
(for the case $icode%order_up% == 0%$$) must be implemented.
Otherwise, only those functions and orders
required by the your calculations need to be implemented.
For example,
$icode forward$$ for the case $icode%order_up% == 2%$$ can just return
$icode%ok% == false%$$ unless you require
forward mode calculation of second derivatives.
$head Base$$
This is the type of the elements of
$cref/ax/atomic_three_afun/ax/$$ and $cref/ay/atomic_three_afun/ay/$$
in the corresponding $icode%afun%(%ax%, %ay%)%$$ call.
$head parameter_x$$
All the virtual functions include this argument which has prototype
$codei%
const CppAD::vector<%Base%> %parameter_x%
%$$
Its size is equal to $icode%n% = %ax%.size()%$$
in corresponding $icode%afun%(%ax%, %ay%)%$$ call.
$subhead Constant$$
For $icode%j% =0,%...%,%n%-1%$$,
if $icode%ax%[%j%]%$$ is a $cref/constant/con_dyn_var/Constant/$$ parameter,
$codei%
%parameter_x%[%j%] == %ax%[%j%]
%$$
$subhead Dynamic$$
If $icode%ax%[%j%]%$$ is a $cref/dynamic/con_dyn_var/Dynamic/$$ parameter,
$icode%parameter_x%[%j%]%$$ value of $icode%ax%[%j%]%$$ corresponding to the
previous call to $cref new_dynamic$$ for the corresponding function object.
$subhead Variable$$
If $icode%ax%[%j%]%$$ is a variable,
the value of $icode%parameter_x%[%j%]%$$ is not specified.
See the
$cref/atomic_three_mat_mul.hpp/atomic_three_mat_mul.hpp/Purpose/parameter_x/$$
for an example using $icode parameter_x$$.
$head type_x$$
All the virtual functions include this argument.
Its size is equal to $icode%n% = %ax%.size()%$$
in corresponding $icode%afun%(%ax%, %ay%)%$$ call.
For $icode%j% =0,%...%,%n%-1%$$,
if $icode%ax%[%j%]%$$ is a constant parameter,
$codei%
%type_x%[%j%] == CppAD::constant_enum
%$$
if $icode%ax%[%j%]%$$ is a dynamic parameter,
$codei%
%type_x%[%j%] == CppAD::dynamic_enum
%$$
if $icode%ax%[%j%]%$$ is a variable,
$codei%
%type_x%[%j%] == CppAD::variable_enum
%$$
See the
$cref/atomic_three_mat_mul.hpp/atomic_three_mat_mul.hpp/Purpose/type_x/$$
for an example using $icode type_x$$.
$childtable%include/cppad/core/atomic/three_ctor.hpp
%include/cppad/core/atomic/three_afun.hpp
%include/cppad/core/atomic/three_for_type.hpp
%include/cppad/core/atomic/three_forward.hpp
%include/cppad/core/atomic/three_reverse.hpp
%include/cppad/core/atomic/three_jac_sparsity.hpp
%include/cppad/core/atomic/three_hes_sparsity.hpp
%include/cppad/core/atomic/three_rev_depend.hpp
%$$
$end
-------------------------------------------------------------------------------
$begin atomic_three_example$$
$section Example Defining Atomic Functions: Third Generation$$
$childtable%example/atomic_three/get_started.cpp
%example/atomic_three/norm_sq.cpp
%example/atomic_three/tangent.cpp
%example/atomic_three/base2ad.cpp
%example/atomic_three/reciprocal.cpp
%example/atomic_three/mat_mul.cpp
%$$
$end
-------------------------------------------------------------------------------
*/
# include <set>
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/atomic_index.hpp>
// needed before one can use in_parallel
# include <cppad/utility/thread_alloc.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic_three.hpp
Base class for atomic function operations.
*/
template <class Base>
class atomic_three {
// ===================================================================
private:
// ------------------------------------------------------
// constants
//
/// index of this object in lcal::atomic_index
/// (set by constructor and not changed; i.e., effectively const)
size_t index_;
//
// -----------------------------------------------------
//
/// temporary work space used by member functions, declared here to avoid
// memory allocation/deallocation for each usage
struct work_struct {
vector<ad_type_enum> type_x;
vector<ad_type_enum> type_y;
//
vector<Base> taylor_x;
vector<Base> taylor_y;
//
vector< AD<Base> > ataylor_x;
vector< AD<Base> > ataylor_y;
//
sparse_rc< vector<size_t> > pattern;
};
// Use pointers, to avoid false sharing between threads.
// Not using: vector<work_struct*> work_;
// so that deprecated atomic examples do not result in a memory leak.
work_struct* work_[CPPAD_MAX_NUM_THREADS];
// -----------------------------------------------------
public:
// =====================================================================
// In User API
// =====================================================================
//
// ---------------------------------------------------------------------
// ctor: doxygen in atomic/three_ctor.hpp
atomic_three(void);
atomic_three(const std::string& name);
// ------------------------------------------------------------------------
// operator(): see doxygen in atomic_three/afun.hpp
template <class ADVector>
void operator()(
const ADVector& ax ,
ADVector& ay
);
// ------------------------------------------------------------------------
// type: doxygen in atomic/three_for_type.hpp
virtual bool for_type(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y
);
// ------------------------------------------------------------------------
// type: doxygen in atomic/three_rev_depend.hpp
virtual bool rev_depend(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<bool>& depend_x ,
const vector<bool>& depend_y
);
// ------------------------------------------------------------------------
// forward: see docygen in atomic/three_forward.hpp
virtual bool forward(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector<Base>& taylor_x ,
vector<Base>& taylor_y
);
virtual bool forward(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
vector< AD<Base> >& ataylor_y
);
// ------------------------------------------------------------------------
// reverse: see docygen in atomic/three_reverse.hpp
virtual bool reverse(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector<Base>& taylor_x ,
const vector<Base>& taylor_y ,
vector<Base>& partial_x ,
const vector<Base>& partial_y
);
virtual bool reverse(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
const vector< AD<Base> >& ataylor_y ,
vector< AD<Base> >& apartial_x ,
const vector< AD<Base> >& apartial_y
);
// ------------------------------------------------------------
// jac_sparsity: see doxygen in atomic/three_jac_sparsity.hpp
virtual bool jac_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
bool dependency ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out
);
template <class InternalSparsity>
bool for_jac_sparsity(
bool dependency ,
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity
);
template <class InternalSparsity>
bool rev_jac_sparsity(
bool dependency ,
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity
);
// ------------------------------------------------------------
// hes_sparsity: see doxygen in atomic/three_jac_sparsity.hpp
virtual bool hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out
);
template <class InternalSparsity>
bool for_hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
size_t np1 ,
size_t numvar ,
const InternalSparsity& rev_jac_sparsity ,
InternalSparsity& for_sparsity
);
template <class InternalSparsity>
bool rev_hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
const InternalSparsity& for_jac_pattern ,
bool* rev_jac_flag ,
InternalSparsity& hes_sparsity
);
// =====================================================================
// Not in User API
// =====================================================================
/// Name corresponding to a atomic_three object
const std::string atomic_name(void) const
{ bool set_null = false;
size_t type = 0; // set to avoid warning
std::string name;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index_, type, &name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 3 );
return name;
}
/// destructor informs CppAD that this atomic function with this index
/// has dropped out of scope by setting its pointer to null
virtual ~atomic_three(void)
{ // change object pointer to null, but leave name for error reporting
bool set_null = true;
size_t type = 0; // set to avoid warning
std::string* name = nullptr;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index_, type, name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 3 );
//
// free temporary work memory
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
free_work(thread);
}
/// allocates work_ for a specified thread
void allocate_work(size_t thread)
{ if( work_[thread] == nullptr )
{ // allocate the raw memory
size_t min_bytes = sizeof(work_struct);
size_t num_bytes;
void* v_ptr = thread_alloc::get_memory(min_bytes, num_bytes);
// save in work_
work_[thread] = reinterpret_cast<work_struct*>( v_ptr );
// call constructor
new( work_[thread] ) work_struct;
}
return;
}
/// frees work_ for a specified thread
void free_work(size_t thread)
{ if( work_[thread] != nullptr )
{ // call destructor
work_[thread]->~work_struct();
// return memory to avialable pool for this thread
thread_alloc::return_memory(
reinterpret_cast<void*>(work_[thread])
);
// mark this thread as not allocated
work_[thread] = nullptr;
}
return;
}
/// atomic_three function object corresponding to a certain index
static atomic_three* class_object(size_t index)
{ bool set_null = false;
size_t type = 0; // set to avoid warning
std::string* name = nullptr;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index, type, name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 3 );
return reinterpret_cast<atomic_three*>( v_ptr );
}
/// atomic_three function name corresponding to a certain index
static const std::string class_name(size_t index)
{ bool set_null = false;
size_t type = 0; // set to avoid warning
std::string name;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index, type, &name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 3 );
return name;
}
/*!
Set value of id (used by deprecated atomic_one class)
This function is called just before calling any of the virtual function
and has the corresponding id of the corresponding virtual call.
*/
virtual void set_old(size_t id)
{ }
// ---------------------------------------------------------------------------
};
} // END_CPPAD_NAMESPACE
// member functions
# include <cppad/core/atomic/three_ctor.hpp>
# include <cppad/core/atomic/three_afun.hpp>
# include <cppad/core/atomic/three_for_type.hpp>
# include <cppad/core/atomic/three_rev_depend.hpp>
# include <cppad/core/atomic/three_forward.hpp>
# include <cppad/core/atomic/three_reverse.hpp>
# include <cppad/core/atomic/three_jac_sparsity.hpp>
# include <cppad/core/atomic/three_hes_sparsity.hpp>
# endif

View File

@@ -0,0 +1,613 @@
# ifndef CPPAD_CORE_ATOMIC_ATOMIC_TWO_HPP
# define CPPAD_CORE_ATOMIC_ATOMIC_TWO_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 atomic_two$$
$spell
ctor
afun
arg
vx
vy
tx
ty
px
py
jac
hes
CppAD
checkpointing
$$
$section Defining Atomic Functions: Second Generation$$
$head Deprecated 2019-01-01$$
Using the $code atomic_base$$ class has been deprecated.
Use $cref atomic_three$$ instead.
$head Syntax$$
$codei%
%atomic_user% %afun%(%ctor_arg_list%)
%afun%(%ax%, %ay%)
%ok% = %afun%.forward(%p%, %q%, %vx%, %vy%, %tx%, %ty%)
%ok% = %afun%.reverse(%q%, %tx%, %ty%, %px%, %py%)
%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%, %x%)
%ok% = %afun%.rev_sparse_jac(%q%, %r%, %s%, %x%)
%ok% = %afun%.for_sparse_hes(%vx%, %r%, %s%, %h%, %x%)
%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%, %x%)
atomic_base<%Base%>::clear()%$$
$head See Also$$
$cref/checkpoint/chkpoint_one/$$
$head Purpose$$
$subhead Speed$$
In some cases, the user knows how to compute derivatives of a function
$latex \[
y = f(x) \; {\rm where} \; f : \B{R}^n \rightarrow \B{R}^m
\] $$
more efficiently than by coding it using $codei%AD<%Base%>%$$
$cref/atomic_base/glossary/Operation/Atomic/$$ operations
and letting CppAD do the rest.
In this case $codei%atomic_base%<%Base%>%$$ can use
the user code for $latex f(x)$$, and its derivatives,
as $codei%AD<%Base%>%$$ atomic operations.
$subhead Reduce Memory$$
If the function $latex f(x)$$ is used often,
using an atomic version of $latex f(x)$$ remove the need for repeated
copies of the corresponding $codei%AD<%Base%>%$$ operations.
$head Virtual Functions$$
User defined derivatives are implemented by defining the
following virtual functions in the $icode atomic_base$$ class:
$cref/forward/atomic_two_forward/$$,
$cref/reverse/atomic_two_reverse/$$,
$cref/for_sparse_jac/atomic_two_for_sparse_jac/$$,
$cref/rev_sparse_jac/atomic_two_rev_sparse_jac/$$, and
$cref/rev_sparse_hes/atomic_two_rev_sparse_hes/$$.
These virtual functions have a default implementation
that returns $icode%ok% == false%$$.
The $code forward$$ function,
for the case $icode%q% == 0%$$, must be implemented.
Otherwise, only those functions
required by the your calculations need to be implemented.
For example,
$icode forward$$ for the case $icode%q% == 2%$$ can just return
$icode%ok% == false%$$ unless you require
forward mode calculation of second derivatives.
$head Examples$$
See $cref atomic_two_example$$.
$childtable%
include/cppad/core/atomic/two_ctor.hpp%
include/cppad/core/atomic/two_option.hpp%
include/cppad/core/atomic/two_afun.hpp%
include/cppad/core/atomic/two_forward.hpp%
include/cppad/core/atomic/two_reverse.hpp%
include/cppad/core/atomic/two_for_sparse_jac.hpp%
include/cppad/core/atomic/two_rev_sparse_jac.hpp%
include/cppad/core/atomic/two_for_sparse_hes.hpp%
include/cppad/core/atomic/two_rev_sparse_hes.hpp%
include/cppad/core/atomic/two_clear.hpp
%$$
$end
-------------------------------------------------------------------------------
$begin atomic_two_example$$
$section Example Defining Atomic Functions: Second Generation$$
$head Getting Started$$
that shows the minimal amount of information required to create
a user defined atomic operation.
$head Scalar Function$$
where the user provides the code for computing derivatives.
This example is simple because the domain and range are scalars.
$head Vector Range$$
where the user provides the code for computing derivatives.
This example is more complex because the range has two components.
$head Hessian Sparsity Patterns$$
where the user provides the code for computing Hessian sparsity patterns.
$childtable%
example/atomic_two/eigen_mat_mul.cpp%
example/atomic_two/eigen_mat_inv.cpp%
example/atomic_two/eigen_cholesky.cpp
%$$
$end
-------------------------------------------------------------------------------
*/
# include <set>
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/sparse/internal.hpp>
# include <cppad/local/atomic_index.hpp>
// needed before one can use in_parallel
# include <cppad/utility/thread_alloc.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic_two.hpp
Base class for atomic function operations.
*/
template <class Base>
class atomic_base {
// ===================================================================
public:
enum option_enum {
pack_sparsity_enum ,
bool_sparsity_enum ,
set_sparsity_enum
};
private:
// ------------------------------------------------------
// constants
//
/// index of this object in local::atomic_index
/// (set by constructor and not changed; i.e., effectively const)
size_t index_;
//
// -----------------------------------------------------
// variables
//
/// sparsity pattern this object is currently using
/// (set by constructor and option member functions)
option_enum sparsity_;
//
/// temporary work space used by member functions, declared here to avoid
// memory allocation/deallocation for each usage
struct work_struct {
vector<bool> vx;
vector<bool> vy;
//
vector<Base> tx;
vector<Base> ty;
//
vector< AD<Base> > atx;
vector< AD<Base> > aty;
//
vector<bool> bool_t;
//
vectorBool pack_h;
vectorBool pack_r;
vectorBool pack_s;
vectorBool pack_u;
//
vector<bool> bool_h;
vector<bool> bool_r;
vector<bool> bool_s;
vector<bool> bool_u;
//
vector< std::set<size_t> > set_h;
vector< std::set<size_t> > set_r;
vector< std::set<size_t> > set_s;
vector< std::set<size_t> > set_u;
};
// Use pointers, to avoid false sharing between threads.
// Not using: vector<work_struct*> work_;
// so that deprecated atomic examples do not result in a memory leak.
work_struct* work_[CPPAD_MAX_NUM_THREADS];
public:
// =====================================================================
// In User API
// =====================================================================
//
// ---------------------------------------------------------------------
// ctor: doxygen in atomic_base/ctor.hpp
atomic_base(void);
atomic_base(
const std::string& name,
option_enum sparsity = bool_sparsity_enum
);
// option: see doxygen in atomic_base/option.hpp
void option(enum option_enum option_value);
// operator(): see doxygen in atomic_base/afun.hpp
template <class ADVector>
void operator()(
const ADVector& ax ,
ADVector& ay ,
size_t id = 0
);
// ------------------------------------------------------------------------
// base_two version of forward
virtual bool forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector<Base>& tx ,
vector<Base>& ty
);
virtual bool forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector< AD<Base> >& atx ,
vector< AD<Base> >& aty
);
// base_three version of forward
bool forward(
size_t order_low ,
size_t order_up ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y ,
const vector<Base>& taylor_x ,
vector<Base>& taylor_y
);
bool forward(
size_t order_low ,
size_t order_up ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y ,
const vector< AD<Base> >& ataylor_x ,
vector< AD<Base> >& ataylor_y
);
// ------------------------------------------------------------------------
// reverse: see doxygen in atomic_base/reverse.hpp
virtual bool reverse(
size_t q ,
const vector<Base>& tx ,
const vector<Base>& ty ,
vector<Base>& px ,
const vector<Base>& py
);
virtual bool reverse(
size_t q ,
const vector< AD<Base> >& atx ,
const vector< AD<Base> >& aty ,
vector< AD<Base> >& apx ,
const vector< AD<Base> >& apy
);
// ------------------------------------------------------------
// for_sparse_jac: see doxygen in atomic_base/for_sparse_jac.hpp
virtual bool for_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& r ,
vector< std::set<size_t> >& s ,
const vector<Base>& x
);
virtual bool for_sparse_jac(
size_t q ,
const vector<bool>& r ,
vector<bool>& s ,
const vector<Base>& x
);
virtual bool for_sparse_jac(
size_t q ,
const vectorBool& r ,
vectorBool& s ,
const vector<Base>& x
);
template <class InternalSparsity>
bool for_sparse_jac(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity
);
// deprecated versions
virtual bool for_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& r ,
vector< std::set<size_t> >& s
);
virtual bool for_sparse_jac(
size_t q ,
const vector<bool>& r ,
vector<bool>& s
);
virtual bool for_sparse_jac(
size_t q ,
const vectorBool& r ,
vectorBool& s
);
// ------------------------------------------------------------
// rev_sparse_jac: see doxygen in atomic_base/rev_sparse_jac.hpp
virtual bool rev_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& rt ,
vector< std::set<size_t> >& st ,
const vector<Base>& x
);
virtual bool rev_sparse_jac(
size_t q ,
const vector<bool>& rt ,
vector<bool>& st ,
const vector<Base>& x
);
virtual bool rev_sparse_jac(
size_t q ,
const vectorBool& rt ,
vectorBool& st ,
const vector<Base>& x
);
template <class InternalSparsity>
bool rev_sparse_jac(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity
);
// deprecated versions
virtual bool rev_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& rt ,
vector< std::set<size_t> >& st
);
virtual bool rev_sparse_jac(
size_t q ,
const vector<bool>& rt ,
vector<bool>& st
);
virtual bool rev_sparse_jac(
size_t q ,
const vectorBool& rt ,
vectorBool& st
);
// ------------------------------------------------------------
// for_sparse_hes: see doxygen in atomic_base/for_sparse_hes.hpp
virtual bool for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector< std::set<size_t> >& h ,
const vector<Base>& x
);
virtual bool for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector<bool>& h ,
const vector<Base>& x
);
virtual bool for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vectorBool& h ,
const vector<Base>& x
);
template <class InternalSparsity>
bool for_sparse_hes(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
size_t np1 ,
size_t numvar ,
const InternalSparsity& rev_jac_sparsity ,
InternalSparsity& for_sparsity
);
// deprecated versions
virtual bool for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector< std::set<size_t> >& h
);
virtual bool for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector<bool>& h
);
virtual bool for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vectorBool& h
);
// ------------------------------------------------------------
// rev_sparse_hes: see doxygen in atomic_base/rev_sparse_hes.hpp
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector< std::set<size_t> >& r ,
const vector< std::set<size_t> >& u ,
vector< std::set<size_t> >& v ,
const vector<Base>& x
);
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector<bool>& r ,
const vector<bool>& u ,
vector<bool>& v ,
const vector<Base>& x
);
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vectorBool& r ,
const vectorBool& u ,
vectorBool& v ,
const vector<Base>& x
);
template <class InternalSparsity>
bool rev_sparse_hes(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
const InternalSparsity& for_jac_sparsity ,
bool* rev_jac_flag ,
InternalSparsity& rev_hes_sparsity
);
// deprecated
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector< std::set<size_t> >& r ,
const vector< std::set<size_t> >& u ,
vector< std::set<size_t> >& v
);
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector<bool>& r ,
const vector<bool>& u ,
vector<bool>& v
);
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vectorBool& r ,
const vectorBool& u ,
vectorBool& v
);
// ------------------------------------------------------------
// atomic_three like interface for reverse dependency analysis
bool rev_depend(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<bool>& depend_x ,
const vector<bool>& depend_y
);
// ------------------------------------------------------------
// clear: see doxygen in atomic_base/clear.hpp
static void clear(void);
// =====================================================================
// Not in User API
// =====================================================================
/// current sparsity setting
option_enum sparsity(void) const
{ return sparsity_; }
/// Name corresponding to a atomic_base object
const std::string atomic_name(void) const
{ bool set_null = false;
size_t type = 0; // set to avoid warning
std::string name;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index_, type, &name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 2 );
return name;
}
/// destructor informs CppAD that this atomic function with this index
/// has dropped out of scope by setting its pointer to null
virtual ~atomic_base(void)
{ // change object pointer to null, but leave name for error reporting
bool set_null = true;
size_t type = 0; // set to avoid warning
std::string* name = nullptr;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index_, type, name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 2 );
//
// free temporary work memory
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
free_work(thread);
}
/// allocates work_ for a specified thread
void allocate_work(size_t thread)
{ if( work_[thread] == nullptr )
{ // allocate the raw memory
size_t min_bytes = sizeof(work_struct);
size_t num_bytes;
void* v_ptr = thread_alloc::get_memory(min_bytes, num_bytes);
// save in work_
work_[thread] = reinterpret_cast<work_struct*>( v_ptr );
// call constructor
new( work_[thread] ) work_struct;
}
return;
}
/// frees work_ for a specified thread
void free_work(size_t thread)
{ if( work_[thread] != nullptr )
{ // call destructor
work_[thread]->~work_struct();
// return memory to avialable pool for this thread
thread_alloc::return_memory(
reinterpret_cast<void*>(work_[thread])
);
// mark this thread as not allocated
work_[thread] = nullptr;
}
return;
}
/// atomic_base function object corresponding to a certain index
static atomic_base* class_object(size_t index)
{ bool set_null = false;
size_t type = 0; // set to avoid warning
std::string* name = nullptr;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index, type, name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 2 );
return reinterpret_cast<atomic_base*>( v_ptr );
}
/// atomic_base function name corresponding to a certain index
static const std::string class_name(size_t index)
{ bool set_null = false;
size_t type = 0; // set to avoid warning
std::string name;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, index, type, &name, v_ptr);
CPPAD_ASSERT_UNKNOWN( type == 2 );
return name;
}
/*!
Set value of id (used by deprecated atomic_one class)
This function is called just before calling any of the virtual function
and has the corresponding id of the corresponding virtual call.
*/
virtual void set_old(size_t id)
{ }
// ---------------------------------------------------------------------------
};
} // END_CPPAD_NAMESPACE
// functitons implemented in cppad/core/atomic_base files
# include <cppad/core/atomic/two_ctor.hpp>
# include <cppad/core/atomic/two_option.hpp>
# include <cppad/core/atomic/two_afun.hpp>
# include <cppad/core/atomic/two_forward.hpp>
# include <cppad/core/atomic/two_reverse.hpp>
# include <cppad/core/atomic/two_for_sparse_jac.hpp>
# include <cppad/core/atomic/two_rev_sparse_jac.hpp>
# include <cppad/core/atomic/two_for_sparse_hes.hpp>
# include <cppad/core/atomic/two_rev_sparse_hes.hpp>
# include <cppad/core/atomic/two_rev_depend.hpp>
# include <cppad/core/atomic/two_clear.hpp>
# endif

View File

@@ -0,0 +1,248 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_AFUN_HPP
# define CPPAD_CORE_ATOMIC_THREE_AFUN_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 atomic_three_afun$$
$spell
sq
mul
afun
const
CppAD
mat_mul.cpp
$$
$section Using AD Version of an Atomic Function$$
$head Syntax$$
$icode%afun%(%ax%, %ay%)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Purpose$$
Given $icode ax$$, this call computes the corresponding value of $icode ay$$.
If $codei%AD<%Base%>%$$ operations are being recorded,
it enters the computation as an atomic operation in the recording;
see $cref/start recording/Independent/Start Recording/$$.
$head Base$$
This is the $icode Base$$ type of the elements of $icode ax$$ and $icode ay$$
in the call to the $icode afun$$ atomic operation.
To be specific, the elements of $icode ax$$ and $icode ay$$ have type
$codei%AD%<%Base%>%$$.
$head ADVector$$
The type $icode ADVector$$ must be a
$cref/simple vector class/SimpleVector/$$ with elements of type
$codei%AD<%Base%>%$$.
$head afun$$
is a $cref/atomic_user/atomic_three_ctor/atomic_user/$$ object
and this $icode afun$$ function call is implemented by the
$cref/atomic_three/atomic_three_ctor/atomic_three/$$ class.
$head ax$$
This argument has prototype
$codei%
const %ADVector%& %ax%
%$$
and size must be equal to $icode n$$.
It specifies vector $latex x \in \B{R}^n$$
at which an $codei%AD<%Base%>%$$ version of
$latex y = g(x)$$ is to be evaluated; see
$cref/Base/atomic_three_ctor/atomic_three/Base/$$.
$head ay$$
This argument has prototype
$codei%
%ADVector%& %ay%
%$$
and size must be equal to $icode m$$.
The input values of its elements
are not specified (must not matter).
Upon return, it is an $codei%AD<%Base%>%$$ version of
$latex y = g(x)$$.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_afun.hpp
Implement user call to an atomic_three function.
*/
/*!
Implement the user call to afun(ax, ay)
\tparam ADVector
A simple vector class with elements of type AD<Base>.
\param ax
is the argument vector for this call,
ax.size() determines the number of arguments.
\param ay
is the result vector for this call,
ay.size() determines the number of results.
*/
// BEGIN_PROTOTYPE
template <class Base>
template <class ADVector>
void atomic_three<Base>::operator()(
const ADVector& ax ,
ADVector& ay )
// END_PROTOTYPE
{
size_t n = ax.size();
size_t m = ay.size();
# ifndef NDEBUG
bool ok = true;
std::string msg = "atomic_three: " + atomic_name() + ".eval: ";
if( (n == 0) | (m == 0) )
{ msg += "ax.size() or ay.size() is zero";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
vector<Base>& taylor_x = work_[thread]->taylor_x;
vector<Base>& taylor_y = work_[thread]->taylor_y;
vector<ad_type_enum>& type_x = work_[thread]->type_x;
vector<ad_type_enum>& type_y = work_[thread]->type_y;
//
type_x.resize(n);
taylor_x.resize(n);
//
type_y.resize(m);
taylor_y.resize(m);
//
// Determine tape corresponding to variables in ax
tape_id_t tape_id = 0;
local::ADTape<Base>* tape = nullptr;
for(size_t j = 0; j < n; j++)
{ taylor_x[j] = ax[j].value_;
if( Constant( ax[j] ) )
type_x[j] = constant_enum;
else
{ type_x[j] = ax[j].ad_type_;
if( tape_id == 0 )
{ tape = ax[j].tape_this();
tape_id = ax[j].tape_id_;
CPPAD_ASSERT_UNKNOWN( tape != nullptr );
}
# ifndef NDEBUG
if( Dynamic( ax[j] ) )
{ CPPAD_ASSERT_UNKNOWN( type_x[j] == dynamic_enum );
}
else
{ CPPAD_ASSERT_UNKNOWN( Variable( ax[j] ) );
CPPAD_ASSERT_UNKNOWN( type_x[j] == variable_enum );
}
if( tape_id != ax[j].tape_id_ )
{ msg += atomic_name() +
": ax contains non-constant values from different threads.";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
# endif
}
}
// Use zero order forward mode to compute all the components of y
size_t need_y = size_t(variable_enum) + 1;
size_t order_low = 0;
size_t order_up = 0;
CPPAD_ASSERT_UNKNOWN( need_y > size_t(variable_enum) );
# ifdef NDEBUG
forward(taylor_x, type_x, need_y, order_low, order_up, taylor_x, taylor_y);
for(size_t j = 0; j < n; ++j)
if( type_x[j] == variable_enum )
taylor_x[j] = CppAD::numeric_limits<Base>::quiet_NaN();
for_type(taylor_x, type_x, type_y);
# else
ok &= forward(
taylor_x, type_x, need_y, order_low, order_up, taylor_x, taylor_y
);
for(size_t j = 0; j < n; ++j)
if( type_x[j] == variable_enum )
taylor_x[j] = CppAD::numeric_limits<Base>::quiet_NaN();
ok &= for_type(taylor_x, type_x, type_y);
if( ! ok )
{ msg += atomic_name() + ": ok is false for "
"type or zero order forward mode calculation.";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
# endif
bool record_dynamic = false;
bool record_variable = false;
//
// set ay to be vector of constant parameters with correct value
for(size_t i = 0; i < m; i++)
{ // pass back values
ay[i].value_ = taylor_y[i];
// initialize entire vector as constants
ay[i].tape_id_ = 0;
ay[i].taddr_ = 0;
// we need to record this operation if
// any of the elemnts of ay are dynamics or variables,
record_dynamic |= type_y[i] == dynamic_enum;
record_variable |= type_y[i] == variable_enum;
}
# ifndef NDEBUG
if( (record_dynamic || record_variable) && tape == nullptr )
{ msg +=
"all elements of x are constants but y contains a non-constant";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
if( record_dynamic)
{ tape->Rec_.put_dyn_atomic(tape_id, index_, type_x, type_y, ax, ay);
}
// case where result contains a variable
if( record_variable )
{ tape->Rec_.put_var_atomic(tape_id, index_, type_x, type_y, ax, ay);
}
# ifndef NDEBUG
for(size_t i = 0; i < m; ++i) switch( type_y[i] )
{ //
case constant_enum:
CPPAD_ASSERT_UNKNOWN( Constant( ay[i] ) );
break;
//
case dynamic_enum:
CPPAD_ASSERT_UNKNOWN( Dynamic( ay[i] ) );
break;
//
case variable_enum:
CPPAD_ASSERT_UNKNOWN( Variable( ay[i] ) );
break;
//
default:
CPPAD_ASSERT_KNOWN( false,
"atomic_three: for_type: type_y[i]: is not a valid type"
);
break;
}
# endif
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,165 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_CTOR_HPP
# define CPPAD_CORE_ATOMIC_THREE_CTOR_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 atomic_three_ctor$$
$spell
enum
sq
std
afun
arg
CppAD
bool
ctor
const
mat_mul_xam.cpp
hpp
$$
$section Atomic Function Constructor$$
$head Syntax$$
$codei%class %atomic_user% : public CppAD::atomic_three<%Base%> {
public:
%atomic_user%(%ctor_arg_list%) : CppAD::atomic_three<%Base%>(%name%)
%...%
};
%$$
$icode%atomic_user afun%(%ctor_arg_list%)
%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head atomic_user$$
$subhead ctor_arg_list$$
Is a list of arguments for the $icode atomic_user$$ constructor.
$subhead afun$$
The object $icode afun$$ must stay in scope for as long
as the corresponding atomic function is used.
This includes use by any $cref/ADFun<Base>/ADFun/$$ that
has this $icode atomic_user$$ operation in its
$cref/operation sequence/glossary/Operation/Sequence/$$.
$subhead Implementation$$
The user defined $icode atomic_user$$ class is a publicly derived class of
$codei%atomic_three<%Base%>%$$.
It should be declared as follows:
$codei%
class %atomic_user% : public CppAD::atomic_three<%Base%> {
public:
%atomic_user%(%ctor_arg_list%) : atomic_three<%Base%>(%name%)
%...%
};
%$$
where $icode ...$$
denotes the rest of the implementation of the derived class.
This includes completing the constructor and
all the virtual functions that have their
$code atomic_three$$ implementations replaced by
$icode atomic_user$$ implementations.
$head atomic_three$$
$subhead Restrictions$$
The $code atomic_three$$ constructor and destructor cannot be called in
$cref/parallel/ta_in_parallel/$$ mode.
$subhead Base$$
The template parameter determines the
$cref/Base/atomic_three_afun/Base/$$
type for this $codei%AD<%Base%>%$$ atomic operation.
$subhead name$$
This $code atomic_three$$ constructor argument has the following prototype
$codei%
const std::string& %name%
%$$
It is the name for this atomic function and is used for error reporting.
The suggested value for $icode name$$ is $icode afun$$ or $icode atomic_user$$,
i.e., the name of the corresponding atomic object or class.
$head Example$$
$subhead Define Constructor$$
The following is an example of a atomic function constructor definition:
$cref%get_started.cpp%atomic_three_get_started.cpp%Constructor%$$.
$subhead Use Constructor$$
The following is an example using a atomic function constructor:
$cref%get_started.cpp
%atomic_three_get_started.cpp
%Use Atomic Function%Constructor
%$$.
$end
-------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_ctor.hpp
Constructors for atomic_three class.
*/
/*!
Base class for atomic_atomic functions.
\tparam Base
This class is used for defining an AD<Base> atomic operation y = g(x).
\par
make sure user does not invoke the default constructor
*/
template <class Base>
atomic_three<Base>::atomic_three(void)
{ CPPAD_ASSERT_KNOWN(false,
"Attempt to use the atomic_three default constructor"
);
}
/*!
Constructor
\param name
name used for error reporting
*/
// BEGIN_PROTOTYPE
template <class Base>
atomic_three<Base>::atomic_three(const std::string& name )
// END_PROTOTYPE
{ CPPAD_ASSERT_KNOWN(
! thread_alloc::in_parallel() ,
"atomic_three: constructor cannot be called in parallel mode."
);
//
// atomic_index
bool set_null = false;
size_t index = 0;
size_t type = 3;
std::string copy_name = name;
void* copy_this = reinterpret_cast<void*>( this );
index_ = local::atomic_index<Base>(
set_null, index, type, &copy_name, copy_this
);
// initialize work pointers as null;
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
work_[thread] = nullptr;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,117 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_FOR_TYPE_HPP
# define CPPAD_CORE_ATOMIC_THREE_FOR_TYPE_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 atomic_three_for_type$$
$spell
afun
enum
cpp
$$
$section Atomic Function Forward Type Calculation$$
$head Syntax$$
$icode%ok% = %afun%.for_type(%parameter_x%, %type_x%, %type_y%)%$$
$subhead Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Dependency Analysis$$
This calculation is sometimes referred to as a forward dependency analysis.
$head Usage$$
This syntax and prototype are used by
$codei%
%afun%(%ax%, %ay%)
%$$
where $cref/afun/atomic_three_ctor/atomic_user/afun/$$
is a user defined atomic function.
$head Implementation$$
This virtual function must be defined by the
$cref/atomic_user/atomic_three_ctor/atomic_user/$$ class.
$head Base$$
See $cref/Base/atomic_three/Base/$$.
$head parameter_x$$
See $cref/parameter_x/atomic_three/parameter_x/$$.
$head type_x$$
See $cref/type_x/atomic_three/type_x/$$.
$head type_y$$
This vector has size equal to the number of results for this atomic function;
i.e. $icode%m%=%ay%.size()%$$.
The input values of the elements of $icode type_y$$
are not specified (must not matter).
Upon return, for $latex i = 0 , \ldots , m-1$$,
$icode%type_y%[%i%]%$$ is set to one of the following values:
$list number$$
It is $code constant_enum$$ if $icode%ay%[%i%]%$$ only depends on
the arguments that are constants.
$lnext
It is $code dynamic_enum$$ if $icode%ay%[%i%]%$$ depends on
a dynamic parameter and does not depend on any variables.
$lnext
It is $code variable_enum$$ if $icode%ay%[%i%]%$$ depends on
a variable.
$lend
$head ok$$
If this calculation succeeded, $icode ok$$ is true.
Otherwise, it is false.
$head Example$$
The following is an example of a atomic function $code for_type$$ definition:
$cref%get_started.cpp%atomic_three_get_started.cpp%for_type%$$.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_for_type.hpp
Third generation atomic type computation.
*/
/*!
Link from atomic_three to type calculation
\param parameter_x [in]
is the value of the parameters in the corresponding function call
afun(ax, ay).
\param type_x [in]
specifies which components of x are
constants, dynamics, and variables
\param type_y [out]
specifies which components of y are
constants, dynamics, and variables
*/
// BEGIN_PROTOTYPE
template <class Base>
bool atomic_three<Base>::for_type(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y )
// END_PROTOTYPE
{ return false; }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,346 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_FORWARD_HPP
# define CPPAD_CORE_ATOMIC_THREE_FORWARD_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 atomic_three_forward$$
$spell
taylor
ataylor
af
afun
enum
CppAD
aparameter
$$
$section Atomic Function Forward Mode$$
$head Base$$
This syntax and prototype are used by
$cref/afun(ax, ay)/atomic_three_afun/$$; see
$cref/Base/atomic_three_afun/Base/$$.
They are also used by
$icode%f%.Forward%$$ and $icode%f%.new_dynamic%$$
where $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
and $icode afun$$ is used during the recording of $icode f$$.
$subhead Syntax$$
$icode%ok% = %afun%.forward(
%parameter_x%, %type_x%,
%need_y%, %order_low%, %order_up%, %type_x%, %taylor_x%, %taylor_y%
)%$$
$subhead Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE_BASE%// END_PROTOTYPE_BASE%1
%$$
$head AD<Base>$$
This syntax and prototype are used by
$icode%af%.Forward%$$ and $icode%af%.new_dynamic%$$
where $icode af$$ has prototype
$codei%
ADFun< AD<%Base%> , %Base% > %af%
%$$
and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$).
$subhead Syntax$$
$icode%ok% = %afun%.forward(
%parameter_x%, %type_x%,
%need_y%, %order_low%, %order_up%, %type_x%, %ataylor_x%, %ataylor_y%
)%$$
$subhead Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE_AD_BASE%// END_PROTOTYPE_AD_BASE%1
%$$
$head Implementation$$
The $icode taylor_x$$, $icode taylor_y$$ version of this function
must be defined by the
$cref/atomic_user/atomic_three_ctor/atomic_user/$$ class.
It can just return $icode%ok% == false%$$
(and not compute anything) for values
of $icode%order_up%$$ that are greater than those used by your
$cref/forward/Forward/$$ mode calculations
(order zero must be implemented).
$head parameter_x$$
See $cref/parameter_x/atomic_three/parameter_x/$$.
$head aparameter_x$$
The specifications for $icode aparameter_x$$
is the same as for $cref/parameter_x/atomic_three/parameter_x/$$
(only the type of $icode ataylor_x$$ is different).
$head type_x$$
See $cref/type_x/atomic_three/type_x/$$.
$head need_y$$
One can ignore this argument and compute all the $icode taylor_y$$
Taylor coefficient.
Often, this is not necessary and $icode need_y$$ is used to specify this.
The value $cref/type_y/atomic_three_for_type/type_y/$$ is used
to determine which coefficients are necessary as follows:
$subhead Constant Parameters$$
If $icode%need_y% == size_t(constant_enum)%$$,
then only the taylor coefficients
for $latex Y_i (t)$$ where $icode%type_y%[%i%] == constant_enum%$$
are necessary.
This is the case during a $cref from_json$$ operation.
$subhead Dynamic Parameters$$
If $icode%need_y% == size_t(dynamic_enum)%$$,
then only the taylor coefficients
for $latex Y_i (t)$$ where $icode%type_y%[%i%] == dynamic_enum%$$
are necessary.
This is the case during an $cref new_dynamic$$ operation.
$subhead Variables$$
If $icode%need_y% == size_t(variable_enum)%$$,
If $codei%ad_type_enum(%need_y%)% == variable_enum%$$,
then only the taylor coefficients
for $latex Y_i (t)$$ where $icode%type_y%[%i%] == variable_enum%$$
are necessary.
This is the case during a $cref/f.Forward/Forward/$$ operation.
T
$subhead All$$
If $icode%need_y > size_t(variable_enum)%$$,
then the taylor coefficients for all $latex Y_i (t)$$ are necessary.
This is the case during an $icode%afun%(%ax%, %ay%)%$$ operation.
$head order_low$$
This argument
specifies the lowest order Taylor coefficient that we are computing.
$subhead p$$
We sometimes use the notation $icode%p% = %order_low%$$ below.
$head order_up$$
This argument
specifies the highest order Taylor coefficient that we are computing
($icode%order_low% <= %order_up%$$).
$subhead q$$
We sometimes use the notation $icode%q% = %order_up%$$ below.
$head taylor_x$$
The size of $icode taylor_x$$ is $codei%(%q%+1)*%n%$$.
For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$,
we use the Taylor coefficient notation
$latex \[
\begin{array}{rcl}
x_j^k & = & \R{taylor\_x} [ j * ( q + 1 ) + k ]
\\
X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q
\end{array}
\] $$
Note that superscripts represent an index for $latex x_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex X(t)$$ correspond
to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way:
$latex \[
x_j^k = \frac{1}{ k ! } X_j^{(k)} (0)
\] $$
$subhead parameters$$
If the $th j$$ component of $icode x$$ corresponds to a parameter,
$codei%
%type_x%[%j%] < CppAD::variable_enum
%$$
In this case,
the $th j$$ component of $icode parameter_x$$ is equal to $latex x_j^0$$;
i.e.,
$codei%
%parameter_x%[%j%] == %taylor_x%[ %j% * ( %q% + 1 ) + 0 ]
%$$
Furthermore, for $icode%k% > 0%$$,
$codei%
%taylor_x%[ %j% * ( %q% + 1 ) + %k% ] == 0
%$$
$head ataylor_x$$
The specifications for $icode ataylor_x$$ is the same as for $icode taylor_x$$
(only the type of $icode ataylor_x$$ is different).
$head taylor_y$$
The size of $icode taylor_y$$ is $codei%(%q%+1)*%m%$$.
Upon return,
For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$,
$latex \[
\begin{array}{rcl}
Y_i (t) & = & g_i [ X(t) ]
\\
Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q )
\\
\R{taylor\_y} [ i * ( q + 1 ) + k ] & = & y_i^k
\end{array}
\] $$
where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$.
Note that superscripts represent an index for $latex y_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex Y(t)$$ correspond
to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way:
$latex \[
y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0)
\] $$
If $latex p > 0$$,
for $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , p-1$$,
the input of $icode taylor_y$$ satisfies
$latex \[
\R{taylor\_y} [ i * ( q + 1 ) + k ] = y_i^k
\]$$
These values do not need to be recalculated
and can be used during the computation of the higher order coefficients.
$head ataylor_y$$
The specifications for $icode ataylor_y$$ is the same as for $icode taylor_y$$
(only the type of $icode ataylor_y$$ is different).
$head ok$$
If this calculation succeeded, $icode ok$$ is true.
Otherwise, it is false.
$head Discussion$$
For example, suppose that $icode%order_up% == 2%$$,
and you know how to compute the function $latex g(x)$$,
its first derivative $latex f^{(1)} (x)$$,
and it component wise Hessian $latex g_i^{(2)} (x)$$.
Then you can compute $icode taylor_x$$ using the following formulas:
$latex \[
\begin{array}{rcl}
y_i^0 & = & Y(0)
= g_i ( x^0 )
\\
y_i^1 & = & Y^{(1)} ( 0 )
= g_i^{(1)} ( x^0 ) X^{(1)} ( 0 )
= g_i^{(1)} ( x^0 ) x^1
\\
y_i^2
& = & \frac{1}{2 !} Y^{(2)} (0)
\\
& = & \frac{1}{2} X^{(1)} (0)^\R{T} g_i^{(2)} ( x^0 ) X^{(1)} ( 0 )
+ \frac{1}{2} g_i^{(1)} ( x^0 ) X^{(2)} ( 0 )
\\
& = & \frac{1}{2} (x^1)^\R{T} g_i^{(2)} ( x^0 ) x^1
+ g_i^{(1)} ( x^0 ) x^2
\end{array}
\] $$
For $latex i = 0 , \ldots , m-1$$, and $latex k = 0 , 1 , 2$$,
$latex \[
\R{taylor\_y} [ i * (q + 1) + k ] = y_i^k
\] $$
$children%
example/atomic_three/forward.cpp%
example/atomic_three/dynamic.cpp
%$$
$head Examples$$
The files
$cref atomic_three_forward.cpp$$ and $cref atomic_three_dynamic.cpp$$
contain examples and tests that uses this routine.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_forward.hpp
Third generation atomic forward mode.
*/
/*!
Link from atomic_three to forward mode
\param parameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param need_y [in]
specifies which components of taylor_y are needed,
\param order_low [in]
lowerest order for this forward mode calculation.
\param order_up [in]
highest order for this forward mode calculation.
\param taylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param taylor_y [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_three
*/
// BEGIN_PROTOTYPE_BASE
template <class Base>
bool atomic_three<Base>::forward(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector<Base>& taylor_x ,
vector<Base>& taylor_y )
// END_PROTOTYPE_BASE
{ return false; }
/*!
Link from atomic_three to forward mode
\param aparameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param need_y [in]
specifies which components of taylor_y are needed,
\param order_low [in]
lowerest order for this forward mode calculation.
\param order_up [in]
highest order for this forward mode calculation.
\param ataylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param ataylor_y [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for base_three
*/
// BEGIN_PROTOTYPE_AD_BASE
template <class Base>
bool atomic_three<Base>::forward(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
vector< AD<Base> >& ataylor_y )
// END_PROTOTYPE_AD_BASE
{ return false; }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,412 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_HES_SPARSITY_HPP
# define CPPAD_CORE_ATOMIC_THREE_HES_SPARSITY_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 atomic_three_hes_sparsity$$
$spell
Hessian
afun
hes
$$
$section Atomic Function Hessian Sparsity Patterns$$
$head Syntax$$
$icode%ok% = %afun%.hes_sparsity(
%parameter_x%, %type_x%, %select_x%, %select_y%, %pattern_out%
)%$$
$head Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Implementation$$
This function must be defined if
$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is
used to define an $cref ADFun$$ object $icode f$$,
and Hessian sparsity patterns are computed for $icode f$$.
$head Base$$
See $cref/Base/atomic_three_afun/Base/$$.
$head parameter_x$$
See $cref/parameter_x/atomic_three/parameter_x/$$.
$head type_x$$
See $cref/type_x/atomic_three/type_x/$$.
$head select_x$$
This argument has size equal to the number of arguments to this
atomic function; i.e. the size of $icode ax$$.
It specifies which domain components are included in
the calculation of $icode pattern_out$$.
If $icode%select_x%[%j%]%$$ is false, then there will be no indices
$icode k$$ such that either of the following hold:
$codei%
%pattern_out%.row()[%k%] == %j%
%pattern_out%.col()[%k%] == %j%
%$$.
$head select_y$$
This argument has size equal to the number of results to this
atomic function; i.e. the size of $icode ay$$.
It specifies which range component functions $latex g_i (x)$$ are included in
of $icode pattern_out$$.
$head pattern_out$$
This input value of $icode pattern_out$$ does not matter.
Upon return it is the union,
with respect to $icode i$$ such that $icode%select_y%[%i%]%$$ is true,
of the sparsity pattern for Hessian of $latex g_i (x)$$.
To be specific, there are non-negative indices
$icode i$$, $icode r$$, $icode c$$, and $icode k$$ such that
$codei%
%pattern_out%.row()[%k%] == %r%
%pattern_out%.col()[%k%] == %c%
%$$
if and only if
$icode%select_y%[%i%]%$$ is true,
$icode%select_x%[%r%]%$$ is true,
$icode%select_x%[%c%]%$$ is true,
and
$latex \[
\partial_{x(r)} \partial_{x(c)} g_i(x)
\] $$
is possibly non-zero.
Note that the sparsity pattern should be symmetric.
$head ok$$
If this calculation succeeded, $icode ok$$ is true.
Otherwise it is false.
$children%
example/atomic_three/hes_sparsity.cpp
%$$
$head Examples$$
The file $cref atomic_three_hes_sparsity.cpp$$ contains an example and test
that uses this routine.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_hes_sparsity.hpp
Third generation atomic Hessian dependency and sparsity patterns.
*/
/*!
atomic_three to Hessian dependency and sparsity calculations.
\param parameter_x [in]
contains the values for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param select_x [in]
which domain components to include in the dependency or sparsity pattern.
\param select_y [in]
which range components to include in the dependency or sparsity pattern.
\param pattern_out [out]
is the sparsity pattern for Hessian.
*/
// BEGIN_PROTOTYPE
template <class Base>
bool atomic_three<Base>::hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out )
// END_PROTOTYPE
{ return false; }
/*!
Link from forward Hessian sweep to atomic_three.
2DO: move this functiton outside this file so can change
developer documentation to omhelp formating.
\tparam InternalSparsity
Is the used internaly for sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param parameter_x
is parameter arguments to the function, other components are nan.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param x_index
is the variable index, on the tape, for the arguments to this function.
This size of x_index is n, the number of arguments to this function.
The index zero is used for parameters.
\param y_index
is the variable index, on the tape, for the results for this function.
This size of y_index is m, the number of results for this function.
The index zero is used for parameters.
\param for_jac_sparsity
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the forward Jacobian sparsity for the j-th argument to this atomic function.
\param rev_jac_pattern
On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
is the reverse Jacobian sparsity for the i-th result to this atomic function.
This shows which components of the result affect the function we are
computing the Hessian of.
\param hes_sparsity_for
This is the sparsity pattern for the Hessian. On input, the non-linear
terms in the atomic fuction have not been included. Upon return, they
have been included.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_three<Base>::for_hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
size_t np1 ,
size_t numvar ,
const InternalSparsity& rev_jac_pattern ,
InternalSparsity& for_sparsity )
{ typedef typename InternalSparsity::const_iterator const_iterator;
//
CPPAD_ASSERT_UNKNOWN( rev_jac_pattern.end() == 1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar );
size_t n = x_index.size();
size_t m = y_index.size();
//
// select_x
vector<bool> select_x(n);
for(size_t j = 0; j < n; j++)
{ // check if should compute pattern w.r.t x[j]
select_x[j] = for_sparsity.number_elements(np1 + x_index[j]) > 0;
}
//
// bool select_y
vector<bool> select_y(m);
for(size_t i = 0; i < m; i++)
{ // check if we should include y[i]
select_y[i] = rev_jac_pattern.number_elements(y_index[i]) > 0;
}
// ------------------------------------------------------------------------
// call user's version of atomic function for Jacobian
sparse_rc< vector<size_t> > pattern_out;
bool dependency = false;
bool ok = jac_sparsity(
parameter_x, type_x, dependency, select_x, select_y, pattern_out
);
if( ! ok )
return false;
//
// transfer sparsity patterns from pattern_out to var_sparsity
size_t nnz = pattern_out.nnz();
const vector<size_t>& row( pattern_out.row() );
const vector<size_t>& col( pattern_out.col() );
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
CPPAD_ASSERT_KNOWN(
select_y[i] & select_x[j],
"atomic: jac_sparsity: pattern_out not in "
"select_x or select_y range"
);
const_iterator itr(for_sparsity, np1 + x_index[j]);
size_t ell = *itr;
while( ell < np1 )
{ for_sparsity.post_element(np1 + y_index[i], ell );
ell = *(++itr);
}
}
for(size_t i = 0; i < m; ++i)
for_sparsity.process_post( np1 + y_index[i] );
// ------------------------------------------------------------------------
// call user's version of atomic function for Hessian
ok = hes_sparsity(
parameter_x, type_x, select_x, select_y, pattern_out
);
if( ! ok )
return ok;
//
// add new elements to Hessian sparisty in calling routine
nnz = pattern_out.nnz();
for(size_t k = 0; k < nnz; ++k)
{ size_t r = row[k];
size_t c = col[k];
CPPAD_ASSERT_KNOWN(
select_x[r] & select_x[c],
"atomic: hes_sparsity: pattern_out not in select_x range"
);
const_iterator itr_1(for_sparsity, np1 + x_index[r]);
size_t v1 = *itr_1;
while( v1 < np1 )
{ for_sparsity.binary_union(
v1, v1, np1 + x_index[c], for_sparsity
);
v1 = *(++itr_1);
}
// no need to add same elements twice
if( c != r )
{ const_iterator itr_2(for_sparsity, np1 + x_index[c]);
size_t v2 = *itr_2;
while( v2 < np1 )
{ for_sparsity.binary_union(
v2, v2, np1 + x_index[r], for_sparsity
);
v2 = *(++itr_2);
}
}
}
return ok;
}
/*!
Link from for_reverse Hessian sweep to atomic_three.
\tparam InternalSparsity
Is the used internaly for sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param parameter_x
is parameter arguments to the function, other components are nan.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param x_index
is the variable index, on the tape, for the arguments to this function.
This size of x_index is n, the number of arguments to this function.
The index zero is used for parameters.
\param y_index
is the variable index, on the tape, for the results for this function.
This size of y_index is m, the number of results for this function.
The index zero is used for parameters.
\param for_jac_pattern
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the forward Jacobian pattern for the j-th argument to this atomic function.
\param rev_jac_flag
On input, for i = 0, ... , m-1, rev_jac_flag[ y_index[i] ] is true
if the function we are computing the Hessian of has possibly non-zero Jacobian
w.r.t varialbe y_index[i].
On output, for j = 0, ... , n, rev_jac_flag[ x_index[j] ] is set to true
if the varialbe with index x_index[j] has possible non-zero Jacobian
with repect to one of the true y_index[i] cases.
Otherwise, rev_jac_flag [ x_inde[j] ] is not changed.
\param hes_sparsity_rev
Is the reverse mode sparsity pattern for the Hessian. On input, the non-linear
terms in the atomic fuction have not been included. Upon return, they
have been included.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_three<Base>::rev_hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
const InternalSparsity& for_jac_pattern ,
bool* rev_jac_flag ,
InternalSparsity& hes_sparsity_rev )
{ typedef typename InternalSparsity::const_iterator const_iterator;
size_t n = x_index.size();
size_t m = y_index.size();
//
// select_x
vector<bool> select_x(n);
for(size_t j = 0; j < n; j++)
{ // check if should compute pattern w.r.t x[j]
const_iterator itr(for_jac_pattern, x_index[j]);
size_t i = *itr;
select_x[j] = i < for_jac_pattern.end();
CPPAD_ASSERT_UNKNOWN( x_index[j] > 0 || ! select_x[j] );
}
//
// bool select_y
vector<bool> select_y(m);
for(size_t i = 0; i < m; i++)
{ // check if we should include y[i]
select_y[i] = rev_jac_flag[ y_index[i] ];
CPPAD_ASSERT_UNKNOWN( y_index[i] > 0 || ! select_y[i] );
}
//
// call atomic function for Jacobain sparsity
bool dependency = false;
sparse_rc< vector<size_t> > pattern_jac;
bool ok = jac_sparsity(
parameter_x, type_x, dependency, select_x, select_y, pattern_jac
);
const vector<size_t>& row_jac( pattern_jac.row() );
const vector<size_t>& col_jac( pattern_jac.col() );
size_t nnz_jac = pattern_jac.nnz();
if( ! ok )
return ok;
//
// call atomic function for Hessian sparsity
sparse_rc< vector<size_t> > pattern_hes;
ok = hes_sparsity(parameter_x, type_x, select_x, select_y, pattern_hes);
const vector<size_t>& row_hes( pattern_hes.row() );
const vector<size_t>& col_hes( pattern_hes.col() );
size_t nnz_hes = pattern_hes.nnz();
if( ! ok )
return ok;
//
// propagate Hessian sparsity through the Jacobian
for(size_t k = 0; k < nnz_jac; ++k)
{ size_t i = row_jac[k];
size_t j = col_jac[k];
CPPAD_ASSERT_KNOWN(
select_y[i] & select_x[j] ,
"atomic: jac_sparsity: pattern_out not in "
"select_x or select_y range"
);
// from y_index[i] to x_index[j]
hes_sparsity_rev.binary_union(
x_index[j], x_index[j], y_index[i], hes_sparsity_rev
);
}
//
// propagate rev_jac_flag through the Jacobian
// (seems OK to exclude variables with zero forward jacobian)
for(size_t k = 0; k < nnz_jac; ++k)
{ size_t j = col_jac[k];
rev_jac_flag[ x_index[j] ] = true;
}
//
// new hessian sparsity terms between y and x
for(size_t k = 0; k < nnz_hes; ++k)
{ size_t r = row_hes[k];
size_t c = col_hes[k];
CPPAD_ASSERT_KNOWN(
select_x[r] & select_x[c] ,
"atomic: hes_sparsity: pattern_out not in select_x range"
);
hes_sparsity_rev.binary_union(
x_index[r], x_index[r], x_index[c], for_jac_pattern
);
hes_sparsity_rev.binary_union(
x_index[c], x_index[c], x_index[r], for_jac_pattern
);
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,355 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_JAC_SPARSITY_HPP
# define CPPAD_CORE_ATOMIC_THREE_JAC_SPARSITY_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 atomic_three_jac_sparsity$$
$spell
Jacobian
afun
jac
$$
$section Atomic Function Jacobian Sparsity Patterns$$
$head Syntax$$
$icode%ok% = %afun%.jac_sparsity(
%parameter_x%, %type_x%, %dependency%, %select_x%, %select_y%, %pattern_out%
)%$$
$head Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Implementation$$
This function must be defined if
$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is
used to define an $cref ADFun$$ object $icode f$$,
and Jacobian sparsity patterns are computed for $icode f$$.
(Computing Hessian sparsity patterns and optimizing
requires Jacobian sparsity patterns.)
$head Base$$
See $cref/Base/atomic_three_afun/Base/$$.
$head parameter_x$$
See $cref/parameter_x/atomic_three/parameter_x/$$.
$head type_x$$
See $cref/type_x/atomic_three/type_x/$$.
$head dependency$$
If $icode dependency$$ is true,
then $icode pattern_out$$ is a
$cref/dependency pattern/dependency.cpp/Dependency Pattern/$$
for this atomic function.
Otherwise it is a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$ for the
derivative of the atomic function.
$head select_x$$
This argument has size equal to the number of arguments to this
atomic function; i.e. the size of $icode ax$$.
It specifies which domain components are included in
the calculation of $icode pattern_out$$.
If $icode%select_x%[%j%]%$$ is false, then there will be no indices
$icode k$$ such that
$codei%
%pattern_out%.col()[%k%] == %j%
%$$.
$head select_y$$
This argument has size equal to the number of results to this
atomic function; i.e. the size of $icode ay$$.
It specifies which range components are included in
the calculation of $icode pattern_out$$.
If $icode%select_y%[%i%]%$$ is false, then there will be no indices
$icode k$$ such that
$codei%
%pattern_out%.row()[%k%] == %i%
%$$.
$head pattern_out$$
This input value of $icode pattern_out$$ does not matter.
Upon return it is a
dependency or sparsity pattern for the Jacobian of $latex g(x)$$,
the function corresponding to
$cref/afun/atomic_three_ctor/atomic_user/afun/$$;
$icode dependency$$ above.
To be specific, there are non-negative indices
$icode i$$, $icode j$$, $icode k$$ such that
$codei%
%pattern_out%.row()[%k%] == %i%
%pattern_out%.col()[%k%] == %j%
%$$
if and only if
$icode%select_x%[%j%]%$$ is true,
$icode%select_y%[%j%]%$$ is true,
and $latex g_i(x)$$ depends on the value of $latex x_j$$
(and the partial of $latex g_i(x)$$ with respect to
$latex x_j$$ is possibly non-zero).
$head ok$$
If this calculation succeeded, $icode ok$$ is true.
Otherwise it is false.
$children%
example/atomic_three/jac_sparsity.cpp
%$$
$head Examples$$
The file $cref atomic_three_jac_sparsity.cpp$$ contains an example and test
that uses this routine.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_jac_sparsity.hpp
Third generation atomic Jacobian dependency and sparsity patterns.
*/
/*!
atomic_three to Jacobian dependency and sparsity calculations.
\param parameter_x [in]
contains the values for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param dependency [in]
if true, calculate dependency pattern,
otherwise calcuate sparsity pattern.
\param select_x [in]
which domain components to include in the dependency or sparsity pattern.
The index zero is used for parameters.
\param select_y [in]
which range components to include in the dependency or sparsity pattern.
The index zero is used for parameters.
\param pattern_out [out]
is the dependency or sparsity pattern.
*/
// BEGIN_PROTOTYPE
template <class Base>
bool atomic_three<Base>::jac_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
bool dependency ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out )
// END_PROTOTYPE
{ return false; }
/*!
Link from forward Jacobian sparsity calcuations to atomic_three
\tparam InternalSparsity
Is the type used for internal sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param dependency
if true, calcuate dependency pattern,
otherwise calcuate sparsity pattern.
\param parameter_x
is parameter arguments to the function, other components are nan.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param x_index
is the variable index, on the tape, for the arguments to this atomic function.
This size of x_index is n, the number of arguments to this atomic function.
The index zero is used for parameters.
\param y_index
is the variable index, on the tape, for the results for this atomic function.
This size of y_index is m, the number of results for this atomic function.
The index zero is used for parameters.
\param var_sparsity
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the sparsity for the j-th argument to this atomic function.
On output, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
is the sparsity for the i-th result for this atomic function.
\return
is true if the computation succeeds.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_three<Base>::for_jac_sparsity(
bool dependency ,
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity )
{ typedef typename InternalSparsity::const_iterator iterator;
// number of arguments and resutls for this atomic function
size_t n = x_index.size();
size_t m = y_index.size();
// select_y
vector<bool> select_y(m);
for(size_t i = 0; i < m; ++i)
select_y[i] = y_index[i] != 0;
// determine select_x
vector<bool> select_x(n);
for(size_t j = 0; j < n; ++j)
{ // check if x_j depends on any previous variable
iterator itr(var_sparsity, x_index[j]);
size_t ell = *itr;
select_x[j] = ell < var_sparsity.end();
CPPAD_ASSERT_UNKNOWN( x_index[j] > 0 || ! select_x[j] );
}
sparse_rc< vector<size_t> > pattern_out;
bool ok = jac_sparsity(
parameter_x, type_x, dependency, select_x, select_y, pattern_out
);
if( ! ok )
return false;
//
// transfer sparsity patterns from pattern_out to var_sparsity
size_t nnz = pattern_out.nnz();
const vector<size_t>& row( pattern_out.row() );
const vector<size_t>& col( pattern_out.col() );
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
CPPAD_ASSERT_KNOWN(
select_y[i] & select_x[j],
"atomic: jac_sparsity: pattern_out not in "
"select_x or select_y range"
);
iterator itr(var_sparsity, x_index[j]);
size_t ell = *itr;
while( ell < var_sparsity.end() )
{ var_sparsity.post_element( y_index[i], ell );
ell = *(++itr);
}
}
for(size_t i = 0; i < m; ++i)
var_sparsity.process_post( y_index[i] );
//
return true;
}
/*!
Link from reverse Jacobian sparsity calcuations to atomic_three
\tparam InternalSparsity
Is the type used for internal sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param dependency
if true, calcuate dependency pattern,
otherwise calcuate sparsity pattern.
\param parameter_x
is parameter arguments to the function, other components are nan.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param x_index
is the variable index, on the tape, for the arguments to this atomic function.
This size of x_index is n, the number of arguments to this atomic function.
\param y_index
is the variable index, on the tape, for the results for this atomic function.
This size of y_index is m, the number of results for this atomic function.
\param var_sparsity
On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
is the sparsity of the outter function with respect to the i-th
result for this atomic function.
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the sparsity for the outter function with repsect to the j-th
argument to this atomic function.
On output, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the sparsity for the outter function with repsect to the j-th
argument to this atomic function with the atomic function results
removed as arguments to the outter function.
\return
is true if the computation succeeds.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_three<Base>::rev_jac_sparsity(
bool dependency ,
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity )
{ typedef typename InternalSparsity::const_iterator iterator;
// number of arguments and resutls for this atomic function
size_t n = x_index.size();
size_t m = y_index.size();
// selection vectors
vector<bool> select_x(n), select_y(m);
// 2DO: perhaps we could use for_type(type_x, type_y)
// to reduce the true components in select_x
for(size_t j = 0; j < n; ++j)
select_x[j] = true;
// determine select_y
for(size_t i = 0; i < m; ++i)
{ // check if y_i has sparsity is non-empty
iterator itr(var_sparsity, y_index[i]);
size_t ell = *itr;
select_y[i] = ell < var_sparsity.end();
}
sparse_rc< vector<size_t> > pattern_out;
bool ok = jac_sparsity(
parameter_x, type_x, dependency, select_x, select_y, pattern_out
);
if( ! ok )
return false;
//
// transfer sparsity patterns from pattern_out to var_sparsity
size_t nnz = pattern_out.nnz();
const vector<size_t>& row( pattern_out.row() );
const vector<size_t>& col( pattern_out.col() );
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
CPPAD_ASSERT_KNOWN(
select_y[i] & select_x[j],
"atomic: jac_sparsity: pattern_out not in "
"select_x or select_y range"
);
iterator itr(var_sparsity, y_index[i]);
size_t ell = *itr;
while( ell < var_sparsity.end() )
{ var_sparsity.post_element( x_index[j], ell );
ell = *(++itr);
}
}
for(size_t j = 0; j < n; ++j)
var_sparsity.process_post( x_index[j] );
//
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,125 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_REV_DEPEND_HPP
# define CPPAD_CORE_ATOMIC_THREE_REV_DEPEND_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 atomic_three_rev_depend$$
$spell
afun
enum
cpp
taylor.hpp
$$
$section Atomic Function Reverse Dependency Calculation$$
$head Syntax$$
$icode%ok% = %afun%.rev_depend(
%parameter_x%, %type_x%, %depend_x%, %depend_y%
)%$$
$subhead Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Dependency Analysis$$
This calculation is sometimes referred to as a reverse dependency analysis.
$head Implementation$$
This function must be defined if
$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is
used to define an $cref ADFun$$ object $icode f$$,
and $cref/f.optimize()/optimize/$$ is used.
$head Base$$
See $cref/Base/atomic_three_afun/Base/$$.
$head parameter_x$$
See $cref/parameter_x/atomic_three/parameter_x/$$.
$head type_x$$
See $cref/type_x/atomic_three/type_x/$$.
$head depend_x$$
This vector has size equal to the number of arguments for this atomic function;
i.e. $icode%n%=%ax%.size()%$$.
The input values of the elements of $icode depend_x$$
are not specified (must not matter).
Upon return, for $latex j = 0 , \ldots , n-1$$,
$icode%depend_x%[%j%]%$$ is true if the values of interest depend
on the value of $cref/ax[j]/atomic_three_afun/ax/$$ in the corresponding
$icode%afun%(%ax%, %ay%)%$$ call.
Note that parameters and variables,
that the values of interest do not depend on,
may get removed by $cref/optimization/optimize/$$.
The corresponding values in $cref/parameter_x/atomic_three/parameter_x/$$,
and $cref/taylor_x/atomic_three_forward/taylor_x/$$
(after optimization has removed them) are not specified.
$head depend_y$$
This vector has size equal to the number of results for this atomic function;
i.e. $icode%m%=%ay%.size()%$$.
For $latex i = 0 , \ldots , m-1$$,
$icode%depend_y%[%i%]%$$ is true if the values of interest depend
on the value of $cref/ay[i]/atomic_three_afun/ay/$$ in the corresponding
$icode%afun%(%ax%, %ay%)%$$ call.
$head ok$$
If this calculation succeeded, $icode ok$$ is true.
Otherwise, it is false.
$childtable%
example/atomic_three/rev_depend.cpp
%$$
$head Example$$
The following is an example of a atomic function $code rev_depend$$ definition:
$cref atomic_three_rev_depend.cpp$$.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_rev_depend.hpp
Third generation atomic type computation.
*/
/*!
Link from atomic_three to reverse dependency calculation
\param parameter_x [in]
is the value of the parameters in the corresponding function call
afun(ax, ay).
\param type_x [in]
is the value for each of the components of x.
\param depend_x [out]
specifies which components of x affect values of interest.
\param depend_y [in]
specifies which components of y affect values of interest.
*/
// BEGIN_PROTOTYPE
template <class Base>
bool atomic_three<Base>::rev_depend(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<bool>& depend_x ,
const vector<bool>& depend_y )
// END_PROTOTYPE
{ return false; }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,354 @@
# ifndef CPPAD_CORE_ATOMIC_THREE_REVERSE_HPP
# define CPPAD_CORE_ATOMIC_THREE_REVERSE_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 atomic_three_reverse$$
$spell
sq
mul.hpp
afun
ty
px
py
Taylor
const
CppAD
atx
aty
apx
apy
af
aparameter
enum
$$
$section Atomic Function Reverse Mode$$
$spell
ataylor
apartial
$$
$head Base$$
This syntax is used by $icode%f%.Reverse%$$ where $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
and $icode afun$$ is used in $icode f$$;
see $cref/Base/atomic_three_afun/Base/$$.
$subhead Syntax$$
$icode%ok% = %afun%.reverse(
%parameter_x%, %type_x%,
%order_up%, %taylor_x%, %taylor_y%, %partial_x%, %partial_y%
)
%$$
$subhead Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE_BASE%// END_PROTOTYPE_BASE%1
%$$
$head AD<Base>$$
This syntax is used by $icode%af%.Reverse%$$ where $icode af$$ has prototype
$codei%
ADFun< AD<%Base%> , %Base% > %af%
%$$
and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$).
$subhead Syntax$$
$icode%ok% = %afun%.reverse(
%aparameter_x%, %type_x%,
%order_up%, %ataylor_x%, %ataylor_y%, %apartial_x%, %apartial_y%
)
%$$
$subhead Prototype$$
$srcthisfile%0%// BEGIN_PROTOTYPE_AD_BASE%// END_PROTOTYPE_AD_BASE%1
%$$
$head Implementation$$
This function must be defined if
$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is
used to define an $cref ADFun$$ object $icode f$$,
and reverse mode derivatives are computed for $icode f$$.
It can return $icode%ok% == false%$$
(and not compute anything) for values
of $icode order_up$$ that are greater than those used by your
$cref/reverse/Reverse/$$ mode calculations.
$head parameter_x$$
See $cref/parameter_x/atomic_three/parameter_x/$$.
$head aparameter_x$$
The specifications for $icode aparameter_x$$
is the same as for $cref/parameter_x/atomic_three/parameter_x/$$
(only the type of $icode ataylor_x$$ is different).
$head type_x$$
See $cref/type_x/atomic_three/type_x/$$.
$head order_up$$
This argument specifies the highest order Taylor coefficient that
computing the derivative of.
$head taylor_x$$
The size of $icode taylor_x$$ is $codei%(%q%+1)*%n%$$.
For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$,
we use the Taylor coefficient notation
$latex \[
\begin{array}{rcl}
x_j^k & = & \R{taylor\_x} [ j * ( q + 1 ) + k ]
\\
X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q
\end{array}
\] $$
Note that superscripts represent an index for $latex x_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex X(t)$$ correspond
to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way:
$latex \[
x_j^k = \frac{1}{ k ! } X_j^{(k)} (0)
\] $$
$subhead parameters$$
If the $th j$$ component of $icode x$$ corresponds to a parameter,
$codei%
%type_x%[%j%] < CppAD::variable_enum
%$$
In this case,
the $th j$$ component of $icode parameter_x$$ is equal to $latex x_j^0$$;
i.e.,
$codei%
%parameter_x%[%j%] == %taylor_x%[ %j% * ( %q% + 1 ) + 0 ]
%$$
Furthermore, for $icode%k% > 0%$$,
$codei%
%taylor_x%[ %j% * ( %q% + 1 ) + %k% ] == 0
%$$
$head ataylor_x$$
The specifications for $icode ataylor_x$$ is the same as for $icode taylor_x$$
(only the type of $icode ataylor_x$$ is different).
$head taylor_y$$
The size of $icode taylor_y$$ is $codei%(%q%+1)*%m%$$.
Upon return,
For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$,
we use the Taylor coefficient notation
$latex \[
\begin{array}{rcl}
Y_i (t) & = & g_i [ X(t) ]
\\
Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q )
\\
y_i^k & = & \R{taylor\_y} [ i * ( q + 1 ) + k ]
\end{array}
\] $$
where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$.
Note that superscripts represent an index for $latex y_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex Y(t)$$ correspond
to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way:
$latex \[
y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0)
\] $$
$head ataylor_y$$
The specifications for $icode ataylor_y$$ is the same as for $icode taylor_y$$
(only the type of $icode ataylor_y$$ is different).
$head F$$
We use the notation $latex \{ x_j^k \} \in \B{R}^{n \times (q+1)}$$ for
$latex \[
\{ x_j^k \W{:} j = 0 , \ldots , n-1, k = 0 , \ldots , q \}
\]$$
We use the notation $latex \{ y_i^k \} \in \B{R}^{m \times (q+1)}$$ for
$latex \[
\{ y_i^k \W{:} i = 0 , \ldots , m-1, k = 0 , \ldots , q \}
\]$$
We define the function
$latex F : \B{R}^{n \times (q+1)} \rightarrow \B{R}^{m \times (q+1)}$$ by
$latex \[
y_i^k = F_i^k [ \{ x_j^k \} ]
\] $$
Note that
$latex \[
F_i^0 ( \{ x_j^k \} ) = g_i ( X(0) ) = g_i ( x^0 )
\] $$
We also note that
$latex F_i^\ell ( \{ x_j^k \} )$$ is a function of
$latex x^0 , \ldots , x^\ell$$
and is determined by the derivatives of $latex g_i (x)$$
up to order $latex \ell$$.
$head G, H$$
We use $latex G : \B{R}^{m \times (q+1)} \rightarrow \B{R}$$
to denote an arbitrary scalar valued function of $latex \{ y_i^k \}$$.
We use $latex H : \B{R}^{n \times (q+1)} \rightarrow \B{R}$$
defined by
$latex \[
H ( \{ x_j^k \} ) = G[ F( \{ x_j^k \} ) ]
\] $$
$head partial_y$$
The size of $icode partial_y$$ is $codei%(%q%+1)*%m%%$$.
For $latex i = 0 , \ldots , m-1$$, $latex k = 0 , \ldots , q$$,
$latex \[
\R{partial\_y} [ i * (q + 1 ) + k ] = \partial G / \partial y_i^k
\] $$
$head apartial_y$$
The specifications for $icode apartial_y$$ is the same as for
$icode partial_y$$ (only the type of $icode apartial_y$$ is different).
$head partial_x$$
The size of $icode partial_x$$ is $codei%(%q%+1)*%n%%$$.
The input values of the elements of $icode partial_x$$
are not specified (must not matter).
Upon return,
for $latex j = 0 , \ldots , n-1$$ and $latex \ell = 0 , \ldots , q$$,
$latex \[
\begin{array}{rcl}
\R{partial\_x} [ j * (q + 1) + \ell ] & = & \partial H / \partial x_j^\ell
\\
& = &
( \partial G / \partial \{ y_i^k \} ) \cdot
( \partial \{ y_i^k \} / \partial x_j^\ell )
\\
& = &
\sum_{k=0}^q
\sum_{i=0}^{m-1}
( \partial G / \partial y_i^k ) ( \partial y_i^k / \partial x_j^\ell )
\\
& = &
\sum_{k=\ell}^q
\sum_{i=0}^{m-1}
\R{partial\_y}[ i * (q + 1 ) + k ] ( \partial F_i^k / \partial x_j^\ell )
\end{array}
\] $$
Note that we have used the fact that for $latex k < \ell$$,
$latex \partial F_i^k / \partial x_j^\ell = 0$$.
$subhead Short Circuit Operations$$
Note that if
$codei%IdenticalZero(%partial_y%[%i%*(%q%+1)+%k%])%$$ is true,
one does not need to compute $latex ( \partial F_i^k / \partial x_j^\ell )$$;
see $cref base_identical$$.
This can be used,
in a similar way to $cref/need_y/atomic_three_forward/need_y/$$,
to avoid unnecessary operations.
$head apartial_x$$
The specifications for $icode apartial_x$$ is the same as for
$icode partial_x$$ (only the type of $icode apartial_x$$ is different).
$head ok$$
If this calculation succeeded, $icode ok$$ is true.
Otherwise it is false.
$children%
example/atomic_three/reverse.cpp
%$$
$head Examples$$
The file $cref atomic_three_reverse.cpp$$ contains an example and test
that uses this routine.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/three_reverse.hpp
Third Generation Atomic reverse mode.
*/
/*!
Link from reverse mode sweep to users routine.
\param parameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param order_up [in]
highest order for this reverse mode calculation.
\param taylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param taylor_y [in]
Taylor coefficient corresponding to y for this calculation
\param partial_x [out]
Partials w.r.t. the x Taylor coefficients.
\param partial_y [in]
Partials w.r.t. the y Taylor coefficients.
See atomic_three_reverse mode use documentation
*/
// BEGIN_PROTOTYPE_BASE
template <class Base>
bool atomic_three<Base>::reverse(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector<Base>& taylor_x ,
const vector<Base>& taylor_y ,
vector<Base>& partial_x ,
const vector<Base>& partial_y )
// END_PROTOTYPE_BASE
{ return false; }
/*!
Link from reverse mode sweep to users routine.
\param aparameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param order_up [in]
highest order for this reverse mode calculation.
\param ataylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param ataylor_y [in]
Taylor coefficient corresponding to y for this calculation
\param apartial_x [out]
Partials w.r.t. the x Taylor coefficients.
\param apartial_y [in]
Partials w.r.t. the y Taylor coefficients.
See atomic_three_reverse mode use documentation
*/
// BEGIN_PROTOTYPE_AD_BASE
template <class Base>
bool atomic_three<Base>::reverse(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
const vector< AD<Base> >& ataylor_y ,
vector< AD<Base> >& apartial_x ,
const vector< AD<Base> >& apartial_y )
// END_PROTOTYPE_AD_BASE
{ return false; }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,258 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_AFUN_HPP
# define CPPAD_CORE_ATOMIC_TWO_AFUN_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 atomic_two_afun$$
$spell
sq
mul
afun
const
CppAD
mat_mul.cpp
$$
$section Using AD Version of Atomic Function$$
$head Syntax$$
$icode%afun%(%ax%, %ay%)%$$
$head Purpose$$
Given $icode ax$$,
this call computes the corresponding value of $icode ay$$.
If $codei%AD<%Base%>%$$ operations are being recorded,
it enters the computation as an atomic operation in the recording;
see $cref/start recording/Independent/Start Recording/$$.
$head ADVector$$
The type $icode ADVector$$ must be a
$cref/simple vector class/SimpleVector/$$ with elements of type
$codei%AD<%Base%>%$$; see $cref/Base/atomic_two_ctor/atomic_base/Base/$$.
$head afun$$
is a $cref/atomic_user/atomic_two_ctor/atomic_user/$$ object
and this $icode afun$$ function call is implemented by the
$cref/atomic/atomic_two_ctor/atomic_base/$$ class.
$head ax$$
This argument has prototype
$codei%
const %ADVector%& %ax%
%$$
and size must be equal to $icode n$$.
It specifies vector $latex x \in \B{R}^n$$
at which an $codei%AD<%Base%>%$$ version of
$latex y = f(x)$$ is to be evaluated; see
$cref/Base/atomic_two_ctor/atomic_base/Base/$$.
$head ay$$
This argument has prototype
$codei%
%ADVector%& %ay%
%$$
and size must be equal to $icode m$$.
The input values of its elements
are not specified (must not matter).
Upon return, it is an $codei%AD<%Base%>%$$ version of
$latex y = f(x)$$.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_afun.hpp
Implement user call to an atomic_two function.
*/
/*!
Implement the user call to afun(ax, ay) and atomic_one call to
afun(ax, ay, id).
\tparam ADVector
A simple vector class with elements of type <code>AD<Base></code>.
\param id
optional extra information vector that is just passed through by CppAD,
and used by atomic_one derived class (not other derived classes).
This is an extra parameter to the virtual callbacks for atomic_one;
see the set_old member function.
\param ax
is the argument vector for this call,
<tt>ax.size()</tt> determines the number of arguments.
\param ay
is the result vector for this call,
<tt>ay.size()</tt> determines the number of results.
*/
template <class Base>
template <class ADVector>
void atomic_base<Base>::operator()(
const ADVector& ax ,
ADVector& ay ,
size_t id )
{ size_t i, j;
size_t n = ax.size();
size_t m = ay.size();
# ifndef NDEBUG
bool ok;
std::string msg = "atomic_base: " + atomic_name() + ".eval: ";
if( (n == 0) | (m == 0) )
{ msg += "ax.size() or ay.size() is zero";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
vector <Base>& tx = work_[thread]->tx;
vector <Base>& ty = work_[thread]->ty;
vector <bool>& vx = work_[thread]->vx;
vector <bool>& vy = work_[thread]->vy;
//
if( vx.size() != n )
{ vx.resize(n);
tx.resize(n);
}
if( vy.size() != m )
{ vy.resize(m);
ty.resize(m);
}
//
// Determine tape corresponding to variables in ax
tape_id_t tape_id = 0;
local::ADTape<Base>* tape = nullptr;
for(j = 0; j < n; j++)
{ tx[j] = ax[j].value_;
vx[j] = ! Constant( ax[j] );
if( vx[j] )
{
if( tape_id == 0 )
{ tape = ax[j].tape_this();
tape_id = ax[j].tape_id_;
CPPAD_ASSERT_UNKNOWN( tape != nullptr );
}
# ifndef NDEBUG
if( tape_id != ax[j].tape_id_ )
{ msg += atomic_name() +
": ax contains variables from different threads.";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
# endif
}
}
// Use zero order forward mode to compute values
size_t p = 0, q = 0;
set_old(id);
# ifdef NDEBUG
forward(p, q, vx, vy, tx, ty);
# else
ok = forward(p, q, vx, vy, tx, ty);
if( ! ok )
{ msg += atomic_name() + ": ok is false for "
"zero order forward mode calculation.";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
# endif
bool record_operation = false;
for(i = 0; i < m; i++)
{
// pass back values
ay[i].value_ = ty[i];
// initialize entire vector parameters (not in tape)
ay[i].tape_id_ = 0;
ay[i].taddr_ = 0;
// we need to record this operation if
// any of the elemnts of ay are variables,
record_operation |= vy[i];
}
# ifndef NDEBUG
if( record_operation & (tape == nullptr) )
{ msg +=
"all elements of vx are false but vy contains a true element";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
// if tape is not null, ay is on the tape
if( record_operation )
{
// Operator that marks beginning of this atomic operation
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AFunOp) == 0 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AFunOp) == 4 );
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >=
std::max( std::max( std::max(index_, id), n), m ),
"atomic_base: cppad_tape_addr_type maximum not large enough"
);
tape->Rec_.PutArg(addr_t(index_), addr_t(id), addr_t(n), addr_t(m));
tape->Rec_.PutOp(local::AFunOp);
// Now put n operators, one for each element of argument vector
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunavOp) == 0 );
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunapOp) == 0 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunavOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunapOp) == 1 );
for(j = 0; j < n; j++)
{ if( Variable(ax[j]) )
{ // information for an argument that is a variable
tape->Rec_.PutArg(ax[j].taddr_);
tape->Rec_.PutOp(local::FunavOp);
}
else
{ // information for an argument that is parameter
addr_t par = ax[j].taddr_;
if( ! Dynamic( ax[j] ) )
par = tape->Rec_.put_con_par(ax[j].value_);
tape->Rec_.PutArg(par);
tape->Rec_.PutOp(local::FunapOp);
}
}
// Now put m operators, one for each element of result vector
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunrpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunrpOp) == 0 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunrvOp) == 0 );
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunrvOp) == 1 );
for(i = 0; i < m; i++)
{ if( vy[i] )
{ ay[i].taddr_ = tape->Rec_.PutOp(local::FunrvOp);
ay[i].tape_id_ = tape_id;
ay[i].ad_type_ = variable_enum;
}
else
{ CPPAD_ASSERT_UNKNOWN( ! Dynamic( ay[i] ) );
addr_t par = tape->Rec_.put_con_par(ay[i].value_);
tape->Rec_.PutArg(par);
tape->Rec_.PutOp(local::FunrpOp);
}
}
// Put a duplicate AFunOp at end of AFunOp sequence
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >=
std::max( std::max( std::max(index_, id), n), m ),
"atomic_base: cppad_tape_addr_type maximum not large enough"
);
tape->Rec_.PutArg(addr_t(index_), addr_t(id), addr_t(n), addr_t(m));
tape->Rec_.PutOp(local::AFunOp);
}
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,91 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_CLEAR_HPP
# define CPPAD_CORE_ATOMIC_TWO_CLEAR_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 atomic_two_clear$$
$spell
sq
alloc
$$
$section Free Static Variables$$
$head Syntax$$
$codei%atomic_base<%Base%>::clear()%$$
$head Purpose$$
Each $code atomic_base$$ objects holds onto work space in order to
avoid repeated memory allocation calls and thereby increase speed
(until it is deleted).
If an the $code atomic_base$$ object is global or static because,
the it does not get deleted.
This is a problem when using
$code thread_alloc$$ $cref/free_all/ta_free_all/$$
to check that all allocated memory has been freed.
Calling this $code clear$$ function will free all the
memory currently being held onto by the
$codei%atomic_base<%Base%>%$$ class.
$head Future Use$$
If there is future use of an $code atomic_base$$ object,
after a call to $code clear$$,
the work space will be reallocated and held onto.
$head Restriction$$
This routine cannot be called
while in $cref/parallel/ta_in_parallel/$$ execution mode.
$end
------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_clear.hpp
Free static variables in atomic_base class.
*/
/*!
Free all thread_alloc static memory held by atomic_base (avoids reallocations).
(This does not include class_object() which is an std::vector.)
*/
template <class Base>
void atomic_base<Base>::clear(void)
{ CPPAD_ASSERT_KNOWN(
! thread_alloc::in_parallel() ,
"cannot use atomic_base clear during parallel execution"
);
bool set_null = true;
size_t index = 0;
size_t type = 0; // set to avoid warning
std::string* name = nullptr;
void* v_ptr = nullptr; // set to avoid warning
size_t n_atomic = local::atomic_index<Base>(
set_null, index, type, name, v_ptr
);
//
set_null = false;
for(index = 1; index <= n_atomic; ++index)
{ local::atomic_index<Base>(set_null, index, type, name, v_ptr);
if( type == 2 )
{ atomic_base* op = reinterpret_cast<atomic_base*>(v_ptr);
if( op != nullptr )
{ for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
op->free_work(thread);
}
}
}
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,173 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_CTOR_HPP
# define CPPAD_CORE_ATOMIC_TWO_CTOR_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 atomic_two_ctor$$
$spell
enum
sq
std
afun
arg
CppAD
bool
ctor
const
mat_mul_xam.cpp
hpp
$$
$section Atomic Function Constructor$$
$head Syntax$$
$icode%atomic_user afun%(%ctor_arg_list%)
%$$
$codei%atomic_base<%Base%>(%name%, %sparsity%)
%$$
$head atomic_user$$
$subhead ctor_arg_list$$
Is a list of arguments for the $icode atomic_user$$ constructor.
$subhead afun$$
The object $icode afun$$ must stay in scope for as long
as the corresponding atomic function is used.
This includes use by any $cref/ADFun<Base>/ADFun/$$ that
has this $icode atomic_user$$ operation in its
$cref/operation sequence/glossary/Operation/Sequence/$$.
$subhead Implementation$$
The user defined $icode atomic_user$$ class is a publicly derived class of
$codei%atomic_base<%Base%>%$$.
It should be declared as follows:
$codei%
class %atomic_user% : public CppAD::atomic_base<%Base%> {
public:
%atomic_user%(%ctor_arg_list%) : atomic_base<%Base%>(%name%, %sparsity%)
%...%
};
%$$
where $icode ...$$
denotes the rest of the implementation of the derived class.
This includes completing the constructor and
all the virtual functions that have their
$code atomic_base$$ implementations replaced by
$icode atomic_user$$ implementations.
$head atomic_base$$
$subhead Restrictions$$
The $code atomic_base$$ constructor and destructor cannot be called in
$cref/parallel/ta_in_parallel/$$ mode.
$subhead Base$$
The template parameter determines the
$icode Base$$ type for this $codei%AD<%Base%>%$$ atomic operation.
$subhead name$$
This $code atomic_base$$ constructor argument has the following prototype
$codei%
const std::string& %name%
%$$
It is the name for this atomic function and is used for error reporting.
The suggested value for $icode name$$ is $icode afun$$ or $icode atomic_user$$,
i.e., the name of the corresponding atomic object or class.
$subhead sparsity$$
This $code atomic_base$$ constructor argument has prototype
$codei%
atomic_base<%Base%>::option_enum %sparsity%
%$$
The current $icode sparsity$$ for an $code atomic_base$$ object
determines which type of sparsity patterns it uses
and its value is one of the following:
$table
$icode sparsity$$ $cnext sparsity patterns $rnext
$codei%atomic_base<%Base%>::pack_sparsity_enum%$$ $pre $$ $cnext
$cref/vectorBool/CppAD_vector/vectorBool/$$
$rnext
$codei%atomic_base<%Base%>::bool_sparsity_enum%$$ $pre $$ $cnext
$cref/vector/CppAD_vector/$$$code <bool>$$
$rnext
$codei%atomic_base<%Base%>::set_sparsity_enum%$$ $pre $$ $cnext
$cref/vector/CppAD_vector/$$$code <std::set<std::size_t> >$$
$tend
There is a default value for $icode sparsity$$ if it is not
included in the constructor (which may be either the bool or set option).
$end
-------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_ctor.hpp
Constructors for atomic_base class.
*/
/*!
Base class for atomic_atomic functions.
\tparam Base
This class is used for defining an AD<Base> atomic operation y = f(x).
\par
make sure user does not invoke the default constructor
*/
template <class Base>
atomic_base<Base>::atomic_base(void)
{ CPPAD_ASSERT_KNOWN(false,
"Attempt to use the atomic_base default constructor"
);
}
/*!
Constructor
\param name
name used for error reporting
\param sparsity [in]
what type of sparsity patterns are computed by this function,
bool_sparsity_enum or set_sparsity_enum. Default value is
bool sparsity patterns.
*/
template <class Base>
atomic_base<Base>::atomic_base(
const std::string& name,
option_enum sparsity
) :
sparsity_( sparsity )
{ CPPAD_ASSERT_KNOWN(
! thread_alloc::in_parallel() ,
"atomic_base: constructor cannot be called in parallel mode."
);
CPPAD_ASSERT_UNKNOWN( constant_enum < dynamic_enum );
CPPAD_ASSERT_UNKNOWN( dynamic_enum < variable_enum );
//
// atomic_index
bool set_null = false;
size_t index = 0;
size_t type = 2;
std::string copy_name = name;
void* copy_this = reinterpret_cast<void*>( this );
index_ = local::atomic_index<Base>(
set_null, index, type, &copy_name, copy_this
);
// initialize work pointers as null;
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
work_[thread] = nullptr;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,356 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_HES_HPP
# define CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_HES_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 atomic_two_for_sparse_hes$$
$spell
sq
mul.hpp
vx
afun
Jacobian
jac
CppAD
std
bool
hes
const
$$
$section Atomic Forward Hessian Sparsity Patterns$$
$head Syntax$$
$icode%ok% = %afun%.for_sparse_hes(%vx%, %r%, %s%, %h%, %x%)%$$
$head Deprecated 2016-06-27$$
$icode%ok% = %afun%.for_sparse_hes(%vx%, %r%, %s%, %h%)%$$
$head Purpose$$
This function is used by $cref ForSparseHes$$ to compute
Hessian sparsity patterns.
If you are using $cref ForSparseHes$$,
one of the versions of this
virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$pre
$$
Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for
a diagonal matrix $latex R \in \B{R}^{n \times n}$$, and
a row vector $latex S \in \B{R}^{1 \times m}$$,
this routine computes the sparsity pattern for
$latex \[
H(x) = R^\R{T} \cdot (S \cdot f)^{(2)}( x ) \cdot R
\] $$
$head Implementation$$
If you are using and $cref ForSparseHes$$,
this virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$subhead vx$$
The argument $icode vx$$ has prototype
$codei%
const CppAD:vector<bool>& %vx%
%$$
$icode%vx%.size() == %n%$$, and
for $latex j = 0 , \ldots , n-1$$,
$icode%vx%[%j%]%$$ is true if and only if
$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$
or $cref/dynamic parameter/glossary/Parameter/Dynamic/$$
in the corresponding call to
$codei%
%afun%(%ax%, %ay%)
%$$
$subhead r$$
This argument has prototype
$codei%
const CppAD:vector<bool>& %r%
%$$
and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
the diagonal of $latex R \in \B{R}^{n \times n}$$.
$subhead s$$
The argument $icode s$$ has prototype
$codei%
const CppAD:vector<bool>& %s%
%$$
and its size is $icode m$$.
It is a sparsity pattern for $latex S \in \B{R}^{1 \times m}$$.
$subhead h$$
This argument has prototype
$codei%
%atomic_sparsity%& %h%
%$$
The input value of its elements
are not specified (must not matter).
Upon return, $icode h$$ is a
$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex H(x) \in \B{R}^{n \times n}$$ which is defined above.
$subhead x$$
$index deprecated$$
The argument has prototype
$codei%
const CppAD::vector<%Base%>& %x%
%$$
and size is equal to the $icode n$$.
This is the $cref Value$$ value corresponding to the parameters in the
vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called).
To be specific, if
$codei%
if( Parameter(%ax%[%i%]) == true )
%x%[%i%] = Value( %ax%[%i%] );
else
%x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN();
%$$
The version of this function with out the $icode x$$ argument is deprecated;
i.e., you should include the argument even if you do not use it.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_for_sparse_hes.hpp
Atomic forward mode Hessian sparsity patterns.
*/
/*!
Link, after case split, from for_hes_sweep to atomic_base.
\param vx [in]
which componens of x are variables.
\param r [in]
is the forward Jacobian sparsity pattern w.r.t the argument vector x.
\param s [in]
is the reverse Jacobian sparsity pattern w.r.t the result vector y.
\param h [out]
is the Hessian sparsity pattern w.r.t the argument vector x.
\param x
is the integer value of the x arguments that are parameters.
*/
template <class Base>
bool atomic_base<Base>::for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector< std::set<size_t> >& h ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector<bool>& h ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vectorBool& h ,
const vector<Base>& x )
// deprecated versions
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector< std::set<size_t> >& h )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vector<bool>& h )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& r ,
const vector<bool>& s ,
vectorBool& h )
{ return false; }
/*!
Link, before case split, from for_hes_sweep to atomic_base.
2DO: move this functiton outside this file so can change
developer documentation to omhelp formating.
\tparam InternalSparsity
Is the used internaly for sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param x
is parameter arguments to the function, other components are nan.
\param x_index
is the variable index, on the tape, for the arguments to this function.
This size of x_index is n, the number of arguments to this function.
\param y_index
is the variable index, on the tape, for the results for this function.
This size of y_index is m, the number of results for this function.
\param for_jac_sparsity
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the forward Jacobian sparsity for the j-th argument to this atomic function.
\param rev_jac_sparsity
On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
is the reverse Jacobian sparsity for the i-th result to this atomic function.
This shows which components of the result affect the function we are
computing the Hessian of.
\param for_hes_sparsity
This is the sparsity pattern for the Hessian. On input, the non-linear
terms in the atomic fuction have not been included. Upon return, they
have been included.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_base<Base>::for_sparse_hes(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
size_t np1 ,
size_t numvar ,
const InternalSparsity& rev_jac_sparsity ,
InternalSparsity& for_sparsity )
{ typedef typename InternalSparsity::const_iterator const_iterator;
CPPAD_ASSERT_UNKNOWN( rev_jac_sparsity.end() == 1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar );
size_t n = x_index.size();
size_t m = y_index.size();
bool ok = false;
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
//
// vx
vector<bool> vx(n);
for(size_t j = 0; j < n; j++)
vx[j] = x_index[j] != 0;
//
// bool_r
vector<bool>& bool_r( work_[thread]->bool_r );
bool_r.resize(n);
for(size_t j = 0; j < n; j++)
{ // check if we must compute row and column j of h
const_iterator itr(for_sparsity, np1 + x_index[j]);
size_t i = *itr;
bool_r[j] = i < np1;
}
//
// bool s
vector<bool>& bool_s( work_[thread]->bool_s );
bool_s.resize(m);
for(size_t i = 0; i < m; i++)
{ // check if row i of result is included in h
bool_s[i] = rev_jac_sparsity.is_element(y_index[i], 0);
}
//
// h
vectorBool& pack_h( work_[thread]->pack_h );
vector<bool>& bool_h( work_[thread]->bool_h );
vector< std::set<size_t> >& set_h( work_[thread]->set_h );
//
// call user's version of atomic function
std::string msg = ": atomic_base.for_sparse_hes: returned false";
if( sparsity_ == pack_sparsity_enum )
{ pack_h.resize(n * n);
ok = for_sparse_hes(vx, bool_r, bool_s, pack_h, x);
if( ! ok )
ok = for_sparse_hes(vx, bool_r, bool_s, pack_h);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = pack_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
}
else if( sparsity_ == bool_sparsity_enum )
{ bool_h.resize(n * n);
ok = for_sparse_hes(vx, bool_r, bool_s, bool_h, x);
if( ! ok )
ok = for_sparse_hes(vx, bool_r, bool_s, bool_h);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = bool_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
}
else
{ CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum )
set_h.resize(n);
ok = for_sparse_hes(vx, bool_r, bool_s, set_h, x);
if( ! ok )
ok = for_sparse_hes(vx, bool_r, bool_s, set_h);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = set_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
}
CPPAD_ASSERT_UNKNOWN( ok );
//
// modify hessian in calling routine
for(size_t i = 0; i < n; i++)
{ for(size_t j = 0; j < n; j++)
{ if( (x_index[i] > 0) & (x_index[j] > 0) )
{ bool flag = false;
switch( sparsity_ )
{ case pack_sparsity_enum:
flag = pack_h[i * n + j];
break;
//
case bool_sparsity_enum:
flag = bool_h[i * n + j];
break;
//
case set_sparsity_enum:
flag = set_h[i].find(j) != set_h[i].end();
break;
}
if( flag )
{ const_iterator itr_i(for_sparsity, np1 + x_index[i]);
size_t i_x = *itr_i;
while( i_x < np1 )
{ for_sparsity.binary_union(
i_x, i_x, np1 + x_index[j], for_sparsity
);
i_x = *(++itr_i);
}
const_iterator itr_j(for_sparsity, np1 + x_index[j]);
size_t j_x = *itr_j;
while( j_x < np1 )
{ for_sparsity.binary_union(
j_x, j_x, np1 + x_index[i], for_sparsity
);
j_x = *(++itr_j);
}
}
}
}
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,283 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_JAC_HPP
# define CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_JAC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 atomic_two_for_sparse_jac$$
$spell
sq
mul.hpp
afun
Jacobian
jac
const
CppAD
std
bool
std
$$
$section Atomic Forward Jacobian Sparsity Patterns$$
$head Syntax$$
$icode%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%, %x%)
%$$
$head Deprecated 2016-06-27$$
$icode%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%)
%$$
$head Purpose$$
This function is used by $cref ForSparseJac$$ to compute
Jacobian sparsity patterns.
For a fixed matrix $latex R \in \B{R}^{n \times q}$$,
the Jacobian of $latex f( x + R * u)$$ with respect to $latex u \in \B{R}^q$$ is
$latex \[
S(x) = f^{(1)} (x) * R
\] $$
Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$,
$code for_sparse_jac$$ computes a sparsity pattern for $latex S(x)$$.
$head Implementation$$
If you are using
$cref ForSparseJac$$,
$cref ForSparseHes$$, or
$cref RevSparseHes$$,
one of the versions of this
virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$subhead 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 Jacobian
$latex S(x) \in \B{R}^{m \times q}$$.
$subhead r$$
This argument has prototype
$codei%
const %atomic_sparsity%& %r%
%$$
and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex R \in \B{R}^{n \times q}$$.
$subhead s$$
This argument has prototype
$codei%
%atomic_sparsity%& %s%
%$$
The input values of its elements
are not specified (must not matter).
Upon return, $icode s$$ is a
$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex S(x) \in \B{R}^{m \times q}$$.
$subhead x$$
$index deprecated$$
The argument has prototype
$codei%
const CppAD::vector<%Base%>& %x%
%$$
and size is equal to the $icode n$$.
This is the $cref Value$$ value corresponding to the parameters in the
vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called).
To be specific, if
$codei%
if( Parameter(%ax%[%i%]) == true )
%x%[%i%] = Value( %ax%[%i%] );
else
%x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN();
%$$
The version of this function with out the $icode x$$ argument is deprecated;
i.e., you should include the argument even if you do not use it.
$head ok$$
The return value $icode ok$$ has prototype
$codei%
bool %ok%
%$$
If it is $code true$$, the corresponding evaluation succeeded,
otherwise it failed.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_for_sparse_jac.hpp
Atomic forward Jacobian sparsity pattern.
*/
/*!
Link, after case split, from for_jac_sweep to atomic_base.
\param q
is the column dimension for the Jacobian sparsity partterns.
\param r
is the Jacobian sparsity pattern for the argument vector x
\param s
is the Jacobian sparsity pattern for the result vector y
\param x
is the integer value for x arguments that are parameters.
*/
template <class Base>
bool atomic_base<Base>::for_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& r ,
vector< std::set<size_t> >& s ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_jac(
size_t q ,
const vector<bool>& r ,
vector<bool>& s ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_jac(
size_t q ,
const vectorBool& r ,
vectorBool& s ,
const vector<Base>& x )
{ return false; }
// deprecated versions
template <class Base>
bool atomic_base<Base>::for_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& r ,
vector< std::set<size_t> >& s )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_jac(
size_t q ,
const vector<bool>& r ,
vector<bool>& s )
{ return false; }
template <class Base>
bool atomic_base<Base>::for_sparse_jac(
size_t q ,
const vectorBool& r ,
vectorBool& s )
{ return false; }
/*!
Link, before case split, from for_jac_sweep to atomic_base.
\tparam InternalSparsity
Is the type used for internal sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param x
is parameter arguments to the function, other components are nan.
\param x_index
is the variable index, on the tape, for the arguments to this function.
This size of x_index is n, the number of arguments to this function.
\param y_index
is the variable index, on the tape, for the results for this function.
This size of y_index is m, the number of results for this function.
\param var_sparsity
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the sparsity for the j-th argument to this atomic function.
On output, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
is the sparsity for the i-th result for this atomic function.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_base<Base>::for_sparse_jac(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity )
{
// intial results are empty during forward mode
size_t q = var_sparsity.end();
bool input_empty = true;
bool zero_empty = true;
bool transpose = false;
size_t m = y_index.size();
bool ok = false;
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
//
std::string msg = ": atomic_base.for_sparse_jac: returned false";
if( sparsity_ == pack_sparsity_enum )
{ vectorBool& pack_r ( work_[thread]->pack_r );
vectorBool& pack_s ( work_[thread]->pack_s );
local::sparse::get_internal_pattern(
transpose, x_index, var_sparsity, pack_r
);
//
pack_s.resize(m * q );
ok = for_sparse_jac(q, pack_r, pack_s, x);
if( ! ok )
ok = for_sparse_jac(q, pack_r, pack_s);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = pack_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, y_index, var_sparsity, pack_s
);
}
else if( sparsity_ == bool_sparsity_enum )
{ vector<bool>& bool_r ( work_[thread]->bool_r );
vector<bool>& bool_s ( work_[thread]->bool_s );
local::sparse::get_internal_pattern(
transpose, x_index, var_sparsity, bool_r
);
bool_s.resize(m * q );
ok = for_sparse_jac(q, bool_r, bool_s, x);
if( ! ok )
ok = for_sparse_jac(q, bool_r, bool_s);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = bool_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, y_index, var_sparsity, bool_s
);
}
else
{ CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum );
vector< std::set<size_t> >& set_r ( work_[thread]->set_r );
vector< std::set<size_t> >& set_s ( work_[thread]->set_s );
local::sparse::get_internal_pattern(
transpose, x_index, var_sparsity, set_r
);
//
set_s.resize(m);
ok = for_sparse_jac(q, set_r, set_s, x);
if( ! ok )
ok = for_sparse_jac(q, set_r, set_s);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = set_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, y_index, var_sparsity, set_s
);
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,402 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_FORWARD_HPP
# define CPPAD_CORE_ATOMIC_TWO_FORWARD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 atomic_two_forward$$
$spell
sq
mul.hpp
hes
afun
vx
vy
ty
Taylor
const
CppAD
bool
atx
aty
af
$$
$section Atomic Forward Mode$$
$head Syntax$$
$subhead Base$$
$icode%ok% = %afun%.forward(%p%, %q%, %vx%, %vy%, %tx%, %ty%)
%$$
This syntax is used by $icode%f%.Forward%$$ where $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
and $icode afun$$ is used in $icode f$$.
$subhead AD<Base>$$
$icode%ok% = %afun%.forward(%p%, %q%, %vx%, %vy%, %atx%, %aty%)
%$$
This syntax is used by $icode%af%.Forward%$$ where $icode af$$ has prototype
$codei%
ADFun< AD<%Base%> , %Base% > %af%
%$$
and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$).
$head Purpose$$
This virtual function is used by $cref atomic_two_afun$$
to evaluate function values.
It is also used buy
$cref/f.Forward/Forward/$$ (and $icode%af%.Forward%$$)
to compute function vales and derivatives.
$head Implementation$$
This virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
It can just return $icode%ok% == false%$$
(and not compute anything) for values
of $icode%q% > 0%$$ that are greater than those used by your
$cref/forward/Forward/$$ mode calculations.
$head p$$
The argument $icode p$$ has prototype
$codei%
size_t %p%
%$$
It specifies the lowest order Taylor coefficient that we are evaluating.
During calls to $cref atomic_two_afun$$, $icode%p% == 0%$$.
$head q$$
The argument $icode q$$ has prototype
$codei%
size_t %q%
%$$
It specifies the highest order Taylor coefficient that we are evaluating.
During calls to $cref atomic_two_afun$$, $icode%q% == 0%$$.
$head vx$$
The $code forward$$ argument $icode vx$$ has prototype
$codei%
const CppAD::vector<bool>& %vx%
%$$
The case $icode%vx%.size() > 0%$$ only occurs while evaluating a call to
$cref atomic_two_afun$$.
In this case,
$icode%p% == %q% == 0%$$,
$icode%vx%.size() == %n%$$, and
for $latex j = 0 , \ldots , n-1$$,
$icode%vx%[%j%]%$$ is true if and only if
$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$
or $cref/dynamic parameter/glossary/Parameter/Dynamic/$$
in the corresponding call to
$codei%
%afun%(%ax%, %ay%)
%$$
If $icode%vx%.size() == 0%$$,
then $icode%vy%.size() == 0%$$ and neither of these vectors
should be used.
$head vy$$
The $code forward$$ argument $icode vy$$ has prototype
$codei%
CppAD::vector<bool>& %vy%
%$$
If $icode%vy%.size() == 0%$$, it should not be used.
Otherwise,
$icode%q% == 0%$$ and $icode%vy%.size() == %m%$$.
The input values of the elements of $icode vy$$
are not specified (must not matter).
Upon return, for $latex j = 0 , \ldots , m-1$$,
$icode%vy%[%i%]%$$ is true if and only if
$icode%ay%[%i%]%$$ is a variable
or dynamic parameter
(CppAD uses $icode vy$$ to reduce the necessary computations).
$head tx$$
The argument $icode tx$$ has prototype
$codei%
const CppAD::vector<%Base%>& %tx%
%$$
and $icode%tx%.size() == (%q%+1)*%n%$$.
It is used by $icode%f%.Forward%$$ where $icode f$$ has type
$codei%ADFun<%Base%> %f%$$ and $icode afun$$ is used in $icode f$$.
For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$,
we use the Taylor coefficient notation
$latex \[
\begin{array}{rcl}
x_j^k & = & tx [ j * ( q + 1 ) + k ]
\\
X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q
\end{array}
\] $$
Note that superscripts represent an index for $latex x_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex X(t)$$ correspond
to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way:
$latex \[
x_j^k = \frac{1}{ k ! } X_j^{(k)} (0)
\] $$
$head atx$$
The argument $icode atx$$ has prototype
$codei%
const CppAD::vector< AD<%Base%> >& %atx%
%$$
Otherwise, $icode atx$$ specifications are the same as for $icode tx$$.
$head ty$$
The argument $icode ty$$ has prototype
$codei%
CppAD::vector<%Base%>& %ty%
%$$
and $icode%tx%.size() == (%q%+1)*%m%$$.
It is set by $icode%f%.Forward%$$ where $icode f$$ has type
$codei%ADFun<%Base%> %f%$$ and $icode afun$$ is used in $icode f$$.
Upon return,
For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$,
$latex \[
\begin{array}{rcl}
Y_i (t) & = & f_i [ X(t) ]
\\
Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q )
\\
ty [ i * ( q + 1 ) + k ] & = & y_i^k
\end{array}
\] $$
where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$.
Note that superscripts represent an index for $latex y_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex Y(t)$$ correspond
to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way:
$latex \[
y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0)
\] $$
If $latex p > 0$$,
for $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , p-1$$,
the input of $icode ty$$ satisfies
$latex \[
ty [ i * ( q + 1 ) + k ] = y_i^k
\]$$
and hence the corresponding elements need not be recalculated.
$head aty$$
The argument $icode aty$$ has prototype
$codei%
const CppAD::vector< AD<%Base%> >& %aty%
%$$
Otherwise, $icode aty$$ specifications are the same as for $icode ty$$.
$head ok$$
If the required results are calculated, $icode ok$$ should be true.
Otherwise, it should be false.
$head Discussion$$
For example, suppose that $icode%q% == 2%$$,
and you know how to compute the function $latex f(x)$$,
its first derivative $latex f^{(1)} (x)$$,
and it component wise Hessian $latex f_i^{(2)} (x)$$.
Then you can compute $icode ty$$ using the following formulas:
$latex \[
\begin{array}{rcl}
y_i^0 & = & Y(0)
= f_i ( x^0 )
\\
y_i^1 & = & Y^{(1)} ( 0 )
= f_i^{(1)} ( x^0 ) X^{(1)} ( 0 )
= f_i^{(1)} ( x^0 ) x^1
\\
y_i^2
& = & \frac{1}{2 !} Y^{(2)} (0)
\\
& = & \frac{1}{2} X^{(1)} (0)^\R{T} f_i^{(2)} ( x^0 ) X^{(1)} ( 0 )
+ \frac{1}{2} f_i^{(1)} ( x^0 ) X^{(2)} ( 0 )
\\
& = & \frac{1}{2} (x^1)^\R{T} f_i^{(2)} ( x^0 ) x^1
+ f_i^{(1)} ( x^0 ) x^2
\end{array}
\] $$
For $latex i = 0 , \ldots , m-1$$, and $latex k = 0 , 1 , 2$$,
$latex \[
ty [ i * (q + 1) + k ] = y_i^k
\] $$
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_forward.hpp
Atomic forward mode
*/
/*!
Link from atomic_base to forward mode (for replacement by derived class)
\param p [in]
lowerest order for this forward mode calculation.
\param q [in]
highest order for this forward mode calculation.
\param vx [in]
if size not zero, which components of x are variables
\param vy [out]
if size not zero, which components of y are variables
\param tx [in]
Taylor coefficients corresponding to x for this calculation.
\param ty [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_two
*/
template <class Base>
bool atomic_base<Base>::forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector<Base>& tx ,
vector<Base>& ty )
{ return false; }
/*!
Link from atomic_base to forward mode (for replacement by derived class)
\param p [in]
lowerest order for this forward mode calculation.
\param q [in]
highest order for this forward mode calculation.
\param vx [in]
if size not zero, which components of x are variables
\param vy [out]
if size not zero, which components of y are variables
\param atx [in]
Taylor coefficients corresponding to x for this calculation.
\param aty [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_two
*/
template <class Base>
bool atomic_base<Base>::forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector< AD<Base> >& atx ,
vector< AD<Base> >& aty )
{ return false; }
/*!
Convert atomic_three interface to atomic_two interface
\param order_low [in]
lowerest order for this forward mode calculation.
\param order_up [in]
highest order for this forward mode calculation.
\param type_x [in]
if size not zero, which components of x are variables
\param type_y [out]
if size not zero, which components of y are variables
\param taylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param taylor_y [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_three
*/
# define CPPAD_ATOMIC_BASE_MUSTDO 0
template <class Base>
bool atomic_base<Base>::forward(
size_t order_low ,
size_t order_up ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y ,
const vector<Base>& taylor_x ,
vector<Base>& taylor_y )
{ //
// atomic_base::afun(ax, ay) calls bool version directly
CPPAD_ASSERT_UNKNOWN( type_x.size() == 0 );
CPPAD_ASSERT_UNKNOWN( type_y.size() == 0 );
//
# if CPPAD_ATOMIC_BASE_MUSTDO
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
vector <bool>& vx = work_[thread]->vx;
vector <bool>& vy = work_[thread]->vy;
vx.resize(type_x.size());
vy.resize(type_y.size());
# else
vector<bool> vx, vy;
# endif
//
bool ok = forward(order_low, order_up, vx, vy, taylor_x, taylor_y);
//
return ok;
}
# undef CPPAD_ATOMIC_BASE_MUSTDO
/*!
Convert atomic_three interface to atomic_two interface
\param order_low [in]
lowerest order for this forward mode calculation.
\param order_up [in]
highest order for this forward mode calculation.
\param type_x [in]
if size not zero, which components of x are variables
\param type_y [out]
if size not zero, which components of y are variables
\param ataylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param ataylor_y [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_three
*/
template <class Base>
bool atomic_base<Base>::forward(
size_t order_low ,
size_t order_up ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y ,
const vector< AD<Base> >& ataylor_x ,
vector< AD<Base> >& ataylor_y )
{ //
// atomic_base::afun(ax, ay) calls bool version directly
CPPAD_ASSERT_UNKNOWN( type_x.size() == 0 );
CPPAD_ASSERT_UNKNOWN( type_y.size() == 0 );
//
vector<bool> vx, vy;
bool ok = forward(order_low, order_up, vx, vy, ataylor_x, ataylor_y);
//
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,113 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_OPTION_HPP
# define CPPAD_CORE_ATOMIC_TWO_OPTION_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 atomic_two_option$$
$spell
sq
enum
afun
bool
CppAD
std
typedef
$$
$section Set Atomic Function Options$$
$head Syntax$$
$icode%afun%.option(%option_value%)%$$
$head Scope$$
These settings do not apply to individual $icode afun$$ calls,
but rather all subsequent uses of the corresponding atomic operation
in an $cref ADFun$$ object.
$head atomic_sparsity$$
Note that, if you use $cref optimize$$, these sparsity patterns are used
to determine the $cref/dependency/dependency.cpp/$$ relationship between
argument and result variables.
$subhead pack_sparsity_enum$$
If $icode option_value$$ is $codei%atomic_base<%Base%>::pack_sparsity_enum%$$,
then the type used by $icode afun$$ for
$cref/sparsity patterns/glossary/Sparsity Pattern/$$,
(after the option is set) will be
$codei%
typedef CppAD::vectorBool %atomic_sparsity%
%$$
If $icode r$$ is a sparsity pattern
for a matrix $latex R \in \B{R}^{p \times q}$$:
$icode%r%.size() == %p% * %q%$$.
$subhead bool_sparsity_enum$$
If $icode option_value$$ is $codei%atomic_base<%Base%>::bool_sparsity_enum%$$,
then the type used by $icode afun$$ for
$cref/sparsity patterns/glossary/Sparsity Pattern/$$,
(after the option is set) will be
$codei%
typedef CppAD::vector<bool> %atomic_sparsity%
%$$
If $icode r$$ is a sparsity pattern
for a matrix $latex R \in \B{R}^{p \times q}$$:
$icode%r%.size() == %p% * %q%$$.
$subhead set_sparsity_enum$$
If $icode option_value$$ is $icode%atomic_base<%Base%>::set_sparsity_enum%$$,
then the type used by $icode afun$$ for
$cref/sparsity patterns/glossary/Sparsity Pattern/$$,
(after the option is set) will be
$codei%
typedef CppAD::vector< std::set<size_t> > %atomic_sparsity%
%$$
If $icode r$$ is a sparsity pattern
for a matrix $latex R \in \B{R}^{p \times q}$$:
$icode%r%.size() == %p%$$, and for $latex i = 0 , \ldots , p-1$$,
the elements of $icode%r%[%i%]%$$ are between zero and $latex q-1$$ inclusive.
$end
------------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_option.hpp
Setting atomic_base options.
*/
/*!
Setting atomic_base options.
\param option_value
new option value.
*/
template <class Base>
void atomic_base<Base>::option(enum option_enum option_value)
{ switch( option_value )
{ case pack_sparsity_enum:
case bool_sparsity_enum:
case set_sparsity_enum:
sparsity_ = option_value;
break;
default:
CPPAD_ASSERT_KNOWN(
false,
"atoic_base::option: option_value is not valid"
);
}
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,99 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_REV_DEPEND_HPP
# define CPPAD_CORE_ATOMIC_TWO_REV_DEPEND_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_rev_depend.hpp
Third generation atomic type computation.
*/
/*!
Link from atomic_two to reverse dependency calculation
\param parameter_x [in]
is the value of the parameters in the corresponding function call
afun(ax, ay).
\param type_x [in]
is the type for each component of ax in the corresponding function call
afun(ax, ay).
\param depend_x [out]
specifies which components of x affect values of interest.
\param depend_y [in]
specifies which components of y affect values of interest.
*/
// BEGIN_PROTOTYPE
template <class Base>
bool atomic_base<Base>::rev_depend(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<bool>& depend_x ,
const vector<bool>& depend_y )
// END_PROTOTYPE
{ bool ok = true;
CPPAD_ASSERT_UNKNOWN( depend_x.size() == parameter_x.size() );
size_t n = depend_x.size();
size_t m = depend_y.size();
//
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
//
if( sparsity_ == pack_sparsity_enum )
{ vectorBool& rt ( work_[thread]->pack_r );
vectorBool& st ( work_[thread]->pack_s );
//
st.resize(n * 1 );
rt.resize(m * 1 );
for(size_t i = 0; i < m; ++i)
rt[i] = depend_y[i];
ok = rev_sparse_jac(1, rt, st, parameter_x);
if( ! ok )
ok = rev_sparse_jac(1, rt, st);
if( ! ok )
return false;
for(size_t j = 0; j < n; ++j)
depend_x[j] = st[j];
}
else if( sparsity_ == bool_sparsity_enum )
{
ok = rev_sparse_jac(1, depend_y, depend_x, parameter_x);
if( ! ok )
ok = rev_sparse_jac(m, depend_y, depend_x);
if( ! ok )
return false;
}
else
{ CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum );
vector< std::set<size_t> >& rt ( work_[thread]->set_r );
vector< std::set<size_t> >& st ( work_[thread]->set_s );
rt.resize(m);
st.resize(n);
for(size_t i = 0; i < m; ++i)
{ if( depend_y[i] )
rt[i].insert(0);
}
ok = rev_sparse_jac(m, rt, st, parameter_x);
if( ! ok )
ok = rev_sparse_jac(m, rt, st);
if( ! ok )
return false;
for(size_t j = 0; j < n; ++j)
depend_x[j] = ! st[j].empty();
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,451 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_HES_HPP
# define CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_HES_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 atomic_two_rev_sparse_hes$$
$spell
sq
mul.hpp
vx
afun
Jacobian
jac
CppAD
std
bool
hes
const
$$
$section Atomic Reverse Hessian Sparsity Patterns$$
$head Syntax$$
$icode%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%, %x%)%$$
$head Deprecated 2016-06-27$$
$icode%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%)%$$
$head Purpose$$
This function is used by $cref RevSparseHes$$ to compute
Hessian sparsity patterns.
If you are using $cref RevSparseHes$$ to compute
one of the versions of this
virtual function muse be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$pre
$$
There is an unspecified scalar valued function
$latex g : \B{R}^m \rightarrow \B{R}$$.
Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for
$latex R \in \B{R}^{n \times q}$$,
and information about the function $latex z = g(y)$$,
this routine computes the sparsity pattern for
$latex \[
V(x) = (g \circ f)^{(2)}( x ) R
\] $$
$head Implementation$$
If you are using and $cref RevSparseHes$$,
this virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$subhead vx$$
The argument $icode vx$$ has prototype
$codei%
const CppAD:vector<bool>& %vx%
%$$
$icode%vx%.size() == %n%$$, and
for $latex j = 0 , \ldots , n-1$$,
$icode%vx%[%j%]%$$ is true if and only if
$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$
or $cref/dynamic parameter/glossary/Parameter/Dynamic/$$
in the corresponding call to
$codei%
%afun%(%ax%, %ay%)
%$$
$subhead s$$
The argument $icode s$$ has prototype
$codei%
const CppAD:vector<bool>& %s%
%$$
and its size is $icode m$$.
It is a sparsity pattern for
$latex S(x) = g^{(1)} [ f(x) ] \in \B{R}^{1 \times m}$$.
$subhead t$$
This argument has prototype
$codei%
CppAD:vector<bool>& %t%
%$$
and its size is $icode m$$.
The input values of its elements
are not specified (must not matter).
Upon return, $icode t$$ is a
sparsity pattern for
$latex T(x) \in \B{R}^{1 \times n}$$ where
$latex \[
T(x) = (g \circ f)^{(1)} (x) = S(x) * f^{(1)} (x)
\]$$
$subhead 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}$$,
$latex U(x) \in \B{R}^{m \times q}$$, and
$latex V(x) \in \B{R}^{n \times q}$$.
$subhead r$$
This argument has prototype
$codei%
const %atomic_sparsity%& %r%
%$$
and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex R \in \B{R}^{n \times q}$$.
$head u$$
This argument has prototype
$codei%
const %atomic_sparsity%& %u%
%$$
and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex U(x) \in \B{R}^{m \times q}$$ which is defined by
$latex \[
\begin{array}{rcl}
U(x)
& = &
\{ \partial_u \{ \partial_y g[ y + f^{(1)} (x) R u ] \}_{y=f(x)} \}_{u=0}
\\
& = &
\partial_u \{ g^{(1)} [ f(x) + f^{(1)} (x) R u ] \}_{u=0}
\\
& = &
g^{(2)} [ f(x) ] f^{(1)} (x) R
\end{array}
\] $$
$subhead v$$
This argument has prototype
$codei%
%atomic_sparsity%& %v%
%$$
The input value of its elements
are not specified (must not matter).
Upon return, $icode v$$ is a
$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex V(x) \in \B{R}^{n \times q}$$ which is defined by
$latex \[
\begin{array}{rcl}
V(x)
& = &
\partial_u [ \partial_x (g \circ f) ( x + R u ) ]_{u=0}
\\
& = &
\partial_u [ (g \circ f)^{(1)}( x + R u ) ]_{u=0}
\\
& = &
(g \circ f)^{(2)}( x ) R
\\
& = &
f^{(1)} (x)^\R{T} g^{(2)} [ f(x) ] f^{(1)} (x) R
+
\sum_{i=1}^m g_i^{(1)} [ f(x) ] \; f_i^{(2)} (x) R
\\
& = &
f^{(1)} (x)^\R{T} U(x)
+
\sum_{i=1}^m S_i (x) \; f_i^{(2)} (x) R
\end{array}
\] $$
$subhead x$$
$index deprecated$$
The argument has prototype
$codei%
const CppAD::vector<%Base%>& %x%
%$$
and size is equal to the $icode n$$.
This is the $cref Value$$ value corresponding to the parameters in the
vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called).
To be specific, if
$codei%
if( Parameter(%ax%[%i%]) == true )
%x%[%i%] = Value( %ax%[%i%] );
else
%x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN();
%$$
The version of this function with out the $icode x$$ argument is deprecated;
i.e., you should include the argument even if you do not use it.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_rev_sparse_hes.hpp
Atomic reverse mode Hessian sparsity patterns.
*/
/*!
Link from reverse Hessian sparsity sweep to atomic_base
\param vx [in]
which componens of x are variables.
\param s [in]
is the reverse Jacobian sparsity pattern w.r.t the result vector y.
\param t [out]
is the reverse Jacobian sparsity pattern w.r.t the argument vector x.
\param q [in]
is the column dimension for the sparsity partterns.
\param r [in]
is the forward Jacobian sparsity pattern w.r.t the argument vector x
\param u [in]
is the Hessian sparsity pattern w.r.t the result vector y.
\param v [out]
is the Hessian sparsity pattern w.r.t the argument vector x.
\param x [in]
is the integer value of the x arguments that are parameters.
*/
template <class Base>
bool atomic_base<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector< std::set<size_t> >& r ,
const vector< std::set<size_t> >& u ,
vector< std::set<size_t> >& v ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector<bool>& r ,
const vector<bool>& u ,
vector<bool>& v ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vectorBool& r ,
const vectorBool& u ,
vectorBool& v ,
const vector<Base>& x )
{ return false; }
// deprecated
template <class Base>
bool atomic_base<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector< std::set<size_t> >& r ,
const vector< std::set<size_t> >& u ,
vector< std::set<size_t> >& v )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector<bool>& r ,
const vector<bool>& u ,
vector<bool>& v )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vectorBool& r ,
const vectorBool& u ,
vectorBool& v )
{ return false; }
/*!
Link, before case split, from rev_hes_sweep to atomic_base.
\tparam InternalSparsity
Is the used internaly for sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param x
is parameter arguments to the function, other components are nan.
\param x_index
is the variable index, on the tape, for the arguments to this function.
This size of x_index is n, the number of arguments to this function.
\param y_index
is the variable index, on the tape, for the results for this function.
This size of y_index is m, the number of results for this function.
\param for_jac_sparsity
On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
is the forward Jacobian sparsity for the j-th argument to this atomic function.
\param rev_jac_flag
This shows which variables affect the function we are
computing the Hessian of.
On input, for i = 0, ... , m-1, the rev_jac_flag[ y_index[i] ] is true
if the Jacobian of function (we are computing sparsity for) is no-zero.
Upon return, for j = 0, ... , n-1, rev_jac_flag [ x_index[j] ]
as been adjusted to accound removing this atomic function.
\param rev_hes_sparsity
This is the sparsity pattern for the Hessian.
On input, for i = 0, ... , m-1, row y_index[i] is the reverse Hessian sparsity
with one of the partials with respect to to y_index[i].
*/
template <class Base>
template <class InternalSparsity>
bool atomic_base<Base>::rev_sparse_hes(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
const InternalSparsity& for_jac_sparsity ,
bool* rev_jac_flag ,
InternalSparsity& rev_hes_sparsity )
{ CPPAD_ASSERT_UNKNOWN( for_jac_sparsity.end() == rev_hes_sparsity.end() );
size_t q = rev_hes_sparsity.end();
size_t n = x_index.size();
size_t m = y_index.size();
bool ok = false;
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
bool zero_empty = true;
bool input_empty = false;
bool transpose = false;
//
// vx
vector<bool> vx(n);
for(size_t j = 0; j < n; j++)
vx[j] = x_index[j] != 0;
//
// note that s and t are vectors so transpose does not matter for bool case
vector<bool> bool_s( work_[thread]->bool_s );
vector<bool> bool_t( work_[thread]->bool_t );
//
bool_s.resize(m);
bool_t.resize(n);
//
for(size_t i = 0; i < m; i++)
{ if( y_index[i] > 0 )
bool_s[i] = rev_jac_flag[ y_index[i] ];
}
//
std::string msg = ": atomic_base.rev_sparse_hes: returned false";
if( sparsity_ == pack_sparsity_enum )
{ vectorBool& pack_r( work_[thread]->pack_r );
vectorBool& pack_u( work_[thread]->pack_u );
vectorBool& pack_v( work_[thread]->pack_h );
//
pack_v.resize(n * q);
//
local::sparse::get_internal_pattern(
transpose, x_index, for_jac_sparsity, pack_r
);
local::sparse::get_internal_pattern(
transpose, y_index, rev_hes_sparsity, pack_u
);
//
ok = rev_sparse_hes(vx, bool_s, bool_t, q, pack_r, pack_u, pack_v, x);
if( ! ok )
ok = rev_sparse_hes(vx, bool_s, bool_t, q, pack_r, pack_u, pack_v);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = pack_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, x_index, rev_hes_sparsity, pack_v
);
}
else if( sparsity_ == bool_sparsity_enum )
{ vector<bool>& bool_r( work_[thread]->bool_r );
vector<bool>& bool_u( work_[thread]->bool_u );
vector<bool>& bool_v( work_[thread]->bool_h );
//
bool_v.resize(n * q);
//
local::sparse::get_internal_pattern(
transpose, x_index, for_jac_sparsity, bool_r
);
local::sparse::get_internal_pattern(
transpose, y_index, rev_hes_sparsity, bool_u
);
//
ok = rev_sparse_hes(vx, bool_s, bool_t, q, bool_r, bool_u, bool_v, x);
if( ! ok )
ok = rev_sparse_hes(vx, bool_s, bool_t, q, bool_r, bool_u, bool_v);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = bool_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, x_index, rev_hes_sparsity, bool_v
);
}
else
{ CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum );
vector< std::set<size_t> >& set_r( work_[thread]->set_r );
vector< std::set<size_t> >& set_u( work_[thread]->set_u );
vector< std::set<size_t> >& set_v( work_[thread]->set_h );
//
set_v.resize(n);
//
local::sparse::get_internal_pattern(
transpose, x_index, for_jac_sparsity, set_r
);
local::sparse::get_internal_pattern(
transpose, y_index, rev_hes_sparsity, set_u
);
//
ok = rev_sparse_hes(vx, bool_s, bool_t, q, set_r, set_u, set_v, x);
if( ! ok )
ok = rev_sparse_hes(vx, bool_s, bool_t, q, set_r, set_u, set_v);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = set_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, x_index, rev_hes_sparsity, set_v
);
}
for(size_t j = 0; j < n; j++)
{ if( x_index[j] > 0 )
rev_jac_flag[ x_index[j] ] |= bool_t[j];
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,289 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_JAC_HPP
# define CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_JAC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 atomic_two_rev_sparse_jac$$
$spell
sq
mul.hpp
rt
afun
Jacobian
jac
CppAD
std
bool
const
hes
$$
$section Atomic Reverse Jacobian Sparsity Patterns$$
$head Syntax$$
$icode%ok% = %afun%.rev_sparse_jac(%q%, %rt%, %st%, %x%)
%$$
$head Deprecated 2016-06-27$$
$icode%ok% = %afun%.rev_sparse_jac(%q%, %rt%, %st%)
%$$
$head Purpose$$
This function is used by
$cref RevSparseJac$$ to compute
Jacobian sparsity patterns.
If you are using $cref RevSparseJac$$,
one of the versions of this
virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$pre
$$
For a fixed matrix $latex R \in \B{R}^{q \times m}$$,
the Jacobian of $latex R * f( x )$$ with respect to $latex x \in \B{R}^n$$ is
$latex \[
S(x) = R * f^{(1)} (x)
\] $$
Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$,
$code rev_sparse_jac$$ computes a sparsity pattern for $latex S(x)$$.
$head Implementation$$
If you are using
$cref RevSparseJac$$ or $cref ForSparseHes$$,
this virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
$subhead q$$
The argument $icode q$$ has prototype
$codei%
size_t %q%
%$$
It specifies the number of rows in
$latex R \in \B{R}^{q \times m}$$ and the Jacobian
$latex S(x) \in \B{R}^{q \times n}$$.
$subhead rt$$
This argument has prototype
$codei%
const %atomic_sparsity%& %rt%
%$$
and is a
$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex R^\R{T} \in \B{R}^{m \times q}$$.
$subhead st$$
This argument has prototype
$codei%
%atomic_sparsity%& %st%
%$$
The input value of its elements
are not specified (must not matter).
Upon return, $icode s$$ is a
$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for
$latex S(x)^\R{T} \in \B{R}^{n \times q}$$.
$subhead x$$
$index deprecated$$
The argument has prototype
$codei%
const CppAD::vector<%Base%>& %x%
%$$
and size is equal to the $icode n$$.
This is the $cref Value$$ corresponding to the parameters in the
vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called).
To be specific, if
$codei%
if( Parameter(%ax%[%i%]) == true )
%x%[%i%] = Value( %ax%[%i%] );
else
%x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN();
%$$
The version of this function with out the $icode x$$ argument is deprecated;
i.e., you should include the argument even if you do not use it.
$head ok$$
The return value $icode ok$$ has prototype
$codei%
bool %ok%
%$$
If it is $code true$$, the corresponding evaluation succeeded,
otherwise it failed.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_rev_sparse_jac.hpp
Atomic reverse mode Jacobian sparsity patterns.
*/
/*!
Link, after case split, from rev_jac_sweep to atomic_base
\param q [in]
is the row dimension for the Jacobian sparsity partterns
\param rt [out]
is the tansposed Jacobian sparsity pattern w.r.t to range variables y
\param st [in]
is the tansposed Jacobian sparsity pattern for the argument variables x
\param x
is the integer value for x arguments that are parameters.
*/
template <class Base>
bool atomic_base<Base>::rev_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& rt ,
vector< std::set<size_t> >& st ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_jac(
size_t q ,
const vector<bool>& rt ,
vector<bool>& st ,
const vector<Base>& x )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_jac(
size_t q ,
const vectorBool& rt ,
vectorBool& st ,
const vector<Base>& x )
{ return false; }
// deprecated versions
template <class Base>
bool atomic_base<Base>::rev_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& rt ,
vector< std::set<size_t> >& st )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_jac(
size_t q ,
const vector<bool>& rt ,
vector<bool>& st )
{ return false; }
template <class Base>
bool atomic_base<Base>::rev_sparse_jac(
size_t q ,
const vectorBool& rt ,
vectorBool& st )
{ return false; }
/*!
Link, before case split, from rev_jac_sweep to atomic_base.
\tparam InternalSparsity
Is the used internaly for sparsity calculations; i.e.,
sparse_pack or sparse_list.
\param x
is parameter arguments to the function, other components are nan.
\param x_index
is the variable index, on the tape, for the arguments to this function.
This size of x_index is n, the number of arguments to this function.
\param y_index
is the variable index, on the tape, for the results for this function.
This size of y_index is m, the number of results for this function.
\param var_sparsity
On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
is the sparsity for the i-th argument to this atomic function.
On output, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
the sparsity has been updated to remove y as a function of x.
*/
template <class Base>
template <class InternalSparsity>
bool atomic_base<Base>::rev_sparse_jac(
const vector<Base>& x ,
const local::pod_vector<size_t>& x_index ,
const local::pod_vector<size_t>& y_index ,
InternalSparsity& var_sparsity )
{
// initial results may be non-empty during reverse mode
size_t q = var_sparsity.end();
bool input_empty = false;
bool zero_empty = true;
bool transpose = false;
size_t n = x_index.size();
bool ok = false;
size_t thread = thread_alloc::thread_num();
allocate_work(thread);
//
std::string msg = ": atomic_base.rev_sparse_jac: returned false";
if( sparsity_ == pack_sparsity_enum )
{ vectorBool& pack_rt ( work_[thread]->pack_r );
vectorBool& pack_st ( work_[thread]->pack_s );
local::sparse::get_internal_pattern(
transpose, y_index, var_sparsity, pack_rt
);
//
pack_st.resize(n * q );
ok = rev_sparse_jac(q, pack_rt, pack_st, x);
if( ! ok )
ok = rev_sparse_jac(q, pack_rt, pack_st);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = pack_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, x_index, var_sparsity, pack_st
);
}
else if( sparsity_ == bool_sparsity_enum )
{ vector<bool>& bool_rt ( work_[thread]->bool_r );
vector<bool>& bool_st ( work_[thread]->bool_s );
local::sparse::get_internal_pattern(
transpose, y_index, var_sparsity, bool_rt
);
bool_st.resize(n * q );
ok = rev_sparse_jac(q, bool_rt, bool_st, x);
if( ! ok )
ok = rev_sparse_jac(q, bool_rt, bool_st);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = bool_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, x_index, var_sparsity, bool_st
);
}
else
{ CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum );
vector< std::set<size_t> >& set_rt ( work_[thread]->set_r );
vector< std::set<size_t> >& set_st ( work_[thread]->set_s );
local::sparse::get_internal_pattern(
transpose, y_index, var_sparsity, set_rt
);
set_st.resize(n);
ok = rev_sparse_jac(q, set_rt, set_st, x);
if( ! ok )
ok = rev_sparse_jac(q, set_rt, set_st);
if( ! ok )
{ msg = atomic_name() + msg + " sparsity = set_sparsity_enum";
CPPAD_ASSERT_KNOWN(false, msg.c_str());
}
local::sparse::set_internal_pattern(zero_empty, input_empty,
transpose, x_index, var_sparsity, set_st
);
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,291 @@
# ifndef CPPAD_CORE_ATOMIC_TWO_REVERSE_HPP
# define CPPAD_CORE_ATOMIC_TWO_REVERSE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 atomic_two_reverse$$
$spell
sq
mul.hpp
afun
ty
px
py
Taylor
const
CppAD
atx
aty
apx
apy
af
$$
$section Atomic Reverse Mode$$
$spell
bool
$$
$head Syntax$$
$subhead Base$$
$icode%ok% = %afun%.reverse(%q%, %tx%, %ty%, %px%, %py%)
%$$
This syntax is used by $icode%f%.Forward%$$ where $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
and $icode afun$$ is used in $icode f$$.
$subhead AD<Base>$$
$icode%ok% = %afun%.reverse(%q%, %atx%, %aty%, %apx%, %apy%)
%$$
This syntax is used by $icode%af%.Forward%$$ where $icode af$$ has prototype
$codei%
ADFun< AD<%Base%> , %Base% > %af%
%$$
and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$).
$head Purpose$$
This function is used by $cref/reverse/Reverse/$$
to compute derivatives.
$head Implementation$$
If you are using
$cref/reverse/Reverse/$$ mode,
this virtual function must be defined by the
$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class.
It can just return $icode%ok% == false%$$
(and not compute anything) for values
of $icode q$$ that are greater than those used by your
$cref/reverse/Reverse/$$ mode calculations.
$head q$$
The argument $icode q$$ has prototype
$codei%
size_t %q%
%$$
It specifies the highest order Taylor coefficient that
computing the derivative of.
$head tx$$
The argument $icode tx$$ has prototype
$codei%
const CppAD::vector<%Base%>& %tx%
%$$
and $icode%tx%.size() == (%q%+1)*%n%$$.
For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$,
we use the Taylor coefficient notation
$latex \[
\begin{array}{rcl}
x_j^k & = & tx [ j * ( q + 1 ) + k ]
\\
X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q
\end{array}
\] $$
Note that superscripts represent an index for $latex x_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex X(t)$$ correspond
to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way:
$latex \[
x_j^k = \frac{1}{ k ! } X_j^{(k)} (0)
\] $$
$head atx$$
The argument $icode atx$$ has prototype
$codei%
const CppAD::vector< AD<%Base%> >& %atx%
%$$
Otherwise, $icode atx$$ specifications are the same as for $icode tx$$.
$head ty$$
The argument $icode ty$$ has prototype
$codei%
const CppAD::vector<%Base%>& %ty%
%$$
and $icode%tx%.size() == (%q%+1)*%m%$$.
For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$,
we use the Taylor coefficient notation
$latex \[
\begin{array}{rcl}
Y_i (t) & = & f_i [ X(t) ]
\\
Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q )
\\
y_i^k & = & ty [ i * ( q + 1 ) + k ]
\end{array}
\] $$
where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$.
Note that superscripts represent an index for $latex y_j^k$$
and an exponent for $latex t^k$$.
Also note that the Taylor coefficients for $latex Y(t)$$ correspond
to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way:
$latex \[
y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0)
\] $$
$head aty$$
The argument $icode aty$$ has prototype
$codei%
const CppAD::vector< AD<%Base%> >& %aty%
%$$
Otherwise, $icode aty$$ specifications are the same as for $icode ty$$.
$head F$$
We use the notation $latex \{ x_j^k \} \in \B{R}^{n \times (q+1)}$$ for
$latex \[
\{ x_j^k \W{:} j = 0 , \ldots , n-1, k = 0 , \ldots , q \}
\]$$
We use the notation $latex \{ y_i^k \} \in \B{R}^{m \times (q+1)}$$ for
$latex \[
\{ y_i^k \W{:} i = 0 , \ldots , m-1, k = 0 , \ldots , q \}
\]$$
We define the function
$latex F : \B{R}^{n \times (q+1)} \rightarrow \B{R}^{m \times (q+1)}$$ by
$latex \[
y_i^k = F_i^k [ \{ x_j^k \} ]
\] $$
Note that
$latex \[
F_i^0 ( \{ x_j^k \} ) = f_i ( X(0) ) = f_i ( x^0 )
\] $$
We also note that
$latex F_i^\ell ( \{ x_j^k \} )$$ is a function of
$latex x^0 , \ldots , x^\ell$$
and is determined by the derivatives of $latex f_i (x)$$
up to order $latex \ell$$.
$head G, H$$
We use $latex G : \B{R}^{m \times (q+1)} \rightarrow \B{R}$$
to denote an arbitrary scalar valued function of $latex \{ y_i^k \}$$.
We use $latex H : \B{R}^{n \times (q+1)} \rightarrow \B{R}$$
defined by
$latex \[
H ( \{ x_j^k \} ) = G[ F( \{ x_j^k \} ) ]
\] $$
$head py$$
The argument $icode py$$ has prototype
$codei%
const CppAD::vector<%Base%>& %py%
%$$
and $icode%py%.size() == m * (%q%+1)%$$.
For $latex i = 0 , \ldots , m-1$$, $latex k = 0 , \ldots , q$$,
$latex \[
py[ i * (q + 1 ) + k ] = \partial G / \partial y_i^k
\] $$
$head apy$$
The argument $icode apy$$ has prototype
$codei%
const CppAD::vector< AD<%Base%> >& %apy%
%$$
Otherwise, $icode apy$$ specifications are the same as for $icode py$$.
$subhead px$$
The $icode px$$ has prototype
$codei%
CppAD::vector<%Base%>& %px%
%$$
and $icode%px%.size() == n * (%q%+1)%$$.
The input values of the elements of $icode px$$
are not specified (must not matter).
Upon return,
for $latex j = 0 , \ldots , n-1$$ and $latex \ell = 0 , \ldots , q$$,
$latex \[
\begin{array}{rcl}
px [ j * (q + 1) + \ell ] & = & \partial H / \partial x_j^\ell
\\
& = &
( \partial G / \partial \{ y_i^k \} ) \cdot
( \partial \{ y_i^k \} / \partial x_j^\ell )
\\
& = &
\sum_{k=0}^q
\sum_{i=0}^{m-1}
( \partial G / \partial y_i^k ) ( \partial y_i^k / \partial x_j^\ell )
\\
& = &
\sum_{k=\ell}^q
\sum_{i=0}^{m-1}
py[ i * (q + 1 ) + k ] ( \partial F_i^k / \partial x_j^\ell )
\end{array}
\] $$
Note that we have used the fact that for $latex k < \ell$$,
$latex \partial F_i^k / \partial x_j^\ell = 0$$.
$head apx$$
The argument $icode apx$$ has prototype
$codei%
CppAD::vector< AD<%Base%> >& %apx%
%$$
Otherwise, $icode apx$$ specifications are the same as for $icode px$$.
$head ok$$
The return value $icode ok$$ has prototype
$codei%
bool %ok%
%$$
If it is $code true$$, the corresponding evaluation succeeded,
otherwise it failed.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file atomic/two_reverse.hpp
Atomic reverse mode.
*/
/*!
Link from reverse mode sweep to users routine.
\param q [in]
highest order for this reverse mode calculation.
\param tx [in]
Taylor coefficients corresponding to x for this calculation.
\param ty [in]
Taylor coefficient corresponding to y for this calculation
\param px [out]
Partials w.r.t. the x Taylor coefficients.
\param py [in]
Partials w.r.t. the y Taylor coefficients.
See atomic_reverse mode use documentation
*/
template <class Base>
bool atomic_base<Base>::reverse(
size_t q ,
const vector<Base>& tx ,
const vector<Base>& ty ,
vector<Base>& px ,
const vector<Base>& py )
{ return false; }
template <class Base>
bool atomic_base<Base>::reverse(
size_t q ,
const vector< AD<Base> >& atx ,
const vector< AD<Base> >& aty ,
vector< AD<Base> >& apx ,
const vector< AD<Base> >& apy )
{ return false; }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,247 @@
# ifndef CPPAD_CORE_AZMUL_HPP
# define CPPAD_CORE_AZMUL_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 azmul$$
$spell
azmul
const
namespace
Vec
$$
$section Absolute Zero Multiplication$$
$head Syntax$$
$icode%z% = azmul(%x%, %y%)%$$
$head Purpose$$
Evaluates multiplication with an absolute zero
for any of the possible types listed below.
The result is given by
$latex \[
z = \left\{ \begin{array}{ll}
0 & {\rm if} \; x = 0 \\
x \cdot y & {\rm otherwise}
\end{array} \right.
\] $$
Note if $icode x$$ is zero and $icode y$$ is infinity,
ieee multiplication would result in not a number whereas
$icode z$$ would be zero.
$head Base$$
If $icode Base$$ satisfies the
$cref/base type requirements/base_require/$$
and arguments $icode x$$, $icode y$$ have prototypes
$codei%
const %Base%& %x%
const %Base%& %y%
%$$
then the result $icode z$$ has prototype
$codei%
%Base% %z%
%$$
$head AD<Base>$$
If the arguments $icode x$$, $icode y$$ have prototype
$codei%
const AD<%Base%>& %x%
const AD<%Base%>& %y%
%$$
then the result $icode z$$ has prototype
$codei%
AD<%Base%> %z%
%$$
$head VecAD<Base>$$
If the arguments $icode x$$, $icode y$$ have prototype
$codei%
const VecAD<%Base%>::reference& %x%
const VecAD<%Base%>::reference& %y%
%$$
then the result $icode z$$ has prototype
$codei%
AD<%Base%> %z%
%$$
$head Example$$
$children%
example/general/azmul.cpp
%$$
The file
$cref azmul.cpp$$
is an examples and tests of this function.
$end
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
// ==========================================================================
// case where x and y are AD<Base> -------------------------------------------
template <class Base> AD<Base>
azmul(const AD<Base>& x, const AD<Base>& y)
{
// compute the Base part
AD<Base> result;
result.value_ = azmul(x.value_, y.value_);
// 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 x and y tapes match
bool match_x = x.tape_id_ == tape_id;
bool match_y = y.tape_id_ == tape_id;
// check if x and y are dynamic parameters
bool dyn_x = match_x & (x.ad_type_ == dynamic_enum);
bool dyn_y = match_y & (y.ad_type_ == dynamic_enum);
// check if x and y are variables
bool var_x = match_x & (x.ad_type_ != dynamic_enum);
bool var_y = match_y & (y.ad_type_ != dynamic_enum);
CPPAD_ASSERT_KNOWN(
x.tape_id_ == y.tape_id_ || ! match_x || ! match_y ,
"azmul: AD variables or dynamic parameters on different threads."
);
if( var_x )
{ if( var_y )
{ // result = azmul(variable, variable)
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ZmulvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::ZmulvvOp) == 2 );
// put operand addresses in tape
tape->Rec_.PutArg(x.taddr_, y.taddr_);
// put operator in the tape
result.taddr_ = tape->Rec_.PutOp(local::ZmulvvOp);
// make result a variable
result.tape_id_ = tape_id;
result.ad_type_ = variable_enum;
}
else if( ( ! dyn_y ) & IdenticalZero( y.value_ ) )
{ // result = variable * 0
}
else if( ( ! dyn_y ) & IdenticalOne( y.value_ ) )
{ // result = variable * 1
result.make_variable(x.tape_id_, x.taddr_);
}
else
{ // result = zmul(variable, parameter)
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ZmulvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::ZmulvpOp) == 2 );
// put operand addresses in tape
addr_t p = y.taddr_;
if( ! dyn_y )
p = tape->Rec_.put_con_par(y.value_);
tape->Rec_.PutArg(x.taddr_, p);
// put operator in the tape
result.taddr_ = tape->Rec_.PutOp(local::ZmulvpOp);
// make result a variable
result.tape_id_ = tape_id;
result.ad_type_ = variable_enum;
}
}
else if( var_y )
{ if( ( ! dyn_x ) & IdenticalZero(x.value_) )
{ // result = 0 * variable
}
else if( ( ! dyn_x ) & IdenticalOne( x.value_ ) )
{ // result = 1 * variable
result.make_variable(y.tape_id_, y.taddr_);
}
else
{ // result = zmul(parameter, variable)
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ZmulpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::ZmulpvOp) == 2 );
// put operand addresses in tape
addr_t p = x.taddr_;
if( ! dyn_x )
p = tape->Rec_.put_con_par(x.value_);
tape->Rec_.PutArg(p, y.taddr_);
// put operator in the tape
result.taddr_ = tape->Rec_.PutOp(local::ZmulpvOp);
// make result a variable
result.tape_id_ = tape_id;
result.ad_type_ = variable_enum;
}
}
else if( dyn_x | dyn_y )
{ addr_t arg0 = x.taddr_;
addr_t arg1 = y.taddr_;
if( ! dyn_x )
arg0 = tape->Rec_.put_con_par(x.value_);
if( ! dyn_y )
arg1 = tape->Rec_.put_con_par(y.value_);
//
// parameters with a dynamic parameter result
result.taddr_ = tape->Rec_.put_dyn_par(
result.value_, local::zmul_dyn, arg0, arg1
);
result.tape_id_ = tape_id;
result.ad_type_ = dynamic_enum;
}
return result;
}
// =========================================================================
// Fold operations into case above
// -------------------------------------------------------------------------
// Operations with VecAD_reference<Base> and AD<Base> only
template <class Base> AD<Base>
azmul(const AD<Base>& x, const VecAD_reference<Base>& y)
{ return azmul(x, y.ADBase()); }
template <class Base> AD<Base>
azmul(const VecAD_reference<Base>& x, const VecAD_reference<Base>& y)
{ return azmul(x.ADBase(), y.ADBase()); }
template <class Base> AD<Base>
azmul(const VecAD_reference<Base>& x, const AD<Base>& y)
{ return azmul(x.ADBase(), y); }
// -------------------------------------------------------------------------
// Operations with Base
template <class Base> AD<Base>
azmul(const Base& x, const AD<Base>& y)
{ return azmul(AD<Base>(x), y); }
template <class Base> AD<Base>
azmul(const Base& x, const VecAD_reference<Base>& y)
{ return azmul(AD<Base>(x), y.ADBase()); }
template <class Base> AD<Base>
azmul(const AD<Base>& x, const Base& y)
{ return azmul(x, AD<Base>(y)); }
template <class Base> AD<Base>
azmul(const VecAD_reference<Base>& x, const Base& y)
{ return azmul(x.ADBase(), AD<Base>(y)); }
// ==========================================================================
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,117 @@
# ifndef CPPAD_CORE_BASE2AD_HPP
# define CPPAD_CORE_BASE2AD_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 base2ad$$
$spell
af
Taylor
$$
$spell
$$
$section Create an AD<Base> Function From a Base Function$$
$head Syntax$$
$icode%af% = %f%.base2ad()%$$
$head See Also$$
$cref mul_level$$
$head Base$$
This is the base type used to recorded the operation sequence in $icode f$$
and $icode af$$; i.e., the type $codei%AD<%Base%>%$$ was used to record
the operation sequence.
$head f$$
This object has prototype
$codei%
ADFun<%Base%> %f%
%$$
It does it's derivative calculations using the type $icode Base$$.
$head af$$
This object has prototype
$codei%
ADFun< AD<%Base%> , %Base% > %af%
%$$
It has the same operation sequence as $icode f$$,
but it does it's derivative calculations using the type
$codei%AD<%Base>%$$.
This enables one to record new functions that are defined
using derivatives of the function $icode f$$.
Initially, there are no Taylor coefficients stored in $icode af$$ and
$cref%af.size_order()%size_order%$$ is zero.
$children%
example/general/base2ad.cpp
%$$
$head Example$$
The file $cref base2ad.cpp$$
contains an example and test of this operation.
$end
----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file base2ad.hpp
*/
/// Create an ADFun< AD<Base>, Base > from this ADFun<Base>
template <class Base, class RecBase>
ADFun< AD<Base>, RecBase > ADFun<Base,RecBase>::base2ad(void) const
{ ADFun< AD<Base>, RecBase > fun;
//
// bool values
fun.has_been_optimized_ = has_been_optimized_;
fun.check_for_nan_ = check_for_nan_;
//
// size_t values
fun.compare_change_count_ = compare_change_count_;
fun.compare_change_number_ = compare_change_number_;
fun.compare_change_op_index_ = compare_change_op_index_;
CPPAD_ASSERT_UNKNOWN( fun.num_order_taylor_ == 0 ) ;
CPPAD_ASSERT_UNKNOWN( fun.cap_order_taylor_ == 0 );
CPPAD_ASSERT_UNKNOWN( fun.num_direction_taylor_ == 0 );
fun.num_var_tape_ = num_var_tape_;
//
// pod_vector objects
fun.ind_taddr_ = ind_taddr_;
fun.dep_taddr_ = dep_taddr_;
fun.dep_parameter_ = dep_parameter_;
fun.cskip_op_ = cskip_op_;
fun.load_op2var_ = load_op2var_;
//
// pod_maybe_vector< AD<Base> > = pod_maybe_vector<Base>
CPPAD_ASSERT_UNKNOWN( fun.taylor_.size() == 0 );
//
// player
// (uses move semantics)
fun.play_ = play_.base2ad();
//
// subgraph
fun.subgraph_info_ = subgraph_info_;
//
// sparse_pack
fun.for_jac_sparse_pack_ = for_jac_sparse_pack_;
//
// sparse_list
fun.for_jac_sparse_set_ = for_jac_sparse_set_;
//
return fun;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,384 @@
# ifndef CPPAD_CORE_BASE_COMPLEX_HPP
# define CPPAD_CORE_BASE_COMPLEX_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.
---------------------------------------------------------------------------- */
# include <cppad/configure.hpp>
# include <limits>
# include <complex>
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
# include <cppad/utility/thread_alloc.hpp>
/*
$begin base_complex.hpp$$
$spell
azmul
expm1
atanh
acosh
asinh
endif
eps
abs_geq
Rel
Lt Le Eq Ge Gt
imag
gcc
isnan
cppad.hpp
sqrt
exp
cos
std
const
CppAD
Op
inline
enum
undef
acos
asin
atan
erf
erfc
Cond
namespace
bool
$$
$section Enable use of AD<Base> where Base is std::complex<double>$$
$children%example/general/complex_poly.cpp
%$$
$head Example$$
The file $cref complex_poly.cpp$$ contains an example use of
$code std::complex<double>$$ type for a CppAD $icode Base$$ type.
$head Include Order$$
This file is included before $code <cppad/cppad.hpp>$$
so it is necessary to define the error handler
in addition to including
$cref/base_require.hpp/base_require/Include Order/$$
$srccode%cpp% */
# include <limits>
# include <complex>
# include <cppad/base_require.hpp>
# include <cppad/core/cppad_assert.hpp>
/* %$$
$head CondExpOp$$
The type $code std::complex<double>$$ does not supports the
$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators; see
$cref/not ordered/base_cond_exp/CondExpTemplate/Not Ordered/$$.
Hence its $code CondExpOp$$ function is defined by
$srccode%cpp% */
namespace CppAD {
inline std::complex<double> CondExpOp(
enum CppAD::CompareOp cop ,
const std::complex<double> &left ,
const std::complex<double> &right ,
const std::complex<double> &trueCase ,
const std::complex<double> &falseCase )
{ CppAD::ErrorHandler::Call(
true , __LINE__ , __FILE__ ,
"std::complex<float> CondExpOp(...)",
"Error: cannot use CondExp with a complex type"
);
return std::complex<double>(0);
}
}
/* %$$
$head CondExpRel$$
The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation
$srccode%cpp% */
namespace CppAD {
CPPAD_COND_EXP_REL( std::complex<double> )
}
/* %$$
used $code CondExpOp$$ above to
define $codei%CondExp%Rel%$$ for $code std::complex<double>$$ arguments
and $icode%Rel%$$ equal to
$code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, and $code Gt$$.
$head EqualOpSeq$$
Complex numbers do not carry operation sequence information.
Thus they are equal in this sense if and only if there values are equal.
$srccode%cpp% */
namespace CppAD {
inline bool EqualOpSeq(
const std::complex<double> &x ,
const std::complex<double> &y )
{ return x == y;
}
}
/* %$$
$head Identical$$
Complex numbers do not carry operation sequence information.
Thus they are all parameters so the identical functions just check values.
$srccode%cpp% */
namespace CppAD {
inline bool IdenticalCon(const std::complex<double> &x)
{ return true; }
inline bool IdenticalZero(const std::complex<double> &x)
{ return (x == std::complex<double>(0., 0.) ); }
inline bool IdenticalOne(const std::complex<double> &x)
{ return (x == std::complex<double>(1., 0.) ); }
inline bool IdenticalEqualCon(
const std::complex<double> &x, const std::complex<double> &y)
{ return (x == y); }
}
/* %$$
$head Ordered$$
Complex types do not support comparison operators,
$srccode%cpp% */
# undef CPPAD_USER_MACRO
# define CPPAD_USER_MACRO(Fun) \
inline bool Fun(const std::complex<double>& x) \
{ CppAD::ErrorHandler::Call( \
true , __LINE__ , __FILE__ , \
#Fun"(x)", \
"Error: cannot use " #Fun " with x complex<double> " \
); \
return false; \
}
namespace CppAD {
CPPAD_USER_MACRO(LessThanZero)
CPPAD_USER_MACRO(LessThanOrZero)
CPPAD_USER_MACRO(GreaterThanOrZero)
CPPAD_USER_MACRO(GreaterThanZero)
inline bool abs_geq(
const std::complex<double>& x ,
const std::complex<double>& y )
{ return std::abs(x) >= std::abs(y); }
}
/* %$$
$head Integer$$
The implementation of this function must agree
with the CppAD user specifications for complex arguments to the
$cref/Integer/Integer/x/Complex Types/$$ function:
$srccode%cpp% */
namespace CppAD {
inline int Integer(const std::complex<double> &x)
{ return static_cast<int>( x.real() ); }
}
/* %$$
$head azmul$$
$srccode%cpp% */
namespace CppAD {
CPPAD_AZMUL( std::complex<double> )
}
/* %$$
$head isnan$$
The gcc 4.1.1 complier defines the function
$codei%
int std::complex<double>::isnan( std::complex<double> %z% )
%$$
(which is not specified in the C++ 1998 standard ISO/IEC 14882).
This causes an ambiguity between the function above and the CppAD
$cref/isnan/nan/$$ template function.
We avoid this ambiguity by defining a non-template version of
this function in the CppAD namespace.
$srccode%cpp% */
namespace CppAD {
inline bool isnan(const std::complex<double>& z)
{ return (z != z);
}
}
/* %$$
$head Valid Unary Math$$
The following macro invocations define the standard unary
math functions that are valid with complex arguments and are
required to use $code AD< std::complex<double> >$$.
$srccode%cpp% */
namespace CppAD {
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, cos)
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, cosh)
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, exp)
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, log)
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, sin)
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, sinh)
CPPAD_STANDARD_MATH_UNARY(std::complex<double>, sqrt)
}
/* %$$
$head Invalid Unary Math$$
The following macro definition and invocations define the standard unary
math functions that are invalid with complex arguments and are
required to use $code AD< std::complex<double> >$$.
$srccode%cpp% */
# undef CPPAD_USER_MACRO
# define CPPAD_USER_MACRO(Fun) \
inline std::complex<double> Fun(const std::complex<double>& x) \
{ CppAD::ErrorHandler::Call( \
true , __LINE__ , __FILE__ , \
#Fun"(x)", \
"Error: cannot use " #Fun " with x complex<double> " \
); \
return std::complex<double>(0); \
}
namespace CppAD {
CPPAD_USER_MACRO(abs)
CPPAD_USER_MACRO(fabs)
CPPAD_USER_MACRO(acos)
CPPAD_USER_MACRO(asin)
CPPAD_USER_MACRO(atan)
CPPAD_USER_MACRO(sign)
CPPAD_USER_MACRO(asinh)
CPPAD_USER_MACRO(acosh)
CPPAD_USER_MACRO(atanh)
CPPAD_USER_MACRO(erf)
CPPAD_USER_MACRO(erfc)
CPPAD_USER_MACRO(expm1)
CPPAD_USER_MACRO(log1p)
}
/* %$$
$head pow $$
The following defines a $code CppAD::pow$$ function that
is required to use $code AD< std::complex<double> >$$:
$srccode%cpp% */
namespace CppAD {
inline std::complex<double> pow(
const std::complex<double> &x ,
const std::complex<double> &y )
{ return std::pow(x, y); }
}
/* %$$
$head numeric_limits$$
The following defines the CppAD $cref numeric_limits$$
for the type $code std::complex<double>$$:
$srccode%cpp% */
namespace CppAD {
CPPAD_NUMERIC_LIMITS(double, std::complex<double>)
}
/* %$$
$head to_string$$
The following defines the function CppAD $cref to_string$$
for the type $code std::complex<double>$$:
$srccode%cpp% */
namespace CppAD {
CPPAD_TO_STRING(std::complex<double>)
}
/* %$$
$end
*/
# undef CPPAD_USER_MACRO_ONE
# define CPPAD_USER_MACRO_ONE(Fun) \
inline bool Fun(const std::complex<float>& x) \
{ CppAD::ErrorHandler::Call( \
true , __LINE__ , __FILE__ , \
#Fun"(x)", \
"Error: cannot use " #Fun " with x complex<float> " \
); \
return false; \
}
# undef CPPAD_USER_MACRO_TWO
# define CPPAD_USER_MACRO_TWO(Fun) \
inline std::complex<float> Fun(const std::complex<float>& x) \
{ CppAD::ErrorHandler::Call( \
true , __LINE__ , __FILE__ , \
#Fun"(x)", \
"Error: cannot use " #Fun " with x complex<float> " \
); \
return std::complex<float>(0); \
}
namespace CppAD {
// CondExpOp ------------------------------------------------------
inline std::complex<float> CondExpOp(
enum CppAD::CompareOp cop ,
const std::complex<float> &left ,
const std::complex<float> &right ,
const std::complex<float> &trueCase ,
const std::complex<float> &falseCase )
{ CppAD::ErrorHandler::Call(
true , __LINE__ , __FILE__ ,
"std::complex<float> CondExpOp(...)",
"Error: cannot use CondExp with a complex type"
);
return std::complex<float>(0);
}
// CondExpRel --------------------------------------------------------
CPPAD_COND_EXP_REL( std::complex<float> )
// EqualOpSeq -----------------------------------------------------
inline bool EqualOpSeq(
const std::complex<float> &x ,
const std::complex<float> &y )
{ return x == y;
}
// Identical ------------------------------------------------------
inline bool IdenticalCon(const std::complex<float> &x)
{ return true; }
inline bool IdenticalZero(const std::complex<float> &x)
{ return (x == std::complex<float>(0., 0.) ); }
inline bool IdenticalOne(const std::complex<float> &x)
{ return (x == std::complex<float>(1., 0.) ); }
inline bool IdenticalEqualCon(
const std::complex<float> &x, const std::complex<float> &y)
{ return (x == y); }
// Ordered --------------------------------------------------------
CPPAD_USER_MACRO_ONE(LessThanZero)
CPPAD_USER_MACRO_ONE(LessThanOrZero)
CPPAD_USER_MACRO_ONE(GreaterThanOrZero)
CPPAD_USER_MACRO_ONE(GreaterThanZero)
inline bool abs_geq(
const std::complex<float>& x ,
const std::complex<float>& y )
{ return std::abs(x) >= std::abs(y); }
// Integer ------------------------------------------------------
inline int Integer(const std::complex<float> &x)
{ return static_cast<int>( x.real() ); }
// isnan -------------------------------------------------------------
inline bool isnan(const std::complex<float>& z)
{ return (z != z);
}
// Valid standard math functions --------------------------------
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, cos)
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, cosh)
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, exp)
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, log)
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, sin)
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, sinh)
CPPAD_STANDARD_MATH_UNARY(std::complex<float>, sqrt)
// Invalid standrd math functions -------------------------------
CPPAD_USER_MACRO_TWO(abs)
CPPAD_USER_MACRO_TWO(acos)
CPPAD_USER_MACRO_TWO(asin)
CPPAD_USER_MACRO_TWO(atan)
CPPAD_USER_MACRO_TWO(sign)
// The pow function
inline std::complex<float> pow(
const std::complex<float> &x ,
const std::complex<float> &y )
{ return std::pow(x, y); }
// numeric_limits -------------------------------------------------
CPPAD_NUMERIC_LIMITS(float, std::complex<float>)
// to_string -------------------------------------------------
CPPAD_TO_STRING(std::complex<float>)
}
// undefine macros only used by this file
# undef CPPAD_USER_MACRO
# undef CPPAD_USER_MACRO_ONE
# undef CPPAD_USER_MACRO_TWO
# endif

View File

@@ -0,0 +1,284 @@
# ifndef CPPAD_CORE_BASE_COND_EXP_HPP
# define CPPAD_CORE_BASE_COND_EXP_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 base_cond_exp$$
$spell
alloc
Rel
hpp
enum
namespace
Op
Lt
Le
Eq
Ge
Gt
Ne
cond
exp
const
adolc
CppAD
inline
$$
$section Base Type Requirements for Conditional Expressions$$
$head Purpose$$
These definitions are required by the user's code to support the
$codei%AD<%Base%>%$$ type for $cref CondExp$$ operations:
$head CompareOp$$
The following $code enum$$ type is used in the specifications below:
$codep
namespace CppAD {
// The conditional expression operator enum type
enum CompareOp
{ CompareLt, // less than
CompareLe, // less than or equal
CompareEq, // equal
CompareGe, // greater than or equal
CompareGt, // greater than
CompareNe // not equal
};
}
$$
$head CondExpTemplate$$
The type $icode Base$$ must support the syntax
$codei%
%result% = CppAD::CondExpOp(
%cop%, %left%, %right%, %exp_if_true%, %exp_if_false%
)
%$$
which computes implements the corresponding $cref CondExp$$
function when the result has prototype
$codei%
%Base% %result%
%$$
The argument $icode cop$$ has prototype
$codei%
enum CppAD::CompareOp %cop%
%$$
The other arguments have the prototype
$codei%
const %Base%& %left%
const %Base%& %right%
const %Base%& %exp_if_true%
const %Base%& %exp_if_false%
%$$
$subhead Ordered Type$$
If $icode Base$$ is a relatively simple type
that supports
$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators
its $code CondExpOp$$ function can be defined by
$codei%
namespace CppAD {
inline %Base% CondExpOp(
enum CppAD::CompareOp %cop% ,
const %Base% &%left% ,
const %Base% &%right% ,
const %Base% &%exp_if_true% ,
const %Base% &%exp_if_false% )
{ return CondExpTemplate(
cop, left, right, trueCase, falseCase);
}
}
%$$
For example, see
$cref/double CondExpOp/base_alloc.hpp/CondExpOp/$$.
For an example of and implementation of $code CondExpOp$$ with
a more involved $icode Base$$ type see
$cref/adolc CondExpOp/base_adolc.hpp/CondExpOp/$$.
$subhead Not Ordered$$
If the type $icode Base$$ does not support ordering,
the $code CondExpOp$$ function does not make sense.
In this case one might (but need not) define $code CondExpOp$$ as follows:
$codei%
namespace CppAD {
inline %Base% CondExpOp(
enum CompareOp %cop% ,
const %Base% &%left% ,
const %Base% &%right% ,
const %Base% &%exp_if_true% ,
const %Base% &%exp_if_false% )
{ // attempt to use CondExp with a %Base% argument
assert(0);
return %Base%(0);
}
}
%$$
For example, see
$cref/complex CondExpOp/base_complex.hpp/CondExpOp/$$.
$head CondExpRel$$
The macro invocation
$codei%
CPPAD_COND_EXP_REL(%Base%)
%$$
uses $code CondExpOp$$ above to define the following functions
$codei%
CondExpLt(%left%, %right%, %exp_if_true%, %exp_if_false%)
CondExpLe(%left%, %right%, %exp_if_true%, %exp_if_false%)
CondExpEq(%left%, %right%, %exp_if_true%, %exp_if_false%)
CondExpGe(%left%, %right%, %exp_if_true%, %exp_if_false%)
CondExpGt(%left%, %right%, %exp_if_true%, %exp_if_false%)
%$$
where the arguments have type $icode Base$$.
This should be done inside of the CppAD namespace.
For example, see
$cref/base_alloc/base_alloc.hpp/CondExpRel/$$.
$end
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file base_cond_exp.hpp
CondExp operations that aid in meeting Base type requirements.
*/
/*!
\def CPPAD_COND_EXP_BASE_REL(Type, Rel, Op)
This macro defines the operation
\verbatim
CondExpRel(left, right, exp_if_true, exp_if_false)
\endverbatim
The argument Type is the Base type for this base require operation.
The argument Rel is one of Lt, Le, Eq, Ge, Gt.
The argument Op is the corresponding CompareOp value.
*/
# define CPPAD_COND_EXP_BASE_REL(Type, Rel, Op) \
inline Type CondExp##Rel( \
const Type& left , \
const Type& right , \
const Type& exp_if_true , \
const Type& exp_if_false ) \
{ return CondExpOp(Op, left, right, exp_if_true, exp_if_false); \
}
/*!
\def CPPAD_COND_EXP_REL(Type)
The macro defines the operations
\verbatim
CondExpLt(left, right, exp_if_true, exp_if_false)
CondExpLe(left, right, exp_if_true, exp_if_false)
CondExpEq(left, right, exp_if_true, exp_if_false)
CondExpGe(left, right, exp_if_true, exp_if_false)
CondExpGt(left, right, exp_if_true, exp_if_false)
\endverbatim
The argument Type is the Base type for this base require operation.
*/
# define CPPAD_COND_EXP_REL(Type) \
CPPAD_COND_EXP_BASE_REL(Type, Lt, CompareLt) \
CPPAD_COND_EXP_BASE_REL(Type, Le, CompareLe) \
CPPAD_COND_EXP_BASE_REL(Type, Eq, CompareEq) \
CPPAD_COND_EXP_BASE_REL(Type, Ge, CompareGe) \
CPPAD_COND_EXP_BASE_REL(Type, Gt, CompareGt)
/*!
Template function to implement Conditional Expressions for simple types
that have comparison operators.
\tparam CompareType
is the type of the left and right operands to the comparison operator.
\tparam ResultType
is the type of the result, which is the same as CompareType except
during forward and reverse mode sparese calculations.
\param cop
specifices which comparison to use; i.e.,
$code <$$,
$code <=$$,
$code ==$$,
$code >=$$,
$code >$$, or
$code !=$$.
\param left
is the left operand to the comparison operator.
\param right
is the right operand to the comparison operator.
\param exp_if_true
is the return value is the comparison results in true.
\param exp_if_false
is the return value is the comparison results in false.
\return
see exp_if_true and exp_if_false above.
*/
template <class CompareType, class ResultType>
ResultType CondExpTemplate(
enum CompareOp cop ,
const CompareType& left ,
const CompareType& right ,
const ResultType& exp_if_true ,
const ResultType& exp_if_false )
{ ResultType returnValue;
switch( cop )
{
case CompareLt:
if( left < right )
returnValue = exp_if_true;
else
returnValue = exp_if_false;
break;
case CompareLe:
if( left <= right )
returnValue = exp_if_true;
else
returnValue = exp_if_false;
break;
case CompareEq:
if( left == right )
returnValue = exp_if_true;
else
returnValue = exp_if_false;
break;
case CompareGe:
if( left >= right )
returnValue = exp_if_true;
else
returnValue = exp_if_false;
break;
case CompareGt:
if( left > right )
returnValue = exp_if_true;
else
returnValue = exp_if_false;
break;
default:
CPPAD_ASSERT_UNKNOWN(0);
returnValue = exp_if_true;
}
return returnValue;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,229 @@
# ifndef CPPAD_CORE_BASE_DOUBLE_HPP
# define CPPAD_CORE_BASE_DOUBLE_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.
---------------------------------------------------------------------------- */
# include <cppad/configure.hpp>
# include <limits>
/*
$begin base_double.hpp$$
$spell
namespaces
cppad
hpp
azmul
expm1
atanh
acosh
asinh
erf
erfc
endif
abs_geq
acos
asin
atan
cos
sqrt
tanh
std
fabs
bool
Lt Le Eq Ge Gt
Rel
CppAD
CondExpOp
namespace
inline
enum
const
exp
const
$$
$section Enable use of AD<Base> where Base is double$$
$head CondExpOp$$
The type $code double$$ is a relatively simple type that supports
$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators; see
$cref/ordered type/base_cond_exp/CondExpTemplate/Ordered Type/$$.
Hence its $code CondExpOp$$ function is defined by
$srccode%cpp% */
namespace CppAD {
inline double CondExpOp(
enum CompareOp cop ,
const double& left ,
const double& right ,
const double& exp_if_true ,
const double& exp_if_false )
{ return CondExpTemplate(cop, left, right, exp_if_true, exp_if_false);
}
}
/* %$$
$head CondExpRel$$
The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation
$srccode%cpp% */
namespace CppAD {
CPPAD_COND_EXP_REL(double)
}
/* %$$
uses $code CondExpOp$$ above to
define $codei%CondExp%Rel%$$ for $code double$$ arguments
and $icode%Rel%$$ equal to
$code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, and $code Gt$$.
$head EqualOpSeq$$
The type $code double$$ is simple (in this respect) and so we define
$srccode%cpp% */
namespace CppAD {
inline bool EqualOpSeq(const double& x, const double& y)
{ return x == y; }
}
/* %$$
$head Identical$$
The type $code double$$ is simple (in this respect) and so we define
$srccode%cpp% */
namespace CppAD {
inline bool IdenticalCon(const double& x)
{ return true; }
inline bool IdenticalZero(const double& x)
{ return (x == 0.); }
inline bool IdenticalOne(const double& x)
{ return (x == 1.); }
inline bool IdenticalEqualCon(const double& x, const double& y)
{ return (x == y); }
}
/* %$$
$head Integer$$
$srccode%cpp% */
namespace CppAD {
inline int Integer(const double& x)
{ return static_cast<int>(x); }
}
/* %$$
$head azmul$$
$srccode%cpp% */
namespace CppAD {
CPPAD_AZMUL( double )
}
/* %$$
$head Ordered$$
The $code double$$ type supports ordered comparisons
$srccode%cpp% */
namespace CppAD {
inline bool GreaterThanZero(const double& x)
{ return x > 0.; }
inline bool GreaterThanOrZero(const double& x)
{ return x >= 0.; }
inline bool LessThanZero(const double& x)
{ return x < 0.; }
inline bool LessThanOrZero(const double& x)
{ return x <= 0.; }
inline bool abs_geq(const double& x, const double& y)
{ return std::fabs(x) >= std::fabs(y); }
}
/* %$$
$head Unary Standard Math$$
The following macro invocations import the $code double$$ versions of
the unary standard math functions into the $code CppAD$$ namespace.
Importing avoids ambiguity errors when using both the
$code CppAD$$ and $code std$$ namespaces.
Note this also defines the $cref/float/base_float.hpp/Unary Standard Math/$$
versions of these functions.
$srccode%cpp% */
namespace CppAD {
using std::acos;
using std::asin;
using std::atan;
using std::cos;
using std::cosh;
using std::exp;
using std::fabs;
using std::log;
using std::log10;
using std::sin;
using std::sinh;
using std::sqrt;
using std::tan;
using std::tanh;
using std::asinh;
using std::acosh;
using std::atanh;
using std::erf;
using std::erfc;
using std::expm1;
using std::log1p;
}
/* %$$
The absolute value function is special because its $code std$$ name is
$code fabs$$
$srccode%cpp% */
namespace CppAD {
inline double abs(const double& x)
{ return std::fabs(x); }
}
/* %$$
$head sign$$
The following defines the $code CppAD::sign$$ function that
is required to use $code AD<double>$$:
$srccode%cpp% */
namespace CppAD {
inline double sign(const double& x)
{ if( x > 0. )
return 1.;
if( x == 0. )
return 0.;
return -1.;
}
}
/* %$$
$head pow$$
The following defines a $code CppAD::pow$$ function that
is required to use $code AD<double>$$.
As with the unary standard math functions,
this has the exact same signature as $code std::pow$$,
so use it instead of defining another function.
$srccode%cpp% */
namespace CppAD {
using std::pow;
}
/* %$$
$head numeric_limits$$
The following defines the CppAD $cref numeric_limits$$
for the type $code double$$:
$srccode%cpp% */
namespace CppAD {
CPPAD_NUMERIC_LIMITS(double, double)
}
/* %$$
$head to_string$$
There is no need to define $code to_string$$ for $code double$$
because it is defined by including $code cppad/utility/to_string.hpp$$;
see $cref to_string$$.
See $cref/base_complex.hpp/base_complex.hpp/to_string/$$ for an example where
it is necessary to define $code to_string$$ for a $icode Base$$ type.
$end
*/
# endif

View File

@@ -0,0 +1,230 @@
# ifndef CPPAD_CORE_BASE_FLOAT_HPP
# define CPPAD_CORE_BASE_FLOAT_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.
---------------------------------------------------------------------------- */
# include <cppad/configure.hpp>
# include <limits>
/*
$begin base_float.hpp$$
$spell
namespaces
cppad
hpp
azmul
expm1
atanh
acosh
asinh
erf
erfc
endif
abs_geq
acos
asin
atan
cos
sqrt
tanh
std
fabs
bool
Lt Le Eq Ge Gt
Rel
CppAD
CondExpOp
namespace
inline
enum
const
exp
const
$$
$section Enable use of AD<Base> where Base is float$$
$head CondExpOp$$
The type $code float$$ is a relatively simple type that supports
$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators; see
$cref/ordered type/base_cond_exp/CondExpTemplate/Ordered Type/$$.
Hence its $code CondExpOp$$ function is defined by
$srccode%cpp% */
namespace CppAD {
inline float CondExpOp(
enum CompareOp cop ,
const float& left ,
const float& right ,
const float& exp_if_true ,
const float& exp_if_false )
{ return CondExpTemplate(cop, left, right, exp_if_true, exp_if_false);
}
}
/* %$$
$head CondExpRel$$
The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation
$srccode%cpp% */
namespace CppAD {
CPPAD_COND_EXP_REL(float)
}
/* %$$
uses $code CondExpOp$$ above to
define $codei%CondExp%Rel%$$ for $code float$$ arguments
and $icode%Rel%$$ equal to
$code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, and $code Gt$$.
$head EqualOpSeq$$
The type $code float$$ is simple (in this respect) and so we define
$srccode%cpp% */
namespace CppAD {
inline bool EqualOpSeq(const float& x, const float& y)
{ return x == y; }
}
/* %$$
$head Identical$$
The type $code float$$ is simple (in this respect) and so we define
$srccode%cpp% */
namespace CppAD {
inline bool IdenticalCon(const float& x)
{ return true; }
inline bool IdenticalZero(const float& x)
{ return (x == 0.f); }
inline bool IdenticalOne(const float& x)
{ return (x == 1.f); }
inline bool IdenticalEqualCon(const float& x, const float& y)
{ return (x == y); }
}
/* %$$
$head Integer$$
$srccode%cpp% */
namespace CppAD {
inline int Integer(const float& x)
{ return static_cast<int>(x); }
}
/* %$$
$head azmul$$
$srccode%cpp% */
namespace CppAD {
CPPAD_AZMUL( float )
}
/* %$$
$head Ordered$$
The $code float$$ type supports ordered comparisons
$srccode%cpp% */
namespace CppAD {
inline bool GreaterThanZero(const float& x)
{ return x > 0.f; }
inline bool GreaterThanOrZero(const float& x)
{ return x >= 0.f; }
inline bool LessThanZero(const float& x)
{ return x < 0.f; }
inline bool LessThanOrZero(const float& x)
{ return x <= 0.f; }
inline bool abs_geq(const float& x, const float& y)
{ return std::fabs(x) >= std::fabs(y); }
}
/* %$$
$head Unary Standard Math$$
The following macro invocations import the $code float$$ versions of
the unary standard math functions into the $code CppAD$$ namespace.
Importing avoids ambiguity errors when using both the
$code CppAD$$ and $code std$$ namespaces.
Note this also defines the $cref/double/base_double.hpp/Unary Standard Math/$$
versions of these functions.
$srccode%cpp% */
namespace CppAD {
using std::acos;
using std::asin;
using std::atan;
using std::cos;
using std::cosh;
using std::exp;
using std::fabs;
using std::log;
using std::log10;
using std::sin;
using std::sinh;
using std::sqrt;
using std::tan;
using std::tanh;
using std::asinh;
using std::acosh;
using std::atanh;
using std::erf;
using std::erfc;
using std::expm1;
using std::log1p;
}
/* %$$
The absolute value function is special because its $code std$$ name is
$code fabs$$
$srccode%cpp% */
namespace CppAD {
inline float abs(const float& x)
{ return std::fabs(x); }
}
/* %$$
$head sign$$
The following defines the $code CppAD::sign$$ function that
is required to use $code AD<float>$$:
$srccode%cpp% */
namespace CppAD {
inline float sign(const float& x)
{ if( x > 0.f )
return 1.f;
if( x == 0.f )
return 0.f;
return -1.f;
}
}
/* %$$
$head pow$$
The following defines a $code CppAD::pow$$ function that
is required to use $code AD<float>$$.
As with the unary standard math functions,
this has the exact same signature as $code std::pow$$,
so use it instead of defining another function.
$srccode%cpp% */
namespace CppAD {
using std::pow;
}
/* %$$
$head numeric_limits$$
The following defines the CppAD $cref numeric_limits$$
for the type $code float$$:
$srccode%cpp% */
namespace CppAD {
CPPAD_NUMERIC_LIMITS(float, float)
}
/* %$$
$head to_string$$
There is no need to define $code to_string$$ for $code float$$
because it is defined by including $code cppad/utility/to_string.hpp$$;
see $cref to_string$$.
See $cref/base_complex.hpp/base_complex.hpp/to_string/$$ for an example where
it is necessary to define $code to_string$$ for a $icode Base$$ type.
$end
*/
# endif

View File

@@ -0,0 +1,84 @@
# ifndef CPPAD_CORE_BASE_HASH_HPP
# define CPPAD_CORE_BASE_HASH_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 base_hash$$
$spell
alloc
Cpp
adouble
valgrind
const
inline
$$
$section Base Type Requirements for Hash Coding Values$$
$head Syntax$$
$icode%code% = hash_code(%x%)%$$
$head Purpose$$
CppAD uses a table of $icode Base$$ type values when recording
$codei%AD<%Base%>%$$ operations.
A hashing function is used to reduce number of values stored in this table;
for example, it is not necessary to store the value 3.0 every
time it is used as a $cref/parameter/con_dyn_var/Parameter/$$.
$head Default$$
The default hashing function works with the set of bits that correspond
to a $icode Base$$ value.
In most cases this works well, but in some cases
it does not. For example, in the
$cref base_adolc.hpp$$ case, an $code adouble$$ value can have
fields that are not initialized and $code valgrind$$ reported an error
when these are used to form the hash code.
$head x$$
This argument has prototype
$codei%
const %Base%& %x
%$$
It is the value we are forming a hash code for.
$head code$$
The return value $icode code$$ has prototype
$codei%
unsigned short %code%
%$$
It is the hash code corresponding to $icode x$$. This intention is the
commonly used values will have different hash codes.
The hash code must satisfy
$codei%
%code% < CPPAD_HASH_TABLE_SIZE
%$$
so that it is a valid index into the hash code table.
$head inline$$
If you define this function, it should declare it to be $code inline$$,
so that you do not get multiple definitions from different compilation units.
$head Example$$
See the $code base_alloc$$ $cref/hash_code/base_alloc.hpp/hash_code/$$
and the $code adouble$$ $cref/hash_code/base_adolc.hpp/hash_code/$$.
$end
*/
/*!
\def CPPAD_HASH_TABLE_SIZE
the codes retruned by hash_code are between zero and CPPAD_HASH_TABLE_SIZE
minus one.
*/
# define CPPAD_HASH_TABLE_SIZE 10000
# endif

View File

@@ -0,0 +1,67 @@
# ifndef CPPAD_CORE_BASE_LIMITS_HPP
# define CPPAD_CORE_BASE_LIMITS_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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 base_limits$$
$spell
std
namespace
CppAD
$$
$section Base Type Requirements for Numeric Limits$$
$head CppAD::numeric_limits$$
A specialization for
$cref/CppAD::numeric_limits/numeric_limits/$$
must be defined in order to use the type $codei%AD<%Base%>%$$.
CppAD does not use a specialization of
$codei%std::numeric_limits<%Base%>%$$.
Since C++11, using a specialization of
$codei%std::numeric_limits<%Base%>%$$
would require that $icode Base$$ be a literal type.
$head CPPAD_NUMERIC_LIMITS$$
In most cases, this macro can be used to define the specialization where
the numeric limits for the type $icode Base$$
are the same as the standard numeric limits for the type $icode Other$$.
For most $icode Base$$ types,
there is a choice of $icode Other$$,
for which the following preprocessor macro invocation suffices:
$codei%
namespace CppAD {
CPPAD_NUMERIC_LIMITS(%Other%, %Base%)
}
%$$
where the macro is defined by
$srccode%cpp% */
# define CPPAD_NUMERIC_LIMITS(Other, Base) \
template <> class numeric_limits<Base>\
{\
public:\
static Base min(void) \
{ return static_cast<Base>( std::numeric_limits<Other>::min() ); }\
static Base max(void) \
{ return static_cast<Base>( std::numeric_limits<Other>::max() ); }\
static Base epsilon(void) \
{ return static_cast<Base>( std::numeric_limits<Other>::epsilon() ); }\
static Base quiet_NaN(void) \
{ return static_cast<Base>( std::numeric_limits<Other>::quiet_NaN() ); }\
static const int digits10 = std::numeric_limits<Other>::digits10;\
};
/* %$$
$end
*/
# endif

View File

@@ -0,0 +1,171 @@
# ifndef CPPAD_CORE_BASE_STD_MATH_HPP
# define CPPAD_CORE_BASE_STD_MATH_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 base_std_math$$
$spell
expm1
atanh
acosh
asinh
inline
fabs
isnan
alloc
std
acos
asin
atan
cos
exp
sqrt
const
CppAD
namespace
erf
erfc
$$
$section Base Type Requirements for Standard Math Functions$$
$head Purpose$$
These definitions are required for the user's code to use the type
$codei%AD<%Base%>%$$:
$head Unary Standard Math$$
The type $icode Base$$ must support the following functions
unary standard math functions (in the CppAD namespace):
$table
$bold Syntax$$ $cnext $bold Result$$
$rnext
$icode%y% = abs(%x%)%$$ $cnext absolute value $rnext
$icode%y% = acos(%x%)%$$ $cnext inverse cosine $rnext
$icode%y% = acosh(%x%)%$$ $cnext inverse hyperbolic cosine $rnext
$icode%y% = asin(%x%)%$$ $cnext inverse sine $rnext
$icode%y% = asinh(%x%)%$$ $cnext inverse hyperbolic sin $rnext
$icode%y% = atan(%x%)%$$ $cnext inverse tangent $rnext
$icode%y% = atanh(%x%)%$$ $cnext inverse hyperbolic tangent $rnext
$icode%y% = cos(%x%)%$$ $cnext cosine $rnext
$icode%y% = cosh(%x%)%$$ $cnext hyperbolic cosine $rnext
$icode%y% = erf(%x%)%$$ $cnext error function $rnext
$icode%y% = erfc(%x%)%$$ $cnext complementary error function $rnext
$icode%y% = exp(%x%)%$$ $cnext exponential $rnext
$icode%y% = expm1(%x%)%$$ $cnext exponential of x minus one $rnext
$icode%y% = fabs(%x%)%$$ $cnext absolute value $rnext
$icode%y% = log(%x%)%$$ $cnext natural logarithm $rnext
$icode%y% = log1p(%x%)%$$ $cnext logarithm of one plus x $rnext
$icode%y% = sin(%x%)%$$ $cnext sine $rnext
$icode%y% = sinh(%x%)%$$ $cnext hyperbolic sine $rnext
$icode%y% = sqrt(%x%)%$$ $cnext square root $rnext
$icode%y% = tan(%x%)%$$ $cnext tangent
$tend
where the arguments and return value have the prototypes
$codei%
const %Base%& %x%
%Base% %y%
%$$
For example,
$cref/base_alloc/base_alloc.hpp/Unary Standard Math/$$,
$head CPPAD_STANDARD_MATH_UNARY$$
The macro invocation, within the CppAD namespace,
$codei%
CPPAD_STANDARD_MATH_UNARY(%Base%, %Fun%)
%$$
defines the syntax
$codei%
%y% = CppAD::%Fun%(%x%)
%$$
This macro uses the functions $codei%std::%Fun%$$ which
must be defined and have the same prototype as $codei%CppAD::%Fun%$$.
For example,
$cref/float/base_float.hpp/Unary Standard Math/$$.
$head sign$$
The type $icode Base$$ must support the syntax
$codei%
%y% = CppAD::sign(%x%)
%$$
which computes
$latex \[
y = \left\{ \begin{array}{ll}
+1 & {\rm if} \; x > 0 \\
0 & {\rm if} \; x = 0 \\
-1 & {\rm if} \; x < 0
\end{array} \right.
\] $$
where $icode x$$ and $icode y$$ have the same prototype as above.
For example, see
$cref/base_alloc/base_alloc.hpp/sign/$$.
Note that, if ordered comparisons are not defined for the type $icode Base$$,
the $code code sign$$ function should generate an assert if it is used; see
$cref/complex invalid unary math/base_complex.hpp/Invalid Unary Math/$$.
$head pow$$
The type $icode Base$$ must support the syntax
$codei%
%z% = CppAD::pow(%x%, %y%)
%$$
which computes $latex z = x^y$$.
The arguments $icode x$$ and $icode y$$ have prototypes
$codei%
const %Base%& %x%
const %Base%& %y%
%$$
and the return value $icode z$$ has prototype
$codei%
%Base% %z%
%$$
For example, see
$cref/base_alloc/base_alloc.hpp/pow/$$.
$head isnan$$
If $icode Base$$ defines the $code isnan$$ function,
you may also have to provide a definition in the CppAD namespace
(to avoid a function ambiguity).
For example, see
$cref/base_complex/base_complex.hpp/isnan/$$.
$end
-------------------------------------------------------------------------------
*/
# include <cmath>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file base_std_math.hpp
Defintions that aid meeting Base type requirements for standard math functions.
*/
/*!
\def CPPAD_STANDARD_MATH_UNARY(Type, Fun)
This macro defines the function
\verbatim
y = CppAD:Fun(x)
\endverbatim
where the argument x and return value y have type Type
using the corresponding function <code>std::Fun</code>.
*/
# define CPPAD_STANDARD_MATH_UNARY(Type, Fun) \
inline Type Fun(const Type& x) \
{ return std::Fun(x); }
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,65 @@
# ifndef CPPAD_CORE_BASE_TO_STRING_HPP
# define CPPAD_CORE_BASE_TO_STRING_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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 base_to_string$$
$spell
std
namespace
CppAD
struct
const
stringstream
setprecision
str
$$
$section Extending to_string To Another Floating Point Type$$
$head Base Requirement$$
If the function $cref to_string$$ is used by an
$cref/AD type above Base/glossary/AD Type Above Base/$$,
A specialization for the template structure
$code CppAD::to_string_struct$$ must be defined.
$head CPPAD_TO_STRING$$
For most $icode Base$$ types,
the following can be used to define the specialization:
$codei%
namespace CppAD {
CPPAD_TO_STRING(%Base%)
}
%$$
Note that the $code CPPAD_TO_STRING$$ macro assumes that the
$cref base_limits$$ and $cref base_std_math$$ have already been defined
for this type.
This macro is defined as follows:
$srccode%cpp% */
# define CPPAD_TO_STRING(Base) \
template <> struct to_string_struct<Base>\
{ std::string operator()(const Base& value) \
{ std::stringstream os;\
int n_digits = 1 + CppAD::numeric_limits<Base>::digits10; \
os << std::setprecision(n_digits);\
os << value;\
return os.str();\
}\
};
/* %$$
$end
------------------------------------------------------------------------------
*/
// make sure to_string has been included
# include <cppad/utility/to_string.hpp>
# endif

View File

@@ -0,0 +1,402 @@
# ifndef CPPAD_CORE_BENDER_QUAD_HPP
# define CPPAD_CORE_BENDER_QUAD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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 BenderQuad$$
$spell
cppad.hpp
BAvector
gx
gxx
CppAD
Fy
dy
Jacobian
ADvector
const
dg
ddg
$$
$section Computing Jacobian and Hessian of Bender's Reduced Objective$$
$head Syntax$$
$codei%
# include <cppad/cppad.hpp>
BenderQuad(%x%, %y%, %fun%, %g%, %gx%, %gxx%)%$$
$head See Also$$
$cref opt_val_hes$$
$head Problem$$
The type $cref/ADvector/BenderQuad/ADvector/$$ cannot be determined
form the arguments above
(currently the type $icode ADvector$$ must be
$codei%CPPAD_TESTVECTOR(%Base%)%$$.)
This will be corrected in the future by requiring $icode Fun$$
to define $icode%Fun%::vector_type%$$ which will specify the
type $icode ADvector$$.
$head Purpose$$
We are given the optimization problem
$latex \[
\begin{array}{rcl}
{\rm minimize} & F(x, y) & {\rm w.r.t.} \; (x, y) \in \B{R}^n \times \B{R}^m
\end{array}
\] $$
that is convex with respect to $latex y$$.
In addition, we are given a set of equations $latex H(x, y)$$
such that
$latex \[
H[ x , Y(x) ] = 0 \;\; \Rightarrow \;\; F_y [ x , Y(x) ] = 0
\] $$
(In fact, it is often the case that $latex H(x, y) = F_y (x, y)$$.)
Furthermore, it is easy to calculate a Newton step for these equations; i.e.,
$latex \[
dy = - [ \partial_y H(x, y)]^{-1} H(x, y)
\] $$
The purpose of this routine is to compute the
value, Jacobian, and Hessian of the reduced objective function
$latex \[
G(x) = F[ x , Y(x) ]
\] $$
Note that if only the value and Jacobian are needed, they can be
computed more quickly using the relations
$latex \[
G^{(1)} (x) = \partial_x F [x, Y(x) ]
\] $$
$head x$$
The $code BenderQuad$$ argument $icode x$$ has prototype
$codei%
const %BAvector% &%x%
%$$
(see $cref/BAvector/BenderQuad/BAvector/$$ below)
and its size must be equal to $icode n$$.
It specifies the point at which we evaluating
the reduced objective function and its derivatives.
$head y$$
The $code BenderQuad$$ argument $icode y$$ has prototype
$codei%
const %BAvector% &%y%
%$$
and its size must be equal to $icode m$$.
It must be equal to $latex Y(x)$$; i.e.,
it must solve the problem in $latex y$$ for this given value of $latex x$$
$latex \[
\begin{array}{rcl}
{\rm minimize} & F(x, y) & {\rm w.r.t.} \; y \in \B{R}^m
\end{array}
\] $$
$head fun$$
The $code BenderQuad$$ object $icode fun$$
must support the member functions listed below.
The $codei%AD<%Base%>%$$ arguments will be variables for
a tape created by a call to $cref Independent$$ from $code BenderQuad$$
(hence they can not be combined with variables corresponding to a
different tape).
$subhead fun.f$$
The $code BenderQuad$$ argument $icode fun$$ supports the syntax
$codei%
%f% = %fun%.f(%x%, %y%)
%$$
The $icode%fun%.f%$$ argument $icode x$$ has prototype
$codei%
const %ADvector% &%x%
%$$
(see $cref/ADvector/BenderQuad/ADvector/$$ below)
and its size must be equal to $icode n$$.
The $icode%fun%.f%$$ argument $icode y$$ has prototype
$codei%
const %ADvector% &%y%
%$$
and its size must be equal to $icode m$$.
The $icode%fun%.f%$$ result $icode f$$ has prototype
$codei%
%ADvector% %f%
%$$
and its size must be equal to one.
The value of $icode f$$ is
$latex \[
f = F(x, y)
\] $$.
$subhead fun.h$$
The $code BenderQuad$$ argument $icode fun$$ supports the syntax
$codei%
%h% = %fun%.h(%x%, %y%)
%$$
The $icode%fun%.h%$$ argument $icode x$$ has prototype
$codei%
const %ADvector% &%x%
%$$
and its size must be equal to $icode n$$.
The $icode%fun%.h%$$ argument $icode y$$ has prototype
$codei%
const %BAvector% &%y%
%$$
and its size must be equal to $icode m$$.
The $icode%fun%.h%$$ result $icode h$$ has prototype
$codei%
%ADvector% %h%
%$$
and its size must be equal to $icode m$$.
The value of $icode h$$ is
$latex \[
h = H(x, y)
\] $$.
$subhead fun.dy$$
The $code BenderQuad$$ argument $icode fun$$ supports the syntax
$codei%
%dy% = %fun%.dy(%x%, %y%, %h%)
%x%
%$$
The $icode%fun%.dy%$$ argument $icode x$$ has prototype
$codei%
const %BAvector% &%x%
%$$
and its size must be equal to $icode n$$.
Its value will be exactly equal to the $code BenderQuad$$ argument
$icode x$$ and values depending on it can be stored as private objects
in $icode f$$ and need not be recalculated.
$codei%
%y%
%$$
The $icode%fun%.dy%$$ argument $icode y$$ has prototype
$codei%
const %BAvector% &%y%
%$$
and its size must be equal to $icode m$$.
Its value will be exactly equal to the $code BenderQuad$$ argument
$icode y$$ and values depending on it can be stored as private objects
in $icode f$$ and need not be recalculated.
$codei%
%h%
%$$
The $icode%fun%.dy%$$ argument $icode h$$ has prototype
$codei%
const %ADvector% &%h%
%$$
and its size must be equal to $icode m$$.
$codei%
%dy%
%$$
The $icode%fun%.dy%$$ result $icode dy$$ has prototype
$codei%
%ADvector% %dy%
%$$
and its size must be equal to $icode m$$.
The return value $icode dy$$ is given by
$latex \[
dy = - [ \partial_y H (x , y) ]^{-1} h
\] $$
Note that if $icode h$$ is equal to $latex H(x, y)$$,
$latex dy$$ is the Newton step for finding a zero
of $latex H(x, y)$$ with respect to $latex y$$;
i.e.,
$latex y + dy$$ is an approximate solution for the equation
$latex H (x, y + dy) = 0$$.
$head g$$
The argument $icode g$$ has prototype
$codei%
%BAvector% &%g%
%$$
and has size one.
The input value of its element does not matter.
On output,
it contains the value of $latex G (x)$$; i.e.,
$latex \[
g[0] = G (x)
\] $$
$head gx$$
The argument $icode gx$$ has prototype
$codei%
%BAvector% &%gx%
%$$
and has size $latex n $$.
The input values of its elements do not matter.
On output,
it contains the Jacobian of $latex G (x)$$; i.e.,
for $latex j = 0 , \ldots , n-1$$,
$latex \[
gx[ j ] = G^{(1)} (x)_j
\] $$
$head gxx$$
The argument $icode gx$$ has prototype
$codei%
%BAvector% &%gxx%
%$$
and has size $latex n \times n$$.
The input values of its elements do not matter.
On output,
it contains the Hessian of $latex G (x)$$; i.e.,
for $latex i = 0 , \ldots , n-1$$, and
$latex j = 0 , \ldots , n-1$$,
$latex \[
gxx[ i * n + j ] = G^{(2)} (x)_{i,j}
\] $$
$head BAvector$$
The type $icode BAvector$$ must be a
$cref SimpleVector$$ class.
We use $icode Base$$ to refer to the type of the elements of
$icode BAvector$$; i.e.,
$codei%
%BAvector%::value_type
%$$
$head ADvector$$
The type $icode ADvector$$ must be a
$cref SimpleVector$$ class with elements of type
$codei%AD<%Base%>%$$; i.e.,
$codei%
%ADvector%::value_type
%$$
must be the same type as
$codei%
AD< %BAvector%::value_type >
%$$.
$head Example$$
$children%
example/general/bender_quad.cpp
%$$
The file
$cref bender_quad.cpp$$
contains an example and test of this operation.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN CppAD namespace
template <class BAvector, class Fun>
void BenderQuad(
const BAvector &x ,
const BAvector &y ,
Fun fun ,
BAvector &g ,
BAvector &gx ,
BAvector &gxx )
{ // determine the base type
typedef typename BAvector::value_type Base;
// check that BAvector is a SimpleVector class
CheckSimpleVector<Base, BAvector>();
// declare the ADvector type
typedef CPPAD_TESTVECTOR(AD<Base>) ADvector;
// size of the x and y spaces
size_t n = size_t(x.size());
size_t m = size_t(y.size());
// check the size of gx and gxx
CPPAD_ASSERT_KNOWN(
g.size() == 1,
"BenderQuad: size of the vector g is not equal to 1"
);
CPPAD_ASSERT_KNOWN(
size_t(gx.size()) == n,
"BenderQuad: size of the vector gx is not equal to n"
);
CPPAD_ASSERT_KNOWN(
size_t(gxx.size()) == n * n,
"BenderQuad: size of the vector gxx is not equal to n * n"
);
// some temporary indices
size_t i, j;
// variable versions x
ADvector vx(n);
for(j = 0; j < n; j++)
vx[j] = x[j];
// declare the independent variables
Independent(vx);
// evaluate h = H(x, y)
ADvector h(m);
h = fun.h(vx, y);
// evaluate dy (x) = Newton step as a function of x through h only
ADvector dy(m);
dy = fun.dy(x, y, h);
// variable version of y
ADvector vy(m);
for(j = 0; j < m; j++)
vy[j] = y[j] + dy[j];
// evaluate G~ (x) = F [ x , y + dy(x) ]
ADvector gtilde(1);
gtilde = fun.f(vx, vy);
// AD function object that corresponds to G~ (x)
// We will make heavy use of this tape, so optimize it
ADFun<Base> Gtilde;
Gtilde.Dependent(vx, gtilde);
Gtilde.optimize();
// value of G(x)
g = Gtilde.Forward(0, x);
// initial forward direction vector as zero
BAvector dx(n);
for(j = 0; j < n; j++)
dx[j] = Base(0.0);
// weight, first and second order derivative values
BAvector dg(1), w(1), ddw(2 * n);
w[0] = 1.;
// Jacobian and Hessian of G(x) is equal Jacobian and Hessian of Gtilde
for(j = 0; j < n; j++)
{ // compute partials in x[j] direction
dx[j] = Base(1.0);
dg = Gtilde.Forward(1, dx);
gx[j] = dg[0];
// restore the dx vector to zero
dx[j] = Base(0.0);
// compute second partials w.r.t x[j] and x[l] for l = 1, n
ddw = Gtilde.Reverse(2, w);
for(i = 0; i < n; i++)
gxx[ i * n + j ] = ddw[ i * 2 + 1 ];
}
return;
}
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,241 @@
# ifndef CPPAD_CORE_BOOL_FUN_HPP
# define CPPAD_CORE_BOOL_FUN_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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 BoolFun$$
$spell
namespace
bool
CppAD
const
$$
$section AD Boolean Functions$$
$head Syntax$$
$codei%CPPAD_BOOL_UNARY(%Base%, %unary_name%)
%$$
$icode%b% = %unary_name%(%u%)
%$$
$icode%b% = %unary_name%(%x%)
%$$
$codei%CPPAD_BOOL_BINARY(%Base%, %binary_name%)
%$$
$icode%b% = %binary_name%(%u%, %v%)
%$$
$icode%b% = %binary_name%(%x%, %y%)%$$
$head Purpose$$
Create a $code bool$$ valued function that has $codei%AD<%Base%>%$$ arguments.
$head unary_name$$
This is the name of the $code bool$$ valued function with one argument
(as it is used in the source code).
The user must provide a version of $icode unary_name$$ where
the argument has type $icode Base$$.
CppAD uses this to create a version of $icode unary_name$$ where the
argument has type $codei%AD<%Base%>%$$.
$head u$$
The argument $icode u$$ has prototype
$codei%
const %Base% &%u%
%$$
It is the value at which the user provided version of $icode unary_name$$
is to be evaluated.
It is also used for the first argument to the
user provided version of $icode binary_name$$.
$head x$$
The argument $icode x$$ has prototype
$codei%
const AD<%Base%> &%x%
%$$
It is the value at which the CppAD provided version of $icode unary_name$$
is to be evaluated.
It is also used for the first argument to the
CppAD provided version of $icode binary_name$$.
$head b$$
The result $icode b$$ has prototype
$codei%
bool %b%
%$$
$head Create Unary$$
The preprocessor macro invocation
$codei%
CPPAD_BOOL_UNARY(%Base%, %unary_name%)
%$$
defines the version of $icode unary_name$$ with a $codei%AD<%Base%>%$$
argument.
This can with in a namespace
(not the $code CppAD$$ namespace)
but must be outside of any routine.
$head binary_name$$
This is the name of the $code bool$$ valued function with two arguments
(as it is used in the source code).
The user must provide a version of $icode binary_name$$ where
the arguments have type $icode Base$$.
CppAD uses this to create a version of $icode binary_name$$ where the
arguments have type $codei%AD<%Base%>%$$.
$head v$$
The argument $icode v$$ has prototype
$codei%
const %Base% &%v%
%$$
It is the second argument to
the user provided version of $icode binary_name$$.
$head y$$
The argument $icode x$$ has prototype
$codei%
const AD<%Base%> &%y%
%$$
It is the second argument to
the CppAD provided version of $icode binary_name$$.
$head Create Binary$$
The preprocessor macro invocation
$codei%
CPPAD_BOOL_BINARY(%Base%, %binary_name%)
%$$
defines the version of $icode binary_name$$ with $codei%AD<%Base%>%$$
arguments.
This can with in a namespace
(not the $code CppAD$$ namespace)
but must be outside of any routine.
$head Operation Sequence$$
The result of this operation is not an
$cref/AD of Base/glossary/AD of Base/$$ object.
Thus it will not be recorded as part of an
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Example$$
$children%
example/general/bool_fun.cpp
%$$
The file
$cref bool_fun.cpp$$
contains an example and test of these operations.
$head Deprecated 2007-07-31$$
The preprocessor symbols $code CppADCreateUnaryBool$$
and $code CppADCreateBinaryBool$$ are defined to be the same as
$code CPPAD_BOOL_UNARY$$ and $code CPPAD_BOOL_BINARY$$ respectively
(but their use is deprecated).
$end
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file bool_fun.hpp
Routines and macros that implement functions from AD<Base> to bool.
*/
/*!
Macro that defines a unary function <tt>bool F(AD<Base> x)</tt>
using <tt>bool F(Base x)</tt>.
\param Base
base for the AD type of arguments to this unary bool valued function.
\param unary_name
name of this unary function; i.e., F.
*/
# define CPPAD_BOOL_UNARY(Base, unary_name) \
inline bool unary_name (const CppAD::AD<Base> &x) \
{ \
return CppAD::AD<Base>::UnaryBool(unary_name, x); \
}
/*!
Deprecated name for CPPAD_BOOL_UNARY
*/
# define CppADCreateUnaryBool CPPAD_BOOL_UNARY
/*!
Link a function name, and AD value pair to function call with base argument
and bool retrun value.
\param FunName
is the name of the function that we are linking.
\param x
is the argument where we are evaluating the function.
*/
template <class Base>
bool AD<Base>::UnaryBool(
bool FunName(const Base &x),
const AD<Base> &x
)
{
return FunName(x.value_);
}
/*!
Macro that defines a binary function <tt>bool F(AD<Base> x, AD<Base> y)</tt>
using <tt>bool F(Base x, Base y)</tt>.
\param Base
base for the AD type of arguments to this binary bool valued function.
\param binary_name
name of this binary function; i.e., F.
*/
# define CPPAD_BOOL_BINARY(Base, binary_name) \
inline bool binary_name ( \
const CppAD::AD<Base> &x, const CppAD::AD<Base> &y) \
{ \
return CppAD::AD<Base>::BinaryBool(binary_name, x, y); \
}
/*!
Deprecated name for CPPAD_BOOL_BINARY
*/
# define CppADCreateBinaryBool CPPAD_BOOL_BINARY
/*!
Link a function name, and two AD values to function call with base arguments
and bool retrun value.
\param FunName
is the name of the function that we are linking.
\param x
is the first argument where we are evaluating the function at.
\param y
is the second argument where we are evaluating the function at.
*/
template <class Base>
bool AD<Base>::BinaryBool(
bool FunName(const Base &x, const Base &y),
const AD<Base> &x, const AD<Base> &y
)
{
return FunName(x.value_, y.value_);
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,49 @@
# ifndef CPPAD_CORE_BOOL_VALUED_HPP
# define CPPAD_CORE_BOOL_VALUED_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 BoolValued$$
$spell
Bool
$$
$section Bool Valued Operations and Functions with AD Arguments$$
$children%
include/cppad/core/compare.hpp%
include/cppad/core/near_equal_ext.hpp%
include/cppad/core/bool_fun.hpp%
include/cppad/core/con_dyn_var.hpp%
include/cppad/core/equal_op_seq.hpp
%$$
$table
$rref Compare$$
$rref NearEqualExt$$
$rref BoolFun$$
$rref con_dyn_var$$
$rref EqualOpSeq$$
$tend
$end
*/
# include <cppad/core/compare.hpp>
# include <cppad/core/near_equal_ext.hpp>
# include <cppad/core/bool_fun.hpp>
# include <cppad/core/con_dyn_var.hpp>
# include <cppad/core/equal_op_seq.hpp>
# endif

View File

@@ -0,0 +1,256 @@
# ifndef CPPAD_CORE_CAPACITY_ORDER_HPP
# define CPPAD_CORE_CAPACITY_ORDER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 capacity_order$$
$spell
var
taylor_
xq
yq
$$
$section Controlling Taylor Coefficients Memory Allocation$$
$head Syntax$$
$icode%f%.capacity_order(%c%)%$$
$subhead See Also$$
$cref seq_property$$
$head Purpose$$
The Taylor coefficients calculated by $cref Forward$$ mode calculations
are retained in an $cref ADFun$$ object for subsequent use during
$cref Reverse$$ mode and higher order Forward mode calculations.
For example, a call to $cref/Forward/forward_order/$$ with the syntax
$codei%
%yq% = %f%.Forward(%q%, %xq%)
%$$
where $icode%q% > 0%$$ and $icode%xq%.size() == %f%.Domain()%$$,
uses the lower order Taylor coefficients and
computes the $th q$$ order Taylor coefficients for all
the variables in the operation sequence corresponding to $icode f$$.
The $code capacity_order$$ operation allows you to control that
amount of memory that is retained by an AD function object
(to hold $code Forward$$ results for subsequent calculations).
$head f$$
The object $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
$head c$$
The argument $icode c$$ has prototype
$codei%
size_t %c%
%$$
It specifies the number of Taylor coefficient orders that are allocated
in the AD operation sequence corresponding to $icode f$$.
$subhead Pre-Allocating Memory$$
If you plan to make calls to $code Forward$$ with the maximum value of
$icode q$$ equal to $icode Q$$,
it should be faster to pre-allocate memory for these calls using
$codei%
%f%.capacity_order(%c%)
%$$
with $icode c$$ equal to $latex Q + 1$$.
If you do no do this, $code Forward$$ will automatically allocate memory
and will copy the results to a larger buffer, when necessary.
$pre
$$
Note that each call to $cref Dependent$$ frees the old memory
connected to the function object and sets the corresponding
taylor capacity to zero.
$subhead Freeing Memory$$
If you no longer need the Taylor coefficients of order $icode q$$
and higher (that are stored in $icode f$$),
you can reduce the memory allocated to $icode f$$ using
$codei%
%f%.capacity_order(%c%)
%$$
with $icode c$$ equal to $icode q$$.
Note that, if $cref ta_hold_memory$$ is true, this memory is not actually
returned to the system, but rather held for future use by the same thread.
$head Original State$$
If $icode f$$ is $cref/constructed/FunConstruct/$$ with the syntax
$codei%
ADFun<%Base%> %f%(%x%, %y%)
%$$,
there is an implicit call to $cref forward_zero$$ with $icode xq$$ equal to
the value of the
$cref/independent variables/glossary/Tape/Independent Variable/$$
when the AD operation sequence was recorded.
This corresponds to $icode%c% == 1%$$.
$children%
example/general/capacity_order.cpp
%$$
$head Example$$
The file
$cref capacity_order.cpp$$
contains an example and test of these operations.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file capacity_order.hpp
Control of number of orders allocated.
\}
*/
/*!
Control of number of orders and directions allocated.
\tparam Base
The type used during the forward mode computations; i.e., the corresponding
recording of operations used the type AD<Base>.
\param c
is the number of orders to allocate memory for.
If <code>c == 0</code> then r must also be zero.
In this case num_order_taylor_, cap_order_taylor_, and num_direction_taylor_
are all set to zero.
In addition, taylor_.clear() is called.
\param r
is the number of directions to allocate memory for.
If <code>c == 1</code> then r must also be one.
In all cases, it must hold that
<code>
r == num_direction_taylor_ || num_order_taylor <= 1
</code>
Upon return, num_direction_taylor_ is equal to r.
\par num_order_taylor_
The output value of num_order_taylor_ is the mininumum of its input
value and c. This minimum is the number of orders that are copied to the
new taylor coefficient buffer.
\par num_direction_taylor_
The output value of num_direction_taylor_ is equal to r.
*/
template <class Base, class RecBase>
void ADFun<Base,RecBase>::capacity_order(size_t c, size_t r)
{ // temporary indices
size_t i, k, ell;
if( (c == cap_order_taylor_) & (r == num_direction_taylor_) )
return;
if( c == 0 )
{ CPPAD_ASSERT_UNKNOWN( r == 0 );
taylor_.clear();
num_order_taylor_ = 0;
cap_order_taylor_ = 0;
num_direction_taylor_ = r;
return;
}
CPPAD_ASSERT_UNKNOWN(r==num_direction_taylor_ || num_order_taylor_<=1);
// Allocate new taylor with requested number of orders and directions
size_t new_len = ( (c-1)*r + 1 ) * num_var_tape_;
local::pod_vector_maybe<Base> new_taylor(new_len);
// number of orders to copy
size_t p = std::min(num_order_taylor_, c);
if( p > 0 )
{
// old order capacity
size_t C = cap_order_taylor_;
// old number of directions
size_t R = num_direction_taylor_;
// copy the old data into the new matrix
CPPAD_ASSERT_UNKNOWN( p == 1 || r == R );
for(i = 0; i < num_var_tape_; i++)
{ // copy zero order
size_t old_index = ((C-1) * R + 1) * i + 0;
size_t new_index = ((c-1) * r + 1) * i + 0;
new_taylor[ new_index ] = taylor_[ old_index ];
// copy higher orders
for(k = 1; k < p; k++)
{ for(ell = 0; ell < R; ell++)
{ old_index = ((C-1) * R + 1) * i + (k-1) * R + ell + 1;
new_index = ((c-1) * r + 1) * i + (k-1) * r + ell + 1;
new_taylor[ new_index ] = taylor_[ old_index ];
}
}
}
}
// replace taylor_ by new_taylor
taylor_.swap(new_taylor);
cap_order_taylor_ = c;
num_order_taylor_ = p;
num_direction_taylor_ = r;
// note that the destructor for new_taylor will free the old taylor memory
return;
}
/*!
User API control of number of orders allocated.
\tparam Base
The type used during the forward mode computations; i.e., the corresponding
recording of operations used the type AD<Base>.
\param c
is the number of orders to allocate memory for.
If <code>c == 0</code>,
num_order_taylor_, cap_order_taylor_, and num_direction_taylor_
are all set to zero.
In addition, taylor_.clear() is called.
\par num_order_taylor_
The output value of num_order_taylor_ is the mininumum of its input
value and c. This minimum is the number of orders that are copied to the
new taylor coefficient buffer.
\par num_direction_taylor_
If is zero (one), num_direction_taylor_ is set to zero (one).
Otherwise, if num_direction_taylor_ is zero, it is set to one.
Othwerwise, num_direction_taylor_ is not modified.
*/
template <class Base, class RecBase>
void ADFun<Base,RecBase>::capacity_order(size_t c)
{ size_t r;
if( (c == 0) | (c == 1) )
{ r = c;
capacity_order(c, r);
return;
}
r = num_direction_taylor_;
if( r == 0 )
r = 1;
capacity_order(c, r);
return;
}
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,244 @@
# ifndef CPPAD_CORE_CHECK_FOR_NAN_HPP
# define CPPAD_CORE_CHECK_FOR_NAN_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 check_for_nan$$
$spell
std
vec
Cpp
const
bool
newline
$$
$section Check an ADFun Object For Nan Results$$
$head Syntax$$
$icode%f%.check_for_nan(%b%)
%$$
$icode%b% = %f%.check_for_nan()
%$$
$codei%get_check_for_nan(%vec%, %file%)
%$$
$head Debugging$$
If $code NDEBUG$$ is not defined, and
the result of a $cref/forward/forward_order/$$ or $cref/reverse/reverse_any/$$
calculation contains a $cref nan$$,
CppAD can halt with an error message.
$head f$$
For the syntax where $icode b$$ is an argument,
$icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
(see $codei%ADFun<%Base%>%$$ $cref/constructor/FunConstruct/$$).
For the syntax where $icode b$$ is the result,
$icode f$$ has prototype
$codei%
const ADFun<%Base%> %f%
%$$
$head b$$
This argument or result has prototype
$codei%
bool %b%
%$$
If $icode b$$ is true (false),
future calls to $icode%f%.Forward%$$ will (will not) check for $code nan$$.
$head Default$$
The value for this setting after construction of $icode f$$ is true.
The value of this setting is not affected by calling
$cref Dependent$$ for this function object.
$head Error Message$$
If this error is detected during zero order forward mode,
the values of the independent variables that resulted in the $code nan$$
are written to a temporary binary file.
This is so that you can run the original source code with those values
to see what is causing the $code nan$$.
$subhead vector_size$$
The error message with contain the text
$codei%vector_size = %vector_size%$$ followed the newline character
$code '\n'$$.
The value of $icode vector_size$$ is the number of elements
in the independent vector.
$subhead file_name$$
The error message with contain the text
$codei%file_name = %file_name%$$ followed the newline character
$code '\n'$$.
The value of $icode file_name$$ is the name of the temporary file
that contains the dependent variable values.
$subhead index$$
The error message will contain the text
$codei%index = %index%$$ followed by the newline character $code '\n'$$.
The value of $icode index$$ is the lowest dependent variable index
that has the value $code nan$$.
$head get_check_for_nan$$
This routine can be used to get the independent variable
values that result in a $code nan$$.
$subhead vec$$
This argument has prototype
$codei%
CppAD::vector<%Base%>& %vec%
%$$
It size must be equal to the corresponding value of
$cref/vector_size/check_for_nan/Error Message/vector_size/$$
in the corresponding error message.
The input value of its elements does not matter.
Upon return, it will contain the values for the independent variables,
in the corresponding call to $cref Independent$$,
that resulted in the $code nan$$.
(Note that the call to $code Independent$$ uses an vector with elements
of type $codei%AD<%Base%>%$$ and $icode vec$$ has elements of type
$icode Base$$.)
$subhead file$$
This argument has prototype
$codei%
const std::string& %file%
%$$
It must be the value of
$cref/file_name/check_for_nan/Error Message/file_name/$$
in the corresponding error message.
$head Example$$
$children%
example/general/check_for_nan.cpp
%$$
The file
$cref check_for_nan.cpp$$
contains an example and test of these operations.
$end
*/
# include <cppad/utility/vector.hpp>
# include <cppad/configure.hpp>
# include <fstream>
# if CPPAD_HAS_MKSTEMP
# include <stdlib.h>
# include <unistd.h>
# else
# if CPPAD_HAS_TMPNAM_S
# include <stdio.h>
# else
# include <stdlib.h>
# endif
# endif
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
Set check_for_nan
\param value
new value for this flag.
*/
template <class Base, class RecBase>
void ADFun<Base,RecBase>::check_for_nan(bool value)
{ check_for_nan_ = value; }
/*!
Get check_for_nan
\return
current value of check_for_nan_.
*/
template <class Base, class RecBase>
bool ADFun<Base,RecBase>::check_for_nan(void) const
{ return check_for_nan_; }
/*!
Stores a vector in a file when nans occur.
\param vec [in]
is the vector that is stored.
\param [out] file_name
is the file where the vector is stored
*/
template <class Base>
void put_check_for_nan(const CppAD::vector<Base>& vec, std::string& file_name)
{
size_t char_size = sizeof(Base) * vec.size();
// 2DO: add vec.data() to C11 tests and use it when C11 true
// const char* char_ptr = reinterpret_cast<const char*>( vec.data() );
const char* char_ptr = reinterpret_cast<const char*>( &vec[0] );
# if CPPAD_HAS_MKSTEMP
char pattern[] = "/tmp/fileXXXXXX";
int fd = mkstemp(pattern);
file_name = pattern;
ssize_t flag = write(fd, char_ptr, char_size);
if( flag < 0 )
{ std::cerr << "put_check_nan: write error\n";
std::exit(1);
}
close(fd);
# else
# if CPPAD_HAS_TMPNAM_S
std::vector<char> name(L_tmpnam_s);
// if( tmpnam_s( name.data(), L_tmpnam_s ) != 0 )
if( tmpnam_s( &name[0], L_tmpnam_s ) != 0 )
{ CPPAD_ASSERT_KNOWN(
false,
"Cannot create a temporary file name"
);
}
// file_name = name.data();
file_name = &name[0];
# else
file_name = tmpnam( nullptr );
# endif
std::fstream file_out(file_name.c_str(), std::ios::out|std::ios::binary );
file_out.write(char_ptr, char_size);
file_out.close();
# endif
return;
}
/*!
Gets a vector that was stored by put_check_for_nan.
\param vec [out]
is the vector that is stored.
\param file_name [in]
is the file where the vector is stored
*/
template <class Base>
void get_check_for_nan(CppAD::vector<Base>& vec, const std::string& file_name)
{ //
std::streamsize char_size = std::streamsize( sizeof(Base) * vec.size() );
// char* char_ptr = reinterpret_cast<char*>( vec.data() );
char* char_ptr = reinterpret_cast<char*>( &vec[0] );
//
std::fstream file_in(file_name.c_str(), std::ios::in|std::ios::binary );
file_in.read(char_ptr, char_size);
//
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,621 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_CHKPOINT_ONE_HPP
# define CPPAD_CORE_CHKPOINT_ONE_CHKPOINT_ONE_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.
---------------------------------------------------------------------------- */
# include <cppad/local/sparse/list_setvec.hpp>
# include <cppad/local/sparse/pack_setvec.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_one.hpp
First generation checkpoint functions.
*/
/*
$begin chkpoint_one$$
$spell
mul
chkpoint
alloc
inuse
sv
var
cppad.hpp
CppAD
checkpoint
checkpointing
algo
atom_fun
const
enum
bool
recomputed
$$
$section Checkpoint Functions: First Generation$$
$head Deprecated 2019-01-14$$
Using the $code checkpoint$$ class has been deprecated.
Use $cref chkpoint_two$$ instead.
$head Syntax$$
$codei%checkpoint<%Base%> %atom_fun%(
%name%, %algo%, %ax%, %ay%, %sparsity%, %optimize%
)
%sv% = %atom_fun%.size_var()
%atom_fun%.option(%option_value%)
%algo%(%ax%, %ay%)
%atom_fun%(%ax%, %ay%)
checkpoint<%Base%>::clear()%$$
$head See Also$$
$cref atomic_two$$, $cref rev_checkpoint.cpp$$
$head Purpose$$
$subhead Reduce Memory$$
You can reduce the size of the tape and memory required for AD by
checkpointing functions of the form $latex y = f(x)$$ where
$latex f : \B{R}^n \rightarrow \B{R}^m$$.
$subhead Faster Recording$$
It may also reduce the time to make a recording the same function
for different values of the independent variable.
Note that the operation sequence for a recording that uses $latex f(x)$$
may depend on its independent variables.
$subhead Repeating Forward$$
Normally, CppAD store $cref forward$$ mode results until they freed
using $cref capacity_order$$ or the corresponding $cref ADFun$$ object is
deleted. This is not true for checkpoint functions because a checkpoint
function may be used repeatedly with different arguments in the same tape.
Thus, forward mode results are recomputed each time a checkpoint function
is used during a forward or reverse mode sweep.
$subhead Restriction$$
The $cref/operation sequence/glossary/Operation/Sequence/$$
representing $latex f(x)$$ cannot depend on the value of $latex x$$.
The approach in the $cref rev_checkpoint.cpp$$ example case be applied
when the operation sequence depends on $latex x$$.
$subhead Multiple Level AD$$
If $icode Base$$ is an AD type, it is possible to record $icode Base$$
operations.
Note that $icode atom_fun$$ will treat $icode algo$$ as an atomic
operation while recording $codei%AD%<%Base%>%$$ operations, but not while
recording $icode Base$$ operations.
See the $code chkpoint_one_mul_level.cpp$$ example.
$head Method$$
The $code checkpoint$$ class is derived from $code atomic_base$$
and makes this easy.
It implements all the $code atomic_base$$
$cref/virtual functions/atomic_two/Virtual Functions/$$
and hence its source code $code cppad/core/chkpoint_one/chkpoint_one.hpp$$
provides an example implementation of $cref atomic_two$$.
The difference is that $code chkpoint_one.hpp$$ uses AD
instead of user provided derivatives.
$head constructor$$
The syntax for the checkpoint constructor is
$codei%
checkpoint<%Base%> %atom_fun%(%name%, %algo%, %ax%, %ay%)
%$$
$list number$$
This constructor cannot be called in $cref/parallel/ta_in_parallel/$$ mode.
$lnext
You cannot currently be recording
$codei%AD<%Base%>%$$ operations when the constructor is called.
$lnext
This object $icode atom_fun$$ must not be destructed for as long
as any $codei%ADFun<%Base%>%$$ object uses its atomic operation.
$lnext
This class is implemented as a derived class of
$cref/atomic/atomic_two_ctor/atomic_base/$$ and hence
some of its error message will refer to $code atomic_base$$.
$lend
$head Base$$
The type $icode Base$$ specifies the base type for AD operations.
$head ADVector$$
The type $icode ADVector$$ must be a
$cref/simple vector class/SimpleVector/$$ with elements of type
$codei%AD<%Base%>%$$.
$head name$$
This $icode checkpoint$$ constructor argument has prototype
$codei%
const char* %name%
%$$
It is the name used for error reporting.
The suggested value for $icode name$$ is $icode atom_fun$$; i.e.,
the same name as used for the object being constructed.
$head ax$$
This argument has prototype
$codei%
const %ADVector%& %ax%
%$$
and size must be equal to $icode n$$.
It specifies vector $latex x \in \B{R}^n$$
at which an $codei%AD<%Base%>%$$ version of
$latex y = f(x)$$ is to be evaluated.
$head ay$$
This argument has prototype
$codei%
%ADVector%& %ay%
%$$
Its input size must be equal to $icode m$$ and does not change.
The input values of its elements do not matter.
Upon return, it is an $codei%AD<%Base%>%$$ version of
$latex y = f(x)$$.
$head sparsity$$
This argument has prototype
$codei%
atomic_base<%Base%>::option_enum %sparsity%
%$$
It specifies $cref/sparsity/atomic_two_ctor/atomic_base/sparsity/$$
in the $code atomic_base$$ constructor and must be either
$codei%atomic_base<%Base%>::pack_sparsity_enum%$$,
$codei%atomic_base<%Base%>::bool_sparsity_enum%$$, or
$codei%atomic_base<%Base%>::set_sparsity_enum%$$.
This argument is optional and its default value is unspecified.
$head optimize$$
This argument has prototype
$codei%
bool %optimize%
%$$
It specifies if the recording corresponding to the atomic function
should be $cref/optimized/optimize/$$.
One expects to use a checkpoint function many times, so it should
be worth the time to optimize its operation sequence.
For debugging purposes, it may be useful to use the
original operation sequence (before optimization)
because it corresponds more closely to $icode algo$$.
This argument is optional and its default value is true.
$head size_var$$
This $code size_var$$ member function return value has prototype
$codei%
size_t %sv%
%$$
It is the $cref/size_var/seq_property/size_var/$$ for the
$codei%ADFun<%Base%>%$$ object is used to store the operation sequence
corresponding to $icode algo$$.
$head option$$
The $code option$$ syntax can be used to set the type of sparsity
pattern used by $icode atom_fun$$.
This is an $codei%atomic_base<%Base%>%$$ function and its documentation
can be found at $cref atomic_two_option$$.
$head algo$$
The type of $icode algo$$ is arbitrary, except for the fact that
the syntax
$codei%
%algo%(%ax%, %ay%)
%$$
must evaluate the function $latex y = f(x)$$ using
$codei%AD<%Base%>%$$ operations.
In addition, we assume that the
$cref/operation sequence/glossary/Operation/Sequence/$$
does not depend on the value of $icode ax$$.
$head atom_fun$$
Given $icode ax$$ it computes the corresponding value of $icode ay$$
using the operation sequence corresponding to $icode algo$$.
If $codei%AD<%Base%>%$$ operations are being recorded,
it enters the computation as single operation in the recording
see $cref/start recording/Independent/Start Recording/$$.
(Currently each use of $icode atom_fun$$ actually corresponds to
$icode%m%+%n%+2%$$ operations and creates $icode m$$ new variables,
but this is not part of the CppAD specifications and my change.)
$head Memory$$
$subhead Restriction$$
The $code clear$$ routine cannot be called
while in $cref/parallel/ta_in_parallel/$$ execution mode.
$head Parallel Mode$$
The CppAD checkpoint function delays the caching of certain calculations
until they are needed.
In $cref/parallel model/ta_parallel_setup/$$,
this may result in $cref/thread_alloc::inuse(thread)/ta_inuse/$$
being non-zero even though the specified thread is no longer active.
This memory will be freed when the checkpoint object is deleted.
$subhead clear$$
The $code atomic_base$$ class holds onto static work space
that is not connected to a particular object
(in order to increase speed by avoiding system memory allocation calls).
This call makes to work space $cref/available/ta_available/$$ to
for other uses by the same thread.
This should be called when you are done using the
atomic functions for a specific value of $icode Base$$.
$end
*/
template <class Base>
class checkpoint : public atomic_base<Base> {
// ---------------------------------------------------------------------------
private:
/// same as option_enum in base class
typedef typename atomic_base<Base>::option_enum option_enum;
//
// ------------------------------------------------------------------------
// member_
// ------------------------------------------------------------------------
// same checkpoint object can be used by multiple threads
struct member_struct {
//
/// AD function corresponding to this checkpoint object
ADFun<Base> f_;
ADFun< AD<Base>, Base > af_;
//
/// sparsity for entire Jacobian f(x)^{(1)}
/// does not change so can cache it
local::sparse::list_setvec jac_sparse_set_;
vectorBool jac_sparse_bool_;
//
/// sparsity for sum_i f_i(x)^{(2)} does not change so can cache it
local::sparse::list_setvec hes_sparse_set_;
vectorBool hes_sparse_bool_;
};
/// This version of work is const except during constructor
member_struct const_member_;
/// use pointers and allocate memory to avoid false sharing
member_struct* member_[CPPAD_MAX_NUM_THREADS];
//
/// allocate member_ for this thread
void allocate_member(size_t thread)
{ if( member_[thread] == nullptr )
{ member_[thread] = new member_struct;
// The function is recorded in sequential mode and placed in
// const_member_.f_, other threads have copy.
member_[thread]->f_ = const_member_.f_;
}
return;
}
//
/// free member_ for this thread
void free_member(size_t thread)
{ if( member_[thread] != nullptr )
{ delete member_[thread];
member_[thread] = nullptr;
}
return;
}
// ------------------------------------------------------------------------
option_enum sparsity(void)
{ return static_cast< atomic_base<Base>* >(this)->sparsity(); }
// ------------------------------------------------------------------------
/// set jac_sparse_set_
void set_jac_sparse_set(void);
/// set jac_sparse_bool_
void set_jac_sparse_bool(void);
// ------------------------------------------------------------------------
/// set hes_sparse_set_
void set_hes_sparse_set(void);
/// set hes_sparse_bool_
void set_hes_sparse_bool(void);
// ------------------------------------------------------------------------
/*!
Link from user_atomic to forward sparse Jacobian pack and bool
\copydetails atomic_base::for_sparse_jac
*/
template <class sparsity_type>
bool for_sparse_jac(
size_t q ,
const sparsity_type& r ,
sparsity_type& s ,
const vector<Base>& x
);
// ------------------------------------------------------------------------
/*!
Link from user_atomic to reverse sparse Jacobian pack and bool
\copydetails atomic_base::rev_sparse_jac
*/
template <class sparsity_type>
bool rev_sparse_jac(
size_t q ,
const sparsity_type& rt ,
sparsity_type& st ,
const vector<Base>& x
);
/*!
Link from user_atomic to reverse sparse Hessian bools
\copydetails atomic_base::rev_sparse_hes
*/
template <class sparsity_type>
bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const sparsity_type& r ,
const sparsity_type& u ,
sparsity_type& v ,
const vector<Base>& x
);
public:
// ------------------------------------------------------------------------
/*!
Constructor of a checkpoint object
\param name [in]
is the user's name for the AD version of this atomic operation.
\param algo [in/out]
user routine that compute AD function values
(not const because state may change during evaluation).
\param ax [in]
argument value where algo operation sequence is taped.
\param ay [out]
function value at specified argument value.
\param sparsity [in]
what type of sparsity patterns are computed by this function,
pack_sparsity_enum bool_sparsity_enum, or set_sparsity_enum.
The default value is unspecified.
\param optimize [in]
should the operation sequence corresponding to the algo be optimized.
The default value is true, but it is
sometimes useful to use false for debugging purposes.
*/
template <class Algo, class ADVector>
checkpoint(
const char* name ,
Algo& algo ,
const ADVector& ax ,
ADVector& ay ,
option_enum sparsity =
atomic_base<Base>::pack_sparsity_enum ,
bool optimize = true
);
/// destructor
~checkpoint(void)
{
# ifndef NDEBUG
if( thread_alloc::in_parallel() )
{ std::string msg = atomic_base<Base>::atomic_name();
msg += ": checkpoint destructor called in parallel mode.";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread)
free_member(thread);
}
// ------------------------------------------------------------------------
/*!
Implement the user call to atom_fun.size_var().
*/
size_t size_var(void)
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return member_[thread]->f_.size_var();
}
// ------------------------------------------------------------------------
/*!
Implement the user call to atom_fun(ax, ay).
\tparam ADVector
A simple vector class with elements of type AD<Base>.
\param id
optional parameter which must be zero if present.
\param ax
is the argument vector for this call,
ax.size() determines the number of arguments.
\param ay
is the result vector for this call,
ay.size() determines the number of results.
*/
template <class ADVector>
void operator()(const ADVector& ax, ADVector& ay, size_t id = 0)
{ CPPAD_ASSERT_KNOWN(
id == 0,
"checkpoint: id is non-zero in atom_fun(ax, ay, id)"
);
this->atomic_base<Base>::operator()(ax, ay, id);
}
// ------------------------------------------------------------------------
/*!
Link from user_atomic to forward mode
\copydetails atomic_base::forward
*/
virtual bool forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector<Base>& tx ,
vector<Base>& ty
);
virtual bool forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector< AD<Base> >& atx ,
vector< AD<Base> >& aty
);
// ------------------------------------------------------------------------
/*!
Link from user_atomic to reverse mode
\copydetails atomic_base::reverse
*/
virtual bool reverse(
size_t q ,
const vector<Base>& tx ,
const vector<Base>& ty ,
vector<Base>& px ,
const vector<Base>& py
);
virtual bool reverse(
size_t q ,
const vector< AD<Base> >& atx ,
const vector< AD<Base> >& aty ,
vector< AD<Base> >& apx ,
const vector< AD<Base> >& apy
);
// ------------------------------------------------------------------------
/*!
Link from user_atomic to forward sparse Jacobian pack
\copydetails atomic_base::for_sparse_jac
*/
virtual bool for_sparse_jac(
size_t q ,
const vectorBool& r ,
vectorBool& s ,
const vector<Base>& x
);
/*!
Link from user_atomic to forward sparse Jacobian bool
\copydetails atomic_base::for_sparse_jac
*/
virtual bool for_sparse_jac(
size_t q ,
const vector<bool>& r ,
vector<bool>& s ,
const vector<Base>& x
);
/*!
Link from user_atomic to forward sparse Jacobian sets
\copydetails atomic_base::for_sparse_jac
*/
virtual bool for_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& r ,
vector< std::set<size_t> >& s ,
const vector<Base>& x
);
// ------------------------------------------------------------------------
/*!
Link from user_atomic to reverse sparse Jacobian pack
\copydetails atomic_base::rev_sparse_jac
*/
virtual bool rev_sparse_jac(
size_t q ,
const vectorBool& rt ,
vectorBool& st ,
const vector<Base>& x
);
/*!
Link from user_atomic to reverse sparse Jacobian bool
\copydetails atomic_base::rev_sparse_jac
*/
virtual bool rev_sparse_jac(
size_t q ,
const vector<bool>& rt ,
vector<bool>& st ,
const vector<Base>& x
);
/*!
Link from user_atomic to reverse Jacobian sets
\copydetails atomic_base::rev_sparse_jac
*/
virtual bool rev_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& rt ,
vector< std::set<size_t> >& st ,
const vector<Base>& x
);
// ------------------------------------------------------------------------
/*!
Link from user_atomic to reverse sparse Hessian pack
\copydetails atomic_base::rev_sparse_hes
*/
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vectorBool& r ,
const vectorBool& u ,
vectorBool& v ,
const vector<Base>& x
);
/*!
Link from user_atomic to reverse sparse Hessian bool
\copydetails atomic_base::rev_sparse_hes
*/
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector<bool>& r ,
const vector<bool>& u ,
vector<bool>& v ,
const vector<Base>& x
);
/*!
Link from user_atomic to reverse sparse Hessian sets
\copydetails atomic_base::rev_sparse_hes
*/
virtual bool rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector< std::set<size_t> >& r ,
const vector< std::set<size_t> >& u ,
vector< std::set<size_t> >& v ,
const vector<Base>& x
);
};
} // END_CPPAD_NAMESPACE
// functions implemented in cppad/core/checkpoint files
# include <cppad/core/chkpoint_one/ctor.hpp>
# include <cppad/core/chkpoint_one/reverse.hpp>
# include <cppad/core/chkpoint_one/forward.hpp>
# include <cppad/core/chkpoint_one/rev_sparse_hes.hpp>
# include <cppad/core/chkpoint_one/rev_sparse_jac.hpp>
# include <cppad/core/chkpoint_one/for_sparse_jac.hpp>
# include <cppad/core/chkpoint_one/set_hes_sparse_bool.hpp>
# include <cppad/core/chkpoint_one/set_hes_sparse_set.hpp>
# include <cppad/core/chkpoint_one/set_jac_sparse_bool.hpp>
# include <cppad/core/chkpoint_one/set_jac_sparse_set.hpp>
# endif

View File

@@ -0,0 +1,62 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_CTOR_HPP
# define CPPAD_CORE_CHKPOINT_ONE_CTOR_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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
template <class Algo, class ADVector>
checkpoint<Base>::checkpoint(
const char* name ,
Algo& algo ,
const ADVector& ax ,
ADVector& ay ,
option_enum sparsity ,
bool optimize
) : atomic_base<Base>(name, sparsity)
{
# ifndef NDEBUG
if( thread_alloc::in_parallel() )
{ std::string msg = name;
msg += ": checkpoint constructor called in parallel mode.";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread)
member_[thread] = nullptr;
//
CheckSimpleVector< CppAD::AD<Base> , ADVector>();
//
// make a copy of ax because Independent modifies AD information
ADVector x_tmp(ax);
// delcare x_tmp as the independent variables
Independent(x_tmp);
// record mapping from x_tmp to ay
algo(x_tmp, ay);
// create function f_ : x -> y
const_member_.f_.Dependent(ay);
if( optimize )
{ // suppress checking for nan in f_ results
// (see optimize documentation for atomic functions)
const_member_.f_.check_for_nan(false);
//
// now optimize
const_member_.f_.optimize();
}
// now disable checking of comparison operations
// 2DO: add a debugging mode that checks for changes and aborts
const_member_.f_.compare_change_count(0);
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,135 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_FOR_SPARSE_JAC_HPP
# define CPPAD_CORE_CHKPOINT_ONE_FOR_SPARSE_JAC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
template <class sparsity_type>
bool checkpoint<Base>::for_sparse_jac(
size_t q ,
const sparsity_type& r ,
sparsity_type& s ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
// during user sparsity calculations
size_t m = member_[thread]->f_.Range();
size_t n = member_[thread]->f_.Domain();
if( member_[thread]->jac_sparse_bool_.size() == 0 )
set_jac_sparse_bool();
if( member_[thread]->jac_sparse_set_.n_set() != 0 )
member_[thread]->jac_sparse_set_.resize(0, 0);
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == m * n );
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == 0 );
CPPAD_ASSERT_UNKNOWN( r.size() == n * q );
CPPAD_ASSERT_UNKNOWN( s.size() == m * q );
//
bool ok = true;
for(size_t i = 0; i < m; i++)
{ for(size_t k = 0; k < q; k++)
s[i * q + k] = false;
}
// sparsity for s = jac_sparse_bool_ * r
for(size_t i = 0; i < m; i++)
{ for(size_t k = 0; k < q; k++)
{ // initialize sparsity for S(i,k)
bool s_ik = false;
// S(i,k) = sum_j J(i,j) * R(j,k)
for(size_t j = 0; j < n; j++)
{ bool J_ij = member_[thread]->jac_sparse_bool_[ i * n + j];
bool R_jk = r[j * q + k ];
s_ik |= ( J_ij & R_jk );
}
s[i * q + k] = s_ik;
}
}
return ok;
}
template <class Base>
bool checkpoint<Base>::for_sparse_jac(
size_t q ,
const vectorBool& r ,
vectorBool& s ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return for_sparse_jac< vectorBool >(q, r, s, x);
}
template <class Base>
bool checkpoint<Base>::for_sparse_jac(
size_t q ,
const vector<bool>& r ,
vector<bool>& s ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return for_sparse_jac< vector<bool> >(q, r, s, x);
}
template <class Base>
bool checkpoint<Base>::for_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& r ,
vector< std::set<size_t> >& s ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
// during user sparsity calculations
size_t m = member_[thread]->f_.Range();
size_t n = member_[thread]->f_.Domain();
if( member_[thread]->jac_sparse_bool_.size() != 0 )
member_[thread]->jac_sparse_bool_.clear();
if( member_[thread]->jac_sparse_set_.n_set() == 0 )
set_jac_sparse_set();
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == 0 );
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == m );
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.end() == n );
CPPAD_ASSERT_UNKNOWN( r.size() == n );
CPPAD_ASSERT_UNKNOWN( s.size() == m );
bool ok = true;
for(size_t i = 0; i < m; i++)
s[i].clear();
// sparsity for s = jac_sparse_set_ * r
for(size_t i = 0; i < m; i++)
{ // compute row i of the return pattern
local::sparse::list_setvec::const_iterator set_itr(
member_[thread]->jac_sparse_set_, i
);
size_t j = *set_itr;
while(j < n )
{ std::set<size_t>::const_iterator itr_j;
const std::set<size_t>& r_j( r[j] );
for(itr_j = r_j.begin(); itr_j != r_j.end(); itr_j++)
{ size_t k = *itr_j;
CPPAD_ASSERT_UNKNOWN( k < q );
s[i].insert(k);
}
j = *(++set_itr);
}
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,170 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_FORWARD_HPP
# define CPPAD_CORE_CHKPOINT_ONE_FORWARD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
// ---------------------------------------------------------------------------
template <class Base>
bool checkpoint<Base>::forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector<Base>& tx ,
vector<Base>& ty )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
//
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 );
CPPAD_ASSERT_UNKNOWN( tx.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( ty.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( n == tx.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( m == ty.size() / (q+1) );
bool ok = true;
//
if( vx.size() == 0 )
{ // during user forward mode
if( member_[thread]->jac_sparse_set_.n_set() != 0 )
member_[thread]->jac_sparse_set_.resize(0,0);
if( member_[thread]->jac_sparse_bool_.size() != 0 )
member_[thread]->jac_sparse_bool_.clear();
//
if( member_[thread]->hes_sparse_set_.n_set() != 0 )
member_[thread]->hes_sparse_set_.resize(0,0);
if( member_[thread]->hes_sparse_bool_.size() != 0 )
member_[thread]->hes_sparse_bool_.clear();
}
if( vx.size() > 0 )
{ // need Jacobian sparsity pattern to determine variable relation
// during user recording using checkpoint functions
if( sparsity() == atomic_base<Base>::set_sparsity_enum )
{ if( member_[thread]->jac_sparse_set_.n_set() == 0 )
set_jac_sparse_set();
CPPAD_ASSERT_UNKNOWN(
member_[thread]->jac_sparse_set_.n_set() == m
);
CPPAD_ASSERT_UNKNOWN(
member_[thread]->jac_sparse_set_.end() == n
);
//
for(size_t i = 0; i < m; i++)
{ vy[i] = false;
local::sparse::list_setvec::const_iterator set_itr(
member_[thread]->jac_sparse_set_, i
);
size_t j = *set_itr;
while(j < n )
{ // y[i] depends on the value of x[j]
// cast avoid Microsoft warning (should not be needed)
vy[i] |= static_cast<bool>( vx[j] );
j = *(++set_itr);
}
}
}
else
{ if( member_[thread]->jac_sparse_set_.n_set() != 0 )
member_[thread]->jac_sparse_set_.resize(0, 0);
if( member_[thread]->jac_sparse_bool_.size() == 0 )
set_jac_sparse_bool();
CPPAD_ASSERT_UNKNOWN(
member_[thread]->jac_sparse_set_.n_set() == 0
);
CPPAD_ASSERT_UNKNOWN(
member_[thread]->jac_sparse_bool_.size() == m * n
);
//
for(size_t i = 0; i < m; i++)
{ vy[i] = false;
for(size_t j = 0; j < n; j++)
{ if( member_[thread]->jac_sparse_bool_[ i * n + j ] )
{ // y[i] depends on the value of x[j]
// cast avoid Microsoft warning
vy[i] |= static_cast<bool>( vx[j] );
}
}
}
}
}
// compute forward results for orders zero through q
ty = member_[thread]->f_.Forward(q, tx);
// no longer need the Taylor coefficients in f_
// (have to reconstruct them every time)
// Hold onto sparsity pattern because it is always good.
size_t c = 0;
size_t r = 0;
member_[thread]->f_.capacity_order(c, r);
return ok;
}
// ---------------------------------------------------------------------------
template <class Base>
bool checkpoint<Base>::forward(
size_t p ,
size_t q ,
const vector<bool>& vx ,
vector<bool>& vy ,
const vector< AD<Base> >& atx ,
vector< AD<Base> >& aty )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
// make sure af_ is defined
if( member_[thread]->af_.size_var() == 0 )
member_[thread]->af_ = member_[thread]->f_.base2ad();
//
# ifndef NDEBUG
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
# endif
//
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 );
CPPAD_ASSERT_UNKNOWN( atx.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( aty.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( n == atx.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( m == aty.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( vx.size() == 0 )
bool ok = true;
//
// during user forward mode
if( member_[thread]->jac_sparse_set_.n_set() != 0 )
member_[thread]->jac_sparse_set_.resize(0,0);
if( member_[thread]->jac_sparse_bool_.size() != 0 )
member_[thread]->jac_sparse_bool_.clear();
//
if( member_[thread]->hes_sparse_set_.n_set() != 0 )
member_[thread]->hes_sparse_set_.resize(0,0);
if( member_[thread]->hes_sparse_bool_.size() != 0 )
member_[thread]->hes_sparse_bool_.clear();
//
// compute forward results for orders zero through q
aty = member_[thread]->af_.Forward(q, atx);
// no longer need the Taylor coefficients in af_
// (have to reconstruct them every time)
// Hold onto sparsity pattern because it is always good.
size_t c = 0;
size_t r = 0;
member_[thread]->af_.capacity_order(c, r);
//
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,214 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_HES_HPP
# define CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_HES_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
template <class sparsity_type>
bool checkpoint<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const sparsity_type& r ,
const sparsity_type& u ,
sparsity_type& v ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
size_t n = member_[thread]->f_.Domain();
# ifndef NDEBUG
size_t m = member_[thread]->f_.Range();
# endif
CPPAD_ASSERT_UNKNOWN( vx.size() == n );
CPPAD_ASSERT_UNKNOWN( s.size() == m );
CPPAD_ASSERT_UNKNOWN( t.size() == n );
CPPAD_ASSERT_UNKNOWN( r.size() == n * q );
CPPAD_ASSERT_UNKNOWN( u.size() == m * q );
CPPAD_ASSERT_UNKNOWN( v.size() == n * q );
//
bool ok = true;
// make sure hes_sparse_bool_ has been set
if( member_[thread]->hes_sparse_bool_.size() == 0 )
set_hes_sparse_bool();
if( member_[thread]->hes_sparse_set_.n_set() != 0 )
member_[thread]->hes_sparse_set_.resize(0, 0);
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == n * n );
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == 0 );
// compute sparsity pattern for T(x) = S(x) * f'(x)
t = member_[thread]->f_.RevSparseJac(1, s);
# ifndef NDEBUG
for(size_t j = 0; j < n; j++)
CPPAD_ASSERT_UNKNOWN( vx[j] || ! t[j] )
# endif
// V(x) = f'(x)^T * g''(y) * f'(x) * R + g'(y) * f''(x) * R
// U(x) = g''(y) * f'(x) * R
// S(x) = g'(y)
// compute sparsity pattern for A(x) = f'(x)^T * U(x)
bool transpose = true;
sparsity_type a(n * q);
a = member_[thread]->f_.RevSparseJac(q, u, transpose);
// Need sparsity pattern for H(x) = (S(x) * f(x))''(x) * R,
// but use less efficient sparsity for f(x)''(x) * R so that
// hes_sparse_set_ can be used every time this is needed.
for(size_t i = 0; i < n; i++)
{ for(size_t k = 0; k < q; k++)
{ // initialize sparsity pattern for H(i,k)
bool h_ik = false;
// H(i,k) = sum_j f''(i,j) * R(j,k)
for(size_t j = 0; j < n; j++)
{ bool f_ij = member_[thread]->hes_sparse_bool_[i * n + j];
bool r_jk = r[j * q + k];
h_ik |= ( f_ij & r_jk );
}
// sparsity for H(i,k)
v[i * q + k] = h_ik;
}
}
// compute sparsity pattern for V(x) = A(x) + H(x)
for(size_t i = 0; i < n; i++)
{ for(size_t k = 0; k < q; k++)
// v[ i * q + k ] |= a[ i * q + k];
v[ i * q + k ] = bool(v[ i * q + k]) | bool(a[ i * q + k]);
}
return ok;
}
template <class Base>
bool checkpoint<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vectorBool& r ,
const vectorBool& u ,
vectorBool& v ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return rev_sparse_hes< vectorBool >(vx, s, t, q, r, u, v, x);
}
template <class Base>
bool checkpoint<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector<bool>& r ,
const vector<bool>& u ,
vector<bool>& v ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return rev_sparse_hes< vector<bool> >(vx, s, t, q, r, u, v, x);
}
template <class Base>
bool checkpoint<Base>::rev_sparse_hes(
const vector<bool>& vx ,
const vector<bool>& s ,
vector<bool>& t ,
size_t q ,
const vector< std::set<size_t> >& r ,
const vector< std::set<size_t> >& u ,
vector< std::set<size_t> >& v ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
size_t n = member_[thread]->f_.Domain();
# ifndef NDEBUG
size_t m = member_[thread]->f_.Range();
# endif
CPPAD_ASSERT_UNKNOWN( vx.size() == n );
CPPAD_ASSERT_UNKNOWN( s.size() == m );
CPPAD_ASSERT_UNKNOWN( t.size() == n );
CPPAD_ASSERT_UNKNOWN( r.size() == n );
CPPAD_ASSERT_UNKNOWN( u.size() == m );
CPPAD_ASSERT_UNKNOWN( v.size() == n );
//
bool ok = true;
// make sure hes_sparse_set_ has been set
if( member_[thread]->hes_sparse_bool_.size() != 0 )
member_[thread]->hes_sparse_bool_.clear();
if( member_[thread]->hes_sparse_set_.n_set() == 0 )
set_hes_sparse_set();
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == 0 );
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == n );
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.end() == n );
// compute sparsity pattern for T(x) = S(x) * f'(x)
t = member_[thread]->f_.RevSparseJac(1, s);
# ifndef NDEBUG
for(size_t j = 0; j < n; j++)
CPPAD_ASSERT_UNKNOWN( vx[j] || ! t[j] )
# endif
// V(x) = f'(x)^T * g''(y) * f'(x) * R + g'(y) * f''(x) * R
// U(x) = g''(y) * f'(x) * R
// S(x) = g'(y)
// compute sparsity pattern for A(x) = f'(x)^T * U(x)
// 2DO: change a to use INTERNAL_SPARSE_SET
bool transpose = true;
vector< std::set<size_t> > a(n);
a = member_[thread]->f_.RevSparseJac(q, u, transpose);
// Need sparsity pattern for H(x) = (S(x) * f(x))''(x) * R,
// but use less efficient sparsity for f(x)''(x) * R so that
// hes_sparse_set_ can be used every time this is needed.
for(size_t i = 0; i < n; i++)
{ v[i].clear();
local::sparse::list_setvec::const_iterator set_itr(
member_[thread]->hes_sparse_set_, i
);
size_t j = *set_itr;
while( j < n )
{ std::set<size_t>::const_iterator itr_j;
const std::set<size_t>& r_j( r[j] );
for(itr_j = r_j.begin(); itr_j != r_j.end(); itr_j++)
{ size_t k = *itr_j;
v[i].insert(k);
}
j = *(++set_itr);
}
}
// compute sparsity pattern for V(x) = A(x) + H(x)
std::set<size_t>::const_iterator itr;
for(size_t i = 0; i < n; i++)
{ for(itr = a[i].begin(); itr != a[i].end(); itr++)
{ size_t j = *itr;
CPPAD_ASSERT_UNKNOWN( j < q );
v[i].insert(j);
}
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,139 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_JAC_HPP
# define CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_JAC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
template <class sparsity_type>
bool checkpoint<Base>::rev_sparse_jac(
size_t q ,
const sparsity_type& rt ,
sparsity_type& st ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
// during user sparsity calculations
size_t m = member_[thread]->f_.Range();
size_t n = member_[thread]->f_.Domain();
if( member_[thread]->jac_sparse_bool_.size() == 0 )
set_jac_sparse_bool();
if( member_[thread]->jac_sparse_set_.n_set() != 0 )
member_[thread]->jac_sparse_set_.resize(0, 0);
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == m * n );
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == 0 );
CPPAD_ASSERT_UNKNOWN( rt.size() == m * q );
CPPAD_ASSERT_UNKNOWN( st.size() == n * q );
bool ok = true;
//
// S = R * J where J is jacobian
for(size_t i = 0; i < q; i++)
{ for(size_t j = 0; j < n; j++)
{ // initialize sparsity for S(i,j)
bool s_ij = false;
// S(i,j) = sum_k R(i,k) * J(k,j)
for(size_t k = 0; k < m; k++)
{ // sparsity for R(i, k)
bool R_ik = rt[ k * q + i ];
bool J_kj = member_[thread]->jac_sparse_bool_[ k * n + j ];
s_ij |= (R_ik & J_kj);
}
// set sparsity for S^T
st[ j * q + i ] = s_ij;
}
}
return ok;
}
template <class Base>
bool checkpoint<Base>::rev_sparse_jac(
size_t q ,
const vectorBool& rt ,
vectorBool& st ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return rev_sparse_jac< vectorBool >(q, rt, st, x);
}
template <class Base>
bool checkpoint<Base>::rev_sparse_jac(
size_t q ,
const vector<bool>& rt ,
vector<bool>& st ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
return rev_sparse_jac< vector<bool> >(q, rt, st, x);
}
template <class Base>
bool checkpoint<Base>::rev_sparse_jac(
size_t q ,
const vector< std::set<size_t> >& rt ,
vector< std::set<size_t> >& st ,
const vector<Base>& x )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
// during user sparsity calculations
size_t m = member_[thread]->f_.Range();
size_t n = member_[thread]->f_.Domain();
if( member_[thread]->jac_sparse_bool_.size() != 0 )
member_[thread]->jac_sparse_bool_.clear();
if( member_[thread]->jac_sparse_set_.n_set() == 0 )
set_jac_sparse_set();
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == 0 );
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == m );
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.end() == n );
CPPAD_ASSERT_UNKNOWN( rt.size() == m );
CPPAD_ASSERT_UNKNOWN( st.size() == n );
//
bool ok = true;
//
for(size_t j = 0; j < n; j++)
st[j].clear();
//
// sparsity for s = r * jac_sparse_set_
// s^T = jac_sparse_set_^T * r^T
for(size_t i = 0; i < m; i++)
{ // i is the row index in r^T
std::set<size_t>::const_iterator itr_i;
const std::set<size_t>& r_i( rt[i] );
for(itr_i = r_i.begin(); itr_i != r_i.end(); itr_i++)
{ // k is the column index in r^T
size_t k = *itr_i;
CPPAD_ASSERT_UNKNOWN( k < q );
//
// i is column index in jac_sparse_set^T
local::sparse::list_setvec::const_iterator set_itr(
member_[thread]->jac_sparse_set_, i
);
size_t j = *set_itr;
while( j < n )
{ // j is row index in jac_sparse_set^T
st[j].insert(k);
j = *(++set_itr);
}
}
}
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,125 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_REVERSE_HPP
# define CPPAD_CORE_CHKPOINT_ONE_REVERSE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
// ---------------------------------------------------------------------------
template <class Base>
bool checkpoint<Base>::reverse(
size_t q ,
const vector<Base>& tx ,
const vector<Base>& ty ,
vector<Base>& px ,
const vector<Base>& py )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
# ifndef NDEBUG
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
# endif
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 );
CPPAD_ASSERT_UNKNOWN( n == tx.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( m == ty.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( tx.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( ty.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( px.size() == n * (q+1) );
CPPAD_ASSERT_UNKNOWN( py.size() == m * (q+1) );
bool ok = true;
// put proper forward mode coefficients in f_
# ifdef NDEBUG
// compute forward results for orders zero through q
member_[thread]->f_.Forward(q, tx);
# else
size_t i, j, k;
//
// compute forward results for orders zero through q
vector<Base> check_ty = member_[thread]->f_.Forward(q, tx);
for(i = 0; i < m; i++)
{ for(k = 0; k <= q; k++)
{ j = i * (q+1) + k;
CPPAD_ASSERT_UNKNOWN( check_ty[j] == ty[j] );
}
}
# endif
// now can run reverse mode
px = member_[thread]->f_.Reverse(q+1, py);
// no longer need the Taylor coefficients in f_
// (have to reconstruct them every time)
size_t c = 0;
size_t r = 0;
member_[thread]->f_.capacity_order(c, r);
return ok;
}
// ---------------------------------------------------------------------------
template <class Base>
bool checkpoint<Base>::reverse(
size_t q ,
const vector< AD<Base> >& atx ,
const vector< AD<Base> >& aty ,
vector< AD<Base> >& apx ,
const vector< AD<Base> >& apy )
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
// make sure af_ is defined
if( member_[thread]->af_.size_var() == 0 )
member_[thread]->af_ = member_[thread]->f_.base2ad();
# ifndef NDEBUG
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
# endif
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 );
CPPAD_ASSERT_UNKNOWN( n == atx.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( m == aty.size() / (q+1) );
CPPAD_ASSERT_UNKNOWN( atx.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( aty.size() % (q+1) == 0 );
CPPAD_ASSERT_UNKNOWN( apx.size() == n * (q+1) );
CPPAD_ASSERT_UNKNOWN( apy.size() == m * (q+1) );
bool ok = true;
// put proper forward mode coefficients in f_
# ifdef NDEBUG
// compute forward results for orders zero through q
member_[thread]->af_.Forward(q, atx);
# else
size_t i, j, k;
//
// compute forward results for orders zero through q
vector< AD<Base> > check_aty = member_[thread]->af_.Forward(q, atx);
for(i = 0; i < m; i++)
{ for(k = 0; k <= q; k++)
{ j = i * (q+1) + k;
CPPAD_ASSERT_UNKNOWN( check_aty[j] == aty[j] );
}
}
# endif
// now can run reverse mode
apx = member_[thread]->af_.Reverse(q+1, apy);
// no longer need the Taylor coefficients in f_
// (have to reconstruct them every time)
size_t c = 0;
size_t r = 0;
member_[thread]->af_.capacity_order(c, r);
return ok;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,53 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_BOOL_HPP
# define CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_BOOL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
void checkpoint<Base>::set_hes_sparse_bool(void)
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == 0 );
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
//
// set version of sparsity for vector of all ones
vectorBool all_one(m);
for(size_t i = 0; i < m; i++)
all_one[i] = true;
// set version of sparsity for n by n idendity matrix
vectorBool identity(n * n);
for(size_t j = 0; j < n; j++)
{ for(size_t i = 0; i < n; i++)
identity[ i * n + j ] = (i == j);
}
// compute sparsity pattern for H(x) = sum_i f_i(x)^{(2)}
bool transpose = false;
bool dependency = false;
member_[thread]->f_.ForSparseJac(n, identity, transpose, dependency);
member_[thread]->hes_sparse_bool_ = member_[thread]->f_.RevSparseHes(n, all_one, transpose);
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == n * n );
//
// drop the forward sparsity results from f_
member_[thread]->f_.size_forward_bool(0);
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_bool() == 0 );
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_set() == 0 );
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,57 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_SET_HPP
# define CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_SET_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
void checkpoint<Base>::set_hes_sparse_set(void)
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == 0 );
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
//
// set version of sparsity for vector of all ones
vector<bool> all_one(m);
for(size_t i = 0; i < m; i++)
all_one[i] = true;
// set version of sparsity for n by n idendity matrix
local::sparse::list_setvec identity;
identity.resize(n, n);
for(size_t j = 0; j < n; j++)
{ // Not using post_element because only adding one element per set
identity.add_element(j, j);
}
// compute sparsity pattern for H(x) = sum_i f_i(x)^{(2)}
bool transpose = false;
bool dependency = false;
member_[thread]->f_.ForSparseJacCheckpoint(
n, identity, transpose, dependency, member_[thread]->jac_sparse_set_
);
member_[thread]->f_.RevSparseHesCheckpoint(
n, all_one, transpose, member_[thread]->hes_sparse_set_
);
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == n );
CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.end() == n );
//
// drop the forward sparsity results from f_
member_[thread]->f_.size_forward_set(0);
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,56 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_BOOL_HPP
# define CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_BOOL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
void checkpoint<Base>::set_jac_sparse_bool(void)
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == 0 );
bool transpose = false;
bool dependency = true;
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
// Use the choice for forward / reverse that results in smaller
// size for the sparsity pattern of all variables in the tape.
if( n <= m )
{ vectorBool identity(n * n);
for(size_t j = 0; j < n; j++)
{ for(size_t i = 0; i < n; i++)
identity[ i * n + j ] = (i == j);
}
member_[thread]->jac_sparse_bool_ = member_[thread]->f_.ForSparseJac(
n, identity, transpose, dependency
);
member_[thread]->f_.size_forward_bool(0);
}
else
{ vectorBool identity(m * m);
for(size_t j = 0; j < m; j++)
{ for(size_t i = 0; i < m; i++)
identity[ i * m + j ] = (i == j);
}
member_[thread]->jac_sparse_bool_ = member_[thread]->f_.RevSparseJac(
m, identity, transpose, dependency
);
}
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_bool() == 0 );
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_set() == 0 );
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,58 @@
# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_SET_HPP
# define CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_SET_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
template <class Base>
void checkpoint<Base>::set_jac_sparse_set(void)
{ // make sure member_ is allocated for this thread
size_t thread = thread_alloc::thread_num();
allocate_member(thread);
//
CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == 0 );
bool transpose = false;
bool dependency = true;
size_t n = member_[thread]->f_.Domain();
size_t m = member_[thread]->f_.Range();
// Use the choice for forward / reverse that results in smaller
// size for the sparsity pattern of all variables in the tape.
if( n <= m )
{ local::sparse::list_setvec identity;
identity.resize(n, n);
for(size_t j = 0; j < n; j++)
{ // Not using post_element because only adding one element per set
identity.add_element(j, j);
}
member_[thread]->f_.ForSparseJacCheckpoint(
n, identity, transpose, dependency, member_[thread]->jac_sparse_set_
);
member_[thread]->f_.size_forward_set(0);
}
else
{ local::sparse::list_setvec identity;
identity.resize(m, m);
for(size_t i = 0; i < m; i++)
{ // Not using post_element because only adding one element per set
identity.add_element(i, i);
}
member_[thread]->f_.RevSparseJacCheckpoint(
m, identity, transpose, dependency, member_[thread]->jac_sparse_set_
);
}
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_set() == 0 );
CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_bool() == 0 );
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,65 @@
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 chkpoint_two_chk_fun$$
$spell
const
chk
chkpoint
$$
$section Using Checkpoint Functions$$
$head Syntax$$
$icode%chk_fun%(%ax%, %ay%)%$$
$head Purpose$$
Given $icode ax$$,
this call computes the corresponding value of $icode ay$$.
If $codei%AD<%Base%>%$$ operations are being recorded,
it enters the computation as an $cref atomic_three$$
operation in the recording;
see $cref/start recording/Independent/Start Recording/$$.
$head chk_fun$$
This object must have been created using the
$cref/chkpoint_two/chkpoint_two_ctor/chk_fun/$$ constructor.
$head ADVector$$
The type $icode ADVector$$ must be a
$cref/simple vector class/SimpleVector/$$ with elements of type
$codei%AD<%Base%>%$$.
$head ax$$
This argument has prototype
$codei%
const %ADVector%& ax
%$$
and its size equal to $icode%n% = %fun%.Domain()%$$
where $cref/fun/chkpoint_two_ctor/fun/$$ is the $codei%ADFun<%Base%>%$$
function in used the constructor for $icode chk_fun$$.
It specifies vector $latex x \in \B{R}^n$$
at which we are computing an $codei%AD<%Base%>%$$ version of
$latex y = g(x)$$.
$head ay$$
This argument has prototype
$codei%
%ADVector%& ay
%$$
and its size must be equal to $icode%m% = %fun%.Range()%$$.
The input values of its elements do not matter.
Upon return, it is an $codei%AD<%Base%>%$$ version of
$latex y = g(x)$$.
$end

View File

@@ -0,0 +1,311 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_CHKPOINT_TWO_HPP
# define CPPAD_CORE_CHKPOINT_TWO_CHKPOINT_TWO_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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two.hpp
Second generation checkpoint functions.
*/
/*
$begin chkpoint_two$$
$spell
CppAD
chk
chkpoint
hpp
cppad
bool
hes
$$
$section Checkpoint Functions: Second Generation$$
$head Syntax$$
$subhead Constructor$$
$codei%chkpoint_two<%Base%> %chk_fun%( %fun%, %name%,
%internal_bool%, %use_hes_sparsity%, %use_base2ad%, %use_in_parallel%
)%$$
$subhead Use Checkpoint Function$$
$codei% %chk_fun%(%ax%, %ay%)%$$
$subhead new_dynamic$$
$icode%chk_fun%.new_dynamic(%dynamic%)%$$
$head Reduce Memory$$
You can reduce the size of the tape and memory required for AD
using a checkpoint representation of a function
$latex g : \B{R}^n \rightarrow \B{R}^m$$.
$head Faster Recording$$
It may also reduce the time to make a recording if the same $latex g(x)$$
is used many times (with different values) during the
recording of an $codei%ADFun<%Base%>%$$ object.
$head Repeating Forward$$
Normally, CppAD stores $cref forward$$ mode results,
until they freed using $cref capacity_order$$,
or the corresponding $cref ADFun$$ object is deleted.
This is not true for $code chkpoint_two$$ functions
because the same checkpoint function may be used repeatedly
with different arguments during a single forward mode operation.
Thus, forward mode results are computed for each use of $icode chk_fun$$
in a forward mode sweep.
$head Operation Sequence$$
The $cref/operation sequence/glossary/Operation/Sequence/$$
representing $latex g(x)$$ is fixed; i.e.,
it cannot depend on the value of $latex x$$.
$head atomic_three$$
The $code chkpoint_two$$ class is derived from $code atomic_three$$,
hence some of its error message will refer to atomic operations.
The $code chkpoint_two$$ class implements all the
$cref/virtual functions/atomic_three/Virtual Functions/$$
and hence its source code,
$codei%
include/cppad/core/chkpoint_two/chkpoint_two.hpp
%$$
provides an example for $cref atomic_three$$ operations.
The difference is that $code chkpoint_two.hpp$$ uses AD
instead of user provided derivatives.
$head Base$$
The type $icode Base$$ specifies the base type for AD operations;
i.e., $icode chk_fun$$ can be used during the recording of
$codei%AD<%Base%>%$$ operations.
$childtable%include/cppad/core/chkpoint_two/ctor.hpp
%include/cppad/core/chkpoint_two/chk_fun.omh
%include/cppad/core/chkpoint_two/dynamic.hpp
%example/chkpoint_two/get_started.cpp
%example/chkpoint_two/compare.cpp
%example/chkpoint_two/base2ad.cpp
%example/chkpoint_two/dynamic.cpp
%example/chkpoint_two/ode.cpp
%$$
$end
*/
template <class Base>
class chkpoint_two : public atomic_three<Base> {
// ---------------------------------------------------------------------------
private:
/// are sparsity calculations using bools or sets of integers
const bool internal_bool_;
//
/// can this checkpoint function calculate Hessian sparsity patterns
const bool use_hes_sparsity_;
//
/// can this checkpoint function be used in base2ad recordings
const bool use_base2ad_;
//
/// can this checkpoint function be used in parallel mode
const bool use_in_parallel_;
//
/// Jacobian sparsity for g(x) with dependncy true.
/// This is set by the constructor and constant after that.
sparse_rc< vector<size_t> > jac_sparsity_;
//
/// Hessian sparsity for g(x). If use_hes_sparsity_ is true,
/// This is set by the constructor and constant after that.
sparse_rc< vector<size_t> > hes_sparsity_;
//
/// Function corresponding to this checkpoint object.
/// If use_in_parallel_, this is constant after the constructor.
ADFun<Base> g_;
//
/// AD version of function corresponding to this checkpoint object
/// If use_in_parallel_, this is constant after the constructor.
ADFun< AD<Base>, Base> ag_;
// ------------------------------------------------------------------------
// member_
// ------------------------------------------------------------------------
/// If use_in_parallel_ is true, must have a separate copy member data
/// that is not constant.
struct member_struct {
//
/// function corresponding to this checkpoint object
ADFun<Base> g_;
//
/// AD version of this function object
ADFun< AD<Base>, Base > ag_;
//
};
/// use pointers and allocate memory to avoid false sharing
/// (initialized to null by constructor)
member_struct* member_[CPPAD_MAX_NUM_THREADS];
//
// ------------------------------------------------------------------------
/// allocate member_ for this thread
void allocate_member(size_t thread)
{ CPPAD_ASSERT_UNKNOWN( use_in_parallel_ );
if( member_[thread] == nullptr )
{ // allocaate raw memory
size_t min_bytes = sizeof(member_struct);
size_t num_bytes;
void* v_ptr = thread_alloc::get_memory(min_bytes, num_bytes);
// convert to member_struct*
member_[thread] = reinterpret_cast<member_struct*>(v_ptr);
// call member_struct constructor
new( member_[thread] ) member_struct;
//
// The thread has a copy of corresponding informaiton.
member_[thread]->g_ = g_;
member_[thread]->ag_ = ag_;
}
return;
}
//
// ------------------------------------------------------------------------
/// free member_ for this thread
void free_member(size_t thread)
{ if( member_[thread] != nullptr )
{ // call destructor
member_[thread]->~member_struct();
// return raw m,emory to available pool for this thread
void* v_ptr = reinterpret_cast<void*>(member_[thread]);
thread_alloc::return_memory(v_ptr);
// mark member for this thread as not allocated
member_[thread] = nullptr;
}
return;
}
// -----------------------------------------------------------------------
// atomic_three virtual functions
// ------------------------------------------------------------------------
// type
virtual bool for_type(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y
);
// forward
virtual bool forward(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector<Base>& taylor_x ,
vector<Base>& taylor_y
);
// AD forward
virtual bool forward(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
vector< AD<Base> >& ataylor_y
);
// reverse
virtual bool reverse(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector<Base>& taylor_x ,
const vector<Base>& taylor_y ,
vector<Base>& partial_x ,
const vector<Base>& partial_y
);
// AD reverse
virtual bool reverse(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
const vector< AD<Base> >& ataylor_y ,
vector< AD<Base> >& apartial_x ,
const vector< AD<Base> >& apartial_y
);
// jac_sparsity
virtual bool jac_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
bool dependency ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out
);
// hes_sparsity
virtual bool hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out
);
// rev_depend
virtual bool rev_depend(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<bool>& depend_x ,
const vector<bool>& depend_y
);
public:
// ctor
chkpoint_two(
const ADFun<Base>& fun ,
const std::string& name ,
bool internal_bool ,
bool use_hes_sparsity ,
bool use_base2ad ,
bool use_in_parallel
);
//
// destructor
~chkpoint_two(void);
//
// assignment operator
void operator=(const chkpoint_two& other)
{ CPPAD_ASSERT_KNOWN(false,
"cannot use chkpoint_two assignment operator"
);
}
// copy constructor
chkpoint_two(const chkpoint_two& other)
:
internal_bool_ ( other.internal_bool_ ) ,
use_hes_sparsity_ ( other.use_hes_sparsity_ ) ,
use_base2ad_ ( other.use_base2ad_ ) ,
use_in_parallel_ ( other.use_in_parallel_ ) ,
jac_sparsity_ ( other.jac_sparsity_ ) ,
hes_sparsity_ ( other.hes_sparsity_ )
{ g_ = other.g_;
ag_ = other.ag_;
}
//
// new_dynamic
template <class BaseVector>
void new_dynamic(const BaseVector& dynamic);
};
} // END_CPPAD_NAMESPACE
# include <cppad/core/chkpoint_two/ctor.hpp>
# include <cppad/core/chkpoint_two/dynamic.hpp>
# include <cppad/core/chkpoint_two/for_type.hpp>
# include <cppad/core/chkpoint_two/forward.hpp>
# include <cppad/core/chkpoint_two/reverse.hpp>
# include <cppad/core/chkpoint_two/jac_sparsity.hpp>
# include <cppad/core/chkpoint_two/hes_sparsity.hpp>
# include <cppad/core/chkpoint_two/rev_depend.hpp>
# endif

View File

@@ -0,0 +1,222 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_CTOR_HPP
# define CPPAD_CORE_CHKPOINT_TWO_CTOR_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 chkpoint_two_ctor$$
$spell
chkpoint
chk
bool
hes
$$
$section Checkpoint Function Constructor$$
$head Syntax$$
$codei%chkpoint_two<%Base%> %chk_fun%( %fun%, %name%,
%internal_bool%, %use_hes_sparsity%, %use_base2ad%, %use_in_parallel%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Parallel$$
This constructor, and its corresponding destructor, must not be called in
$cref/parallel/ta_in_parallel/$$ mode.
The object $icode chk_fun$$ should not be destructed for as long as there is
an $codei%ADFun<%Base%>%$$ object the has $icode chk_fun$$ in its recording.
$head Base$$
The type $icode Base$$ specifies the base type for AD operations.
$head fun$$
This specifies the function $latex g(x)$$.
Note that $icode fun$$ may or may not have been
$cref/optimized/optimize/$$ before calling the constructor.
This will determine if the internal representation for $icode g(x)$$
is optimized.
$head name$$
is the name used for reporting errors using this checkpoint function.
$head internal_bool$$
If true, sparsity calculations are done with sets represented
by vectors of boolean values.
Otherwise, vectors of sets are used for sparsity patterns.
$head use_hes_sparsity$$
If true, Hessian sparsity patterns can be calculated for
$codei%ADFun<%Base%>%$$ objects that have uses of $icode chk_fun$$
in their recording.
This requires some extra memory and extra computation during the constructor.
$head use_base2ad$$
If this is true, $icode chk_fun$$ can be used during the recording
of $codei%ADFun<%Base%>%$$ objects that get converted to
$codei%ADFun< AD<%Base%> >%$$ objects using $cref base2ad$$.
This requires some extra memory and extra computation during the constructor.
$head use_in_parallel$$
If this is true, $icode chk_fun$$ can be used
$cref/in_parallel/ta_parallel_setup/in_parallel/$$.
This requires some extra memory for a constant copy of the $icode fun$$
information and a separate copy (that changes) for each thread.
$head chk_fun$$
This is a checkpoint function representation of $latex g(x)$$
that can be used during the recording of $codei%AD<%Base%>%$$ operations.
$end
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/ctor.hpp
Constructor for chkpoint_two class.
*/
/*!
Constructor
\tparam Base
base class for recording AD<Base> operations using this checkpoint object.
\param fun
is the function g(x) corresponding to this checkpoint object.
\param name
is the name used for error reporting.
\param internal_bool
should sparisity calculations be done using bools (or sets).
\param use_hes_sparsity
will this checkpoint function be used with Hessian sparsity calculations.
\param use_base2ad
will this checkpoint function be used with base2ad.
\param use_in_parallel
will this checkpoint function be used in parallel mode.
*/
// BEGIN_PROTOTYPE
template <class Base>
chkpoint_two<Base>::chkpoint_two(
const ADFun<Base>& fun ,
const std::string& name ,
bool internal_bool ,
bool use_hes_sparsity ,
bool use_base2ad ,
bool use_in_parallel )
// END_PROTOTYPE
:
atomic_three<Base>(name) ,
internal_bool_( internal_bool ) ,
use_hes_sparsity_( use_hes_sparsity ) ,
use_base2ad_ ( use_base2ad ) ,
use_in_parallel_ ( use_in_parallel )
{ CPPAD_ASSERT_KNOWN(
! thread_alloc::in_parallel() ,
"chkpoint_two: constructor cannot be called in parallel mode."
);
// initialize member pointers as null;
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
member_[thread] = nullptr;
//
// g_
g_ = fun;
//
// suppress check for nan because chkpoint_two object can be used in a
// function that gets optimized and some checkpoint results may not matter.
g_.check_for_nan(false);
//
// ag_
if( use_base2ad )
ag_ = g_.base2ad();
//
// jac_sparsity__
size_t n = g_.Domain();
size_t m = g_.Range();
sparse_rc< vector<size_t> > pattern_in;
bool transpose = false;
bool dependency = true;
if( n <= m || use_hes_sparsity )
{ // use forward mode
pattern_in.resize(n, n, n);
for(size_t k = 0; k < n; ++k)
pattern_in.set(k, k, k);
g_.for_jac_sparsity(
pattern_in,
transpose,
dependency,
internal_bool,
jac_sparsity_
);
}
else
{ // use reverse mode
pattern_in.resize(m, m, m);
for(size_t k = 0; k < m; ++k)
pattern_in.set(k, k, k);
g_.rev_jac_sparsity(
pattern_in,
transpose,
dependency,
internal_bool,
jac_sparsity_
);
}
//
// hes_sparsity_
if( use_hes_sparsity )
{ vector<bool> select_y(m), select_x(n);
for(size_t i = 0; i < m; ++i)
select_y[i] = true;
if( n <= m )
{ for(size_t j = 0; j < n; ++j)
select_x[j] = true;
g_.for_hes_sparsity(
select_x, select_y, internal_bool, hes_sparsity_
);
}
else
{ // forward jacobian sparsity is stored in g_
g_.rev_hes_sparsity(
select_y, transpose, internal_bool, hes_sparsity_
);
}
}
// free memory holding forward Jacobian sparsity
if( internal_bool )
g_.size_forward_bool(0);
else
g_.size_forward_set(0);
}
/// destructor
template <class Base>
chkpoint_two<Base>::~chkpoint_two(void)
{
# ifndef NDEBUG
if( thread_alloc::in_parallel() )
{ std::string msg = atomic_three<Base>::atomic_name();
msg += ": chkpoint_two destructor called in parallel mode.";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread)
free_member(thread);
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,102 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_DYNAMIC_HPP
# define CPPAD_CORE_CHKPOINT_TWO_DYNAMIC_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 chkpoint_two_dynamic$$
$spell
chk
chkpoint
dyn_ind
$$
$section Dynamic Parameters in Checkpoint Functions$$
$head Syntax$$
$icode%chk_fun%.new_dynamic(%dynamic%)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head chk_fun$$
This object must have been created using the
$cref/chkpoint_two/chkpoint_two_ctor/chk_fun/$$ constructor.
$subhead Base$$
This is the $cref/Base/chkpoint_two_ctor/Base/$$ type
in the $icode chk_fun$$ constructor.
$subhead fun$$
This is the function $cref/fun/chkpoint_two_ctor/fun/$$
in the $icode chk_fun$$ constructor.
$head BaseVector$$
This must be a $cref SimpleVector$$ with elements of type $icode Base$$.
$head dynamic$$
This is a vector with new values for the dynamic parameters
in the function $icode fun$$.
Is size must be equal to
$cref/fun.size_dyn_ind()/seq_property/size_dyn_par/$$.
This only affects the copy of $icode fun$$ used by $icode chk_fun$$.
$head Multi-Threading$$
If one is using $cref/in_parallel/ta_in_parallel/$$,
there is a separate copy of $icode fun$$ for each thread.
In this case, only the dynamic parameters in the copy for the current
$cref/thread number/ta_thread_num/$$ are changed.
$end
*/
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/dynamic.hpp
Change the dynnamic parameter in a checkpoint function.
*/
/*!
Constructor
\tparam Base
base class for recording AD<Base> operations using this checkpoint object.
\param dynamic
is the new values for the dynamic parameters in the function
defining this checkpoint object.
*/
// BEGIN_PROTOTYPE
template <class Base>
template <class BaseVector>
void chkpoint_two<Base>::new_dynamic(const BaseVector& dynamic)
// END_PROTOTYPE
{ ADFun<Base>* g_ptr = &g_;
if( use_in_parallel_ )
{ size_t thread = thread_alloc::thread_num();
allocate_member(thread);
g_ptr = &(member_[thread]->g_);
}
# ifndef NDEBUG
else if( thread_alloc::in_parallel() )
{ std::string msg = atomic_three<Base>::atomic_name();
msg += ": use_in_parallel is false and in_parallel() is true";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
g_ptr->new_dynamic(dynamic);
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,63 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_FOR_TYPE_HPP
# define CPPAD_CORE_CHKPOINT_TWO_FOR_TYPE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/for_type.hpp
Second generation checkpoint type computation.
*/
/*!
Link from atomic_three to type calculation
\param parameter_x [in]
is the value of the parameters in the corresponding function call
afun(ax, ay).
\param type_x [in]
specifies which components of x are
constants, dynamics, and variables
\param type_y [out]
specifies which components of y are
constants, dynamics, and variables
*/
template <class Base>
bool chkpoint_two<Base>::for_type(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<ad_type_enum>& type_y )
{ size_t nr = jac_sparsity_.nr();
size_t nnz = jac_sparsity_.nnz();
const vector<size_t>& row( jac_sparsity_.row() );
const vector<size_t>& col( jac_sparsity_.col() );
//
CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nr() == type_y.size() );
CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nc() == type_x.size() );
//
// initialize type_y as constant_enum
for(size_t i = 0; i < nr; ++i)
type_y[i] = constant_enum;
//
// loop over entries in Dependency pattern
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
type_y[i] = std::max(type_y[i], type_x[j]);
}
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,130 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_FORWARD_HPP
# define CPPAD_CORE_CHKPOINT_TWO_FORWARD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/forward.hpp
Second generation checkpoint forward mode.
*/
/*!
Link from chkpoint_two to forward mode
\param parameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param need_y [in]
specifies which components of taylor_y are needed,
\param order_low [in]
lowerest order for this forward mode calculation.
\param order_up [in]
highest order for this forward mode calculation.
\param taylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param taylor_y [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_three
*/
template <class Base>
bool chkpoint_two<Base>::forward(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector<Base>& taylor_x ,
vector<Base>& taylor_y )
{ ADFun<Base>* g_ptr = &g_;
if( use_in_parallel_ )
{ size_t thread = thread_alloc::thread_num();
allocate_member(thread);
g_ptr = &(member_[thread]->g_);
}
# ifndef NDEBUG
else if( thread_alloc::in_parallel() )
{ std::string msg = atomic_three<Base>::atomic_name();
msg += ": use_in_parallel is false and in_parallel() is true";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
// compute forward mode results for all values and orders
taylor_y = g_ptr->Forward(order_up, taylor_x);
//
return true;
}
/*!
Link from chkpoint_two to AD forward mode
\param aparameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param need_y [in]
specifies which components of taylor_y are needed,
\param order_low [in]
lowerest order for this forward mode calculation.
\param order_up [in]
highest order for this forward mode calculation.
\param ataylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param ataylor_y [out]
Taylor coefficient corresponding to y for this calculation
See the forward mode in user's documentation for atomic_three
*/
template <class Base>
bool chkpoint_two<Base>::forward(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t need_y ,
size_t order_low ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
vector< AD<Base> >& ataylor_y )
{ if( ! use_base2ad_ )
return false;
//
ADFun< AD<Base>, Base >* ag_ptr = &ag_;
if( use_in_parallel_ )
{ size_t thread = thread_alloc::thread_num();
allocate_member(thread);
ag_ptr = &(member_[thread]->ag_);
}
# ifndef NDEBUG
else if( thread_alloc::in_parallel() )
{ std::string msg = atomic_three<Base>::atomic_name();
msg += ": use_in_parallel is false and in_parallel() is true";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
// compute forward mode results for all values and orders
ataylor_y = ag_ptr->Forward(order_up, ataylor_x);
//
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,86 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_HES_SPARSITY_HPP
# define CPPAD_CORE_CHKPOINT_TWO_HES_SPARSITY_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/hes_sparsity.hpp
Second generation checkpoint Jacobian sparsity patterns.
*/
/*!
chkpoint_two to Hessian sparsity calculations.
\param parameter_x [in]
contains the values for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param select_x [in]
which domain components to include in the dependency or sparsity pattern.
The index zero is used for parameters.
\param select_y [in]
which range components to include in the dependency or sparsity pattern.
The index zero is used for parameters.
This argument is ignored because the sparsity pattern corresponding to
all components true is computed during the construction and used for all cases.
This errors on the side of caution for the sake of speed.
\param pattern_out [out]
is the dependency or sparsity pattern.
*/
// BEGIN_PROTOTYPE
template <class Base>
bool chkpoint_two<Base>::hes_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out )
// END_PROTOTYPE
{ CPPAD_ASSERT_UNKNOWN( hes_sparsity_.nr() == select_x.size() );
CPPAD_ASSERT_UNKNOWN( hes_sparsity_.nc() == select_x.size() );
if( ! use_hes_sparsity_ )
return false;
// count number of non-zeros
size_t nnz = hes_sparsity_.nnz();
size_t nr = hes_sparsity_.nr();
size_t nc = hes_sparsity_.nc();
const vector<size_t>& row = hes_sparsity_.row();
const vector<size_t>& col = hes_sparsity_.col();
size_t nnz_out = 0;
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
if( select_x[j] & select_x[i] )
++nnz_out;
}
// set the output sparsity pattern
pattern_out.resize(nr, nc, nnz_out);
size_t ell = 0;
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
if( select_x[j] & select_x[i] )
pattern_out.set(ell++, i, j);
}
CPPAD_ASSERT_UNKNOWN( ell == nnz_out );
//
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,86 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_JAC_SPARSITY_HPP
# define CPPAD_CORE_CHKPOINT_TWO_JAC_SPARSITY_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/jac_sparsity.hpp
Second generation checkpoint Jacobian sparsity patterns.
*/
/*!
chkpoint_two to Jacobian sparsity calculations.
\param dependency [in]
This argument is ignored.
The return pattern is always a dependency pattern which is a correct,
but possibly not efficient, sparsity pattern.
\param parameter_x [in]
contains the values for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param select_x [in]
which domain components to include in the dependency or sparsity pattern.
The index zero is used for parameters.
\param select_y [in]
which range components to include in the dependency or sparsity pattern.
The index zero is used for parameters.
\param pattern_out [out]
is the dependency or sparsity pattern.
*/
// BEGIN_PROTOTYPE
template <class Base>
bool chkpoint_two<Base>::jac_sparsity(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
bool dependency ,
const vector<bool>& select_x ,
const vector<bool>& select_y ,
sparse_rc< vector<size_t> >& pattern_out )
// END_PROTOTYPE
{ CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nr() == select_y.size() );
CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nc() == select_x.size() );
// count number of non-zeros
size_t nnz = jac_sparsity_.nnz();
size_t nr = jac_sparsity_.nr();
size_t nc = jac_sparsity_.nc();
const vector<size_t>& row = jac_sparsity_.row();
const vector<size_t>& col = jac_sparsity_.col();
size_t nnz_out = 0;
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
if( select_x[j] & select_y[i] )
++nnz_out;
}
// set the output sparsity pattern
pattern_out.resize(nr, nc, nnz_out);
size_t ell = 0;
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
if( select_x[j] & select_y[i] )
pattern_out.set(ell++, i, j);
}
CPPAD_ASSERT_UNKNOWN( ell == nnz_out );
//
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,66 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_REV_DEPEND_HPP
# define CPPAD_CORE_CHKPOINT_TWO_REV_DEPEND_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/rev_depend.hpp
Second generation checkpoint type computation.
*/
/*!
Link from atomic_three to dependency calculation
\param parameter_x [in]
is the value of the parameters in the corresponding function call
afun(ax, ay).
\param type_x [in]
is the AD type for ax in the corresponding afun(ax, ay) call.
\param depend_x [out]
specifies which components of x affect the values of interest
\param depend_y [in]
specifies which components of y affect the vlaues of interest
*/
template <class Base>
bool chkpoint_two<Base>::rev_depend(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
vector<bool>& depend_x ,
const vector<bool>& depend_y )
{ size_t nc = jac_sparsity_.nc();
size_t nnz = jac_sparsity_.nnz();
const vector<size_t>& row( jac_sparsity_.row() );
const vector<size_t>& col( jac_sparsity_.col() );
//
CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nr() == depend_y.size() );
CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nc() == depend_x.size() );
//
// initialize depend_x as false
for(size_t j = 0; j < nc; ++j)
depend_x[j] = false;
//
// loop over entries in Dependency pattern
for(size_t k = 0; k < nnz; ++k)
{ size_t i = row[k];
size_t j = col[k];
if( depend_y[i] )
depend_x[j] = true;
}
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,139 @@
# ifndef CPPAD_CORE_CHKPOINT_TWO_REVERSE_HPP
# define CPPAD_CORE_CHKPOINT_TWO_REVERSE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 { // BEGIN_CPPAD_NAMESPACE
/*!
\file chkpoint_two/reverse.hpp
Second generation checkpoint reverse mode.
*/
/*!
Link from chkpoint_two to reverse mode
\param parameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param order_up [in]
highest order Taylor coefficient aht we are computing derivative of
\param taylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param taylor_y [in]
Taylor coefficient corresponding to y for this calculation
\param partial_x [out]
Partials w.r.t. the x Taylor coefficients.
\param partial_y [in]
Partials w.r.t. the y Taylor coefficients.
See the reverse mode in user's documentation for atomic_three
*/
template <class Base>
bool chkpoint_two<Base>::reverse(
const vector<Base>& parameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector<Base>& taylor_x ,
const vector<Base>& taylor_y ,
vector<Base>& partial_x ,
const vector<Base>& partial_y )
{ ADFun<Base>* g_ptr = &g_;
if( use_in_parallel_ )
{ size_t thread = thread_alloc::thread_num();
allocate_member(thread);
g_ptr = &(member_[thread]->g_);
}
# ifndef NDEBUG
else if( thread_alloc::in_parallel() )
{ std::string msg = atomic_three<Base>::atomic_name();
msg += ": use_in_parallel is false and in_parallel() is true";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
// compute forward mode Taylor coefficient orders 0 through order_up
# ifdef NDEBUG
g_ptr->Forward(order_up, taylor_x);
# else
vector<Base> check = g_ptr->Forward(order_up, taylor_x);
CPPAD_ASSERT_UNKNOWN( taylor_y.size() == check.size() )
for(size_t i = 0; i < taylor_y.size(); ++i)
CPPAD_ASSERT_UNKNOWN( taylor_y[i] == check[i] );
# endif
// now can run reverse mode
partial_x = g_ptr->Reverse(order_up+1, partial_y);
//
return true;
}
/*!
Link from chkpoint_two to AD reverse mode
\param aparameter_x [in]
contains the values, in afun(ax, ay), for arguments that are parameters.
\param type_x [in]
what is the type, in afun(ax, ay), for each component of x.
\param order_up [in]
highest order Taylor coefficient aht we are computing derivative of
\param ataylor_x [in]
Taylor coefficients corresponding to x for this calculation.
\param ataylor_y [in]
Taylor coefficient corresponding to y for this calculation
\param apartial_x [out]
Partials w.r.t. the x Taylor coefficients.
\param apartial_y [in]
Partials w.r.t. the y Taylor coefficients.
See the reverse mode in user's documentation for atomic_three
*/
template <class Base>
bool chkpoint_two<Base>::reverse(
const vector< AD<Base> >& aparameter_x ,
const vector<ad_type_enum>& type_x ,
size_t order_up ,
const vector< AD<Base> >& ataylor_x ,
const vector< AD<Base> >& ataylor_y ,
vector< AD<Base> >& apartial_x ,
const vector< AD<Base> >& apartial_y )
{ ADFun< AD<Base>, Base >* ag_ptr = &ag_;
if( use_in_parallel_ )
{ size_t thread = thread_alloc::thread_num();
allocate_member(thread);
ag_ptr = &(member_[thread]->ag_);
}
// compute forward mode Taylor coefficient orders 0 through order_up
# ifdef NDEBUG
ag_ptr->Forward(order_up, ataylor_x);
# else
vector< AD<Base> > acheck = ag_ptr->Forward(order_up, ataylor_x);
CPPAD_ASSERT_UNKNOWN( ataylor_y.size() == acheck.size() )
for(size_t i = 0; i < ataylor_y.size(); ++i)
CPPAD_ASSERT_UNKNOWN( ataylor_y[i] == acheck[i] );
# endif
// now can run reverse mode
apartial_x = ag_ptr->Reverse(order_up+1, apartial_y);
//
return true;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,635 @@
# ifndef CPPAD_CORE_COMPARE_HPP
# define CPPAD_CORE_COMPARE_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 Compare$$
$spell
cos
Op
bool
const
$$
$section AD Binary Comparison Operators$$
$head Syntax$$
$icode%b% = %x% %Op% %y%$$
$head Purpose$$
Compares two operands where one of the operands is an
$codei%AD<%Base%>%$$ object.
The comparison has the same interpretation as for
the $icode Base$$ type.
$head Op$$
The operator $icode Op$$ is one of the following:
$table
$bold Op$$ $pre $$ $cnext $bold Meaning$$ $rnext
$code <$$ $cnext is $icode x$$ less than $icode y$$ $rnext
$code <=$$ $cnext is $icode x$$ less than or equal $icode y$$ $rnext
$code >$$ $cnext is $icode x$$ greater than $icode y$$ $rnext
$code >=$$ $cnext is $icode x$$ greater than or equal $icode y$$ $rnext
$code ==$$ $cnext is $icode x$$ equal to $icode y$$ $rnext
$code !=$$ $cnext is $icode x$$ not equal to $icode y$$
$tend
$head x$$
The operand $icode x$$ has prototype
$codei%
const %Type% &%x%
%$$
where $icode Type$$ is $codei%AD<%Base%>%$$, $icode Base$$, or $code int$$.
$head y$$
The operand $icode y$$ has prototype
$codei%
const %Type% &%y%
%$$
where $icode Type$$ is $codei%AD<%Base%>%$$, $icode Base$$, or $code int$$.
$head b$$
The result $icode b$$ has type
$codei%
bool %b%
%$$
$head Operation Sequence$$
The result of this operation is a $code bool$$ value
(not an $cref/AD of Base/glossary/AD of Base/$$ object).
Thus it will not be recorded as part of an
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$pre
$$
For example, suppose
$icode x$$ and $icode y$$ are $codei%AD<%Base%>%$$ objects,
the tape corresponding to $codei%AD<%Base%>%$$ is recording,
$icode b$$ is true,
and the subsequent code is
$codei%
if( %b% )
%y% = cos(%x%);
else
%y% = sin(%x%);
%$$
only the assignment $icode%y% = cos(%x%)%$$ is recorded on the tape
(if $icode x$$ is a $cref/parameter/glossary/Parameter/$$,
nothing is recorded).
The $cref CompareChange$$ function can yield
some information about changes in comparison operation results.
You can use $cref CondExp$$ to obtain comparison operations
that depends on the
$cref/independent variable/glossary/Tape/Independent Variable/$$
values with out re-taping the AD sequence of operations.
$head Assumptions$$
If one of the $icode Op$$ operators listed above
is used with an $codei%AD<%Base%>%$$ object,
it is assumed that the same operator is supported by the base type
$icode Base$$.
$head Example$$
$children%
example/general/compare.cpp
%$$
The file
$cref compare.cpp$$
contains an example and test of these operations.
$end
-------------------------------------------------------------------------------
*/
// BEGIN CppAD namespace
namespace CppAD {
// -------------------------------- < --------------------------
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool operator < (const AD<Base> &left , const AD<Base> &right)
{ bool result = (left.value_ < right.value_);
//
// check if we are recording compare operators
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return result;
if( ! tape->Rec_.get_record_compare() )
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 ,
"< : AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // variable < variable
if( result )
{ tape->Rec_.PutOp(local::LtvvOp);
tape->Rec_.PutArg(left.taddr_, right.taddr_);
}
else
{ tape->Rec_.PutOp(local::LevvOp);
tape->Rec_.PutArg(right.taddr_, left.taddr_);
}
}
else
{ // variable < parameter
addr_t p = right.taddr_;
if( ! dyn_right )
p = tape->Rec_.put_con_par(right.value_);
if( result )
{ tape->Rec_.PutOp(local::LtvpOp);
tape->Rec_.PutArg(left.taddr_, p);
}
else
{ tape->Rec_.PutOp(local::LepvOp);
tape->Rec_.PutArg(p, left.taddr_);
}
}
}
else if ( var_right )
{ // parameter < variable
addr_t p = left.taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left.value_);
if( result )
{ tape->Rec_.PutOp(local::LtpvOp);
tape->Rec_.PutArg(p, right.taddr_);
}
else
{ tape->Rec_.PutOp(local::LevpOp);
tape->Rec_.PutArg(right.taddr_, p);
}
}
else if( dyn_left | dyn_right )
{ // parameter < parameter
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_);
//
if( result )
{ tape->Rec_.PutOp(local::LtppOp);
tape->Rec_.PutArg(arg0, arg1);
}
else
{ tape->Rec_.PutOp(local::LeppOp);
tape->Rec_.PutArg(arg1, arg0);
}
}
return result;
}
// convert other cases into the case above
CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(<)
// -------------------------------- <= --------------------------
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool operator <= (const AD<Base> &left , const AD<Base> &right)
{ bool result = (left.value_ <= right.value_);
//
// check if we are recording compare operators
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return result;
if( ! tape->Rec_.get_record_compare() )
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 ,
"<= : AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // variable <= variable
if( result )
{ tape->Rec_.PutOp(local::LevvOp);
tape->Rec_.PutArg(left.taddr_, right.taddr_);
}
else
{ tape->Rec_.PutOp(local::LtvvOp);
tape->Rec_.PutArg(right.taddr_, left.taddr_);
}
}
else
{ // variable <= parameter
addr_t p = right.taddr_;
if( ! dyn_right )
p = tape->Rec_.put_con_par(right.value_);
if( result )
{ tape->Rec_.PutOp(local::LevpOp);
tape->Rec_.PutArg(left.taddr_, p);
}
else
{ tape->Rec_.PutOp(local::LtpvOp);
tape->Rec_.PutArg(p, left.taddr_);
}
}
}
else if ( var_right )
{ // parameter <= variable
addr_t p = left.taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left.value_);
if( result )
{ tape->Rec_.PutOp(local::LepvOp);
tape->Rec_.PutArg(p, right.taddr_);
}
else
{ tape->Rec_.PutOp(local::LtvpOp);
tape->Rec_.PutArg(right.taddr_, p);
}
}
else if( dyn_left | dyn_right )
{ // parameter <= parameter
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_);
//
if( result )
{ tape->Rec_.PutOp(local::LeppOp);
tape->Rec_.PutArg(arg0, arg1);
}
else
{ tape->Rec_.PutOp(local::LtppOp);
tape->Rec_.PutArg(arg1, arg0);
}
}
return result;
}
// convert other cases into the case above
CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(<=)
// -------------------------------- > --------------------------
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool operator > (const AD<Base> &left , const AD<Base> &right)
{ bool result = (left.value_ > right.value_);
//
// check if we are recording compare operators
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return result;
if( ! tape->Rec_.get_record_compare() )
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 ,
"> : AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // variable > variable
if( result )
{ tape->Rec_.PutOp(local::LtvvOp);
tape->Rec_.PutArg(right.taddr_, left.taddr_);
}
else
{ tape->Rec_.PutOp(local::LevvOp);
tape->Rec_.PutArg(left.taddr_, right.taddr_);
}
}
else
{ // variable > parameter
addr_t p = right.taddr_;
if( ! dyn_right )
p = tape->Rec_.put_con_par(right.value_);
if( result )
{ tape->Rec_.PutOp(local::LtpvOp);
tape->Rec_.PutArg(p, left.taddr_);
}
else
{ tape->Rec_.PutOp(local::LevpOp);
tape->Rec_.PutArg(left.taddr_, p);
}
}
}
else if ( var_right )
{ // parameter > variable
addr_t p = left.taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left.value_);
if( result )
{ tape->Rec_.PutOp(local::LtvpOp);
tape->Rec_.PutArg(right.taddr_, p);
}
else
{ tape->Rec_.PutOp(local::LepvOp);
tape->Rec_.PutArg(p, right.taddr_);
}
}
else if( dyn_left | dyn_right )
{ // parameter > parameter
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_);
//
if( result )
{ tape->Rec_.PutOp(local::LtppOp);
tape->Rec_.PutArg(arg1, arg0);
}
else
{ tape->Rec_.PutOp(local::LeppOp);
tape->Rec_.PutArg(arg0, arg1);
}
}
return result;
}
// convert other cases into the case above
CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(>)
// -------------------------------- >= --------------------------
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool operator >= (const AD<Base> &left , const AD<Base> &right)
{ bool result = (left.value_ >= right.value_);
//
// check if we are recording compare operators
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return result;
if( ! tape->Rec_.get_record_compare() )
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 ,
">= : AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // variable >= variable
if( result )
{ tape->Rec_.PutOp(local::LevvOp);
tape->Rec_.PutArg(right.taddr_, left.taddr_);
}
else
{ tape->Rec_.PutOp(local::LtvvOp);
tape->Rec_.PutArg(left.taddr_, right.taddr_);
}
}
else
{ // variable >= parameter
addr_t p = right.taddr_;
if( ! dyn_right )
p = tape->Rec_.put_con_par(right.value_);
if( result )
{ tape->Rec_.PutOp(local::LepvOp);
tape->Rec_.PutArg(p, left.taddr_);
}
else
{ tape->Rec_.PutOp(local::LtvpOp);
tape->Rec_.PutArg(left.taddr_, p);
}
}
}
else if ( var_right )
{ // parameter >= variable
addr_t p = left.taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left.value_);
if( result )
{ tape->Rec_.PutOp(local::LevpOp);
tape->Rec_.PutArg(right.taddr_, p);
}
else
{ tape->Rec_.PutOp(local::LtpvOp);
tape->Rec_.PutArg(p, right.taddr_);
}
}
else if( dyn_left | dyn_right )
{ // parameter >= parameter
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_);
//
if( result )
{ tape->Rec_.PutOp(local::LeppOp);
tape->Rec_.PutArg(arg1, arg0);
}
else
{ tape->Rec_.PutOp(local::LtppOp);
tape->Rec_.PutArg(arg0, arg1);
}
}
return result;
}
// convert other cases into the case above
CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(>=)
// -------------------------------- == -------------------------
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool operator == (const AD<Base> &left , const AD<Base> &right)
{ bool result = (left.value_ == right.value_);
//
// check if we are recording compare operators
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return result;
if( ! tape->Rec_.get_record_compare() )
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 ,
"==: AD variables or dynamic parameters on different threads."
);
//
tape->Rec_.comp_eq(
var_left, var_right, dyn_left, dyn_right, left, right, result
);
//
return result;
}
// convert other cases into the case above
CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(==)
// -------------------------------- != -------------------------
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool operator != (const AD<Base> &left , const AD<Base> &right)
{ bool result = (left.value_ != right.value_);
//
// check if we are recording compare operators
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return result;
if( ! tape->Rec_.get_record_compare() )
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 ,
"!=: AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // variable == variable
tape->Rec_.PutArg(left.taddr_, right.taddr_);
if( result )
tape->Rec_.PutOp(local::NevvOp);
else
tape->Rec_.PutOp(local::EqvvOp);
}
else
{ // variable == parameter
addr_t p = right.taddr_;
if( ! dyn_right )
p = tape->Rec_.put_con_par(right.value_);
tape->Rec_.PutArg(p, left.taddr_);
if( result )
tape->Rec_.PutOp(local::NepvOp);
else
tape->Rec_.PutOp(local::EqpvOp);
}
}
else if ( var_right )
{ // parameter == variable
addr_t p = left.taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left.value_);
tape->Rec_.PutArg(p, right.taddr_);
if( result )
tape->Rec_.PutOp(local::NepvOp);
else
tape->Rec_.PutOp(local::EqpvOp);
}
else if( dyn_left | dyn_right )
{ // parameter == parameter
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_);
//
tape->Rec_.PutArg(arg0, arg1);
if( result )
tape->Rec_.PutOp(local::NeppOp);
else
tape->Rec_.PutOp(local::EqppOp);
}
return result;
}
// convert other cases into the case above
CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(!=)
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,141 @@
# ifndef CPPAD_CORE_COMPOUND_ASSIGN_HPP
# define CPPAD_CORE_COMPOUND_ASSIGN_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 compound_assign$$
$spell
Op
VecAD
const
$$
$section AD Compound Assignment Operators$$
$head Syntax$$
$icode%x% %Op% %y%$$
$head Purpose$$
Performs compound assignment operations
where either $icode x$$ has type
$codei%AD<%Base%>%$$.
$head Op$$
The operator $icode Op$$ is one of the following
$table
$bold Op$$ $cnext $bold Meaning$$ $rnext
$code +=$$ $cnext $icode x$$ is assigned $icode x$$ plus $icode y$$ $rnext
$code -=$$ $cnext $icode x$$ is assigned $icode x$$ minus $icode y$$ $rnext
$code *=$$ $cnext $icode x$$ is assigned $icode x$$ times $icode y$$ $rnext
$code /=$$ $cnext $icode x$$ is assigned $icode x$$ divided by $icode y$$
$tend
$head Base$$
The type $icode Base$$ is determined by the operand $icode x$$.
$head x$$
The operand $icode x$$ has the following prototype
$codei%
AD<%Base%> &%x%
%$$
$head y$$
The operand $icode y$$ has the following prototype
$codei%
const %Type% &%y%
%$$
where $icode Type$$ is
$codei%VecAD<%Base%>::reference%$$,
$codei%AD<%Base%>%$$,
$icode Base$$, or
$code double$$.
$head Result$$
The result of this assignment
can be used as a reference to $icode x$$.
For example, if $icode z$$ has the following type
$codei%
AD<%Base%> %z%
%$$
then the syntax
$codei%
%z% = %x% += %y%
%$$
will compute $icode x$$ plus $icode y$$
and then assign this value to both $icode x$$ and $icode z$$.
$head Operation Sequence$$
This is an $cref/atomic_base/glossary/Operation/Atomic/$$
$cref/AD of Base/glossary/AD of Base/$$ operation
and hence it is part of the current
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$children%
example/general/add_eq.cpp%
example/general/sub_eq.cpp%
example/general/mul_eq.cpp%
example/general/div_eq.cpp
%$$
$head Example$$
The following files contain examples and tests of these functions.
Each test returns true if it succeeds and false otherwise.
$table
$rref AddEq.cpp$$
$rref sub_eq.cpp$$
$rref mul_eq.cpp$$
$rref div_eq.cpp$$
$tend
$head Derivative$$
If $latex f$$ and $latex g$$ are
$cref/Base functions/glossary/Base Function/$$
$subhead Addition$$
$latex \[
\D{[ f(x) + g(x) ]}{x} = \D{f(x)}{x} + \D{g(x)}{x}
\] $$
$subhead Subtraction$$
$latex \[
\D{[ f(x) - g(x) ]}{x} = \D{f(x)}{x} - \D{g(x)}{x}
\] $$
$subhead Multiplication$$
$latex \[
\D{[ f(x) * g(x) ]}{x} = g(x) * \D{f(x)}{x} + f(x) * \D{g(x)}{x}
\] $$
$subhead Division$$
$latex \[
\D{[ f(x) / g(x) ]}{x} =
[1/g(x)] * \D{f(x)}{x} - [f(x)/g(x)^2] * \D{g(x)}{x}
\] $$
$end
-----------------------------------------------------------------------------
*/
# include <cppad/core/add_eq.hpp>
# include <cppad/core/sub_eq.hpp>
# include <cppad/core/mul_eq.hpp>
# include <cppad/core/div_eq.hpp>
# endif

View File

@@ -0,0 +1,186 @@
# ifndef CPPAD_CORE_CON_DYN_VAR_HPP
# define CPPAD_CORE_CON_DYN_VAR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 con_dyn_var$$
$spell
VecAD
const
bool
$$
$section Constant, Dynamic, Parameter, and Variable$$
$head Syntax$$
$icode%b% = Constant(%x%)
%$$
$icode%b% = Dynamic(%x%)
%$$
$icode%b% = Parameter(%x%)
%$$
$icode%b% = Variable(%x%)
%$$
$head x$$
The argument $icode x$$ has prototype
$codei%
const AD<%Base%> &%x%
const VecAD<%Base%> &%x%
%$$
$head b$$
The return value $icode b$$ has prototype
$codei%
bool %b%
%$$
$head Constant$$
The return value for $code Constant$$ is true
is true if and only if $icode x$$ is
a $cref/constant/glossary/Parameter/Constant/$$ parameter.
A $cref/VecAD<Base>/VecAD/$$ object is a constant parameter
if no element of the vector depends on the independent variables.
$head Dynamic$$
The return value for $code Dynamic$$ is true
is true if and only if $icode x$$ is
a $cref/dynamic/glossary/Parameter/Dynamic/$$ parameter.
No element of a $cref/VecAD<Base>/VecAD/$$ object
can depend on the dynamic parameters and this function returns false
for these objects.
$head Parameter$$
The return value for $code Parameter$$ is true
is true if and only if $icode x$$ is
a $cref/parameter/glossary/Parameter/$$.
A $cref/VecAD<Base>/VecAD/$$ object is a parameter
if no element of the vector depends on the independent variables.
$head Variable$$
The return value for $code Variable$$ is true
is true if and only if $icode x$$ is
a $cref/variable/glossary/Variable/$$.
A $cref/VecAD<Base>/VecAD/$$ object is a variable
if any element of the vector depends on the independent variables.
$head Operation Sequence$$
The result of this operation is not an
$cref/AD of Base/glossary/AD of Base/$$ object.
Thus it will not be recorded as part of an
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Example$$
$children%
example/general/con_dyn_var.cpp
%$$
The file
$cref con_dyn_var.cpp$$
contains an example and test of these functions.
$end
-----------------------------------------------------------------------------
*/
namespace CppAD {
// -----------------------------------------------------------------------
// Constant
template <class Base>
bool Constant(const AD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_== 0 || x.ad_type_ != constant_enum );
if( x.tape_id_ == 0 )
return true;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ != *AD<Base>::tape_id_ptr(thread);
}
//
template <class Base>
bool Constant(const VecAD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_== 0 || x.ad_type_ != constant_enum );
if( x.tape_id_ == 0 )
return true;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ != *AD<Base>::tape_id_ptr(thread);
}
// -----------------------------------------------------------------------
// Dynamic
template <class Base>
bool Dynamic(const AD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
if( (x.tape_id_ == 0) | (x.ad_type_ != dynamic_enum) )
return false;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ == *AD<Base>::tape_id_ptr(thread);
}
//
template <class Base>
bool Dynamic(const VecAD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
if( (x.tape_id_ == 0) | (x.ad_type_ != dynamic_enum) )
return false;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ == *AD<Base>::tape_id_ptr(thread);
}
// -----------------------------------------------------------------------
// Parameter
template <class Base>
bool Parameter(const AD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
if( (x.tape_id_ == 0) | (x.ad_type_ == dynamic_enum) )
return true;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ != *AD<Base>::tape_id_ptr(thread);
}
//
template <class Base>
bool Parameter(const VecAD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
if( (x.tape_id_ == 0) | (x.ad_type_ == dynamic_enum) )
return true;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ != *AD<Base>::tape_id_ptr(thread);
}
// -----------------------------------------------------------------------
// Variable
template <class Base>
bool Variable(const AD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
if( (x.tape_id_ == 0) | (x.ad_type_ != variable_enum) )
return false;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ == *AD<Base>::tape_id_ptr(thread);
}
//
template <class Base>
bool Variable(const VecAD<Base> &x)
{ CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
if( (x.tape_id_ == 0) | (x.ad_type_ != variable_enum) )
return false;
//
size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS);
return x.tape_id_ == *AD<Base>::tape_id_ptr(thread);
}
}
// END CppAD namespace
# endif

View File

@@ -0,0 +1,276 @@
# ifndef CPPAD_CORE_COND_EXP_HPP
# define CPPAD_CORE_COND_EXP_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 CondExp$$
$spell
Atan2
CondExp
Taylor
std
Cpp
namespace
inline
const
abs
Rel
bool
Lt
Le
Eq
Ge
Gt
$$
$section AD Conditional Expressions$$
$head Syntax$$
$icode%result% = CondExp%Rel%(%left%, %right%, %if_true%, %if_false%)%$$
$head Purpose$$
Record,
as part of an AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$,
the conditional result
$codei%
if( %left% %Cop% %right% )
%result% = %if_true%
else
%result% = %if_false%
%$$
The relational $icode Rel$$ and comparison operator $icode Cop$$
above have the following correspondence:
$codei%
%Rel% Lt Le Eq Ge Gt
%Cop% < <= == >= >
%$$
If $icode f$$ is the $cref ADFun$$ object corresponding to the
AD operation sequence,
the assignment choice for $icode result$$
in an AD conditional expression is made each time
$cref/f.Forward/Forward/$$ is used to evaluate the zero order Taylor
coefficients with new values for the
$cref/independent variables/glossary/Tape/Independent Variable/$$.
This is in contrast to the $cref/AD comparison operators/Compare/$$
which are boolean valued and not included in the AD operation sequence.
$head Rel$$
In the syntax above, the relation $icode Rel$$ represents one of the following
two characters: $code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, $code Gt$$.
As in the table above,
$icode Rel$$ determines which comparison operator $icode Cop$$ is used
when comparing $icode left$$ and $icode right$$.
$head Type$$
These functions are defined in the CppAD namespace for arguments of
$icode Type$$ is $code float$$ , $code double$$, or any type of the form
$codei%AD<%Base%>%$$.
(Note that all four arguments must have the same type.)
$head left$$
The argument $icode left$$ has prototype
$codei%
const %Type%& %left%
%$$
It specifies the value for the left side of the comparison operator.
$head right$$
The argument $icode right$$ has prototype
$codei%
const %Type%& %right%
%$$
It specifies the value for the right side of the comparison operator.
$head if_true$$
The argument $icode if_true$$ has prototype
$codei%
const %Type%& %if_true%
%$$
It specifies the return value if the result of the comparison is true.
$head if_false$$
The argument $icode if_false$$ has prototype
$codei%
const %Type%& %if_false%
%$$
It specifies the return value if the result of the comparison is false.
$head result$$
The $icode result$$ has prototype
$codei%
%Type%& %if_false%
%$$
$head Optimize$$
The $cref optimize$$ method will optimize conditional expressions
in the following way:
During $cref/zero order forward mode/forward_zero/$$,
once the value of the $icode left$$ and $icode right$$ have been determined,
it is known if the true or false case is required.
From this point on, values corresponding to the case that is not required
are not computed.
This optimization is done for the rest of zero order forward mode
as well as forward and reverse derivatives calculations.
$head Deprecate 2005-08-07$$
Previous versions of CppAD used
$codei%
CondExp(%flag%, %if_true%, %if_false%)
%$$
for the same meaning as
$codei%
CondExpGt(%flag%, %Type%(0), %if_true%, %if_false%)
%$$
Use of $code CondExp$$ is deprecated, but continues to be supported.
$head Operation Sequence$$
This is an AD of $icode Base$$
$cref/atomic operation/glossary/Operation/Atomic/$$
and hence is part of the current
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Example$$
$head Test$$
$children%
example/general/cond_exp.cpp
%$$
The file
$cref cond_exp.cpp$$
contains an example and test of this function.
$head Atan2$$
The following implementation of the
AD $cref atan2$$ function is a more complex
example of using conditional expressions:
$srcfile%include/cppad/core/atan2.hpp%0%BEGIN CondExp%// END CondExp%$$
$end
-------------------------------------------------------------------------------
*/
// BEGIN CppAD namespace
namespace CppAD {
template <class Base>
AD<Base> CondExpOp(
enum CompareOp cop ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &if_true ,
const AD<Base> &if_false )
{
AD<Base> result;
CPPAD_ASSERT_UNKNOWN( Parameter(result) );
// check first case where do not need to tape
if( IdenticalCon(left) & IdenticalCon(right) )
{ switch( cop )
{
case CompareLt:
if( left.value_ < right.value_ )
result = if_true;
else
result = if_false;
break;
case CompareLe:
if( left.value_ <= right.value_ )
result = if_true;
else
result = if_false;
break;
case CompareEq:
if( left.value_ == right.value_ )
result = if_true;
else
result = if_false;
break;
case CompareGe:
if( left.value_ >= right.value_ )
result = if_true;
else
result = if_false;
break;
case CompareGt:
if( left.value_ > right.value_ )
result = if_true;
else
result = if_false;
break;
default:
CPPAD_ASSERT_UNKNOWN(0);
result = if_true;
}
return result;
}
// must use CondExp in case Base is an AD type and recording
result.value_ = CondExpOp(cop,
left.value_, right.value_, if_true.value_, if_false.value_);
local::ADTape<Base> *tape = AD<Base>::tape_ptr();
// add this operation to the tape
if( tape != nullptr ) tape->Rec_.cond_exp(
tape->id_, cop, result, left, right, if_true, if_false
);
return result;
}
// ------------ CondExpOp(left, right, if_true, if_false) ----------------
# define CPPAD_COND_EXP(Name) \
template <class Base> \
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION \
AD<Base> CondExp##Name( \
const AD<Base> &left , \
const AD<Base> &right , \
const AD<Base> &if_true , \
const AD<Base> &if_false ) \
{ \
return CondExpOp(Compare##Name, \
left, right, if_true, if_false); \
}
// AD<Base>
CPPAD_COND_EXP(Lt)
CPPAD_COND_EXP(Le)
CPPAD_COND_EXP(Eq)
CPPAD_COND_EXP(Ge)
CPPAD_COND_EXP(Gt)
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
AD<Base> CondExp(
const AD<Base> &flag ,
const AD<Base> &if_true ,
const AD<Base> &if_false )
{
return CondExpOp(CompareGt, flag, AD<Base>(0), if_true, if_false);
}
# undef CPPAD_COND_EXP
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,50 @@
# ifndef CPPAD_CORE_CONVERT_HPP
# define CPPAD_CORE_CONVERT_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 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 Convert$$
$spell
$$
$section Conversion and I/O of AD Objects$$
$children%
include/cppad/core/value.hpp%
include/cppad/core/integer.hpp%
include/cppad/core/ad_to_string.hpp%
include/cppad/core/ad_io.hpp%
include/cppad/core/print_for.hpp%
include/cppad/core/var2par.hpp
%$$
$table
$rref Value$$
$rref Integer$$
$rref ad_output$$
$rref PrintFor$$
$rref Var2Par$$
$tend
$end
*/
# include <cppad/core/value.hpp>
# include <cppad/core/integer.hpp>
# include <cppad/core/ad_to_string.hpp>
# include <cppad/core/ad_io.hpp>
# include <cppad/core/print_for.hpp>
# include <cppad/core/var2par.hpp>
# endif

View File

@@ -0,0 +1,188 @@
# ifndef CPPAD_CORE_CPPAD_ASSERT_HPP
# define CPPAD_CORE_CPPAD_ASSERT_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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.
---------------------------------------------------------------------------- */
/*!
\file cppad_assert.hpp
Define the CppAD error checking macros (all of which begin with CPPAD_ASSERT_)
*/
/*
-------------------------------------------------------------------------------
$begin cppad_assert$$
$spell
CppAD
exp
const
bool
$$
$section CppAD Assertions During Execution$$
$head Syntax$$
$codei%CPPAD_ASSERT_KNOWN(%exp%, %msg%)
%$$
$codei%CPPAD_ASSERT_UNKNOWN(%exp%)%$$
$head Purpose$$
These CppAD macros are used to detect and report errors.
They are documented here because they correspond to the C++
source code that the error is reported at.
$head NDEBUG$$
If the preprocessor symbol
$cref/NDEBUG/Faq/Speed/NDEBUG/$$ is defined,
these macros do nothing; i.e., they are optimized out.
$head Restriction$$
The CppAD user should not uses these macros.
You can however write your own macros that do not begin with $code CPPAD$$
and that call the $cref/CppAD error handler/ErrorHandler/$$.
$head Known$$
The $code CPPAD_ASSERT_KNOWN$$ macro is used to check for an error
with a known cause.
For example, many CppAD routines uses these macros
to make sure their arguments conform to their specifications.
$head Unknown$$
The $code CPPAD_ASSERT_UNKNOWN$$ macro is used to check that the
CppAD internal data structures conform as expected.
If this is not the case, CppAD does not know why the error has
occurred; for example, the user may have written past the end
of an allocated array.
$head Exp$$
The argument $icode exp$$ is a C++ source code expression
that results in a $code bool$$ value that should be true.
If it is false, an error has occurred.
This expression may be execute any number of times
(including zero times) so it must have not side effects.
$head Msg$$
The argument $icode msg$$ has prototype
$codei%
const char *%msg%
%$$
and contains a $code '\0'$$ terminated character string.
This string is a description of the error
corresponding to $icode exp$$ being false.
$head Error Handler$$
These macros use the
$cref/CppAD error handler/ErrorHandler/$$ to report errors.
This error handler can be replaced by the user.
$end
------------------------------------------------------------------------------
*/
# include <cassert>
# include <iostream>
# include <cppad/utility/error_handler.hpp>
/*!
\def CPPAD_ASSERT_KNOWN(exp, msg)
Check that exp is true, if not print msg and terminate execution.
The C++ expression exp is expected to be true.
If it is false,
the CppAD use has made an error that is described by msg.
If the preprocessor symbol NDEBUG is not defined,
and exp is false,
this macro will report the source code line number at
which this expected result occurred.
In addition, it will print the specified error message msg.
*/
# ifdef NDEBUG
# define CPPAD_ASSERT_KNOWN(exp, msg) // do nothing
# else
# define CPPAD_ASSERT_KNOWN(exp, msg) \
{ if( ! ( exp ) ) \
CppAD::ErrorHandler::Call( \
true , \
__LINE__ , \
__FILE__ , \
#exp , \
msg ); \
}
# endif
/*!
\def CPPAD_ASSERT_UNKNOWN(exp)
Check that exp is true, if not terminate execution.
The C++ expression exp is expected to be true.
If it is false,
CppAD has detected an error but does not know the cause of the error.
If the preprocessor symbol NDEBUG is not defined,
and exp is false,
this macro will report the source code line number at
which this expected result occurred.
*/
# ifdef NDEBUG
# define CPPAD_ASSERT_UNKNOWN(exp) // do nothing
# else
# define CPPAD_ASSERT_UNKNOWN(exp) \
{ if( ! ( exp ) ) \
CppAD::ErrorHandler::Call( \
false , \
__LINE__ , \
__FILE__ , \
#exp , \
"" ); \
}
# endif
/*!
\def CPPAD_ASSERT_NARG_NRES(op, n_arg, n_res)
Check that operator op has the specified number of of arguments and results.
If NDEBUG is not defined and either the number of arguments
or the number of results are not as expected,
execution is terminated and the source code line number is reported.
*/
# define CPPAD_ASSERT_NARG_NRES(op, n_arg, n_res) \
CPPAD_ASSERT_UNKNOWN( NumArg(op) == n_arg ) \
CPPAD_ASSERT_UNKNOWN( NumRes(op) == n_res )
/*!
\def CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
Check that the first call to a routine is not during parallel execution mode.
If NDEBUG is defined, this macro has no effect
(not even the definition of (assert_first_call).
Otherwise, the variable
\code
static bool assert_first_call
\endcode
is defined and if the first call is executed in parallel mode,
execution is terminated and the source code line number is reported.
*/
# ifdef NDEBUG
# define CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
# else
# define CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL \
static bool assert_first_call = true; \
if( assert_first_call ) \
{ CPPAD_ASSERT_KNOWN( \
! (CppAD::thread_alloc::in_parallel() ), \
"In parallel mode and parallel_setup has not been called." \
); \
assert_first_call = false; \
}
# endif
# endif

View File

@@ -0,0 +1,334 @@
# ifndef CPPAD_CORE_DEPENDENT_HPP
# define CPPAD_CORE_DEPENDENT_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 Dependent$$
$spell
alloc
num
taylor_
ADvector
const
$$
$spell
$$
$section Stop Recording and Store Operation Sequence$$
$head Syntax$$
$icode%f%.Dependent(%x%, %y%)%$$
$head Purpose$$
Stop recording and the AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$
that started with the call
$codei%
Independent(%x%)
%$$
and store the operation sequence in $icode f$$.
The operation sequence defines an
$cref/AD function/glossary/AD Function/$$
$latex \[
F : \B{R}^n \rightarrow \B{R}^m
\] $$
where $latex B$$ is the space corresponding to objects of type $icode Base$$.
The value $latex n$$ is the dimension of the
$cref/domain/seq_property/Domain/$$ space for the operation sequence.
The value $latex m$$ is the dimension of the
$cref/range/seq_property/Range/$$ space for the operation sequence
(which is determined by the size of $icode y$$).
$head f$$
The object $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
The AD of $icode Base$$ operation sequence is stored in $icode f$$; i.e.,
it becomes the operation sequence corresponding to $icode f$$.
If a previous operation sequence was stored in $icode f$$,
it is deleted.
$head x$$
The argument $icode x$$
must be the vector argument in a previous call to
$cref Independent$$.
Neither its size, or any of its values, are allowed to change
between calling
$codei%
Independent(%x%)
%$$
and
$codei%
%f%.Dependent(%x%, %y%)
%$$.
$head y$$
The vector $icode y$$ has prototype
$codei%
const %ADvector% &%y%
%$$
(see $cref/ADvector/FunConstruct/$$ below).
The length of $icode y$$ must be greater than zero
and is the dimension of the range space for $icode f$$.
$head ADvector$$
The type $icode ADvector$$ must be a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$codei%AD<%Base%>%$$.
The routine $cref CheckSimpleVector$$ will generate an error message
if this is not the case.
$head Taping$$
The tape,
that was created when $codei%Independent(%x%)%$$ was called,
will stop recording.
The AD operation sequence will be transferred from
the tape to the object $icode f$$ and the tape will then be deleted.
$head Forward$$
No $cref Forward$$ calculation is preformed during this operation.
Thus, directly after this operation,
$codei%
%f%.size_order()
%$$
is zero (see $cref size_order$$).
$head Parallel Mode$$
The call to $code Independent$$,
and the corresponding call to
$codei%
ADFun<%Base%> %f%( %x%, %y%)
%$$
or
$codei%
%f%.Dependent( %x%, %y%)
%$$
or $cref abort_recording$$,
must be preformed by the same thread; i.e.,
$cref/thread_alloc::thread_num/ta_thread_num/$$ must be the same.
$head Example$$
The file
$cref fun_check.cpp$$
contains an example and test of this operation.
$end
----------------------------------------------------------------------------
*/
// BEGIN CppAD namespace
namespace CppAD {
/*!
\file dependent.hpp
Different versions of Dependent function.
*/
/*!
Determine the tape corresponding to this exeuction thread and then use
<code>Dependent(tape, y)</code> to store this tapes recording in a function.
\param y [in]
The dependent variable vector for the corresponding function.
*/
template <class Base, class RecBase>
template <class ADvector>
void ADFun<Base,RecBase>::Dependent(const ADvector &y)
{ local::ADTape<Base>* tape = AD<Base>::tape_ptr();
CPPAD_ASSERT_KNOWN(
tape != nullptr,
"Can't store current operation sequence in this ADFun object"
"\nbecause there is no active tape (for this thread)."
);
// code above just determines the tape and checks for errors
Dependent(tape, y);
}
/*!
Determine the tape corresponding to this exeuction thread and then use
<code>Dependent(tape, y)</code> to store this tapes recording in a function.
\param x [in]
The independent variable vector for this tape. This informaiton is
also stored in the tape so a check is done to make sure it is correct
(if NDEBUG is not defined).
\param y [in]
The dependent variable vector for the corresponding function.
*/
template <class Base, class RecBase>
template <class ADvector>
void ADFun<Base,RecBase>::Dependent(const ADvector &x, const ADvector &y)
{
CPPAD_ASSERT_KNOWN(
x.size() > 0,
"Dependent: independent variable vector has size zero."
);
CPPAD_ASSERT_KNOWN(
Variable(x[0]),
"Dependent: independent variable vector has been changed."
);
local::ADTape<Base> *tape = AD<Base>::tape_ptr(x[0].tape_id_);
CPPAD_ASSERT_KNOWN(
tape->size_independent_ == size_t( x.size() ),
"Dependent: independent variable vector has been changed."
);
# ifndef NDEBUG
size_t i, j;
for(j = 0; j < size_t(x.size()); j++)
{ CPPAD_ASSERT_KNOWN(
size_t(x[j].taddr_) == (j+1),
"ADFun<Base>: independent variable vector has been changed."
);
CPPAD_ASSERT_KNOWN(
x[j].tape_id_ == x[0].tape_id_,
"ADFun<Base>: independent variable vector has been changed."
);
}
for(i = 0; i < size_t(y.size()); i++)
{ CPPAD_ASSERT_KNOWN(
CppAD::Parameter( y[i] ) | (y[i].tape_id_ == x[0].tape_id_) ,
"ADFun<Base>: dependent vector contains a variable for"
"\na different tape (thread) than the independent variables."
);
}
# endif
// code above just determines the tape and checks for errors
Dependent(tape, y);
}
/*!
Replace the floationg point operations sequence for this function object.
\param tape
is a tape that contains the new floating point operation sequence
for this function.
After this operation, all memory allocated for this tape is deleted.
\param y
The dependent variable vector for the function being stored in this object.
\par
All of the private member data in ad_fun.hpp is set to correspond to the
new tape except for check_for_nan_.
*/
template <class Base, class RecBase>
template <class ADvector>
void ADFun<Base,RecBase>::Dependent(local::ADTape<Base> *tape, const ADvector &y)
{
size_t m = y.size();
size_t n = tape->size_independent_;
// check ADvector is Simple Vector class with AD<Base> elements
CheckSimpleVector< AD<Base>, ADvector>();
CPPAD_ASSERT_KNOWN(
y.size() > 0,
"ADFun operation sequence dependent variable size is zero size"
);
// ---------------------------------------------------------------------
// Begin setting ad_fun.hpp private member data
// ---------------------------------------------------------------------
// dep_parameter_, dep_taddr_
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ParOp) == 1 );
dep_parameter_.resize(m);
dep_taddr_.resize(m);
for(size_t i = 0; i < m; i++)
{ dep_parameter_[i] = CppAD::Parameter(y[i]);
addr_t y_taddr;
if( dep_parameter_[i] )
{ // make a tape copy of dependent variables that are parameters,
y_taddr = tape->RecordParOp( y[i] );
}
else
y_taddr = y[i].taddr_;
CPPAD_ASSERT_UNKNOWN( y_taddr > 0 );
dep_taddr_[i] = size_t( y_taddr );
}
// put an EndOp at the end of the tape
tape->Rec_.PutOp(local::EndOp);
// bool values in this object except check_for_nan_
has_been_optimized_ = false;
//
// size_t values in this object
compare_change_count_ = 1;
compare_change_number_ = 0;
compare_change_op_index_ = 0;
num_order_taylor_ = 0;
cap_order_taylor_ = 0;
num_direction_taylor_ = 0;
num_var_tape_ = tape->Rec_.num_var_rec();
// taylor_
taylor_.resize(0);
// cskip_op_
cskip_op_.resize( tape->Rec_.num_op_rec() );
// load_op2var_
load_op2var_.resize( tape->Rec_.num_var_load_rec() );
// play_
// Now that each dependent variable has a place in the tape,
// and there is a EndOp at the end of the tape, we can transfer the
// recording to the player and and erase the recording; i.e. ERASE Rec_.
play_.get_recording(tape->Rec_, n);
// ind_taddr_
// Note that play_ has been set, we can use it to check operators
ind_taddr_.resize(n);
CPPAD_ASSERT_UNKNOWN( n < num_var_tape_);
for(size_t j = 0; j < n; j++)
{ CPPAD_ASSERT_UNKNOWN( play_.GetOp(j+1) == local::InvOp );
ind_taddr_[j] = j+1;
}
// for_jac_sparse_pack_, for_jac_sparse_set_
for_jac_sparse_pack_.resize(0, 0);
for_jac_sparse_set_.resize(0,0);
// resize subgraph_info_
subgraph_info_.resize(
ind_taddr_.size(), // n_dep
dep_taddr_.size(), // n_ind
play_.num_op_rec(), // n_op
play_.num_var_rec() // n_var
);
// ---------------------------------------------------------------------
// End set ad_fun.hpp private member data
// ---------------------------------------------------------------------
// now we can delete the tape
AD<Base>::tape_manage(delete_tape_manage);
// total number of varables in this recording
CPPAD_ASSERT_UNKNOWN( num_var_tape_ == play_.num_var_rec() );
// used to determine if there is an operation sequence in *this
CPPAD_ASSERT_UNKNOWN( num_var_tape_ > 0 );
}
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,22 @@
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 devel_discrete$$
$spell
$$
$section Developer Documentation for Discrete Function$$
$childtable%
include/cppad/core/discrete/discrete.hpp
%$$
$end

View File

@@ -0,0 +1,334 @@
# ifndef CPPAD_CORE_DISCRETE_DISCRETE_HPP
# define CPPAD_CORE_DISCRETE_DISCRETE_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.
---------------------------------------------------------------------------- */
# include <vector>
# include <cppad/core/cppad_assert.hpp>
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
# include <cppad/utility/thread_alloc.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*
------------------------------------------------------------------------------
$begin discrete_create$$
$spell
$$
$section Create a Discrete AD Function$$
$head Syntax$$
$codei%CPPAD_DISCRETE_FUNCTION(%Base%, %name%)
%$$
$icode%name(%ax%, %ay%)
%$$
$head Base$$
is the base type for the discrete function.
$head name$$
is the name of the user defined function that corresponding to this operation.
$head ax$$
Is a $codei%AD<%Base%>%$$ corresponding to the argument for the function.
$head ay$$
Is a $codei%AD<%Base%>%$$ corresponding to the result for the function.
$head fun$$
The local object $code fun$$ is a member of the $code discrete$$ class.
$head Source Code$$
$srccode%hpp% */
# define CPPAD_DISCRETE_FUNCTION(Base, name) \
inline CppAD::AD<Base> name (const CppAD::AD<Base>& ax) \
{ static CppAD::discrete<Base> fun(#name, name); \
return fun.ad(ax); \
}
# define CppADCreateDiscrete CPPAD_DISCRETE_FUNCTION
/* %$$
$end
-----------------------------------------------------------------------------
$begin discrete_class$$
$section Declare discrete Class and Member Data$$
$head parallel_ad$$
is a friend of this class so it can call List to initialize
its static data.
$head F$$
is the type for the user routine that computes $icode Base$$ function values.
$head name_$$
name of this user defined discrete function.
$head f_$$
user routine that computes $icode Base$$ function values.
$head index_$$
index of this object in $cref discrete_list$$ for this $icode Base$$.
$head Source Code$$
$srccode%hpp% */
template <class Base>
class discrete {
private:
template <class Type> friend void parallel_ad(void);
typedef Base (*F) (const Base& x);
const std::string name_;
const F f_;
const size_t index_;
/* %$$
$end
------------------------------------------------------------------------------
$begin discrete_list$$
$spell
alloc
std
CppAD
$$
$section List of all objects in the discrete class$$
$head Syntax$$
$icode%list% = discrete<%Base%>::List()%$$
$head Base$$
Is the $cref/Base/discrete_create/Base/$$
type for this list of discrete functions.
$head list$$
is a reference to the list of all the
$code discrete$$ object currently defined.
$subhead std::vector$$
We use $code std::vector$$ instead of $code CppAD::vector$$
so it does not appear that there is a $cref memory_leak$$
this list is not destroyed before
$cref/thread_alloc::free_all/ta_free_all/$$ is called by testing routines.
$head Source Code$$
$srccode%hpp% */
private:
static std::vector<discrete *>& List(void)
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
static std::vector<discrete *> list;
return list;
}
/* %$$
$end
------------------------------------------------------------------------------
$begin discrete_list_size$$
$spell
$$
$section Size of the Discrete Function List$$
$head Syntax$$
$icode%size% = discrete<%Base%>::list_size()%$$
$head Base$$
Is the $cref/Base/discrete_create/Base/$$
type for this list of discrete functions.
$head size$$
is the number of discrete functions for this $icode Base$$ type.
$head Source Code$$
$srccode%hpp% */
public:
static size_t list_size(void)
{ return List().size(); }
/* %$$
$end
------------------------------------------------------------------------------
$begin discrete_ctor$$
$spell
$$
$section Constructor Called by each Use of CPPAD_DISCRETE_FUNCTION$$
$head Syntax$$
$codei%discrete<%Base%> %fun%(%name%, %f%)%$$
$head name$$
is the name of this function.
$head f$$
user routine that implements this function for Base class.
$head fun$$
is the $code discrete$$ object created by this call to the constructor.
$subhead name_$$
is set equal to $icode name$$.
$subhead f_$$
is set equal to $icode f$$.
$subhead index_$$
This object is put at the end of $cref discrete_list$$ and $code index_$$
is set to the index of this object in the discrete list.
$head Parallel$$
This constructor cannot be used in parallel mode because it changes
the static object returned by $cref discrete_list$$.
$end
*/
public:
discrete(const char* name, F f) :
name_(name), f_(f) , index_( List().size() )
{ std::string msg = "discrete: first call to the discrete function ";
msg += name;
msg += " is in parallel mode.";
CPPAD_ASSERT_KNOWN(
! thread_alloc::in_parallel() ,
msg.c_str()
);
List().push_back(this);
}
/*
------------------------------------------------------------------------------
$begin discrete_ad$$
$spell
$$
$section Implement AD Version of a Discrete Function$$
$head Syntax$$
$icode%ay% = %fun%.ad(%ax)%$$
$head ax$$
is the argument for the AD version of this function.
$head ay$$
is the return value for the AD version of this function.
$head Prototype$$
$srccode%hpp% */
AD<Base> ad(const AD<Base> &ax) const
/* %$$
$end
*/
{
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= index_,
"discrete: cppad_tape_addr_type maximum not large enough"
);
//
AD<Base> ay;
ay.value_ = f_(ax.value_);
//
// check if there is a recording in progress
local::ADTape<Base>* tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return ay;
//
// check if argument is a constant parameter
if( ax.tape_id_ != tape->id_ )
return ay;
//
if( ax.ad_type_ == dynamic_enum )
{
// tape dynamic paramter operation
ay.taddr_ = tape->Rec_.put_dyn_par(
ay.value_, local::dis_dyn, addr_t(index_), ax.taddr_
);
ay.tape_id_ = ax.tape_id_;
ay.ad_type_ = dynamic_enum;
// make result a dynamic parameter
ay.tape_id_ = tape->id_;
ay.ad_type_ = dynamic_enum;
CPPAD_ASSERT_UNKNOWN( Dynamic(ay) );
}
else if( ax.ad_type_ == variable_enum )
{
CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DisOp) == 1 );
CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DisOp) == 2 );
// put operand addresses in the tape
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= index_,
"discrete: cppad_tape_addr_type maximum not large enough"
);
tape->Rec_.PutArg(addr_t(index_), ax.taddr_);
// put operator in the tape
ay.taddr_ = tape->Rec_.PutOp(local::DisOp);
// make result a variable
ay.tape_id_ = tape->id_;
ay.ad_type_ = variable_enum;
CPPAD_ASSERT_UNKNOWN( Variable(ay) );
}
else
{ // other types not yet being used and should have this tape id
CPPAD_ASSERT_UNKNOWN(false);
}
return ay;
}
/*
------------------------------------------------------------------------------
$begin discrete_name$$
$section Name Corresponding to a discrete Function$$
$head Syntax$$
$codei%discrete<%Base%>::name(%index%)%$$
$head Base$$
Is the $cref/Base/discrete_create/Base/$$
type for this list of discrete functions.
$head index$$
Is the index, in the list, for this discrete function.
$head Source Code$$
$srccode%hpp% */
static const char* name(size_t index)
{ return List()[index]->name_.c_str(); }
/* %$$
$end
------------------------------------------------------------------------------
$begin discrete_eval$$
$spell
eval
$$
$section Link From Forward Mode Sweep to Users Routine$$
$head Syntax$$
$icode%y% = discrete<%Base%>::eval(%index%, %x%)%$$
$head Base$$
Is the $cref/Base/discrete_create/Base/$$
type for this list of discrete functions.
$head index$$
index for this function in $cref discrete_list$$.
$head x$$
argument at which to evaluate $icode Base$$ version of this function.
$head y$$
result for the $icode Base$$ version of this function.
$head Source Code$$
$srccode%hpp% */
static Base eval(size_t index, const Base& x)
{ CPPAD_ASSERT_UNKNOWN(index < List().size() );
return List()[index]->f_(x);
}
/* %$$
$end
*/
};
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,146 @@
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 Discrete$$
$spell
retaping
namespace
std
Eq
Cpp
const
inline
Geq
$$
$section Discrete AD Functions$$
$head Syntax$$
$codei%CPPAD_DISCRETE_FUNCTION(%Base%, %name%)
%$$
$icode%y% = %name%(%x%)
%$$
$icode%ay% = %name%(%ax%)
%$$
$head Purpose$$
Record the evaluation of a discrete function as part
of an $codei%AD<%Base%>%$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
The value of a discrete function can depend on the
$cref/independent variables/glossary/Tape/Independent Variable/$$,
but its derivative is identically zero.
For example, suppose that the integer part of
a $cref/variable/glossary/Variable/$$ $icode x$$ is the
index into an array of values.
$head Base$$
This is the
$cref/base type/base_require/$$
corresponding to the operations sequence;
i.e., use of the $icode name$$ with arguments of type
$codei%AD<%Base%>%$$ can be recorded in an operation sequence.
$head name$$
This is the name of the function (as it is used in the source code).
The user must provide a version of $icode name$$
where the argument has type $icode Base$$.
CppAD uses this to create a version of $icode name$$
where the argument has type $codei%AD<%Base%>%$$.
$head x$$
The argument $icode x$$ has prototype
$codei%
const %Base%& %x%
%$$
It is the value at which the user provided version of $icode name$$
is to be evaluated.
$head y$$
The result $icode y$$ has prototype
$codei%
%Base% %y%
%$$
It is the return value for the user provided version of $icode name$$.
$head ax$$
The argument $icode ax$$ has prototype
$codei%
const AD<%Base%>& %ax%
%$$
It is the value at which the CppAD provided version of $icode name$$
is to be evaluated.
$head ay$$
The result $icode ay$$ has prototype
$codei%
AD<%Base%> %ay%
%$$
It is the return value for the CppAD provided version of $icode name$$.
$head Create AD Version$$
The preprocessor macro invocation
$codei%
CPPAD_DISCRETE_FUNCTION(%Base%, %name%)
%$$
defines the $codei%AD<%Base%>%$$ version of $icode name$$.
This can be with in a namespace (not the $code CppAD$$ namespace)
but must be outside of any routine.
$head Operation Sequence$$
This is an AD of $icode Base$$
$cref/atomic operation/glossary/Operation/Atomic/$$
and hence is part of the current
AD of $icode Base$$
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Derivatives$$
During a zero order $cref Forward$$ operation,
an $cref ADFun$$ object will compute the value of $icode name$$
using the user provided $icode Base$$ version of this routine.
All the derivatives of $icode name$$ will be evaluated as zero.
$head Parallel Mode$$
The first call to
$codei%
%name%(%ax%)
%$$
must not be in $cref/parallel/ta_in_parallel/$$ execution mode.
$head Example$$
$children%
example/general/tape_index.cpp%
example/general/interp_onetape.cpp%
example/general/interp_retape.cpp
%$$
The file
$cref tape_index.cpp$$
contains an example and test that uses a discrete function
to vary an array index during $cref Forward$$ mode calculations.
The file
$cref interp_onetape.cpp$$
contains an example and test that uses discrete
functions to avoid retaping a calculation that requires interpolation.
(The file
$cref interp_retape.cpp$$
shows how interpolation can be done with retaping.)
$head CppADCreateDiscrete Deprecated 2007-07-28$$
The preprocessor symbol $code CppADCreateDiscrete$$
is defined to be the same as $code CPPAD_DISCRETE_FUNCTION$$
but its use is deprecated.
$end

View File

@@ -0,0 +1,130 @@
# 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

View File

@@ -0,0 +1,129 @@
# ifndef CPPAD_CORE_DIV_EQ_HPP
# define CPPAD_CORE_DIV_EQ_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>& AD<Base>::operator /= (const AD<Base> &right)
{
// compute the Base part
Base left;
left = value_;
value_ /= right.value_;
// check if there is a recording in progress
local::ADTape<Base>* tape = AD<Base>::tape_ptr();
if( tape == nullptr )
return *this;
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 = 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 & (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 & (ad_type_ != dynamic_enum);
bool var_right = match_right & (right.ad_type_ != dynamic_enum);
CPPAD_ASSERT_KNOWN(
tape_id_ == right.tape_id_ || ! match_left || ! match_right ,
"/= : AD variables or dynamic parameters on different threads."
);
if( var_left )
{ if( var_right )
{ // this = 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(taddr_, right.taddr_);
// put operator in the tape
taddr_ = tape->Rec_.PutOp(local::DivvvOp);
// check that this is a variable
CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id );
CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum);
}
else if( (! dyn_right) & IdenticalOne(right.value_) )
{ // this = variable * 1
}
else
{ // this = 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(taddr_, p);
// put operator in the tape
taddr_ = tape->Rec_.PutOp(local::DivvpOp);
// check that this is a variable
CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id );
CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum);
}
}
else if( var_right )
{ if( (! dyn_left) & IdenticalZero(left) )
{ // this = 0 / variable
}
else
{ // this = 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 = taddr_;
if( ! dyn_left )
p = tape->Rec_.put_con_par(left);
tape->Rec_.PutArg(p, right.taddr_);
// put operator in the tape
taddr_ = tape->Rec_.PutOp(local::DivpvOp);
// make this a variable
tape_id_ = tape_id;
ad_type_ = variable_enum;
}
}
else if( dyn_left | dyn_right )
{ addr_t arg0 = taddr_;
addr_t arg1 = right.taddr_;
if( ! dyn_left )
arg0 = tape->Rec_.put_con_par(left);
if( ! dyn_right )
arg1 = tape->Rec_.put_con_par(right.value_);
//
// parameters with a dynamic parameter results
taddr_ = tape->Rec_.put_dyn_par(
value_, local::div_dyn, arg0, arg1
);
tape_id_ = tape_id;
ad_type_ = dynamic_enum;
}
return *this;
}
CPPAD_FOLD_ASSIGNMENT_OPERATOR(/=)
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,22 @@
# ifndef CPPAD_CORE_DRIVERS_HPP
# define CPPAD_CORE_DRIVERS_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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.
---------------------------------------------------------------------------- */
# include <cppad/core/jacobian.hpp>
# include <cppad/core/hessian.hpp>
# include <cppad/core/for_one.hpp>
# include <cppad/core/rev_one.hpp>
# include <cppad/core/for_two.hpp>
# include <cppad/core/rev_two.hpp>
# endif

View File

@@ -0,0 +1,60 @@
# ifndef CPPAD_CORE_EPSILON_HPP
# define CPPAD_CORE_EPSILON_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 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 epsilon$$
$spell
std
eps
CppAD
namespace
const
$$
$section Machine Epsilon For AD Types$$
$head Deprecated 2012-06-17$$
This routine has been deprecated.
You should use the $cref numeric_limits$$ $code epsilon$$ instead.
$head Syntax$$
$icode%eps% = epsilon<%Float%>()%$$
$head Purpose$$
Obtain the value of machine epsilon corresponding
to the type $icode%Float%$$.
$head Float$$
this type can either be $codei%AD<%Base%>%$$,
or it can be $icode Base$$ for any $codei%AD<%Base%>%$$ type.
$head eps$$
The result $icode eps$$ has prototype
$codei%
%Float% eps
%$$
$end
------------------------------------------------------------------------------
*/
namespace CppAD {
template <class Type>
inline Type epsilon(void)
{ return Type ( numeric_limits<Type>::epsilon() ); }
}
# endif

View File

@@ -0,0 +1,118 @@
# ifndef CPPAD_CORE_EQUAL_OP_SEQ_HPP
# define CPPAD_CORE_EQUAL_OP_SEQ_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 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 EqualOpSeq$$
$spell
Op
const
bool
$$
$section Check if Two Value are Identically Equal$$
$head Syntax$$
$icode%b% = EqualOpSeq(%x%, %y%)%$$
$head Purpose$$
Determine if two $icode x$$ and $icode y$$ are identically equal; i.e.,
not only is $icode%x% == %y%$$ true, but
if they are $cref/variables/glossary/Variable/$$,
they correspond have the same
$cref/operation sequence/glossary/Operation/Sequence/$$.
$head Motivation$$
Sometimes it is useful to cache information
and only recalculate when a function's arguments change.
In the case of AD variables,
it may be important not only when the argument values are equal,
but when they are related to the
$cref/independent variables/glossary/Tape/Independent Variable/$$
by the same operation sequence.
After the assignment
$codei%
%y% = %x%
%$$
these two AD objects would not only have equal values,
but would also correspond to the same operation sequence.
$head x$$
The argument $icode x$$ has prototype
$codei%
const AD<%Base%> &%x%
%$$
$head y$$
The argument $icode y$$ has prototype
$codei%
const AD<%Base%> &%y%
%$$
$head b$$
The result $icode b$$ has prototype
$codei%
bool %b%
%$$
The result is true if and only if one of the following cases holds:
$list number$$
Both $icode x$$ and $icode y$$ are variables
and correspond to the same operation sequence.
$lnext
Both $icode x$$ and $icode y$$ are parameters,
$icode Base$$ is an AD type,
and $codei%EqualOpSeq( Value(%x%) , Value(%y%) )%$$ is true.
$lnext
Both $icode x$$ and $icode y$$ are parameters,
$icode Base$$ is not an AD type,
and $icode%x% == %y%%$$ is true.
$lend
$head Example$$
$children%
example/general/equal_op_seq.cpp
%$$
The file
$cref equal_op_seq.cpp$$
contains an example and test of $code EqualOpSeq$$.
$end
------------------------------------------------------------------------------
*/
namespace CppAD {
template <class Base>
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
bool EqualOpSeq(const AD<Base> &x, const AD<Base> &y)
{
if( Parameter(x) )
{ if( Parameter(y) )
return EqualOpSeq(x.value_, y.value_);
else
return false;
}
else if( Parameter(y) )
return false;
return (x.taddr_ == y.taddr_);
}
}
# endif

View File

@@ -0,0 +1,287 @@
# ifndef CPPAD_CORE_FOR_HES_SPARSITY_HPP
# define CPPAD_CORE_FOR_HES_SPARSITY_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 for_hes_sparsity$$
$spell
Andrea Walther
Jacobian
Hessian
jac
hes
bool
const
rc
cpp
$$
$section Forward Mode Hessian Sparsity Patterns$$
$head Syntax$$
$icode%f%.for_hes_sparsity(
%select_domain%, %select_range%, %internal_bool%, %pattern_out%
)%$$
$head Purpose$$
We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the
$cref/AD function/glossary/AD Function/$$ corresponding to
the operation sequence stored in $icode f$$.
Fix a diagonal matrix $latex D \in \B{R}^{n \times n}$$,
a vector $latex s \in \B{R}^m$$ and define the function
$latex \[
H(x) = D ( s^\R{T} F )^{(2)} ( x ) D
\] $$
Given the sparsity for $latex D$$ and $latex s$$,
$code for_hes_sparsity$$ computes a sparsity pattern for $latex H(x)$$.
$head x$$
Note that the sparsity pattern $latex H(x)$$ corresponds to the
operation sequence stored in $icode f$$ and does not depend on
the argument $icode x$$.
$head BoolVector$$
The type $icode BoolVector$$ is a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$code bool$$.
$head SizeVector$$
The type $icode SizeVector$$ is a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$code size_t$$.
$head f$$
The object $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
$head select_domain$$
The argument $icode select_domain$$ has prototype
$codei%
const %BoolVector%& %select_domain%
%$$
It has size $latex n$$ and specifies which components of the diagonal of
$latex D$$ are non-zero; i.e., $icode%select_domain%[%j%]%$$ is true
if and only if $latex D_{j,j}$$ is possibly non-zero.
$head select_range$$
The argument $icode select_range$$ has prototype
$codei%
const %BoolVector%& %select_range%
%$$
It has size $latex m$$ and specifies which components of the vector
$latex s$$ are non-zero; i.e., $icode%select_range%[%i%]%$$ is true
if and only if $latex s_i$$ is possibly non-zero.
$head internal_bool$$
If this is true, calculations are done with sets represented by a vector
of boolean values. Otherwise, a vector of sets of integers is used.
$head pattern_out$$
This argument has prototype
$codei%
sparse_rc<%SizeVector%>& %pattern_out%
%$$
This input value of $icode pattern_out$$ does not matter.
Upon return $icode pattern_out$$ is a sparsity pattern for $latex H(x)$$.
$head Sparsity for Entire Hessian$$
Suppose that $latex R$$ is the $latex n \times n$$ identity matrix.
In this case, $icode pattern_out$$ is a sparsity pattern for
$latex (s^\R{T} F) F^{(2)} ( x )$$.
$head Algorithm$$
See Algorithm II in
$italic Computing sparse Hessians with automatic differentiation$$
by Andrea Walther.
Note that $icode s$$ provides the information so that
'dead ends' are not included in the sparsity pattern.
$head Example$$
$children%
example/sparse/for_hes_sparsity.cpp
%$$
The file $cref for_hes_sparsity.cpp$$
contains an example and test of this operation.
$end
-----------------------------------------------------------------------------
*/
# include <cppad/core/ad_fun.hpp>
# include <cppad/local/sparse/internal.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
Forward Hessian sparsity patterns.
\tparam Base
is the base type for this recording.
\tparam BoolVector
is the simple vector with elements of type bool that is used for
sparsity for the vector s.
\tparam SizeVector
is the simple vector with elements of type size_t that is used for
row, column index sparsity patterns.
\param select_domain
is a sparsity pattern for for the diagonal of D.
\param select_range
is a sparsity pattern for for s.
\param internal_bool
If this is true, calculations are done with sets represented by a vector
of boolean values. Otherwise, a vector of standard sets is used.
\param pattern_out
The return value is a sparsity pattern for H(x) where
\f[
H(x) = D * F^{(1)} (x) * D
\f]
Here F is the function corresponding to the operation sequence
and x is any argument value.
*/
template <class Base, class RecBase>
template <class BoolVector, class SizeVector>
void ADFun<Base,RecBase>::for_hes_sparsity(
const BoolVector& select_domain ,
const BoolVector& select_range ,
bool internal_bool ,
sparse_rc<SizeVector>& pattern_out )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
size_t n = Domain();
size_t m = Range();
//
CPPAD_ASSERT_KNOWN(
size_t( select_domain.size() ) == n,
"for_hes_sparsity: size of select_domain is not equal to "
"number of independent variables"
);
CPPAD_ASSERT_KNOWN(
size_t( select_range.size() ) == m,
"for_hes_sparsity: size of select_range is not equal to "
"number of dependent variables"
);
// do not need transpose or depenency
bool transpose = false;
bool dependency = false;
//
local::pod_vector<bool> select_domain_pod_vector(n);
for(size_t j = 0; j < n; ++j)
select_domain_pod_vector[j] = select_domain[j];
//
sparse_rc<SizeVector> pattern_tmp;
if( internal_bool )
{
// reverse Jacobian sparsity pattern for select_range
local::sparse::pack_setvec internal_rev_jac;
internal_rev_jac.resize(num_var_tape_, 1);
for(size_t i = 0; i < m; i++) if( select_range[i] )
{ CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
// Not using post_element because only adding one element per set
internal_rev_jac.add_element( dep_taddr_[i] , 0 );
}
// reverse Jacobian sparsity for all variables on tape
local::sweep::rev_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
internal_rev_jac,
not_used_rec_base
);
// internal vector of sets that will hold Hessian
local::sparse::pack_setvec internal_for_hes;
internal_for_hes.resize(n + 1 + num_var_tape_, n + 1);
//
// compute forward Hessian sparsity pattern
local::sweep::for_hes<addr_t>(
&play_,
n,
num_var_tape_,
select_domain_pod_vector,
internal_rev_jac,
internal_for_hes,
not_used_rec_base
);
//
// put the result in pattern_tmp
local::sparse::get_internal_pattern(
transpose, ind_taddr_, internal_for_hes, pattern_tmp
);
}
else
{
// reverse Jacobian sparsity pattern for select_range
// (corresponds to s)
local::sparse::list_setvec internal_rev_jac;
internal_rev_jac.resize(num_var_tape_, 1);
for(size_t i = 0; i < m; i++) if( select_range[i] )
{ CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
// Not using post_element because only adding one element per set
internal_rev_jac.add_element( dep_taddr_[i] , 0 );
}
// reverse Jacobian sparsity for all variables on tape
local::sweep::rev_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
internal_rev_jac,
not_used_rec_base
);
// internal vector of sets that will hold Hessian
local::sparse::list_setvec internal_for_hes;
internal_for_hes.resize(n + 1 + num_var_tape_, n + 1);
//
// compute forward Hessian sparsity pattern
local::sweep::for_hes<addr_t>(
&play_,
n,
num_var_tape_,
select_domain_pod_vector,
internal_rev_jac,
internal_for_hes,
not_used_rec_base
);
//
// put the result in pattern_tmp
local::sparse::get_internal_pattern(
transpose, ind_taddr_, internal_for_hes, pattern_tmp
);
}
// subtract 1 from all column values
CPPAD_ASSERT_UNKNOWN( pattern_tmp.nr() == n );
CPPAD_ASSERT_UNKNOWN( pattern_tmp.nc() == n + 1 );
const SizeVector& row( pattern_tmp.row() );
const SizeVector& col( pattern_tmp.col() );
size_t nr = n;
size_t nc = n;
size_t nnz = pattern_tmp.nnz();
pattern_out.resize(nr, nc, nnz);
for(size_t k = 0; k < nnz; k++)
{ CPPAD_ASSERT_UNKNOWN( 0 < col[k] );
pattern_out.set(k, row[k], col[k] - 1);
}
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,305 @@
# ifndef CPPAD_CORE_FOR_JAC_SPARSITY_HPP
# define CPPAD_CORE_FOR_JAC_SPARSITY_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 for_jac_sparsity$$
$spell
Jacobian
jac
bool
const
rc
cpp
$$
$section Forward Mode Jacobian Sparsity Patterns$$
$head Syntax$$
$icode%f%.for_jac_sparsity(
%pattern_in%, %transpose%, %dependency%, %internal_bool%, %pattern_out%
)%$$
$head Purpose$$
We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the
$cref/AD function/glossary/AD Function/$$ corresponding to
the operation sequence stored in $icode f$$.
Fix $latex R \in \B{R}^{n \times \ell}$$ and define the function
$latex \[
J(x) = F^{(1)} ( x ) * R
\] $$
Given the $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$,
$code for_jac_sparsity$$ computes a sparsity pattern for $latex J(x)$$.
$head x$$
Note that the sparsity pattern $latex J(x)$$ corresponds to the
operation sequence stored in $icode f$$ and does not depend on
the argument $icode x$$.
(The operation sequence may contain
$cref CondExp$$ and $cref VecAD$$ operations.)
$head SizeVector$$
The type $icode SizeVector$$ is a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$code size_t$$.
$head f$$
The object $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
The $cref ADFun$$ object $icode f$$ is not $code const$$.
After a call to $code for_jac_sparsity$$, a sparsity pattern
for each of the variables in the operation sequence
is held in $icode f$$ for possible later use during
reverse Hessian sparsity calculations.
$subhead size_forward_bool$$
After $code for_jac_sparsity$$, if $icode k$$ is a $code size_t$$ object,
$codei%
%k% = %f%.size_forward_bool()
%$$
sets $icode k$$ to the amount of memory (in unsigned character units)
used to store the
$cref/boolean vector/glossary/Sparsity Pattern/Boolean Vector/$$
sparsity patterns.
If $icode internal_bool$$ if false, $icode k$$ will be zero.
Otherwise it will be non-zero.
If you do not need this information for $cref RevSparseHes$$
calculations, it can be deleted
(and the corresponding memory freed) using
$codei%
%f%.size_forward_bool(0)
%$$
after which $icode%f%.size_forward_bool()%$$ will return zero.
$subhead size_forward_set$$
After $code for_jac_sparsity$$, if $icode k$$ is a $code size_t$$ object,
$codei%
%k% = %f%.size_forward_set()
%$$
sets $icode k$$ to the amount of memory (in unsigned character units)
used to store the
$cref/vector of sets/glossary/Sparsity Pattern/Vector of Sets/$$
sparsity patterns.
If $icode internal_bool$$ if true, $icode k$$ will be zero.
Otherwise it will be non-zero.
If you do not need this information for future $cref rev_hes_sparsity$$
calculations, it can be deleted
(and the corresponding memory freed) using
$codei%
%f%.size_forward_set(0)
%$$
after which $icode%f%.size_forward_set()%$$ will return zero.
$head pattern_in$$
The argument $icode pattern_in$$ has prototype
$codei%
const sparse_rc<%SizeVector%>& %pattern_in%
%$$
see $cref sparse_rc$$.
If $icode transpose$$ it is false (true),
$icode pattern_in$$ is a sparsity pattern for $latex R$$ ($latex R^\R{T}$$).
$head transpose$$
This argument has prototype
$codei%
bool %transpose%
%$$
See $cref/pattern_in/for_jac_sparsity/pattern_in/$$ above and
$cref/pattern_out/for_jac_sparsity/pattern_out/$$ below.
$head dependency$$
This argument has prototype
$codei%
bool %dependency%
%$$
see $cref/pattern_out/for_jac_sparsity/pattern_out/$$ below.
$head internal_bool$$
This argument has prototype
$codei%
bool %internal_bool%
%$$
If this is true, calculations are done with sets represented by a vector
of boolean values. Otherwise, a vector of sets of integers is used.
$head pattern_out$$
This argument has prototype
$codei%
sparse_rc<%SizeVector%>& %pattern_out%
%$$
This input value of $icode pattern_out$$ does not matter.
If $icode transpose$$ it is false (true),
upon return $icode pattern_out$$ is a sparsity pattern for
$latex J(x)$$ ($latex J(x)^\R{T}$$).
If $icode dependency$$ is true, $icode pattern_out$$ is a
$cref/dependency pattern/dependency.cpp/Dependency Pattern/$$
instead of sparsity pattern.
$head Sparsity for Entire Jacobian$$
Suppose that
$latex R$$ is the $latex n \times n$$ identity matrix.
In this case, $icode pattern_out$$ is a sparsity pattern for
$latex F^{(1)} ( x )$$ ( $latex F^{(1)} (x)^\R{T}$$ )
if $icode transpose$$ is false (true).
$head Example$$
$children%
example/sparse/for_jac_sparsity.cpp
%$$
The file
$cref for_jac_sparsity.cpp$$
contains an example and test of this operation.
$end
-----------------------------------------------------------------------------
*/
# include <cppad/core/ad_fun.hpp>
# include <cppad/local/sparse/internal.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
Forward Jacobian sparsity patterns.
\tparam Base
is the base type for this recording.
\tparam SizeVector
is the simple vector with elements of type size_t that is used for
row, column index sparsity patterns.
\param pattern_in
is the sparsity pattern for for R or R^T depending on transpose.
\param transpose
Is the input and returned sparsity pattern transposed.
\param dependency
Are the derivatives with respect to left and right of the expression below
considered to be non-zero:
\code
CondExpRel(left, right, if_true, if_false)
\endcode
This is used by the optimizer to obtain the correct dependency relations.
\param internal_bool
If this is true, calculations are done with sets represented by a vector
of boolean values. Othewise, a vector of standard sets is used.
\param pattern_out
The value of transpose is false (true),
the return value is a sparsity pattern for J(x) ( J(x)^T ) where
\f[
J(x) = F^{(1)} (x) * R
\f]
Here F is the function corresponding to the operation sequence
and x is any argument value.
*/
template <class Base, class RecBase>
template <class SizeVector>
void ADFun<Base,RecBase>::for_jac_sparsity(
const sparse_rc<SizeVector>& pattern_in ,
bool transpose ,
bool dependency ,
bool internal_bool ,
sparse_rc<SizeVector>& pattern_out )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
// number or rows, columns, and non-zeros in pattern_in
size_t nr_in = pattern_in.nr();
size_t nc_in = pattern_in.nc();
//
size_t n = nr_in;
size_t ell = nc_in;
if( transpose )
std::swap(n, ell);
//
CPPAD_ASSERT_KNOWN(
n == Domain() ,
"for_jac_sparsity: number rows in R "
"is not equal number of independent variables."
);
bool zero_empty = true;
bool input_empty = true;
if( internal_bool )
{ // allocate memory for bool sparsity calculation
// (sparsity pattern is emtpy after a resize)
for_jac_sparse_pack_.resize(num_var_tape_, ell);
for_jac_sparse_set_.resize(0, 0);
//
// set sparsity patttern for independent variables
local::sparse::set_internal_pattern(
zero_empty ,
input_empty ,
transpose ,
ind_taddr_ ,
for_jac_sparse_pack_ ,
pattern_in
);
// compute sparsity for other variables
local::sweep::for_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
for_jac_sparse_pack_,
not_used_rec_base
);
// set the output pattern
local::sparse::get_internal_pattern(
transpose, dep_taddr_, for_jac_sparse_pack_, pattern_out
);
}
else
{
// allocate memory for set sparsity calculation
// (sparsity pattern is emtpy after a resize)
for_jac_sparse_set_.resize(num_var_tape_, ell);
for_jac_sparse_pack_.resize(0, 0);
//
// set sparsity patttern for independent variables
local::sparse::set_internal_pattern(
zero_empty ,
input_empty ,
transpose ,
ind_taddr_ ,
for_jac_sparse_set_ ,
pattern_in
);
// compute sparsity for other variables
local::sweep::for_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
for_jac_sparse_set_,
not_used_rec_base
);
// get the ouput pattern
local::sparse::get_internal_pattern(
transpose, dep_taddr_, for_jac_sparse_set_, pattern_out
);
}
return;
}
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,163 @@
# ifndef CPPAD_CORE_FOR_ONE_HPP
# define CPPAD_CORE_FOR_ONE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 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 ForOne$$
$spell
dy
typename
Taylor
const
$$
$section First Order Partial Derivative: Driver Routine$$
$head Syntax$$
$icode%dy% = %f%.ForOne(%x%, %j%)%$$
$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$$.
The syntax above sets $icode dy$$ to the
partial of $latex F$$ with respect to $latex x_j$$; i.e.,
$latex \[
dy
= \D{F}{ x_j } (x)
= \left[
\D{ F_0 }{ x_j } (x) , \cdots , \D{ F_{m-1} }{ x_j } (x)
\right]
\] $$
$head f$$
The object $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
Note that the $cref ADFun$$ object $icode f$$ is not $code const$$
(see $cref/ForOne Uses Forward/ForOne/ForOne Uses Forward/$$ below).
$head x$$
The argument $icode x$$ has prototype
$codei%
const %Vector% &%x%
%$$
(see $cref/Vector/ForOne/Vector/$$ below)
and its size
must be equal to $icode n$$, the dimension of the
$cref/domain/seq_property/Domain/$$ space for $icode f$$.
It specifies
that point at which to evaluate the partial derivative.
$head j$$
The argument $icode j$$ has prototype
$codei%
size_t %j%
%$$
an is less than $icode n$$,
$cref/domain/seq_property/Domain/$$ space for $icode f$$.
It specifies the component of $icode F$$
for which we are computing the partial derivative.
$head dy$$
The result $icode dy$$ has prototype
$codei%
%Vector% %dy%
%$$
(see $cref/Vector/ForOne/Vector/$$ below)
and its size is $latex m$$, the dimension of the
$cref/range/seq_property/Range/$$ space for $icode f$$.
The value of $icode dy$$ is the partial of $latex F$$ with respect to
$latex x_j$$ evaluated at $icode x$$; i.e.,
for $latex i = 0 , \ldots , m - 1$$
$latex \[.
dy[i] = \D{ F_i }{ x_j } ( x )
\] $$
$head Vector$$
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$icode Base$$.
The routine $cref CheckSimpleVector$$ will generate an error message
if this is not the case.
$head ForOne Uses Forward$$
After each call to $cref Forward$$,
the object $icode f$$ contains the corresponding
$cref/Taylor coefficients/glossary/Taylor Coefficient/$$.
After a call to $code ForOne$$,
the zero order Taylor coefficients correspond to
$icode%f%.Forward(0,%x%)%$$
and the other coefficients are unspecified.
$head Example$$
$children%
example/general/for_one.cpp
%$$
The routine
$cref/ForOne/for_one.cpp/$$ is both an example and test.
It returns $code true$$, if it succeeds and $code false$$ otherwise.
$end
-----------------------------------------------------------------------------
*/
// BEGIN CppAD namespace
namespace CppAD {
template <class Base, class RecBase>
template <class Vector>
Vector ADFun<Base,RecBase>::ForOne(const Vector &x, size_t j)
{ size_t j1;
size_t n = Domain();
size_t m = Range();
// check Vector is Simple Vector class with Base type elements
CheckSimpleVector<Base, Vector>();
CPPAD_ASSERT_KNOWN(
x.size() == n,
"ForOne: Length of x not equal domain dimension for f"
);
CPPAD_ASSERT_KNOWN(
j < n,
"ForOne: the index j is not less than domain dimension for f"
);
// point at which we are evaluating the second partials
Forward(0, x);
// direction in which are are taking the derivative
Vector dx(n);
for(j1 = 0; j1 < n; j1++)
dx[j1] = Base(0.0);
dx[j] = Base(1.0);
// dimension the return value
Vector dy(m);
// compute the return value
dy = Forward(1, dx);
return dy;
}
} // END CppAD namespace
# endif

View File

@@ -0,0 +1,566 @@
# ifndef CPPAD_CORE_FOR_SPARSE_HES_HPP
# define CPPAD_CORE_FOR_SPARSE_HES_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 ForSparseHes$$
$spell
Andrea Walther
std
VecAD
Jacobian
Jac
Hessian
Hes
const
Bool
Dep
proportional
var
cpp
$$
$section Hessian Sparsity Pattern: Forward Mode$$
$head Syntax$$
$icode%h% = %f%.ForSparseHes(%r%, %s%)
%$$
$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$$.
we define
$latex \[
\begin{array}{rcl}
H(x)
& = & \partial_x \left[ \partial_u S \cdot F[ x + R \cdot u ] \right]_{u=0}
\\
& = & R^\R{T} \cdot (S \cdot F)^{(2)} ( x ) \cdot R
\end{array}
\] $$
Where $latex R \in \B{R}^{n \times n}$$ is a diagonal matrix
and $latex S \in \B{R}^{1 \times m}$$ is a row vector.
Given a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for the diagonal of $latex R$$ and the vector $latex S$$,
$code ForSparseHes$$ 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{R}^n$$,
the sparsity pattern is valid for all values of
(even if it has $cref CondExp$$ or $cref VecAD$$ operations).
$head r$$
The argument $icode r$$ has prototype
$codei%
const %SetVector%& %r%
%$$
(see $cref/SetVector/ForSparseHes/SetVector/$$ below)
If it has elements of type $code bool$$,
its size is $latex n$$.
If it has elements of type $code std::set<size_t>$$,
its size is one and all the elements of $icode%s%[0]%$$
are between zero and $latex n - 1$$.
It specifies a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for the diagonal of $latex R$$.
The fewer non-zero elements in this sparsity pattern,
the faster the calculation should be and the more sparse
$latex H(x)$$ should be.
$head s$$
The argument $icode s$$ has prototype
$codei%
const %SetVector%& %s%
%$$
(see $cref/SetVector/ForSparseHes/SetVector/$$ below)
If it has elements of type $code bool$$,
its size is $latex m$$.
If it has elements of type $code std::set<size_t>$$,
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$$.
The fewer non-zero elements in this sparsity pattern,
the faster the calculation should be and the more sparse
$latex H(x)$$ should be.
$head h$$
The result $icode h$$ has prototype
$codei%
%SetVector%& %h%
%$$
(see $cref/SetVector/ForSparseHes/SetVector/$$ below).
If $icode h$$ has elements of type $code bool$$,
its size is $latex n * n$$.
If it has elements of type $code std::set<size_t>$$,
its size is $latex n$$ 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)$$.
$head SetVector$$
The type $icode SetVector$$ must be a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$code bool$$ or $code std::set<size_t>$$;
see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion
of the difference.
The type of the elements of
$cref/SetVector/ForSparseHes/SetVector/$$ must be the
same as the type of the elements of $icode r$$.
$head Algorithm$$
See Algorithm II in
$italic Computing sparse Hessians with automatic differentiation$$
by Andrea Walther.
Note that $icode s$$ provides the information so that
'dead ends' are not included in the sparsity pattern.
$head Example$$
$children%
example/sparse/for_sparse_hes.cpp
%$$
The file
$cref for_sparse_hes.cpp$$
contains an example and test of this operation.
$end
-----------------------------------------------------------------------------
*/
# include <algorithm>
# include <cppad/local/pod_vector.hpp>
# include <cppad/local/std_set.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file core/for_sparse_hes.hpp
Forward mode Hessian sparsity patterns.
*/
// ===========================================================================
// ForSparseHesCase
/*!
Private helper function for ForSparseHes(q, s) bool sparsity.
All of the description in the public member function ForSparseHes(q, s)
applies.
\param set_type
is a bool value. This argument is used to dispatch to the proper source
code depending on the vlaue of SetVector::value_type.
\param r
See ForSparseHes(r, s).
\param s
See ForSparseHes(r, s).
\param h
is the return value for the corresponging call to ForSparseJac(q, s).
*/
template <class Base, class RecBase>
template <class SetVector>
void ADFun<Base,RecBase>::ForSparseHesCase(
bool set_type ,
const SetVector& r ,
const SetVector& s ,
SetVector& h )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
size_t n = Domain();
size_t m = Range();
//
// check Vector is Simple SetVector class with bool elements
CheckSimpleVector<bool, SetVector>();
//
CPPAD_ASSERT_KNOWN(
size_t(r.size()) == n,
"ForSparseHes: size of r is not equal to\n"
"domain dimension for ADFun object."
);
CPPAD_ASSERT_KNOWN(
size_t(s.size()) == m,
"ForSparseHes: size of s is not equal to\n"
"range dimension for ADFun object."
);
//
// select_domain corresponding to r
local::pod_vector<bool> select_domain(n);
for(size_t j = 0; j < n; ++j)
{ select_domain[j] = r[j];
CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1);
CPPAD_ASSERT_UNKNOWN( play_.GetOp(j + 1) == local::InvOp );
}
// sparsity pattern correspnding to s
local::sparse::pack_setvec rev_jac_pattern;
rev_jac_pattern.resize(num_var_tape_, 1);
for(size_t i = 0; i < m; i++)
{ CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
//
// Not using post_element because only adding one element per set
if( s[i] )
rev_jac_pattern.add_element( dep_taddr_[i], 0);
}
// compute reverse sparsity pattern for dependency analysis
// (note that we are only want non-zero derivatives not true dependency)
bool dependency = false;
local::sweep::rev_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
rev_jac_pattern,
not_used_rec_base
);
// vector of sets that will hold the forward Hessain values
local::sparse::pack_setvec for_hes_pattern;
for_hes_pattern.resize(n+1+num_var_tape_, n+1);
//
// compute the Hessian sparsity patterns
local::sweep::for_hes<addr_t>(
&play_,
n,
num_var_tape_,
select_domain,
rev_jac_pattern,
for_hes_pattern,
not_used_rec_base
);
// initialize return values corresponding to independent variables
h.resize(n * n);
for(size_t i = 0; i < n; i++)
{ for(size_t j = 0; j < n; j++)
h[ i * n + j ] = false;
}
// copy to result pattern
CPPAD_ASSERT_UNKNOWN( for_hes_pattern.end() == n+1 );
for(size_t i = 0; i < n; i++)
{ // ind_taddr_[i] is operator taddr for i-th independent variable
CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] == i + 1 );
CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp );
// extract the result from for_hes_pattern
local::sparse::pack_setvec::const_iterator itr(for_hes_pattern, ind_taddr_[i] );
size_t j = *itr;
while( j < for_hes_pattern.end() )
{ CPPAD_ASSERT_UNKNOWN( 0 < j )
h[ i * n + (j-1) ] = true;
j = *(++itr);
}
}
}
/*!
Private helper function for ForSparseHes(q, s) set sparsity.
All of the description in the public member function ForSparseHes(q, s)
applies.
\param set_type
is a std::set<size_t> value.
This argument is used to dispatch to the proper source
code depending on the vlaue of SetVector::value_type.
\param r
See ForSparseHes(r, s).
\param s
See ForSparseHes(q, s).
\param h
is the return value for the corresponging call to ForSparseJac(q, s).
*/
template <class Base, class RecBase>
template <class SetVector>
void ADFun<Base,RecBase>::ForSparseHesCase(
const std::set<size_t>& set_type ,
const SetVector& r ,
const SetVector& s ,
SetVector& h )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
size_t n = Domain();
# ifndef NDEBUG
size_t m = Range();
# endif
std::set<size_t>::const_iterator itr_1;
//
// check SetVector is Simple Vector class with sets for elements
CheckSimpleVector<std::set<size_t>, SetVector>(
local::one_element_std_set<size_t>(), local::two_element_std_set<size_t>()
);
CPPAD_ASSERT_KNOWN(
r.size() == 1,
"ForSparseHes: size of s is not equal to one."
);
CPPAD_ASSERT_KNOWN(
s.size() == 1,
"ForSparseHes: size of s is not equal to one."
);
//
// select_domain corresponding to r
local::pod_vector<bool> select_domain(n);
for(size_t j = 0; j < n; ++j)
{ select_domain[j] = false;
CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1);
CPPAD_ASSERT_UNKNOWN( play_.GetOp(j + 1) == local::InvOp );
}
itr_1 = r[0].begin();
while( itr_1 != r[0].end() )
{ size_t j = *itr_1++;
select_domain[j] = true;
}
// sparsity pattern correspnding to s
local::sparse::list_setvec rev_jac_pattern;
rev_jac_pattern.resize(num_var_tape_, 1);
itr_1 = s[0].begin();
while( itr_1 != s[0].end() )
{ size_t i = *itr_1++;
CPPAD_ASSERT_KNOWN(
i < m,
"ForSparseHes: an element of the set s[0] has value "
"greater than or equal m"
);
CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
//
// Not using post_element because only adding one element per set
rev_jac_pattern.add_element( dep_taddr_[i], 0);
}
//
// compute reverse sparsity pattern for dependency analysis
// (note that we are only want non-zero derivatives not true dependency)
bool dependency = false;
local::sweep::rev_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
rev_jac_pattern,
not_used_rec_base
);
//
// vector of sets that will hold reverse Hessain values
local::sparse::list_setvec for_hes_pattern;
for_hes_pattern.resize(n+1+num_var_tape_, n+1);
//
// compute the Hessian sparsity patterns
local::sweep::for_hes<addr_t>(
&play_,
n,
num_var_tape_,
select_domain,
rev_jac_pattern,
for_hes_pattern,
not_used_rec_base
);
// return values corresponding to independent variables
// j is index corresponding to reverse mode partial
h.resize(n);
CPPAD_ASSERT_UNKNOWN( for_hes_pattern.end() == n+1 );
for(size_t i = 0; i < n; i++)
{ CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] == i + 1 );
CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp );
// extract the result from for_hes_pattern
local::sparse::list_setvec::const_iterator itr_2(for_hes_pattern, ind_taddr_[i] );
size_t j = *itr_2;
while( j < for_hes_pattern.end() )
{ CPPAD_ASSERT_UNKNOWN( 0 < j )
h[i].insert(j-1);
j = *(++itr_2);
}
}
}
// ===========================================================================
// ForSparseHes
/*!
User API for Hessian sparsity patterns using reverse mode.
The C++ source code corresponding to this operation is
\verbatim
h = f.ForSparseHes(q, r)
\endverbatim
\tparam Base
is the base type for this recording.
\tparam SetVector
is a simple vector with elements of type bool
or std::set<size_t>.
\param r
is a vector with size n that specifies the sparsity pattern
for the diagonal of the matrix \f$ R \f$,
where n is the number of independent variables
corresponding to the operation sequence stored in play.
\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.
\return
The return vector is a sparsity pattern for \f$ H(x) \f$
\f[
H(x) = R^T ( S * F)^{(2)} (x) R
\f]
where \f$ F \f$ is the function corresponding to the operation sequence
and x is any argument value.
*/
template <class Base, class RecBase>
template <class SetVector>
SetVector ADFun<Base,RecBase>::ForSparseHes(
const SetVector& r, const SetVector& s
)
{
SetVector h;
typedef typename SetVector::value_type Set_type;
// Should check to make sure q is same as in previous call to
// forward sparse Jacobian.
ForSparseHesCase(
Set_type() ,
r ,
s ,
h
);
return h;
}
// ===========================================================================
// ForSparseHesCheckpoint
/*!
Hessian sparsity patterns calculation used by checkpoint functions.
\tparam Base
is the base type for this recording.
\param r
is a vector with size n that specifies the sparsity pattern
for the diagonal of \f$ R \f$,
where n is the number of independent variables
corresponding to the operation sequence stored in play_.
\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) R \f$.
\par Assumptions
The forward jacobian sparsity pattern must be currently stored
in this ADFUN object.
*/
// The checkpoint class is not yet using forward sparse Hessians.
# ifdef CPPAD_NOT_DEFINED
template <class Base, class RecBase>
void ADFun<Base,RecBase>::ForSparseHesCheckpoint(
vector<bool>& r ,
vector<bool>& s ,
local::sparse::list_setvec& h )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
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() == 0 );
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<bool> RevJac(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 forward Hessian sparsity pattern for all variables
local::sparse::list_setvec for_hes_pattern;
for_hes_pattern.resize(n+1+num_var_tape_, n+1);
// compute Hessian sparsity pattern for all variables
local::sweep::for_hes<addr_t>(
&play_,
n,
num_var_tape_,
for_jac_sparse_set_,
RevJac.data(),
for_hes_pattern,
not_used_rec_base
);
// dimension the return value
if( transpose )
h.resize(n, n);
else
h.resize(n, 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 for_hes_pattern
CPPAD_ASSERT_UNKNOWN( for_hes_pattern.end() == q );
local::sparse::list_setvec::const_iterator itr(for_hes_pattern, .j + 1);
size_t i = *itr;
while( i < q )
{ if( transpose )
h.post_element(j, i);
else
h.post_element(i, j);
i = *(++itr);
}
}
// process posts
for(size_t i = 0; i < n; ++i)
h.process_post(i);
}
# endif
} // END_CPPAD_NAMESPACE
# endif

View File

@@ -0,0 +1,764 @@
# ifndef CPPAD_CORE_FOR_SPARSE_JAC_HPP
# define CPPAD_CORE_FOR_SPARSE_JAC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 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 ForSparseJac$$
$spell
std
var
Jacobian
Jac
const
Bool
proportional
VecAD
CondExpRel
optimizer
cpp
$$
$section Jacobian Sparsity Pattern: Forward Mode$$
$head Syntax$$
$icode%s% = %f%.ForSparseJac(%q%, %r%)
%$$
$icode%s% = %f%.ForSparseJac(%q%, %r%, %transpose%, %dependency%)%$$
$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 $latex n \times q$$ matrix $latex R$$,
the Jacobian of $latex F[ x + R * u ]$$
with respect to $latex u$$ at $latex u = 0$$ is
$latex \[
S(x) = F^{(1)} ( x ) * R
\] $$
Given a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for $latex R$$,
$code ForSparseJac$$ returns a sparsity pattern for the $latex S(x)$$.
$head f$$
The object $icode f$$ has prototype
$codei%
ADFun<%Base%> %f%
%$$
Note that the $cref ADFun$$ object $icode f$$ is not $code const$$.
After a call to $code ForSparseJac$$, the sparsity pattern
for each of the variables in the operation sequence
is held in $icode f$$ (for possible later use by $cref RevSparseHes$$).
These sparsity patterns are stored with elements of type $code bool$$
or elements of type $code std::set<size_t>$$
(see $cref/SetVector/ForSparseJac/SetVector/$$ below).
$subhead size_forward_bool$$
After $code ForSparseJac$$, if $icode k$$ is a $code size_t$$ object,
$codei%
%k% = %f%.size_forward_bool()
%$$
sets $icode k$$ to the amount of memory (in unsigned character units)
used to store the sparsity pattern with elements of type $code bool$$
in the function object $icode f$$.
If the sparsity patterns for the previous $code ForSparseJac$$ used
elements of type $code bool$$,
the return value for $code size_forward_bool$$ will be non-zero.
Otherwise, its return value will be zero.
This sparsity pattern is stored for use by $cref RevSparseHes$$ and
when it is not longer needed, it can be deleted
(and the corresponding memory freed) using
$codei%
%f%.size_forward_bool(0)
%$$
After this call, $icode%f%.size_forward_bool()%$$ will return zero.
$subhead size_forward_set$$
After $code ForSparseJac$$, if $icode k$$ is a $code size_t$$ object,
$codei%
%k% = %f%.size_forward_set()
%$$
sets $icode k$$ to the amount of memory (in unsigned character units)
used to store the
$cref/vector of sets/glossary/Sparsity Pattern/Vector of Sets/$$
sparsity patterns.
If the sparsity patterns for this operation use elements of type $code bool$$,
the return value for $code size_forward_set$$ will be zero.
Otherwise, its return value will be non-zero.
This sparsity pattern is stored for use by $cref RevSparseHes$$ and
when it is not longer needed, it can be deleted
(and the corresponding memory freed) using
$codei%
%f%.size_forward_set(0)
%$$
After this call, $icode%f%.size_forward_set()%$$ will return zero.
$head x$$
If the operation sequence in $icode f$$ is
$cref/independent/glossary/Operation/Independent/$$ of
the independent variables in $latex x \in \B{R}^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 Jacobian
$latex S(x) \in \B{R}^{m \times q}$$.
$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 dependency$$
The argument $icode dependency$$ has prototype
$codei%
bool %dependency%
%$$
If $icode dependency$$ is true,
the $cref/dependency pattern/dependency.cpp/Dependency Pattern/$$
(instead of sparsity pattern) is computed.
$head r$$
The argument $icode r$$ has prototype
$codei%
const %SetVector%& %r%
%$$
see $cref/SetVector/ForSparseJac/SetVector/$$ below.
$subhead transpose false$$
If $icode r$$ has elements of type $code bool$$,
its size is $latex n * q$$.
If it has elements of type $code std::set<size_t>$$,
its size is $latex n$$ and all the set elements must be between
zero and $icode%q%-1%$$ inclusive.
It specifies a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for the matrix $latex R \in \B{R}^{n \times q}$$.
$subhead transpose true$$
If $icode r$$ has elements of type $code bool$$,
its size is $latex q * n$$.
If it has elements of type $code std::set<size_t>$$,
its size is $latex q$$ and all the set elements must be between
zero and $icode%n%-1%$$ inclusive.
It specifies a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for the matrix $latex R^\R{T} \in \B{R}^{q \times n}$$.
$head s$$
The return value $icode s$$ has prototype
$codei%
%SetVector% %s%
%$$
see $cref/SetVector/ForSparseJac/SetVector/$$ below.
$subhead transpose false$$
If $icode s$$ has elements of type $code bool$$,
its size is $latex m * q$$.
If it has elements of type $code std::set<size_t>$$,
its size is $latex m$$ and all its set elements are between
zero and $icode%q%-1%$$ inclusive.
It specifies a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for the matrix $latex S(x) \in \B{R}^{m \times q}$$.
$subhead transpose true$$
If $icode s$$ has elements of type $code bool$$,
its size is $latex q * m$$.
If it has elements of type $code std::set<size_t>$$,
its size is $latex q$$ and all its set elements are between
zero and $icode%m%-1%$$ inclusive.
It specifies a
$cref/sparsity pattern/glossary/Sparsity Pattern/$$
for the matrix $latex S(x)^\R{T} \in \B{R}^{q \times m}$$.
$head SetVector$$
The type $icode SetVector$$ must be a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$code bool$$ or $code std::set<size_t>$$;
see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion
of the difference.
$head Entire Sparsity Pattern$$
Suppose that $latex q = n$$ and
$latex R$$ is the $latex n \times n$$ identity matrix.
In this case,
the corresponding value for $icode s$$ is a
sparsity pattern for the Jacobian $latex S(x) = F^{(1)} ( x )$$.
$head Example$$
$children%
example/sparse/for_sparse_jac.cpp
%$$
The file
$cref for_sparse_jac.cpp$$
contains an example and test of this operation.
The file
$cref/sparsity_sub.cpp/sparsity_sub.cpp/ForSparseJac/$$
contains an example and test of using $code ForSparseJac$$
to compute the sparsity pattern for a subset of the Jacobian.
$end
-----------------------------------------------------------------------------
*/
# include <cppad/local/std_set.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file core/for_sparse_jac.hpp
Forward mode Jacobian sparsity patterns.
*/
// ---------------------------------------------------------------------------
/*!
Private helper function for ForSparseJac(q, r) boolean sparsity patterns.
All of the description in the public member function ForSparseJac(q, r)
applies.
\param set_type
is a bool value. This argument is used to dispatch to the proper source
code depending on the value of SetVector::value_type.
\param transpose
See ForSparseJac(q, r, transpose, dependency).
\param dependency
See ForSparseJac(q, r, transpose, dependency).
\param q
See ForSparseJac(q, r, transpose, dependency).
\param r
See ForSparseJac(q, r, transpose, dependency).
\param s
is the return value for the corresponding call to ForSparseJac(q, r).
*/
template <class Base, class RecBase>
template <class SetVector>
void ADFun<Base,RecBase>::ForSparseJacCase(
bool set_type ,
bool transpose ,
bool dependency ,
size_t q ,
const SetVector& r ,
SetVector& s )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
size_t m = Range();
size_t n = Domain();
// check SetVector is Simple Vector class with bool elements
CheckSimpleVector<bool, SetVector>();
// dimension size of result vector
s.resize( m * q );
CPPAD_ASSERT_KNOWN(
q > 0,
"ForSparseJac: q is not greater than zero"
);
CPPAD_ASSERT_KNOWN(
size_t(r.size()) == n * q,
"ForSparseJac: size of r is not equal to\n"
"q times domain dimension for ADFun object."
);
//
// allocate memory for the requested sparsity calculation result
for_jac_sparse_pack_.resize(num_var_tape_, q);
// set values corresponding to independent variables
for(size_t i = 0; i < n; i++)
{ CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] < num_var_tape_ );
// ind_taddr_[i] is operator taddr for i-th independent variable
CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp );
// set bits that are true
if( transpose )
{ for(size_t j = 0; j < q; j++) if( r[ j * n + i ] )
for_jac_sparse_pack_.post_element( ind_taddr_[i], j);
}
else
{ for(size_t j = 0; j < q; j++) if( r[ i * q + j ] )
for_jac_sparse_pack_.post_element( ind_taddr_[i], j);
}
}
// process posts
for(size_t j = 0; j < n; j++)
for_jac_sparse_pack_.process_post( ind_taddr_[j] );
// evaluate the sparsity patterns
local::sweep::for_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
for_jac_sparse_pack_,
not_used_rec_base
);
// return values corresponding to dependent variables
CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == m * q );
for(size_t i = 0; i < m; i++)
{ CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
// extract the result from for_jac_sparse_pack_
if( transpose )
{ for(size_t j = 0; j < q; j++)
s[ j * m + i ] = false;
}
else
{ for(size_t j = 0; j < q; j++)
s[ i * q + j ] = false;
}
CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.end() == q );
local::sparse::pack_setvec::const_iterator
itr(for_jac_sparse_pack_, dep_taddr_[i] );
size_t j = *itr;
while( j < q )
{ if( transpose )
s[j * m + i] = true;
else
s[i * q + j] = true;
j = *(++itr);
}
}
}
// ---------------------------------------------------------------------------
/*!
Private helper function for ForSparseJac(q, r) set sparsity.
All of the description in the public member function ForSparseJac(q, r)
applies.
\param set_type
is a std::set<size_t> object.
This argument is used to dispatch to the proper source
code depending on the value of SetVector::value_type.
\param transpose
See ForSparseJac(q, r, transpose, dependency).
\param dependency
See ForSparseJac(q, r, transpose, dependency).
\param q
See ForSparseJac(q, r, transpose, dependency).
\param r
See ForSparseJac(q, r, transpose, dependency).
\param s
is the return value for the corresponding call to ForSparseJac(q, r).
*/
template <class Base, class RecBase>
template <class SetVector>
void ADFun<Base,RecBase>::ForSparseJacCase(
const std::set<size_t>& set_type ,
bool transpose ,
bool dependency ,
size_t q ,
const SetVector& r ,
SetVector& s )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
size_t m = Range();
size_t n = Domain();
// check SetVector is Simple Vector class with sets for elements
CheckSimpleVector<std::set<size_t>, SetVector>(
local::one_element_std_set<size_t>(), local::two_element_std_set<size_t>()
);
// dimension size of result vector
if( transpose )
s.resize(q);
else
s.resize( m );
// temporary iterator
std::set<size_t>::const_iterator itr_1;
CPPAD_ASSERT_KNOWN(
q > 0,
"ForSparseJac: q is not greater than zero"
);
CPPAD_ASSERT_KNOWN(
size_t(r.size()) == n || transpose,
"ForSparseJac: size of r is not equal to n and transpose is false."
);
CPPAD_ASSERT_KNOWN(
size_t(r.size()) == q || ! transpose,
"ForSparseJac: size of r is not equal to q and transpose is true."
);
//
// allocate memory for the requested sparsity calculation
for_jac_sparse_set_.resize(num_var_tape_, q);
// set values corresponding to independent variables
if( transpose )
{ for(size_t i = 0; i < q; i++)
{ // add the elements that are present
itr_1 = r[i].begin();
while( itr_1 != r[i].end() )
{ size_t j = *itr_1++;
CPPAD_ASSERT_KNOWN(
j < n,
"ForSparseJac: transpose is true and element of the set\n"
"r[j] has value greater than or equal n."
);
CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ );
// operator for j-th independent variable
CPPAD_ASSERT_UNKNOWN(
play_.GetOp( ind_taddr_[j] ) == local::InvOp
);
for_jac_sparse_set_.post_element( ind_taddr_[j], i);
}
}
}
else
{ for(size_t i = 0; i < n; i++)
{ CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] < num_var_tape_ );
// ind_taddr_[i] is operator taddr for i-th independent variable
CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp );
// add the elements that are present
itr_1 = r[i].begin();
while( itr_1 != r[i].end() )
{ size_t j = *itr_1++;
CPPAD_ASSERT_KNOWN(
j < q,
"ForSparseJac: an element of the set r[i] "
"has value greater than or equal q."
);
for_jac_sparse_set_.post_element( ind_taddr_[i], j);
}
}
}
// process posts
for(size_t j = 0; j < n; j++)
for_jac_sparse_set_.process_post( ind_taddr_[j] );
// evaluate the sparsity patterns
local::sweep::for_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
for_jac_sparse_set_,
not_used_rec_base
);
// return values corresponding to dependent variables
CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == m || transpose );
CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == q || ! transpose );
for(size_t i = 0; i < m; i++)
{ CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
// extract results from for_jac_sparse_set_
// and add corresponding elements to sets in s
CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.end() == q );
local::sparse::list_setvec::const_iterator
itr_2(for_jac_sparse_set_, dep_taddr_[i] );
size_t j = *itr_2;
while( j < q )
{ if( transpose )
s[j].insert(i);
else
s[i].insert(j);
j = *(++itr_2);
}
}
}
// ---------------------------------------------------------------------------
/*!
User API for Jacobian sparsity patterns using forward mode.
The C++ source code corresponding to this operation is
\verbatim
s = f.ForSparseJac(q, r, transpose, dependency)
\endverbatim
\tparam Base
is the base type for this recording.
\tparam SetVector
is a simple vector with elements of type bool
or std::set<size_t>.
\param q
is the number of columns in the matrix \f$ R \f$.
\param r
is a sparsity pattern for the matrix \f$ R \f$.
\param transpose
are sparsity patterns for \f$ R \f$ and \f$ S(x) \f$ transposed.
\param dependency
Are the derivatives with respect to left and right of the expression below
considered to be non-zero:
\code
CondExpRel(left, right, if_true, if_false)
\endcode
This is used by the optimizer to obtain the correct dependency relations.
\return
The value of transpose is false (true),
the return value is a sparsity pattern for \f$ S(x) \f$ (\f$ S(x)^T \f$) where
\f[
S(x) = F^{(1)} (x) * R
\f]
where \f$ F \f$ is the function corresponding to the operation sequence
and x is any argument value.
If SetVector::value_type is bool,
the return value has size \f$ m * q \f$ (\f$ q * m \f$).
where m is the number of dependent variables
corresponding to the operation sequence stored in f.
If SetVector::value_type is std::set<size_t>,
the return value has size \f$ m \f$ ( \f$ q \f$ )
and with all its elements between zero and
\f$ q - 1 \f$ ( \f$ m - 1 \f$).
\par Side Effects
If SetVector::value_type is bool,
the forward sparsity pattern for all of the variables on the
tape is stored in for_jac_sparse_pack__.
In this case
\verbatim
for_jac_sparse_pack_.n_set() == num_var_tape_
for_jac_sparse_pack_.end() == q
for_jac_sparse_set_.n_set() == 0
for_jac_sparse_set_.end() == 0
\endverbatim
\n
\n
If SetVector::value_type is std::set<size_t>,
the forward sparsity pattern for all of the variables on the
tape is stored in for_jac_sparse_set__.
In this case
\verbatim
for_jac_sparse_set_.n_set() == num_var_tape_
for_jac_sparse_set_.end() == q
for_jac_sparse_pack_.n_set() == 0
for_jac_sparse_pack_.end() == 0
\endverbatim
*/
template <class Base, class RecBase>
template <class SetVector>
SetVector ADFun<Base,RecBase>::ForSparseJac(
size_t q ,
const SetVector& r ,
bool transpose ,
bool dependency )
{
SetVector s;
typedef typename SetVector::value_type Set_type;
// free all memory currently in sparsity patterns
for_jac_sparse_pack_.resize(0, 0);
for_jac_sparse_set_.resize(0, 0);
ForSparseJacCase(
Set_type() ,
transpose ,
dependency ,
q ,
r ,
s
);
return s;
}
// ===========================================================================
// ForSparseJacCheckpoint
/*!
Forward mode Jacobian sparsity calculation used by checkpoint functions.
\tparam Base
is the base type for this recording.
\param transpose
is true (false) s is equal to \f$ S(x) \f$ (\f$ S(x)^T \f$)
where
\f[
S(x) = F^{(1)} (x) * R
\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 number of columns in the matrix \f$ R \f$.
\param r
is a sparsity pattern for the matrix \f$ R \f$.
\param transpose
are the sparsity patterns for \f$ R \f$ and \f$ S(x) \f$ transposed.
\param dependency
Are the derivatives with respect to left and right of the expression below
considered to be non-zero:
\code
CondExpRel(left, right, if_true, if_false)
\endcode
This is used by the optimizer to obtain the correct dependency relations.
\param s
The input size and elements of s do not matter.
On output, s is the sparsity pattern for the matrix \f$ S(x) \f$
or \f$ S(x)^T \f$ depending on transpose.
\par Side Effects
If SetVector::value_type is bool,
the forward sparsity pattern for all of the variables on the
tape is stored in for_jac_sparse_pack__.
In this case
\verbatim
for_jac_sparse_pack_.n_set() == num_var_tape_
for_jac_sparse_pack_.end() == q
for_jac_sparse_set_.n_set() == 0
for_jac_sparse_set_.end() == 0
\endverbatim
\n
\n
If SetVector::value_type is std::set<size_t>,
the forward sparsity pattern for all of the variables on the
tape is stored in for_jac_sparse_set__.
In this case
\verbatim
for_jac_sparse_set_.n_set() == num_var_tape_
for_jac_sparse_set_.end() == q
for_jac_sparse_pack_.n_set() == 0
for_jac_sparse_pack_.end() == 0
\endverbatim
*/
template <class Base, class RecBase>
void ADFun<Base,RecBase>::ForSparseJacCheckpoint(
size_t q ,
const local::sparse::list_setvec& r ,
bool transpose ,
bool dependency ,
local::sparse::list_setvec& s )
{
// used to identify the RecBase type in calls to sweeps
RecBase not_used_rec_base(0.0);
//
size_t n = Domain();
size_t m = Range();
# ifndef NDEBUG
if( transpose )
{ CPPAD_ASSERT_UNKNOWN( r.n_set() == q );
CPPAD_ASSERT_UNKNOWN( r.end() == n );
}
else
{ CPPAD_ASSERT_UNKNOWN( r.n_set() == n );
CPPAD_ASSERT_UNKNOWN( r.end() == q );
}
for(size_t j = 0; j < n; j++)
{ CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == (j+1) );
CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp );
}
# endif
// free all memory currently in sparsity patterns
for_jac_sparse_pack_.resize(0, 0);
for_jac_sparse_set_.resize(0, 0);
// allocate new sparsity pattern
for_jac_sparse_set_.resize(num_var_tape_, q);
// set sparsity pattern for dependent variables
if( transpose )
{ for(size_t i = 0; i < q; i++)
{ local::sparse::list_setvec::const_iterator itr(r, i);
size_t j = *itr;
while( j < n )
{ for_jac_sparse_set_.post_element( ind_taddr_[j], i );
j = *(++itr);
}
}
}
else
{ for(size_t j = 0; j < n; j++)
{ local::sparse::list_setvec::const_iterator itr(r, j);
size_t i = *itr;
while( i < q )
{ for_jac_sparse_set_.post_element( ind_taddr_[j], i );
i = *(++itr);
}
}
}
// process posts
for(size_t j = 0; j < n; j++)
for_jac_sparse_set_.process_post( ind_taddr_[j] );
// evaluate the sparsity pattern for all variables
local::sweep::for_jac<addr_t>(
&play_,
dependency,
n,
num_var_tape_,
for_jac_sparse_set_,
not_used_rec_base
);
// dimension the return value
if( transpose )
s.resize(q, m);
else
s.resize(m, q);
// return values corresponding to dependent variables
for(size_t i = 0; i < m; i++)
{ CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ );
// extract the result from for_jac_sparse_set_
CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.end() == q );
local::sparse::list_setvec::const_iterator
itr(for_jac_sparse_set_, dep_taddr_[i] );
size_t j = *itr;
while( j < q )
{ if( transpose )
s.post_element(j, i);
else
s.post_element(i, j);
j = *(++itr);
}
}
// process posts
for(size_t i = 0; i < s.n_set(); ++i)
s.process_post(i);
}
} // END_CPPAD_NAMESPACE
# endif

Some files were not shown because too many files have changed in this diff Show More