One web page per Section | All as one web page | |
(fast to load) | (slow to load) | |
Math displayed using Latex |
cppad.htm
| _printable.htm |
Math displayed using MathML |
cppad.xml
| _printable.xml |
# include <cppad/cppad.hpp>
# include <cppad/cppad.hpp>
includes the CppAD package for the rest of the current compilation unit.
CppAD or CPPAD_;
see 8: configure
for the few exceptions to this rule.
CppAD namespace; for example, you can access the 4: AD
types as
size_t n = 2;
CppAD::vector< CppAD::AD<Base> > x(n)
You can abbreviate access to one object or function a using
command of the form
using CppAD::AD
CppAD::vector< AD<Base> > x(n)
You can abbreviate access to all CppAD objects and functions
with a command of the form
using namespace CppAD
vector< AD<Base> > x(n)
If you include other namespaces in a similar manner,
this can cause naming conflicts.
| _contents: 1 | Table of Contents |
| Install: 2 | CppAD Download, Test, and Installation Instructions |
| Introduction: 3 | An Introduction by Example to Algorithmic Differentiation |
| AD: 4 | AD Objects |
| ADFun: 5 | ADFun Objects |
| library: 6 | The CppAD General Purpose Library |
| Example: 7 | Examples |
| configure: 8 | Preprocessor Definitions Used by CppAD |
| Appendix: 9 | Appendix |
| _reference: 10 | Alphabetic Listing of Cross Reference Tags |
| _index: 11 | Keyword Index |
| _external: 12 | External Internet References |
% --------------------------------------------------------------------
% Latex macros defined here and used throughout the CppAD documentation
\newcommand{\T}{ {\rm T} }
\newcommand{\R}{ {\bf R} }
\newcommand{\C}{ {\bf C} }
\newcommand{\D}[2]{ \frac{\partial #1}{\partial #2} }
\newcommand{\DD}[3]{ \frac{\partial^2 #1}{\partial #2 \partial #3} }
\newcommand{\Dpow}[2]{ \frac{\partial^{#1}}{\partial {#2}^{#1}} }
\newcommand{\dpow}[2]{ \frac{ {\rm d}^{#1}}{{\rm d}\, {#2}^{#1}} }
cppad-20100315: A Package for Differentiation of C++ Algorithms: : CppAD
Table of Contents: 1: _contents
CppAD Download, Test, and Installation Instructions: 2: Install
Unix Download, Test and Installation: 2.1: InstallUnix
Using Subversion To Download Source Code: 2.1.1: subversion
Windows Download and Test: 2.2: InstallWindows
An Introduction by Example to Algorithmic Differentiation: 3: Introduction
A Simple Program Using CppAD to Compute Derivatives: 3.1: get_started.cpp
Second Order Exponential Approximation: 3.2: exp_2
exp_2: Implementation: 3.2.1: exp_2.hpp
exp_2: Test: 3.2.2: exp_2.cpp
exp_2: Operation Sequence and Zero Order Forward Mode: 3.2.3: exp_2_for0
exp_2: Verify Zero Order Forward Sweep: 3.2.3.1: exp_2_for0.cpp
exp_2: First Order Forward Mode: 3.2.4: exp_2_for1
exp_2: Verify First Order Forward Sweep: 3.2.4.1: exp_2_for1.cpp
exp_2: First Order Reverse Mode: 3.2.5: exp_2_rev1
exp_2: Verify First Order Reverse Sweep: 3.2.5.1: exp_2_rev1.cpp
exp_2: Second Order Forward Mode: 3.2.6: exp_2_for2
exp_2: Verify Second Order Forward Sweep: 3.2.6.1: exp_2_for2.cpp
exp_2: Second Order Reverse Mode: 3.2.7: exp_2_rev2
exp_2: Verify Second Order Reverse Sweep: 3.2.7.1: exp_2_rev2.cpp
exp_2: CppAD Forward and Reverse Sweeps: 3.2.8: exp_2_cppad
An Epsilon Accurate Exponential Approximation: 3.3: exp_eps
exp_eps: Implementation: 3.3.1: exp_eps.hpp
exp_eps: Test of exp_eps: 3.3.2: exp_eps.cpp
exp_eps: Operation Sequence and Zero Order Forward Sweep: 3.3.3: exp_eps_for0
exp_eps: Verify Zero Order Forward Sweep: 3.3.3.1: exp_eps_for0.cpp
exp_eps: First Order Forward Sweep: 3.3.4: exp_eps_for1
exp_eps: Verify First Order Forward Sweep: 3.3.4.1: exp_eps_for1.cpp
exp_eps: First Order Reverse Sweep: 3.3.5: exp_eps_rev1
exp_eps: Verify First Order Reverse Sweep: 3.3.5.1: exp_eps_rev1.cpp
exp_eps: Second Order Forward Mode: 3.3.6: exp_eps_for2
exp_eps: Verify Second Order Forward Sweep: 3.3.6.1: exp_eps_for2.cpp
exp_eps: Second Order Reverse Sweep: 3.3.7: exp_eps_rev2
exp_eps: Verify Second Order Reverse Sweep: 3.3.7.1: exp_eps_rev2.cpp
exp_eps: CppAD Forward and Reverse Sweeps: 3.3.8: exp_eps_cppad
Run the exp_2 and exp_eps Tests: 3.4: exp_apx_main.cpp
AD Objects: 4: AD
AD Default Constructor: 4.1: Default
Default AD Constructor: Example and Test: 4.1.1: Default.cpp
AD Copy Constructor and Assignment Operator: 4.2: ad_copy
AD Copy Constructor: Example and Test: 4.2.1: CopyAD.cpp
AD Constructor From Base Type: Example and Test: 4.2.2: CopyBase.cpp
AD Assignment Operator: Example and Test: 4.2.3: Eq.cpp
Conversion and Printing of AD Objects: 4.3: Convert
Convert From an AD Type to its Base Type: 4.3.1: Value
Convert From AD to its Base Type: Example and Test: 4.3.1.1: Value.cpp
Convert From AD to Integer: 4.3.2: Integer
Convert From AD to Integer: Example and Test: 4.3.2.1: Integer.cpp
AD Output Stream Operator: 4.3.3: Output
AD Output Operator: Example and Test: 4.3.3.1: Output.cpp
Printing AD Values During Forward Mode: 4.3.4: PrintFor
Printing During Forward Mode: Example and Test: 4.3.4.1: PrintFor.cpp
Convert an AD Variable to a Parameter: 4.3.5: Var2Par
Convert an AD Variable to a Parameter: Example and Test: 4.3.5.1: Var2Par.cpp
AD Valued Operations and Functions: 4.4: ADValued
AD Arithmetic Operators and Computed Assignments: 4.4.1: Arithmetic
AD Unary Plus Operator: 4.4.1.1: UnaryPlus
AD Unary Plus Operator: Example and Test: 4.4.1.1.1: UnaryPlus.cpp
AD Unary Minus Operator: 4.4.1.2: UnaryMinus
AD Unary Minus Operator: Example and Test: 4.4.1.2.1: UnaryMinus.cpp
AD Binary Arithmetic Operators: 4.4.1.3: ad_binary
AD Binary Addition: Example and Test: 4.4.1.3.1: Add.cpp
AD Binary Subtraction: Example and Test: 4.4.1.3.2: Sub.cpp
AD Binary Multiplication: Example and Test: 4.4.1.3.3: Mul.cpp
AD Binary Division: Example and Test: 4.4.1.3.4: Div.cpp
AD Computed Assignment Operators: 4.4.1.4: compute_assign
AD Computed Assignment Addition: Example and Test: 4.4.1.4.1: AddEq.cpp
AD Computed Assignment Subtraction: Example and Test: 4.4.1.4.2: SubEq.cpp
AD Computed Assignment Multiplication: Example and Test: 4.4.1.4.3: MulEq.cpp
AD Computed Assignment Division: Example and Test: 4.4.1.4.4: DivEq.cpp
AD Standard Math Unary Functions: 4.4.2: std_math_ad
The AD acos Function: Example and Test: 4.4.2.1: Acos.cpp
The AD asin Function: Example and Test: 4.4.2.2: Asin.cpp
The AD atan Function: Example and Test: 4.4.2.3: Atan.cpp
The AD cos Function: Example and Test: 4.4.2.4: Cos.cpp
The AD cosh Function: Example and Test: 4.4.2.5: Cosh.cpp
The AD exp Function: Example and Test: 4.4.2.6: Exp.cpp
The AD log Function: Example and Test: 4.4.2.7: Log.cpp
The AD log10 Function: Example and Test: 4.4.2.8: Log10.cpp
The AD sin Function: Example and Test: 4.4.2.9: Sin.cpp
The AD sinh Function: Example and Test: 4.4.2.10: Sinh.cpp
The AD sqrt Function: Example and Test: 4.4.2.11: Sqrt.cpp
The AD tan Function: Example and Test: 4.4.2.12: Tan.cpp
The AD tanh Function: Example and Test: 4.4.2.13: Tanh.cpp
Other AD Math Functions: 4.4.3: MathOther
AD Absolute Value Function: 4.4.3.1: abs
AD Absolute Value Function: Example and Test: 4.4.3.1.1: Abs.cpp
AD Two Argument Inverse Tangent Function: 4.4.3.2: atan2
The AD atan2 Function: Example and Test: 4.4.3.2.1: Atan2.cpp
The AD Error Function: 4.4.3.3: erf
The AD erf Function: Example and Test: 4.4.3.3.1: Erf.cpp
The AD Power Function: 4.4.3.4: pow
The AD Power Function: Example and Test: 4.4.3.4.1: Pow.cpp
The Pow Integer Exponent: Example and Test: 4.4.3.4.2: pow_int.cpp
AD Conditional Expressions: 4.4.4: CondExp
Conditional Expressions: Example and Test: 4.4.4.1: CondExp.cpp
Discrete AD Functions: 4.4.5: Discrete
Taping Array Index Operation: Example and Test: 4.4.5.1: TapeIndex.cpp
Interpolation With Out Retaping: Example and Test: 4.4.5.2: interp_onetape.cpp
Interpolation With Retaping: Example and Test: 4.4.5.3: interp_retape.cpp
Bool Valued Operations and Functions with AD Arguments: 4.5: BoolValued
AD Binary Comparison Operators: 4.5.1: Compare
AD Binary Comparison Operators: Example and Test: 4.5.1.1: Compare.cpp
Compare AD and Base Objects for Nearly Equal: 4.5.2: NearEqualExt
Compare AD with Base Objects: Example and Test: 4.5.2.1: NearEqualExt.cpp
AD Boolean Functions: 4.5.3: BoolFun
AD Boolean Functions: Example and Test: 4.5.3.1: BoolFun.cpp
Is an AD Object a Parameter or Variable: 4.5.4: ParVar
AD Parameter and Variable Functions: Example and Test: 4.5.4.1: ParVar.cpp
Check if Equal and Correspond to Same Operation Sequence: 4.5.5: EqualOpSeq
EqualOpSeq: Example and Test: 4.5.5.1: EqualOpSeq.cpp
AD Vectors that Record Index Operations: 4.6: VecAD
AD Vectors that Record Index Operations: Example and Test: 4.6.1: vec_ad.cpp
AD<Base> Requirements for Base Type: 4.7: base_require
Enable use of AD<Base> where Base is std::complex<double>: 4.7.1: base_complex.hpp
Complex Polynomial: Example and Test: 4.7.1.1: ComplexPoly.cpp
Not Complex Differentiable: Example and Test: 4.7.1.2: not_complex_ad.cpp
Enable use of AD<Base> where Base is Adolc's adouble Type: 4.7.2: base_adolc.hpp
Using Adolc with Multiple Levels of Taping: Example and Test: 4.7.2.1: mul_level_adolc.cpp
ADFun Objects: 5: ADFun
Declare Independent Variables and Start Recording: 5.1: Independent
Independent and ADFun Constructor: Example and Test: 5.1.1: Independent.cpp
Construct an ADFun Object and Stop Recording: 5.2: FunConstruct
ADFun Assignment: Example and Test: 5.2.1: fun_assign.cpp
Stop Recording and Store Operation Sequence: 5.3: Dependent
Abort Recording of an Operation Sequence: 5.4: abort_recording
Abort Current Recording: Example and Test: 5.4.1: abort_recording.cpp
ADFun Sequence Properties: 5.5: seq_property
ADFun Sequence Properties: Example and Test: 5.5.1: seq_property.cpp
Evaluate ADFun Functions, Derivatives, and Sparsity Patterns: 5.6: FunEval
Forward Mode: 5.6.1: Forward
Zero Order Forward Mode: Function Values: 5.6.1.1: ForwardZero
First Order Forward Mode: Derivative Values: 5.6.1.2: ForwardOne
Any Order Forward Mode: 5.6.1.3: ForwardAny
Number Taylor Coefficients, Per Variable, Currently Stored: 5.6.1.4: size_taylor
Comparison Changes During Zero Order Forward Mode: 5.6.1.5: CompareChange
CompareChange and Re-Tape: Example and Test: 5.6.1.5.1: CompareChange.cpp
Controlling Taylor Coefficients Memory Allocation: 5.6.1.6: capacity_taylor
Forward Mode: Example and Test: 5.6.1.7: Forward.cpp
Reverse Mode: 5.6.2: Reverse
First Order Reverse Mode: 5.6.2.1: reverse_one
First Order Reverse Mode: Example and Test: 5.6.2.1.1: reverse_one.cpp
Second Order Reverse Mode: 5.6.2.2: reverse_two
Second Order Reverse ModeExample and Test: 5.6.2.2.1: reverse_two.cpp
Hessian Times Direction: Example and Test: 5.6.2.2.2: HesTimesDir.cpp
Any Order Reverse Mode: 5.6.2.3: reverse_any
Third Order Reverse Mode: Example and Test: 5.6.2.3.1: reverse_three.cpp
Reverse Mode General Case: Example and Test: 5.6.2.3.2: reverse_any.cpp
Checkpoint and Function Composition: Example and Test: 5.6.2.3.3: checkpoint.cpp
Calculating Sparsity Patterns: 5.6.3: Sparse
Jacobian Sparsity Pattern: Forward Mode: 5.6.3.1: ForSparseJac
Forward Mode Jacobian Sparsity: Example and Test: 5.6.3.1.1: ForSparseJac.cpp
Jacobian Sparsity Pattern: Reverse Mode: 5.6.3.2: RevSparseJac
Reverse Mode Jacobian Sparsity: Example and Test: 5.6.3.2.1: RevSparseJac.cpp
Hessian Sparsity Pattern: Reverse Mode: 5.6.3.3: RevSparseHes
Reverse Mode Hessian Sparsity: Example and Test: 5.6.3.3.1: RevSparseHes.cpp
First and Second Derivatives: Easy Drivers: 5.7: Drivers
Jacobian: Driver Routine: 5.7.1: Jacobian
Jacobian: Example and Test: 5.7.1.1: Jacobian.cpp
First Order Partial Derivative: Driver Routine: 5.7.2: ForOne
First Order Partial Driver: Example and Test: 5.7.2.1: ForOne.cpp
First Order Derivative: Driver Routine: 5.7.3: RevOne
First Order Derivative Driver: Example and Test: 5.7.3.1: RevOne.cpp
Hessian: Easy Driver: 5.7.4: Hessian
Hessian: Example and Test: 5.7.4.1: Hessian.cpp
Hessian of Lagrangian and ADFun Default Constructor: Example and Test: 5.7.4.2: HesLagrangian.cpp
Forward Mode Second Partial Derivative Driver: 5.7.5: ForTwo
Subset of Second Order Partials: Example and Test: 5.7.5.1: ForTwo.cpp
Reverse Mode Second Partial Derivative Driver: 5.7.6: RevTwo
Second Partials Reverse Driver: Example and Test: 5.7.6.1: RevTwo.cpp
Sparse Jacobian: Easy Driver: 5.7.7: sparse_jacobian
Sparse Jacobian: Example and Test: 5.7.7.1: sparse_jacobian.cpp
Sparse Hessian: Easy Driver: 5.7.8: sparse_hessian
Sparse Hessian: Example and Test: 5.7.8.1: sparse_hessian.cpp
Check an ADFun Sequence of Operations: 5.8: FunCheck
ADFun Check and Re-Tape: Example and Test: 5.8.1: FunCheck.cpp
OpenMP Maximum Thread Number: 5.9: omp_max_thread
Compile and Run the OpenMP Test: 5.9.1: openmp_run.sh
A Simple Parallel Loop: 5.9.1.1: example_a11c.cpp
Multi-Threaded Newton's Method Main Program: 5.9.1.2: multi_newton.cpp
Multi-Threaded Newton's Method Routine: 5.9.1.2.1: multi_newton
OpenMP Multi-Threading Newton's Method Source Code: 5.9.1.2.2: multi_newton.hpp
Sum of 1/i Main Program: 5.9.1.3: sum_i_inv.cpp
Optimize the Tape Corresponding to an ADFun object: 5.10: optimize
ADFun Operation Sequence Optimization: Example and Test: 5.10.1: optimize.cpp
ADFun Object Deprecated Member Functions: 5.11: FunDeprecated
The CppAD General Purpose Library: 6: library
Replacing the CppAD Error Handler: 6.1: ErrorHandler
Replacing The CppAD Error Handler: Example and Test: 6.1.1: ErrorHandler.cpp
CppAD Assertions During Execution: 6.1.2: cppad_assert
Determine if Two Values Are Nearly Equal: 6.2: NearEqual
NearEqual Function: Example and Test: 6.2.1: Near_Equal.cpp
Run One Speed Test and Return Results: 6.3: speed_test
Returns Elapsed Number of Seconds: 6.3.1: elapsed_seconds
Elapsed Seconds: Example and Test: 6.3.1.1: elapsed_seconds.cpp
speed_test: Example and test: 6.3.2: speed_test.cpp
Run One Speed Test and Print Results: 6.4: SpeedTest
Example Use of SpeedTest: 6.4.1: speed_program.cpp
Definition of a Numeric Type: 6.5: NumericType
The NumericType: Example and Test: 6.5.1: NumericType.cpp
Check NumericType Class Concept: 6.6: CheckNumericType
The CheckNumericType Function: Example and Test: 6.6.1: CheckNumericType.cpp
Definition of a Simple Vector: 6.7: SimpleVector
Simple Vector Template Class: Example and Test: 6.7.1: SimpleVector.cpp
Check Simple Vector Concept: 6.8: CheckSimpleVector
The CheckSimpleVector Function: Example and Test: 6.8.1: CheckSimpleVector.cpp
Obtain Nan and Determine if a Value is Nan: 6.9: nan
nan: Example and Test: 6.9.1: nan.cpp
The Integer Power Function: 6.10: pow_int
Evaluate a Polynomial or its Derivative: 6.11: Poly
Polynomial Evaluation: Example and Test: 6.11.1: Poly.cpp
Source: Poly: 6.11.2: poly.hpp
Compute Determinants and Solve Equations by LU Factorization: 6.12: LuDetAndSolve
Compute Determinant and Solve Linear Equations: 6.12.1: LuSolve
LuSolve With Complex Arguments: Example and Test: 6.12.1.1: LuSolve.cpp
Source: LuSolve: 6.12.1.2: lu_solve.hpp
LU Factorization of A Square Matrix: 6.12.2: LuFactor
LuFactor: Example and Test: 6.12.2.1: LuFactor.cpp
Source: LuFactor: 6.12.2.2: lu_factor.hpp
Invert an LU Factored Equation: 6.12.3: LuInvert
LuInvert: Example and Test: 6.12.3.1: LuInvert.cpp
Source: LuInvert: 6.12.3.2: lu_invert.hpp
One DimensionalRomberg Integration: 6.13: RombergOne
One Dimensional Romberg Integration: Example and Test: 6.13.1: RombergOne.cpp
Multi-dimensional Romberg Integration: 6.14: RombergMul
One Dimensional Romberg Integration: Example and Test: 6.14.1: RombergMul.cpp
An Embedded 4th and 5th Order Runge-Kutta ODE Solver: 6.15: Runge45
Runge45: Example and Test: 6.15.1: runge_45_1.cpp
Runge45: Example and Test: 6.15.2: runge_45_2.cpp
A 3rd and 4th Order Rosenbrock ODE Solver: 6.16: Rosen34
Rosen34: Example and Test: 6.16.1: Rosen34.cpp
An Error Controller for ODE Solvers: 6.17: OdeErrControl
OdeErrControl: Example and Test: 6.17.1: OdeErrControl.cpp
OdeErrControl: Example and Test Using Maxabs Argument: 6.17.2: OdeErrMaxabs.cpp
An Arbitrary Order Gear Method: 6.18: OdeGear
OdeGear: Example and Test: 6.18.1: OdeGear.cpp
An Error Controller for Gear's Ode Solvers: 6.19: OdeGearControl
OdeGearControl: Example and Test: 6.19.1: OdeGearControl.cpp
Computing Jacobian and Hessian of Bender's Reduced Objective: 6.20: BenderQuad
BenderQuad: Example and Test: 6.20.1: BenderQuad.cpp
Jacobian and Hessian of Optimal Values: 6.21: opt_val_hes
opt_val_hes: Example and Test: 6.21.1: opt_val_hes.cpp
LU Factorization of A Square Matrix and Stability Calculation: 6.22: LuRatio
LuRatio: Example and Test: 6.22.1: LuRatio.cpp
Float and Double Standard Math Unary Functions: 6.23: std_math_unary
The CppAD::vector Template Class: 6.24: CppAD_vector
CppAD::vector Template Class: Example and Test: 6.24.1: CppAD_vector.cpp
CppAD::vectorBool Class: Example and Test: 6.24.2: vectorBool.cpp
Routines That Track Use of New and Delete: 6.25: TrackNewDel
Tracking Use of New and Delete: Example and Test: 6.25.1: TrackNewDel.cpp
Examples: 7: Example
General Examples: 7.1: General
Creating Your Own Interface to an ADFun Object: 7.1.1: ad_fun.cpp
Example and Test Linking CppAD to Languages Other than C++: 7.1.2: ad_in_c.cpp
Gradient of Determinant Using Expansion by Minors: Example and Test: 7.1.3: HesMinorDet.cpp
Gradient of Determinant Using LU Factorization: Example and Test: 7.1.4: HesLuDet.cpp
Nonlinear Programming Using the CppAD Interface to Ipopt: 7.1.5: cppad_ipopt_nlp
Linking the CppAD Interface to Ipopt in Visual Studio 9.0: 7.1.5.1: cppad_ipopt_windows
Nonlinear Programming Using CppAD and Ipopt: Example and Test: 7.1.5.2: ipopt_get_started.cpp
Example Simultaneous Solution of Forward and Inverse Problem: 7.1.5.3: cppad_ipopt_ode
An ODE Inverse Problem Example: 7.1.5.3.1: ipopt_ode_problem
ODE Inverse Problem Definitions: Source Code: 7.1.5.3.1.1: ipopt_ode_problem.hpp
ODE Fitting Using Simple Representation: 7.1.5.3.2: ipopt_ode_simple
ODE Fitting Using Simple Representation: 7.1.5.3.2.1: ipopt_ode_simple.hpp
ODE Fitting Using Fast Representation: 7.1.5.3.3: ipopt_ode_fast
ODE Fitting Using Fast Representation: 7.1.5.3.3.1: ipopt_ode_fast.hpp
Driver for Running the Ipopt ODE Example: 7.1.5.3.4: ipopt_ode_run.hpp
Correctness Check for Both Simple and Fast Representations: 7.1.5.3.5: ipopt_ode_check.cpp
Speed Test for Both Simple and Fast Representations: 7.1.5.4: ipopt_ode_speed.cpp
Interfacing to C: Example and Test: 7.1.6: Interface2C.cpp
Gradient of Determinant Using Expansion by Minors: Example and Test: 7.1.7: JacMinorDet.cpp
Gradient of Determinant Using Lu Factorization: Example and Test: 7.1.8: JacLuDet.cpp
Using Multiple Levels of AD: 7.1.9: mul_level
Multiple Tapes: Example and Test: 7.1.9.1: mul_level.cpp
A Stiff Ode: Example and Test: 7.1.10: OdeStiff.cpp
Taylor's Ode Solver: An Example and Test: 7.1.11: ode_taylor.cpp
Using Adolc with Taylor's Ode Solver: An Example and Test: 7.1.12: ode_taylor_adolc.cpp
Example Differentiating a Stack Machine Interpreter: 7.1.13: StackMachine.cpp
Utility Routines used by CppAD Examples: 7.2: ExampleUtility
Program That Runs the CppAD Examples: 7.2.1: Example.cpp
Program That Runs the Speed Examples: 7.2.2: speed_example.cpp
Lu Factor and Solve with Recorded Pivoting: 7.2.3: LuVecAD
Lu Factor and Solve With Recorded Pivoting: Example and Test: 7.2.3.1: LuVecADOk.cpp
List of All the CppAD Examples: 7.3: ListAllExamples
Choosing The Vector Testing Template Class: 7.4: test_vector
Preprocessor Definitions Used by CppAD: 8: configure
Appendix: 9: Appendix
Frequently Asked Questions and Answers: 9.1: Faq
Speed Test Routines: 9.2: speed
Speed Testing Main Program: 9.2.1: speed_main
Speed Testing Gradient of Determinant Using Lu Factorization: 9.2.1.1: link_det_lu
Speed Testing Gradient of Determinant by Minor Expansion: 9.2.1.2: link_det_minor
Speed Testing the Jacobian of Ode Solution: 9.2.1.3: link_ode
Speed Testing Second Derivative of a Polynomial: 9.2.1.4: link_poly
Speed Testing Sparse Hessian: 9.2.1.5: link_sparse_hessian
Speed Testing Sparse Jacobian: 9.2.1.6: link_sparse_jacobian
Microsoft Version of Elapsed Number of Seconds: 9.2.1.7: microsoft_timer
Speed Testing Utilities: 9.2.2: speed_utility
Simulate a [0,1] Uniform Random Variate: 9.2.2.1: uniform_01
Source: uniform_01: 9.2.2.1.1: uniform_01.hpp
Determinant of a Minor: 9.2.2.2: det_of_minor
Determinant of a Minor: Example and Test: 9.2.2.2.1: det_of_minor.cpp
Source: det_of_minor: 9.2.2.2.2: det_of_minor.hpp
Determinant Using Expansion by Minors: 9.2.2.3: det_by_minor
Determinant Using Expansion by Minors: Example and Test: 9.2.2.3.1: det_by_minor.cpp
Source: det_by_minor: 9.2.2.3.2: det_by_minor.hpp
Determinant Using Expansion by Lu Factorization: 9.2.2.4: det_by_lu
Determinant Using Lu Factorization: Example and Test: 9.2.2.4.1: det_by_lu.cpp
Source: det_by_lu: 9.2.2.4.2: det_by_lu.hpp
Check Determinant of 3 by 3 matrix: 9.2.2.5: det_33
Source: det_33: 9.2.2.5.1: det_33.hpp
Check Gradient of Determinant of 3 by 3 matrix: 9.2.2.6: det_grad_33
Source: det_grad_33: 9.2.2.6.1: det_grad_33.hpp
Evaluate a Function Defined in Terms of an ODE: 9.2.2.7: ode_evaluate
ode_evaluate: Example and test: 9.2.2.7.1: ode_evaluate.cpp
Source: ode_evaluate: 9.2.2.7.2: ode_evaluate.hpp
Evaluate a Function That Has a Sparse Hessian: 9.2.2.8: sparse_evaluate
sparse_evaluate: Example and test: 9.2.2.8.1: sparse_evaluate.cpp
Source: sparse_evaluate: 9.2.2.8.2: sparse_evaluate.hpp
Speed Test Functions in Double: 9.2.3: speed_double
Double Speed: Determinant by Minor Expansion: 9.2.3.1: double_det_minor.cpp
Double Speed: Determinant Using Lu Factorization: 9.2.3.2: double_det_lu.cpp
Double Speed: Ode Solution: 9.2.3.3: double_ode.cpp
Double Speed: Evaluate a Polynomial: 9.2.3.4: double_poly.cpp
Double Speed: Sparse Hessian: 9.2.3.5: double_sparse_hessian.cpp
Double Speed: Sparse Jacobian: 9.2.3.6: double_sparse_jacobian.cpp
Speed Test Derivatives Using Adolc: 9.2.4: speed_adolc
Adolc Speed: Gradient of Determinant by Minor Expansion: 9.2.4.1: adolc_det_minor.cpp
Adolc Speed: Gradient of Determinant Using Lu Factorization: 9.2.4.2: adolc_det_lu.cpp
Adolc Speed: Ode: 9.2.4.3: adolc_ode.cpp
Adolc Speed: Second Derivative of a Polynomial: 9.2.4.4: adolc_poly.cpp
Adolc Speed: Sparse Hessian: 9.2.4.5: adolc_sparse_hessian.cpp
adolc Speed: sparse_jacobian: 9.2.4.6: adolc_sparse_jacobian.cpp
Speed Test Derivatives Using CppAD: 9.2.5: speed_cppad
CppAD Speed: Gradient of Determinant by Minor Expansion: 9.2.5.1: cppad_det_minor.cpp
CppAD Speed: Gradient of Determinant Using Lu Factorization: 9.2.5.2: cppad_det_lu.cpp
CppAD Speed: Gradient of Ode Solution: 9.2.5.3: cppad_ode.cpp
CppAD Speed: Second Derivative of a Polynomial: 9.2.5.4: cppad_poly.cpp
CppAD Speed: Sparse Hessian: 9.2.5.5: cppad_sparse_hessian.cpp
CppAD Speed: Sparse Jacobian: 9.2.5.6: cppad_sparse_jacobian.cpp
Speed Test Derivatives Using Fadbad: 9.2.6: speed_fadbad
Fadbad Speed: Gradient of Determinant by Minor Expansion: 9.2.6.1: fadbad_det_minor.cpp
Fadbad Speed: Gradient of Determinant Using Lu Factorization: 9.2.6.2: fadbad_det_lu.cpp
Fadbad Speed: Ode: 9.2.6.3: fadbad_ode.cpp
Fadbad Speed: Second Derivative of a Polynomial: 9.2.6.4: fadbad_poly.cpp
Fadbad Speed: Sparse Hessian: 9.2.6.5: fadbad_sparse_hessian.cpp
fadbad Speed: sparse_jacobian: 9.2.6.6: fadbad_sparse_jacobian.cpp
Speed Test Derivatives Using Sacado: 9.2.7: speed_sacado
Sacado Speed: Gradient of Determinant by Minor Expansion: 9.2.7.1: sacado_det_minor.cpp
Sacado Speed: Gradient of Determinant Using Lu Factorization: 9.2.7.2: sacado_det_lu.cpp
Sacado Speed: Gradient of Ode Solution: 9.2.7.3: sacado_ode.cpp
Sacado Speed: Second Derivative of a Polynomial: 9.2.7.4: sacado_poly.cpp
Sacado Speed: Sparse Hessian: 9.2.7.5: sacado_sparse_hessian.cpp
sacado Speed: sparse_jacobian: 9.2.7.6: sacado_sparse_jacobian.cpp
The Theory of Derivative Calculations: 9.3: Theory
The Theory of Forward Mode: 9.3.1: ForwardTheory
Exponential Function Forward Taylor Polynomial Theory: 9.3.1.1: ExpForward
Logarithm Function Forward Taylor Polynomial Theory: 9.3.1.2: LogForward
Square Root Function Forward Taylor Polynomial Theory: 9.3.1.3: SqrtForward
Trigonometric and Hyperbolic Sine and Cosine Forward Theory: 9.3.1.4: SinCosForward
Arctangent Function Forward Taylor Polynomial Theory: 9.3.1.5: AtanForward
Arcsine Function Forward Taylor Polynomial Theory: 9.3.1.6: AsinForward
Arccosine Function Forward Taylor Polynomial Theory: 9.3.1.7: AcosForward
The Theory of Reverse Mode: 9.3.2: ReverseTheory
Exponential Function Reverse Mode Theory: 9.3.2.1: ExpReverse
Logarithm Function Reverse Mode Theory: 9.3.2.2: LogReverse
Square Root Function Reverse Mode Theory: 9.3.2.3: SqrtReverse
Trigonometric and Hyperbolic Sine and Cosine Reverse Theory: 9.3.2.4: SinCosReverse
Arctangent Function Reverse Mode Theory: 9.3.2.5: AtanReverse
Arcsine Function Reverse Mode Theory: 9.3.2.6: AsinReverse
Arccosine Function Reverse Mode Theory: 9.3.2.7: AcosReverse
An Important Reverse Mode Identity: 9.3.3: reverse_identity
Glossary: 9.4: glossary
Bibliography: 9.5: Bib
Know Bugs and Problems Using CppAD: 9.6: Bugs
The CppAD Wish List: 9.7: WishList
Changes and Additions to CppAD: 9.8: whats_new
Changes and Additions to CppAD During 2010: 9.8.1: whats_new_10
Changes and Additions to CppAD During 2009: 9.8.2: whats_new_09
Changes and Additions to CppAD During 2008: 9.8.3: whats_new_08
Changes and Additions to CppAD During 2007: 9.8.4: whats_new_07
Changes and Additions to CppAD During 2006: 9.8.5: whats_new_06
Changes and Additions to CppAD During 2005: 9.8.6: whats_new_05
Changes and Additions to CppAD During 2004: 9.8.7: whats_new_04
Changes and Additions to CppAD During 2003: 9.8.8: whats_new_03
Deprecated Include Files: 9.9: include_deprecated
Your License for the CppAD Software: 9.10: License
Alphabetic Listing of Cross Reference Tags: 10: _reference
Keyword Index: 11: _index
External Internet References: 12: _external
yum install cppad-devel
(In Fedora, devel is used for program development tools.)
You can download and install the corresponding version of the
documentation using the command
yum install cppad-doc
cppad.spec file
to build an RPM for some other operating system,
it can be found at
https://projects.coin-or.org/CppAD/browser/trunk/cppad.spec
tar
and then compressed with gzip:
The ascii files for these downloads are in
Unix format; i.e., each line ends with just a line feed.
CPL License | cppad-20100315.cpl.tgz |
GPL License | cppad-20100315.gpl.tgz |
tar -xvzf cppad-20100315.license.tgz
(where
license
is cpl or gpl)
to decompress and extract the unix format version
into the distribution directory
cppad-20100315
To see if this has been done correctly, check for the following file:
cppad-20100315/cppad/cppad.hpp
distribution_directory
(the directory created by the extraction) and execute the command:
./configure
--prefix=PrefixDir
--with-Documentation
--with-stdvector
POSTFIX_DIR=PostfixDir
ADOLC_DIR=AdolcDir
FADBAD_DIR=FadbadDir
SADADO_DIR=SacadoDir
BOOST_DIR=BoostDir
IPOPT_DIR=IpoptDir
CXX_FLAGS=CompilerFlags
where only the configure command need appear.
The entries one each of the other lines are optional
and the text in italic is replaced values that you choose.
make test in the
distribution_directory
.
A description of the tests, and instructions for running individual tests,
are described below.
make test in the directory
distribution_directory/introduction/get_started
exp_apx function
(used in the 3: Introduction
)
by executing the command make test in the directory
distribution_directory/introduction/exp_apx
make test in the directory
distribution_directory/example
See 7.3: ListAllExamples
for a list of all the CppAD examples.
make test in the directory
distribution_directory/test_more
make test in the directory
distribution_directory/speed/cppad
After executing make test, you can run the CppAD derivative speed tests
by executing the command ./cppad (see 9.2.1: speed_main
).
make test in the directory
distribution_directory/speed/double
After executing make test, you can run the function value speed tests
by executing the command ./double (see 9.2.1: speed_main
).
make test in the directory
distribution_directory/speed/example
make test in the directory
distribution_directory/speed/profile
After executing make test, you can run the profile tests
by executing the command ./profile (see 9.2.1: speed_main
).
You can then obtain the profiling results with
gprof -b speed/profile/profile
If you are using a windows operating system with Cygwin or MinGW,
you may have to replace profile by profile.exe
in the gprof command above; i.e.,
gprof -b speed/profile/profile.exe
In C++, template parameters and argument types become part of a
routines's name.
This can make the gprof output hard to read
(the routine names can be very long).
You can remove the template parameters and argument types from the
routine names by executing the following command
gprof -b speed/profile/profile | sed -f speed/profile/gprof.sed
If you are using a windows operating system with Cygwin or MinGW,
you would need to use
gprof -b speed/profile/profile.exe | sed -f speed/profile/gprof.sed
make test in the directory
distribution_directory/print_for
$HOME
i.e., by default the CppAD include files
will 2.1.v: install
below $HOME.
If you want to install elsewhere, you will have to use this option.
As an example of using the
--prefix=PrefixDir
option,
if you specify
./configure --prefix=/usr/local
the CppAD include files will be installed in the directory
/usr/local/include/cppad
If 2.1.m: --with-Documentation
is specified, the CppAD documentation files will be installed in the directory
/usr/local/share/doc/cppad-20100315
--with-Documentation is specified,
the CppAD documentation HTML and XML files are copied to the directory
PrefixDir/share/doc/PostfixDir/cppad-20100315
(see 2.1.o: PostfixDir
).
The top of the CppAD HTML documentation tree
(with mathematics displayed as LaTex command) will be located at
PrefixDir/share/doc/PostfixDir/cppad-20100315/cppad.htm
and the top of the XML documentation tree
(with mathematics displayed as MathML) will be located at
PrefixDir/share/doc/PostfixDir/cppad-20100315/cppad.xml
--with-stdvector is specified,
the default definition this template class is replaced by
std::vector
(In this case
BoostDir
must not also be specified.)
POSTFIX_DIR=PostfixDir
option,
if you specify
./configure --prefix=/usr/local POSTFIX_DIR=coin
the CppAD include files will be
2.1.v: installed
in the directory
/usr/local/include/coin/cppad
If 2.1.m: --with-Documentation
is specified, the CppAD documentation files will be installed in the directory
/usr/local/share/doc/coin/cppad-20100315
AdolcDir
in the
2.1.d: configure
command line.
The value of
AdolcDir
must be such that
AdolcDir/include/adolc/adouble.h
is a valid way to reference adouble.h.
In this case, you can run the Adolc speed correctness tests by
executing the command make test in the directory
distribution_directory/speed/adolc
After executing make test, you can run the Adolc speed tests
by executing the command ./adolc (see 9.2.1: speed_main
).
.bash_profile in your home directory:
LD_LIBRARY_PATH=AdolcDir/lib:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH
in order for Adolc to run properly.
.bash_profile in your home directory:
PATH=AdolcDir/bin:${PATH}
export PATH
in order for Adolc to run properly.
If
AdolcDir
begins with a disk specification,
you must use the Cygwin format for the disk specification.
For example,
if d:/adolc_base is the proper directory,
/cygdrive/d/adolc_base should be used for
AdolcDir
.
FadbadDir
.
It must be such that
FadbadDir/FADBAD++/badiff.h
is a valid reference to badiff.h.
In this case, you can run the Fadbad speed correctness tests by
executing the command make test in the directory
distribution_directory/speed/fadbad
After executing make test, you can run the Fadbad speed tests
by executing the command ./fadbad (see 9.2.1: speed_main
).
SacadoDir
.
It must be such that
SacadoDir/include/Sacado.hpp
is a valid reference to Sacado.hpp.
In this case, you can run the Sacado speed correctness tests by
executing the command make test in the directory
distribution_directory/speed/sacado
After executing make test, you can run the Sacado speed tests
by executing the command ./sacado (see 9.2.1: speed_main
).
CPPAD_TEST_VECTOR is
6.24: CppAD::vector
.
If the command line argument
BOOST_DIR=BoostDir
is present, it must be such that
BoostDir/boost/numeric/ublas/vector.hpp
is a valid reference to the file vector.hpp.
In this case, the default definition of CPPAD_TEST_VECTOR
is replaced by
boost::numeric::ublas::vector
(see boost
(http://www.boost.org) ).
If
BoostDir
is present, the argument --with-stdvector
must not be present.
IpoptDir
.
It must be such that
IpoptDir/include/coin/IpIpoptApplication.hpp
is a valid reference to IpIpoptApplication.hpp.
In this case, the CppAD interface to Ipopt
7.1.5.t: examples
can be built and tested
by executing the command make test in the directory
distribution_directory/cppad_ipopt/example
You can do more testing of this interface by executing make test
in the directories
distribution_directory/cppad_ipopt/test
distribution_directory/cppad_ipopt/speed
Once this has been done, you can execute the program
distribution_directory/cppad_ipopt/speed/speed
see 7.1.5.4: ipopt_ode_speed.cpp
.
CompilerFlags
is present,
it specifies compiler flags.
For example,
CXX_FLAGS="-Wall -ansi"
would specify that warning flags -Wall
and -ansi should be included
in all the C++ compile commands.
The error and warning flags chosen must be valid options
for the C++ compiler.
The default value for
CompilerFlags
is the
empty string.
make install
This will install CppAD in the location specified by
2.1.l: PrefixDir
.
You must have permission to write in the
PrefixDir
directory to execute this command.
You may optionally specify a destination directory for the install; i.e.,
make install DESTDIR=DestinationDirectory
which svn
which omhelp
svn co https://projects.coin-or.org/svn/CppAD/dir dir
where dir is replaced by trunk.
To see if this has been done correctly, check for the following file:
dir/cppad/cppad.hpp
Since you downloaded the current version,
you should set the version of CppAD to the current date.
Using an editor of you choice, open the file
dir/configure
(if you plan to use the
2.2: Windows install
instructions,
edit dir/cppad/config.h instead of dir/configure).
Search this file for text of the form yyyymmdd
where yyyy are four decimal digits representing a year,
mm is two decimal digits representing a month,
and dd is two decimal digits representing a day.
Replace each occurrence of this text with the decimal digits
for the current year, month, and day
(i.e., the eight decimal digits representing the current date).
| dir | yyyymmdd |
1.0 |
20060913 |
2.0 |
20071016 |
2.1 |
20071124 |
2.2 |
20071210
|
svn co https://projects.coin-or.org/svn/CppAD/stable/dir dir
To see if this has been done correctly, check for the following file:
if dir is 1.0 check for
1.0/CppAD/CppAD.h
otherwise check for
dir/cppad/cppad.hpp
Since you downloaded a stable version,
the version of CppAD configure,
and all the other relevant files, is correct.
mkdir dir/doc
cd dir/doc
omhelp ../doc.omh -noframe -debug -l http://www.coin-or.org/CppAD/
omhelp ../doc.omh -noframe -debug -l http://www.coin-or.org/CppAD/ -xml
dir/doc/index.xml
dir/doc/index.htm
in a web browser and proceeding to the
2.1: Unix
or 2.2: Windows
install instructions.
tar
and then compressed with gzip.
The ascii files are in Unix format; i.e., each line ends with a
line feed (instead of a carriage return and line feed as is standard for
windows formatted files).
Visual Studio can handel this formatting just fine, but you may
want to convert the format to the windows standard if you are using
and editor that has trouble viewing the files in Unix format.
and then a line feed.
CPL License | cppad-20100315.cpl.tgz |
GPL License | cppad-20100315.gpl.tgz |
All archives) as the file type
in the Open browser.
Yes button.
Extract button from the main menu.
Extract to field and then select the Extract button
in the pop-up dialog.
Winzip will create a subdirectory called cppad-20100315
where the files are placed.
cppad-20100315\introduction\get_started\get_started.sln
in Visual Studio and then select Build | Build get_started.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following command
introduction\get_started\Debug\get_started
cppad-20100315\introduction\exp_apx\exp_apx.sln
in Visual Studio.
Then select Build | Build exp_apx.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following command
introduction\exp_apx\Debug\exp_apx
cppad-20100315\example\example.sln
in Visual Studio.
Then select Build | Build Example.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following command
example\Debug\example
cppad-20100315\test_more\test_more.sln
in Visual Studio and then select Build | Build test_more.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following command
test_more\Debug\test_more
cppad-20100315\print_for\print_for.sln
in Visual Studio.
Then select Build | Build print_for.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following command
print_for\Debug\print_for
cppad-20100315\speed\cppad\cppad.sln
in Visual Studio.
Then select Build | Build cppad.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following commands
speed\cppad\Debug\cppad correct 123
speed\cppad\Debug\cppad speed 123
cppad-20100315\speed\double\double.sln
in Visual Studio.
Then select Build | Build double.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following commands
speed\double\Debug\double correct 123
speed\double\Debug\double speed 123
cppad-20100315\speed\example\example.sln
in Visual Studio.
Then select Build | Build example.exe.
Then in a Dos box, and in the cppad-20100315 directory,
execute the following command
speed\example\Debug\example
while loop.
For each of these algorithms, do the following:
| get_started.cpp: 3.1 | A Simple Program Using CppAD to Compute Derivatives |
| exp_2: 3.2 | Second Order Exponential Approximation |
| exp_eps: 3.3 | An Epsilon Accurate Exponential Approximation |
| exp_apx_main.cpp: 3.4 | Run the exp_2 and exp_eps Tests |
f : \R \rightarrow \R
is defined by
\[
f(x) = a_0 + a_1 * x^1 + \cdots + a_{k-1} * x^{k-1}
\]
where a is a fixed vector of length k.
f(x)
is given by
\[
f' (x) = a_1 + 2 * a_2 * x + \cdots + (k-1) * a_{k-1} * x^{k-2}
\]
k
is equal to 5,
a = (1, 1, 1, 1, 1)
, and
x = 3
.
If follows that
\[
f' ( 3 ) = 1 + 2 * 3 + 3 * 3^2 + 4 * 3^3 = 142
\]
Poly is defined below for this particular application.
A general purpose polynomial evaluation routine is documented and
distributed with CppAD (see 6.11: Poly
).
f(x) = 1 + x + x^2 + x^3 + x^4
at the point
x = 2
.
f(x) = 1 + x + x^2 / 2
at the point
x = .5
.
f(x) = \exp (x) - 1 - x - x^2 / 2
at the point
x = .5
.
#include <iostream> // standard input/output
#include <vector> // standard vector
#include <cppad/cppad.hpp> // the CppAD package http://www.coin-or.org/CppAD/
namespace {
// define y(x) = Poly(a, x) in the empty namespace
template <class Type>
Type Poly(const std::vector<double> &a, const Type &x)
{ size_t k = a.size();
Type y = 0.; // initialize summation
Type x_i = 1.; // initialize x^i
size_t i;
for(i = 0; i < k; i++)
{ y += a[i] * x_i; // y = y + a_i * x^i
x_i *= x; // x_i = x_i * x
}
return y;
}
}
// main program
int main(void)
{ using CppAD::AD; // use AD as abbreviation for CppAD::AD
using std::vector; // use vector as abbreviation for std::vector
size_t i; // a temporary index
// vector of polynomial coefficients
size_t k = 5; // number of polynomial coefficients
vector<double> a(k); // vector of polynomial coefficients
for(i = 0; i < k; i++)
a[i] = 1.; // value of polynomial coefficients
// domain space vector
size_t n = 1; // number of domain space variables
vector< AD<double> > X(n); // vector of domain space variables
X[0] = 3.; // value corresponding to operation sequence
// declare independent variables and start recording operation sequence
CppAD::Independent(X);
// range space vector
size_t m = 1; // number of ranges space variables
vector< AD<double> > Y(m); // vector of ranges space variables
Y[0] = Poly(a, X[0]); // value during recording of operations
// store operation sequence in f: X -> Y and stop recording
CppAD::ADFun<double> f(X, Y);
// compute derivative using operation sequence stored in f
vector<double> jac(m * n); // Jacobian of f (m by n matrix)
vector<double> x(n); // domain space vector
x[0] = 3.; // argument value for derivative
jac = f.Jacobian(x); // Jacobian for operation sequence
// print the results
std::cout << "f'(3) computed by CppAD = " << jac[0] << std::endl;
// check if the derivative is correct
int error_code;
if( jac[0] == 142. )
error_code = 0; // return code for correct case
else error_code = 1; // return code for incorrect case
return error_code;
}
f'(3) computed by CppAD = 142
# include "exp_2.hpp"
y = exp_2(x)
\[
\exp (x) = 1 + x^1 / 1 ! + x^2 / 2 ! + \cdots
\]
The second order approximation for the exponential function is
\[
{\rm exp\_2} (x) = 1 + x + x^2 / 2
\]
cppad-yy-mm-dd/introduction/exp_apx
where cppad-yy-mm-dd is the distribution directory
created during the beginning steps of the
2: installation
of CppAD.
const Type &x
(see Type below).
It specifies the point at which to evaluate the
approximation for the second order exponential approximation.
Type y
It is the value of the exponential function
approximation defined above.
int:
| Operation | Result Type | Description |
Type(i)
| Type | object with value equal to i |
u = v
| Type | new u (and result) is value of v |
u * v
| Type |
result is value of
u * v
|
u / v
| Type |
result is value of
u / v
|
u + v
| Type |
result is value of
u + v
|
| exp_2.hpp: 3.2.1 | exp_2: Implementation |
| exp_2.cpp: 3.2.2 | exp_2: Test |
| exp_2_for0: 3.2.3 | exp_2: Operation Sequence and Zero Order Forward Mode |
| exp_2_for1: 3.2.4 | exp_2: First Order Forward Mode |
| exp_2_rev1: 3.2.5 | exp_2: First Order Reverse Mode |
| exp_2_for2: 3.2.6 | exp_2: Second Order Forward Mode |
| exp_2_rev2: 3.2.7 | exp_2: Second Order Reverse Mode |
| exp_2_cppad: 3.2.8 | exp_2: CppAD Forward and Reverse Sweeps |
double x = .1;
double y = exp_2(x);
What is the value assigned to
v1, v2, ... ,v5 in 3.2.1: exp_2.hpp
?
exp_2.hpp to
a routine exp_3.hpp that computes
\[
1 + x^2 / 2 ! + x^3 / 3 !
\]
Do this in a way that only assigns one value to each variable
(as exp_2 does).
double x = .5;
double y = exp_3(x);
using exp_3 created in the previous problem.
What is the value assigned to the new variables in exp_3
(variables that are in exp_3 and not in exp_2) ?
template <class Type>
Type exp_2(const Type &x)
{ Type v1 = x; // v1 = x
Type v2 = Type(1) + v1; // v2 = 1 + x
Type v3 = v1 * v1; // v3 = x^2
Type v4 = v3 / Type(2); // v4 = x^2 / 2
Type v5 = v2 + v4; // v5 = 1 + x + x^2 / 2
return v5; // exp_2(x) = 1 + x + x^2 / 2
}
# include <cmath> // define fabs function
# include "exp_2.hpp" // definition of exp_2 algorithm
bool exp_2(void)
{ double x = .5;
double check = 1 + x + x * x / 2.;
bool ok = std::fabs( exp_2(x) - check ) <= 1e-10;
return ok;
}
\[
f(x) = 1 + x + x^2 / 2
\]
An algorithmic differentiation package
does not operate on the mathematical function
f(x)
but rather on the particular algorithm used to compute the function
(in this case 3.2.1: exp_2.hpp
).
x^{(0)} \in \R^n
and it returns the corresponding vector
y^{(0)} \in \R^m
given by
\[
y^{(0)} = f( x^{(0)} )
\]
The superscript
(0)
denotes zero order derivative;
i.e., it is equal to the value
of the corresponding variable.
For the example we are considering here,
both
n
and
m
are equal to one.
We consider the case where 3.2.1: exp_2.hpp
is executed with
x^{(0)} = .5
.
The table below contains the corresponding operation sequence
and the results of a zero order sweep.
| Index |
| Code |
| Operation |
| Zero Order |
| 1 |
|
Type v1 = x;
|
v_1 = x
|
v_1^{(0)} = 0.5
| ||
| 2 |
|
Type v2 = Type(1) + v1;
|
v_2 = 1 + v_1
|
v_2^{(0)} = 1.5
| ||
| 3 |
|
Type v3 = v1 * v1;
|
v_3 = v_1 * v_1
|
v_3^{(0)} = 0.25
| ||
| 4 |
|
Type v4 = v3 / Type(2);
|
v_4 = v_3 / 2
|
v_4^{(0)} = 0.125
| ||
| 5 |
|
Type v5 = v2 + v4;
|
v_5 = v_2 + v_4
|
v_5^{(0)} = 1.625
|
\[
1.625 =
v_5^{(0)} =
f( x^{(0)} )
\]
x^{(0)} = .2
,
what is the result of a zero order forward sweep for
the operation sequence above;
i.e., what are the corresponding values for
\[
v_1^{(0)} , v_2^{(0)} , \cdots , v_5^{(0)}
\]
# include <cmath> // for fabs function
bool exp_2_for0(double *v0) // double v0[6]
{ bool ok = true;
double x = .5;
v0[1] = x; // v1 = x
ok &= std::fabs( v0[1] - 0.5) < 1e-10;
v0[2] = 1. + v0[1]; // v2 = 1 + v1
ok &= std::fabs( v0[2] - 1.5) < 1e-10;
v0[3] = v0[1] * v0[1]; // v3 = v1 * v1
ok &= std::fabs( v0[3] - 0.25) < 1e-10;
v0[4] = v0[3] / 2.; // v4 = v3 / 2
ok &= std::fabs( v0[4] - 0.125) < 1e-10;
v0[5] = v0[2] + v0[4]; // v5 = v2 + v4
ok &= std::fabs( v0[5] - 1.625) < 1e-10;
return ok;
}
bool exp_2_for0(void)
{ double v0[6];
return exp_2_for0(v0);
}
x(t)
near
t = 0
by the first order expansion
\[
x(t) = x^{(0)} + x^{(1)} * t
\]
it follows that
x^{(0)}
is the zero,
and
x^{(1)}
the first,
order derivative of
x(t)
at
t = 0
.
\[
f(x) = 1 + x + x^2 / 2
\]
The corresponding derivative function is
\[
\partial_x f (x) = 1 + x
\]
An algorithmic differentiation package
does not operate on the mathematical form of the function,
or its derivative,
but rather on the
3.2.3.c: operation sequence
for the for the algorithm that is used to evaluate the function.
x = .5
.
The corresponding operation sequence and
zero order forward mode values
(see 3.2.3.c.e: zero order sweep
)
are inputs and are used by a first order forward sweep.
t
,
at
t = 0
, for each variable in the sequence.
\[
v_j (t) = v_j^{(0)} + v_j^{(1)} t
\]
We use
x^{(0)} = 1
so that differentiation
with respect to
t
,
at
t = 0
, is the same partial differentiation
with respect to
x
at
x = x^{(0)}
.
| Index |
| Operation |
| Zero Order |
| Derivative |
| First Order |
| 1 |
|
v_1 = x
| 0.5 |
v_1^{(1)} = x^{(1)}
|
v_1^{(1)} = 1
| |||
| 2 |
|
v_2 = 1 + v_1
| 1.5 |
v_2^{(1)} = v_1^{(1)}
|
v_2^{(1)} = 1
| |||
| 3 |
|
v_3 = v_1 * v_1
| 0.25 |
v_3^{(1)} = 2 * v_1^{(0)} * v_1^{(1)}
|
v_3^{(1)} = 1
| |||
| 4 |
|
v_4 = v_3 / 2
| 0.125 |
v_4^{(1)} = v_3^{(1)} / 2
|
v_4^{(1)} = 0.5
| |||
| 5 |
|
v_5 = v_2 + v_4
| 1.625 |
v_5^{(1)} = v_2^{(1)} + v_4^{(1)}
|
v_5^{(1)} = 1.5
|
\[
\begin{array}{rcl}
1.5
& = &
v_5^{(1)} =
\left[ \D{v_5}{t} \right]_{t=0} =
\left[ \D{}{t} f ( x^{(0)} + x^{(1)} t ) \right]_{t=0}
\\
& = &
f^{(1)} ( x^{(0)} ) * x^{(1)} =
f^{(1)} ( x^{(0)} )
\end{array}
\]
(We have used the fact that
x^{(1)} = 1
.)
x = .1
,
what are the results of a zero and first order forward sweep for
the operation sequence above;
i.e., what are the corresponding values for
v_1^{(0)}, v_2^{(0)}, \cdots , v_5^{(0)}
and
v_1^{(1)}, v_2^{(1)}, \cdots , v_5^{(1)}
?
# include <cmath> // prototype for fabs
extern bool exp_2_for0(double *v0); // computes zero order forward sweep
bool exp_2_for1(double *v1) // double v1[6]
{ bool ok = true;
double v0[6];
// set the value of v0[j] for j = 1 , ... , 5
ok &= exp_2_for0(v0);
v1[1] = 1.; // v1 = x
ok &= std::fabs( v1[1] - 1. ) <= 1e-10;
v1[2] = v1[1]; // v2 = 1 + v1
ok &= std::fabs( v1[2] - 1. ) <= 1e-10;
v1[3] = v1[1] * v0[1] + v0[1] * v1[1]; // v3 = v1 * v1
ok &= std::fabs( v1[3] - 1. ) <= 1e-10;
v1[4] = v1[3] / 2.; // v4 = v3 / 2
ok &= std::fabs( v1[4] - 0.5) <= 1e-10;
v1[5] = v1[2] + v1[4]; // v5 = v2 + v4
ok &= std::fabs( v1[5] - 1.5) <= 1e-10;
return ok;
}
bool exp_2_for1(void)
{ double v1[6];
return exp_2_for1(v1);
}
\[
f(x) = 1 + x + x^2 / 2
\]
The corresponding derivative function is
\[
\partial_x f (x) = 1 + x
\]
v_5
in the
3.2.3.c: exp_2 operation sequence
.
We begin with the function
f_5
where
v_5
is both an argument and the value of the function; i.e.,
\[
\begin{array}{rcl}
f_5 ( v_1 , v_2 , v_3 , v_4 , v_5 ) & = & v_5
\\
\D{f_5}{v_5} & = & 1
\end{array}
\]
All the other partial derivatives of
f_5
are zero.
\[
v_5 = v_2 + v_4
\]
We define the function
f_4 ( v_1 , v_2 , v_3 , v_4 )
as equal to
f_5
except that
v_5
is eliminated using
this operation; i.e.
\[
f_4 =
f_5 [ v_1 , v_2 , v_3 , v_4 , v_5 ( v_2 , v_4 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_4}{v_2}
& = & \D{f_5}{v_2} +
\D{f_5}{v_5} * \D{v_5}{v_2}
& = 1
\\
\D{f_4}{v_4}
& = & \D{f_5}{v_4} +
\D{f_5}{v_5} * \D{v_5}{v_4}
& = 1
\end{array}
\]
All the other partial derivatives of
f_4
are zero.
\[
v_4 = v_3 / 2
\]
We define the function
f_3 ( v_1 , v_2 , v_3 )
as equal to
f_4
except that
v_4
is eliminated using this operation; i.e.,
\[
f_3 =
f_4 [ v_1 , v_2 , v_3 , v_4 ( v_3 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_3}{v_1}
& = & \D{f_4}{v_1}
& = 0
\\
\D{f_3}{v_2}
& = & \D{f_4}{v_2}
& = 1
\\
\D{f_3}{v_3}
& = & \D{f_4}{v_3} +
\D{f_4}{v_4} * \D{v_4}{v_3}
& = 0.5
\end{array}
\]
\[
v_3 = v_1 * v_1
\]
We define the function
f_2 ( v_1 , v_2 )
as equal to
f_3
except that
v_3
is eliminated using this operation; i.e.,
\[
f_2 =
f_3 [ v_1 , v_2 , v_3 ( v_1 ) ]
\]
Note that the value of
v_1
is equal to
x
which is .5 for this evaluation.
It follows that
\[
\begin{array}{rcll}
\D{f_2}{v_1}
& = & \D{f_3}{v_1} +
\D{f_3}{v_3} * \D{v_3}{v_1}
& = 0.5
\\
\D{f_2}{v_2}
& = & \D{f_3}{v_2}
& = 1
\end{array}
\]
\[
v_2 = 1 + v_1
\]
We define the function
f_1 ( v_1 )
as equal to
f_2
except that
v_2
is eliminated using this operation; i.e.,
\[
f_1 =
f_2 [ v_1 , v_2 ( v_1 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_1}{v_1}
& = & \D{f_2}{v_1} +
\D{f_2}{v_2} * \D{v_2}{v_1}
& = 1.5
\end{array}
\]
Note that
v_1
is equal to
x
,
so the derivative of this is the derivative of
the function defined by 3.2.1: exp_2.hpp
at
x = .5
.
f_j
that might not be equal to the corresponding
partials of
f_{j+1}
; i.e., the
other partials of
f_j
must be equal to the corresponding
partials of
f_{j+1}
.
x = .1
and we first preform a zero order forward sweep
for the operation sequence used above.
What are the results of a
first order reverse sweep; i.e.,
what are the corresponding derivatives of
f_5 , f_4 , \ldots , f_1
.
# include <cstddef> // define size_t
# include <cmath> // prototype for fabs
extern bool exp_2_for0(double *v0); // computes zero order forward sweep
bool exp_2_rev1(void)
{ bool ok = true;
// set the value of v0[j] for j = 1 , ... , 5
double v0[6];
ok &= exp_2_for0(v0);
// initial all partial derivatives as zero
double f_v[6];
size_t j;
for(j = 0; j < 6; j++)
f_v[j] = 0.;
// set partial derivative for f5
f_v[5] = 1.;
ok &= std::fabs( f_v[5] - 1. ) <= 1e-10; // f5_v5
// f4 = f5( v1 , v2 , v3 , v4 , v2 + v4 )
f_v[2] += f_v[5] * 1.;
f_v[4] += f_v[5] * 1.;
ok &= std::fabs( f_v[2] - 1. ) <= 1e-10; // f4_v2
ok &= std::fabs( f_v[4] - 1. ) <= 1e-10; // f4_v4
// f3 = f4( v1 , v2 , v3 , v3 / 2 )
f_v[3] += f_v[4] / 2.;
ok &= std::fabs( f_v[3] - 0.5) <= 1e-10; // f3_v3
// f2 = f3( v1 , v2 , v1 * v1 )
f_v[1] += f_v[3] * 2. * v0[1];
ok &= std::fabs( f_v[1] - 0.5) <= 1e-10; // f2_v1
// f1 = f2( v1 , 1 + v1 )
f_v[1] += f_v[2] * 1.;
ok &= std::fabs( f_v[1] - 1.5) <= 1e-10; // f1_v1
return ok;
}
x(t)
near
t = 0
by the second order expansion
\[
x(t) = x^{(0)} + x^{(1)} * t + x^{(2)} * t^2 / 2
\]
It follows that for
k = 0 , 1 , 2
,
\[
x^{(k)} = \dpow{k}{t} x (0)
\]
\[
f(x) = 1 + x + x^2 / 2
\]
The corresponding second derivative function is
\[
\Dpow{2}{x} f (x) = 1
\]
x = .5
.
The corresponding operation sequence,
zero order forward sweep values,
and first order forward sweep values
are inputs and are used by a second order forward sweep.
t
,
at
t = 0
, for each variable in the sequence.
\[
v_i (t) = v_i^{(0)} + v_i^{(1)} * t + v_i^{(2)} * t^2 / 2
\]
We use
x^{(0)} = 1
, and
x^{(2)} = 0
so that second order differentiation
with respect to
t
, at
t = 0
,
is the same as the second partial differentiation
with respect to
x
at
x = x^{(0)}
.
| Index |
| Zero |
| Operation |
| First |
| Derivative |
| Second |
| 1 | 0.5 |
|
v_1^{(1)} = x^{(1)}
| 1 |
v_1^{(2)} = x^{(2)}
|
v_1^{(2)} = 0
| ||||
| 2 | 1.5 |
|
v_2^{(1)} = v_1^{(1)}
| 1 |
v_2^{(2)} = v_1^{(2)}
|
v_2^{(2)} = 0
| ||||
| 3 | 0.25 |
|
v_3^{(1)} = 2 * v_1^{(0)} * v_1^{(1)}
| 1 |
v_3^{(2)} = 2 * (v_1^{(1)} * v_1^{(1)} + v_1^{(0)} * v_1^{(2)} )
|
v_3^{(2)} = 2
| ||||
| 4 | 0.125 |
|
v_4^{(1)} = v_3^{(1)} / 2
| .5 |
v_4^{(2)} = v_3^{(2)} / 2
|
v_4^{(2)} = 1
| ||||
| 5 | 1.625 |
|
v_5^{(1)} = v_2^{(1)} + v_4^{(1)}
| 1.5 |
v_5^{(2)} = v_2^{(2)} + v_4^{(2)}
|
v_5^{(2)} = 1
|
\[
\begin{array}{rcl}
1
& = &
v_5^{(2)} =
\left[ \Dpow{2}{t} v_5 \right]_{t=0} =
\left[ \Dpow{2}{t} f( x^{(0)} + x^{(1)} * t ) \right]_{t=0}
\\
& = &
x^{(1)} * \Dpow{2}{x} f ( x^{(0)} ) * x^{(1)} =
\Dpow{2}{x} f ( x^{(0)} )
\end{array}
\]
(We have used the fact that
x^{(1)} = 1
and
x^{(2)} = 0
.)
x = .1
,
what are the results of a zero, first, and second order forward sweep for
the operation sequence above;
i.e., what are the corresponding values for
v_i^{(k)}
for
i = 1, \ldots , 5
and
k = 0, 1, 2
.
# include <cmath> // prototype for fabs
extern bool exp_2_for0(double *v0); // computes zero order forward sweep
extern bool exp_2_for1(double *v1); // computes first order forward sweep
bool exp_2_for2(void)
{ bool ok = true;
double v0[6], v1[6], v2[6];
// set the value of v0[j], v1[j], for j = 1 , ... , 5
ok &= exp_2_for0(v0);
ok &= exp_2_for1(v1);
v2[1] = 0.; // v1 = x
ok &= std::fabs( v2[1] - 0. ) <= 1e-10;
v2[2] = v2[1]; // v2 = 1 + v1
ok &= std::fabs( v2[2] - 0. ) <= 1e-10;
v2[3] = 2.*(v0[1]*v2[1] + v1[1]*v1[1]); // v3 = v1 * v1
ok &= std::fabs( v2[3] - 2. ) <= 1e-10;
v2[4] = v2[3] / 2.; // v4 = v3 / 2
ok &= std::fabs( v2[4] - 1. ) <= 1e-10;
v2[5] = v2[2] + v2[4]; // v5 = v2 + v4
ok &= std::fabs( v2[5] - 1. ) <= 1e-10;
return ok;
}
\[
f(x) = 1 + x + x^2 / 2
\]
The corresponding second derivative is
\[
\Dpow{2}{x} f (x) = 1
\]
v_5^{(1)}
with respect to all the independent variable.
For the case computed for the
3.2.4.d.f: first order sweep
,
v_5^{(1)}
is the derivative
of the value returned by 3.2.1: exp_2.hpp
.
This the value computed will be the second derivative of
the value returned by 3.2.1: exp_2.hpp
.
We begin with the function
f_5
where
v_5^{(1)}
is both an argument and the value of the function; i.e.,
\[
\begin{array}{rcl}
f_5 \left(
v_1^{(0)}, v_1^{(1)} , \ldots , v_5^{(0)} , v_5^{(1)}
\right)
& = & v_5^{(1)}
\\
\D{f_5}{v_5^{(1)}} & = & 1
\end{array}
\]
All the other partial derivatives of
f_5
are zero.
\[
\begin{array}{rcl}
v_5^{(0)} & = & v_2^{(0)} + v_4^{(0)}
\\
v_5^{(1)} & = & v_2^{(1)} + v_4^{(1)}
\end{array}
\]
We define the function
f_4 \left( v_1^{(0)} , \ldots , v_4^{(1)} \right)
as equal to
f_5
except that
v_5^{(0)}
and
v_5^{(1)}
are eliminated using
this operation; i.e.
\[
f_4 =
f_5 \left[ v_1^{(0)} , \ldots , v_4^{(1)} ,
v_5^{(0)} \left( v_2^{(0)} , v_4^{(0)} \right) ,
v_5^{(1)} \left( v_2^{(1)} , v_4^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_4}{v_2^{(1)}}
& = & \D{f_5}{v_2^{(1)}} +
\D{f_5}{v_5^{(1)}} * \D{v_5^{(1)}}{v_2^{(1)}}
& = 1
\\
\D{f_4}{v_4^{(1)}}
& = & \D{f_5}{v_4^{(1)}} +
\D{f_5}{v_5^{(1)}} * \D{v_5}{v_4^{(1)}}
& = 1
\end{array}
\]
All the other partial derivatives of
f_4
are zero.
\[
\begin{array}{rcl}
v_4^{(0)} & = & v_3^{(0)} / 2
\\
v_4^{(1)} & = & v_3^{(1)} / 2
\end{array}
\]
We define the function
f_3 \left( v_1^{(0)} , \ldots , v_3^{(1)} \right)
as equal to
f_4
except that
v_4^{(0)}
and
v_4^{(1)}
are eliminated using this operation; i.e.,
\[
f_3 =
f_4 \left[ v_1^{(0)} , \ldots , v_3^{(1)} ,
v_4^{(0)} \left( v_3^{(0)} \right) ,
v_4^{(1)} \left( v_3^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_3}{v_2^{(1)}}
& = & \D{f_4}{v_2^{(1)}}
& = 1
\\
\D{f_3}{v_3^{(1)}}
& = & \D{f_4}{v_3^{(1)}} +
\D{f_4}{v_4^{(1)}} * \D{v_4^{(1)}}{v_3^{(1)}}
& = 0.5
\end{array}
\]
All the other partial derivatives of
f_3
are zero.
\[
\begin{array}{rcl}
v_3^{(0)} & = & v_1^{(0)} * v_1^{(0)}
\\
v_3^{(1)} & = & 2 * v_1^{(0)} * v_1^{(1)}
\end{array}
\]
We define the function
f_2 \left( v_1^{(0)} , \ldots , v_2^{(1)} \right)
as equal to
f_3
except that
v_3^{(0)}
and
v_3^{(1)}
are
eliminated using this operation; i.e.,
\[
f_2 =
f_3 \left[ v_1^{(0)} , \ldots , v_2^{(1)} ,
v_3^{(0)} ( v_1^{(0)} ) ,
v_3^{(1)} ( v_1^{(0)} , v_1^{(1)} )
\right]
\]
Note that, from the
3.2.4.d.f: first order forward sweep
,
the value of
v_1^{(0)}
is equal to
.5
and
v_1^{(1)}
is equal 1.
It follows that
\[
\begin{array}{rcll}
\D{f_2}{v_1^{(0)}}
& = &
\D{f_3}{v_1^{(0)}} +
\D{f_3}{v_3^{(0)}} * \D{v_3^{(0)}}{v_1^{(0)}} +
\D{f_3}{v_3^{(1)}} * \D{v_3^{(1)}}{v_1^{(0)}}
& = 1
\\
\D{f_2}{v_1^{(1)}}
& = &
\D{f_3}{v_1^{(1)}} +
\D{f_3}{v_3^{(1)}} * \D{v_3^{(1)}}{v_1^{(1)}}
& = 0.5
\\
\D{f_2}{v_2^{(0)}}
& = & \D{f_3}{v_2^{(0)}}
& = 0
\\
\D{f_2}{v_2^{(1)}}
& = & \D{f_3}{v_2^{(1)}}
& = 1
\end{array}
\]
\[
\begin{array}{rcl}
v_2^{(0)} & = & 1 + v_1^{(0)}
\\
v_2^{(1)} & = & v_1^{(1)}
\end{array}
\]
We define the function
f_1 ( v_1^{(0)} , v_1^{(1)} )
as equal to
f_2
except that
v_2^{(0)}
and
v_2^{(1)}
are eliminated using this operation; i.e.,
\[
f_1 =
f_2 \left[ v_1^{(0)} , v_1^{(1)} ,
v_2^{(0)} ( v_1^{(0)} ) ,
v_2^{(1)} ( v_1^{(1)} )
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_1}{v_1^{(0)}}
& = & \D{f_2}{v_1^{(0)}} +
\D{f_2}{v_2^{(0)}} * \D{v_2^{(0)}}{v_1^{(0)}}
& = 1
\\
\D{f_1}{v_1^{(1)}}
& = & \D{f_2}{v_1^{(1)}} +
\D{f_2}{v_2^{(1)}} * \D{v_2^{(1)}}{v_1^{(1)}}
& = 1.5
\end{array}
\]
Note that
v_1
is equal to
x
,
so the second derivative of
the function defined by 3.2.1: exp_2.hpp
at
x = .5
is given by
\[
\Dpow{2}{x} v_5^{(0)}
=
\D{ v_5^{(1)} }{x}
=
\D{ v_5^{(1)} }{v_1^{(0)}}
=
\D{f_1}{v_1^{(0)}} = 1
\]
There is a theorem about Algorithmic Differentiation that explains why
the other partial of
f_1
is equal to the
first derivative of
the function defined by 3.2.1: exp_2.hpp
at
x = .5
.
f_j
that might not be equal to the corresponding
partials of
f_{j+1}
; i.e., the
other partials of
f_j
must be equal to the corresponding
partials of
f_{j+1}
.
x = .1
and we first preform a zero order forward sweep,
then a first order sweep,
for the operation sequence used above.
What are the results of a
second order reverse sweep; i.e.,
what are the corresponding derivatives of
f_5 , f_4 , \ldots , f_1
.
# include <cstddef> // define size_t
# include <cmath> // prototype for fabs
extern bool exp_2_for0(double *v0); // computes zero order forward sweep
extern bool exp_2_for1(double *v1); // computes first order forward sweep
bool exp_2_rev2(void)
{ bool ok = true;
// set the value of v0[j], v1[j] for j = 1 , ... , 5
double v0[6], v1[6];
ok &= exp_2_for0(v0);
ok &= exp_2_for1(v1);
// initial all partial derivatives as zero
double f_v0[6], f_v1[6];
size_t j;
for(j = 0; j < 6; j++)
{ f_v0[j] = 0.;
f_v1[j] = 0.;
}
// set partial derivative for f_5
f_v1[5] = 1.;
ok &= std::fabs( f_v1[5] - 1. ) <= 1e-10; // partial f_5 w.r.t v_5^1
// f_4 = f_5( v_1^0 , ... , v_4^1 , v_2^0 + v_4^0 , v_2^1 + v_4^1 )
f_v0[2] += f_v0[5] * 1.;
f_v0[4] += f_v0[5] * 1.;
f_v1[2] += f_v1[5] * 1.;
f_v1[4] += f_v1[5] * 1.;
ok &= std::fabs( f_v0[2] - 0. ) <= 1e-10; // partial f_4 w.r.t. v_2^0
ok &= std::fabs( f_v0[4] - 0. ) <= 1e-10; // partial f_4 w.r.t. v_4^0
ok &= std::fabs( f_v1[2] - 1. ) <= 1e-10; // partial f_4 w.r.t. v_2^1
ok &= std::fabs( f_v1[4] - 1. ) <= 1e-10; // partial f_4 w.r.t. v_4^1
// f_3 = f_4( v_1^0 , ... , v_3^1, v_3^0 / 2 , v_3^1 / 2 )
f_v0[3] += f_v0[4] / 2.;
f_v1[3] += f_v1[4] / 2.;
ok &= std::fabs( f_v0[3] - 0. ) <= 1e-10; // partial f_3 w.r.t. v_3^0
ok &= std::fabs( f_v1[3] - 0.5 ) <= 1e-10; // partial f_3 w.r.t. v_3^1
// f_2 = f_3( v_1^0 , ... , v_2^1, v_1^0 * v_1^0 , 2 * v_1^0 * v_1^1 )
f_v0[1] += f_v0[3] * 2. * v0[1];
f_v0[1] += f_v1[3] * 2. * v1[1];
f_v1[1] += f_v1[3] * 2. * v0[1];
ok &= std::fabs( f_v0[1] - 1. ) <= 1e-10; // partial f_2 w.r.t. v_1^0
ok &= std::fabs( f_v1[1] - 0.5 ) <= 1e-10; // partial f_2 w.r.t. v_1^1
// f_1 = f_2( v_1^0 , v_1^1 , 1 + v_1^0 , v_1^1 )
f_v0[1] += f_v0[2] * 1.;
f_v1[1] += f_v1[2] * 1.;
ok &= std::fabs( f_v0[1] - 1. ) <= 1e-10; // partial f_1 w.r.t. v_1^0
ok &= std::fabs( f_v1[1] - 1.5) <= 1e-10; // partial f_1 w.r.t. v_1^1
return ok;
}
x
,
at the point
x = .5
,
of the function
exp_2(x)
as defined by the 3.2.1: exp_2.hpp
include file.
x
,
at the point
x = .1
of the function
exp_2(x)
exp_3(x)
that evaluates the function
\[
f(x) = 1 + x^2 / 2 + x^3 / 6
\]
Test a modified version of the routine below that computes
the derivative of
f(x)
at the point
x = .5
.
# include <cppad/cppad.hpp> // http://www.coin-or.org/CppAD/
# include "exp_2.hpp" // second order exponential approximation
bool exp_2_cppad(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::vector; // can use any simple vector template class
using CppAD::NearEqual; // checks if values are nearly equal
// domain space vector
size_t n = 1; // dimension of the domain space
vector< AD<double> > X(n);
X[0] = .5; // value of x for this operation sequence
// declare independent variables and start recording operation sequence
CppAD::Independent(X);
// evaluate our exponential approximation
AD<double> x = X[0];
AD<double> apx = exp_2(x);
// range space vector
size_t m = 1; // dimension of the range space
vector< AD<double> > Y(m);
Y[0] = apx; // variable that represents only range space component
// Create f: X -> Y corresponding to this operation sequence
// and stop recording. This also executes a zero order forward
// sweep using values in X for x.
CppAD::ADFun<double> f(X, Y);
// first order forward sweep that computes
// partial of exp_2(x) with respect to x
vector<double> dx(n); // differential in domain space
vector<double> dy(m); // differential in range space
dx[0] = 1.; // direction for partial derivative
dy = f.Forward(1, dx);
double check = 1.5;
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// first order reverse sweep that computes the derivative
vector<double> w(m); // weights for components of the range
vector<double> dw(n); // derivative of the weighted function
w[0] = 1.; // there is only one weight
dw = f.Reverse(1, w); // derivative of w[0] * exp_2(x)
check = 1.5; // partial of exp_2(x) with respect to x
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// second order forward sweep that computes
// second partial of exp_2(x) with respect to x
vector<double> x2(n); // second order Taylor coefficients
vector<double> y2(m);
x2[0] = 0.; // evaluate second partial .w.r.t. x
y2 = f.Forward(2, x2);
check = 0.5 * 1.; // Taylor coef is 1/2 second derivative
ok &= NearEqual(y2[0], check, 1e-10, 1e-10);
// second order reverse sweep that computes
// derivative of partial of exp_2(x) w.r.t. x
dw.resize(2 * n); // space for first and second derivatives
dw = f.Reverse(2, w);
check = 1.; // result should be second derivative
ok &= NearEqual(dw[0*2+1], check, 1e-10, 1e-10);
return ok;
}
# include "exp_eps.hpp"
y = exp_eps(x, epsilon)
\[
\exp (x) = 1 + x^1 / 1 ! + x^2 / 2 ! + \cdots
\]
We define
k ( x, \varepsilon )
as the smallest
non-negative integer such that
\varepsilon \geq x^k / k !
; i.e.,
\[
k( x, \varepsilon ) =
\min \{ k \in {\rm Z}_+ \; | \; \varepsilon \geq x^k / k ! \}
\]
The mathematical form for our approximation of the exponential function is
\[
\begin{array}{rcl}
{\rm exp\_eps} (x , \varepsilon ) & = & \left\{
\begin{array}{ll}
\frac{1}{ {\rm exp\_eps} (-x , \varepsilon ) }
& {\rm if} \; x < 0
\\
1 + x^1 / 1 ! + \cdots + x^{k( x, \varepsilon)} / k( x, \varepsilon ) !
& {\rm otherwise}
\end{array}
\right.
\end{array}
\]
cppad-yy-mm-dd/introduction/exp_apx
where cppad-yy-mm-dd is the distribution directory
created during the beginning steps of the
2: installation
of CppAD.
const Type &x
(see Type below).
It specifies the point at which to evaluate the
approximation for the exponential function.
const Type &epsilon
It specifies the accuracy with which
to approximate the exponential function value; i.e.,
it is the value of
\varepsilon
in the
exponential function approximation defined above.
Type y
It is the value of the exponential function
approximation defined above.
int:
| Operation | Result Type | Description |
Type(i)
| Type | object with value equal to i |
u > v
|
bool
| true, if u greater than v, an false otherwise |
u = v
| Type | new u (and result) is value of v |
u * v
| Type |
result is value of
u * v
|
u / v
| Type |
result is value of
u / v
|
u + v
| Type |
result is value of
u + v
|
-u
| Type |
result is value of
- u
|
k( x, \varepsilon )
above,
what is the value of
k(.5, 1)
,
k(.5, .1)
, and
k(.5, .01)
?
exp_eps:
double x = 1.;
double epsilon = .01;
double y = exp_eps(x, epsilon);
What is the value assigned to
k, temp, term, and sum
the first time through the while loop in 3.3.1: exp_eps.hpp
?
k, temp, term, and sum
the second time through the while loop in 3.3.1: exp_eps.hpp
?
template <class Type>
Type exp_eps(const Type &x, const Type &epsilon)
{ // abs_x = |x|
Type abs_x = x;
if( Type(0) > x )
abs_x = - x;
// initialize
int k = 0; // initial order
Type term = 1.; // term = |x|^k / k !
Type sum = term; // initial sum
while(term > epsilon)
{ k = k + 1; // order for next term
Type temp = term * abs_x; // term = |x|^k / (k-1)!
term = temp / Type(k); // term = |x|^k / k !
sum = sum + term; // sum = 1 + ... + |x|^k / k !
}
// In the case where x is negative, use exp(x) = 1 / exp(-|x|)
if( Type(0) > x )
sum = Type(1) / sum;
return sum;
}
# include <cmath> // for fabs function
# include "exp_eps.hpp" // definition of exp_eps algorithm
bool exp_eps(void)
{ double x = .5;
double epsilon = .2;
double check = 1 + .5 + .125; // include 1 term less than epsilon
bool ok = std::fabs( exp_eps(x, epsilon) - check ) <= 1e-10;
return ok;
}
exp_eps(x, epsilon)
with x is equal to .5
and epsilon is equal to .2.
For this case,
the mathematical form for the operation sequence
corresponding to the exp_eps is
\[
f( x , \varepsilon ) = 1 + x + x^2 / 2
\]
Note that, for these particular values of x and epsilon,
this is the same as the mathematical form for
3.2.3.a: exp_2
.
| Index |
| Code |
| Operation |
| Zero Order |
| 1 |
|
abs_x = x;
|
v_1 = x
|
v_1^{(0)} = 0.5
| ||
| 2 |
|
temp = term * abs_x;
|
v_2 = 1 * v_1
|
v_2^{(0)} = 0.5
| ||
| 3 |
|
term = temp / Type(k);
|
v_3 = v_2 / 1
|
v_3^{(0)} = 0.5
| ||
| 4 |
|
sum = sum + term;
|
v_4 = 1 + v_3
|
v_4^{(0)} = 1.5
| ||
| 5 |
|
temp = term * abs_x;
|
v_5 = v_3 * v_1
|
v_5^{(0)} = 0.25
| ||
| 6 |
|
term = temp / Type(k);
|
v_6 = v_5 / 2
|
v_6^{(0)} = 0.125
| ||
| 7 |
|
sum = sum + term;
|
v_7 = v_4 + v_6
|
v_7^{(0)} = 1.625
|
\[
1.625 =
v_7^{(0)} =
f ( x^{(0)} , \varepsilon^{(0)} )
\]
if( Type(0) > x )
while(term > epsilon)
This in turn would result in a different operation sequence.
Thus the operation sequence above only corresponds to
3.3.1: exp_eps.hpp
for values of x and epsilon within a certain range.
Note that there is a neighborhood
of
x = 0.5
for which the comparisons would have the
same result and hence the operation sequence would be the same.
x^{(0)} = .1
,
what is the result of a zero order forward sweep for
the operation sequence above;
i.e., what are the corresponding values for
v_1^{(0)} , v_2^{(0)} , \ldots , v_7^{(0)}
.
# include <cmath> // for fabs function
bool exp_eps_for0(double *v0) // double v0[8]
{ bool ok = true;
double x = .5;
v0[1] = x; // abs_x = x;
ok &= std::fabs( v0[1] - 0.5) < 1e-10;
v0[2] = 1. * v0[1]; // temp = term * abs_x;
ok &= std::fabs( v0[2] - 0.5) < 1e-10;
v0[3] = v0[2] / 1.; // term = temp / Type(k);
ok &= std::fabs( v0[3] - 0.5) < 1e-10;
v0[4] = 1. + v0[3]; // sum = sum + term;
ok &= std::fabs( v0[4] - 1.5) < 1e-10;
v0[5] = v0[3] * v0[1]; // temp = term * abs_x;
ok &= std::fabs( v0[5] - 0.25) < 1e-10;
v0[6] = v0[5] / 2.; // term = temp / Type(k);
ok &= std::fabs( v0[6] - 0.125) < 1e-10;
v0[7] = v0[4] + v0[6]; // sum = sum + term;
ok &= std::fabs( v0[7] - 1.625) < 1e-10;
return ok;
}
bool exp_eps_for0(void)
{ double v0[8];
return exp_eps_for0(v0);
}
x(t)
and
\varepsilon(t) ]
near
t = 0
by the first order expansions
\[
\begin{array}{rcl}
x(t) & = & x^{(0)} + x^{(1)} * t
\\
\varepsilon(t) & = & \varepsilon^{(0)} + \varepsilon^{(1)} * t
\end{array}
\]
It follows that
x^{(0)}
(
\varepsilon^{(0)}
) is the zero,
and
x^{(1)}
(
\varepsilon^{(1)}
) the first,
order derivative of
x(t)
at
t = 0
(
\varepsilon (t)
)
at
t = 0
.
exp_eps(x, epsilon)
with x is equal to .5
and epsilon is equal to .2.
For this case, the mathematical function for the operation sequence
corresponding to exp_eps is
\[
f ( x , \varepsilon ) = 1 + x + x^2 / 2
\]
The corresponding partial derivative with respect to
x
,
and the value of the derivative, are
\[
\partial_x f ( x , \varepsilon ) = 1 + x = 1.5
\]
t
,
at
t = 0
, for each variable in the sequence.
\[
v_j (t) = v_j^{(0)} + v_j^{(1)} t
\]
We use
x^{(1)} = 1
and
\varepsilon^{(1)} = 0
,
so that differentiation with respect to
t
,
at
t = 0
,
is the same partial differentiation with respect to
x
at
x = x^{(0)}
.
| Index |
| Operation |
| Zero Order |
| Derivative |
| First Order |
| 1 |
|
v_1 = x
| 0.5 |
v_1^{(1)} = x^{(1)}
|
v_1^{(1)} = 1
| |||
| 2 |
|
v_2 = 1 * v_1
| 0.5 |
v_2^{(1)} = 1 * v_1^{(1)}
|
v_2^{(1)} = 1
| |||
| 3 |
|
v_3 = v_2 / 1
| 0.5 |
v_3^{(1)} = v_2^{(1)} / 1
|
v_3^{(1)} = 1
| |||
| 4 |
|
v_4 = 1 + v_3
| 1.5 |
v_4^{(1)} = v_3^{(1)}
|
v_4^{(1)} = 1
| |||
| 5 |
|
v_5 = v_3 * v_1
| 0.25 |
v_5^{(1)} = v_3^{(1)} * v_1^{(0)} + v_3^{(0)} * v_1^{(1)}
|
v_5^{(1)} = 1
| |||
| 6 |
|
v_6 = v_5 / 2
| 0.125 |
v_6^{(1)} = v_5^{(1)} / 2
|
v_6^{(1)} = 0.5
| |||
| 7 |
|
v_7 = v_4 + v_6
| 1.625 |
v_7^{(1)} = v_4^{(1)} + v_6^{(1)}
|
v_7^{(1)} = 1.5
|
\[
\begin{array}{rcl}
1.5
& = &
v_7^{(1)} =
\left[ \D{v_7}{t} \right]_{t=0} =
\left[ \D{}{t} f( x^{(0)} + x^{(1)} * t , \varepsilon^{(0)} ) \right]_{t=0}
\\
& = &
\partial_x f ( x^{(0)} , \varepsilon^{(0)} ) * x^{(1)} =
\partial_x f ( x^{(0)} , \varepsilon^{(0)} )
\end{array}
\]
(We have used the fact that
x^{(1)} = 1
and
\varepsilon^{(1)} = 0
.)
x = .1
,
what are the results of a zero and first order forward mode sweep for
the operation sequence above;
i.e., what are the corresponding values for
v_1^{(0)}, v_2^{(0)}, \cdots , v_7^{(0)}
and
v_1^{(1)}, v_2^{(1)}, \cdots , v_7^{(1)}
?
x = .1
and
\epsilon = .2
,
what is the operation sequence corresponding to
exp_eps(x, epsilon)
# include <cmath> // for fabs function
extern bool exp_eps_for0(double *v0); // computes zero order forward sweep
bool exp_eps_for1(double *v1) // double v[8]
{ bool ok = true;
double v0[8];
// set the value of v0[j] for j = 1 , ... , 7
ok &= exp_eps_for0(v0);
v1[1] = 1.; // v1 = x
ok &= std::fabs( v1[1] - 1. ) <= 1e-10;
v1[2] = 1. * v1[1]; // v2 = 1 * v1
ok &= std::fabs( v1[2] - 1. ) <= 1e-10;
v1[3] = v1[2] / 1.; // v3 = v2 / 1
ok &= std::fabs( v1[3] - 1. ) <= 1e-10;
v1[4] = v1[3]; // v4 = 1 + v3
ok &= std::fabs( v1[4] - 1. ) <= 1e-10;
v1[5] = v1[3] * v0[1] + v0[3] * v1[1]; // v5 = v3 * v1
ok &= std::fabs( v1[5] - 1. ) <= 1e-10;
v1[6] = v1[5] / 2.; // v6 = v5 / 2
ok &= std::fabs( v1[6] - 0.5 ) <= 1e-10;
v1[7] = v1[4] + v1[6]; // v7 = v4 + v6
ok &= std::fabs( v1[7] - 1.5 ) <= 1e-10;
return ok;
}
bool exp_eps_for1(void)
{ double v1[8];
return exp_eps_for1(v1);
}
exp_eps(x, epsilon)
with x is equal to .5
and epsilon is equal to .2.
For this case, the mathematical function for the operation sequence
corresponding to exp_eps is
\[
f ( x , \varepsilon ) = 1 + x + x^2 / 2
\]
The corresponding partial derivatives,
and the value of the derivatives, are
\[
\begin{array}{rcl}
\partial_x f ( x , \varepsilon ) & = & 1 + x = 1.5
\\
\partial_\varepsilon f ( x , \varepsilon ) & = & 0
\end{array}
\]
\varepsilon
is an independent variable,
it could included as an argument to all of the
f_j
functions below.
The result would be that all the partials with respect to
\varepsilon
would be zero and hence we drop it to simplify
the presentation.
v_7
.
We begin with the function
f_7
where
v_7
is both an argument and the value of the function; i.e.,
\[
\begin{array}{rcl}
f_7 ( v_1 , v_2 , v_3 , v_4 , v_5 , v_6 , v_7 ) & = & v_7
\\
\D{f_7}{v_7} & = & 1
\end{array}
\]
All the other partial derivatives of
f_7
are zero.
\[
v_7 = v_4 + v_6
\]
We define the function
f_6 ( v_1 , v_2 , v_3 , v_4 , v_5 , v_6 )
as equal to
f_7
except that
v_7
is eliminated using
this operation; i.e.
\[
f_6 =
f_7 [ v_1 , v_2 , v_3 , v_4 , v_5 , v_6 , v_7 ( v_4 , v_6 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_6}{v_4}
& = & \D{f_7}{v_4} +
\D{f_7}{v_7} * \D{v_7}{v_4}
& = 1
\\
\D{f_6}{v_6}
& = & \D{f_7}{v_6} +
\D{f_7}{v_7} * \D{v_7}{v_6}
& = 1
\end{array}
\]
All the other partial derivatives of
f_6
are zero.
\[
v_6 = v_5 / 2
\]
We define the function
f_5 ( v_1 , v_2 , v_3 , v_4 , v_5 )
as equal to
f_6
except that
v_6
is eliminated using this operation; i.e.,
\[
f_5 =
f_6 [ v_1 , v_2 , v_3 , v_4 , v_5 , v_6 ( v_5 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_5}{v_4}
& = & \D{f_6}{v_4}
& = 1
\\
\D{f_5}{v_5}
& = & \D{f_6}{v_5} +
\D{f_6}{v_6} * \D{v_6}{v_5}
& = 0.5
\end{array}
\]
All the other partial derivatives of
f_5
are zero.
\[
v_5 = v_3 * v_1
\]
We define the function
f_4 ( v_1 , v_2 , v_3 , v_4 )
as equal to
f_5
except that
v_5
is eliminated using this operation; i.e.,
\[
f_4 =
f_5 [ v_1 , v_2 , v_3 , v_4 , v_5 ( v_3 , v_1 ) ]
\]
Given the information from the forward sweep, we have
v_3 = 0.5
and
v_1 = 0.5
.
It follows that
\[
\begin{array}{rcll}
\D{f_4}{v_1}
& = & \D{f_5}{v_1} +
\D{f_5}{v_5} * \D{v_5}{v_1}
& = 0.25
\\
\D{f_4}{v_2} & = & \D{f_5}{v_2} & = 0
\\
\D{f_4}{v_3}
& = & \D{f_5}{v_3} +
\D{f_5}{v_5} * \D{v_5}{v_3}
& = 0.25
\\
\D{f_4}{v_4}
& = & \D{f_5}{v_4}
& = 1
\end{array}
\]
\[
v_4 = 1 + v_3
\]
We define the function
f_3 ( v_1 , v_2 , v_3 )
as equal to
f_4
except that
v_4
is eliminated using this operation; i.e.,
\[
f_3 =
f_4 [ v_1 , v_2 , v_3 , v_4 ( v_3 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_3}{v_1}
& = & \D{f_4}{v_1}
& = 0.25
\\
\D{f_3}{v_2} & = & \D{f_4}{v_2} & = 0
\\
\D{f_3}{v_3}
& = & \D{f_4}{v_3} +
\D{f_4}{v_4} * \D{v_4}{v_3}
& = 1.25
\end{array}
\]
\[
v_3 = v_2 / 1
\]
We define the function
f_2 ( v_1 , v_2 )
as equal to
f_3
except that
v_3
is eliminated using this operation; i.e.,
\[
f_2 =
f_4 [ v_1 , v_2 , v_3 ( v_2 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_2}{v_1}
& = & \D{f_3}{v_1}
& = 0.25
\\
\D{f_2}{v_2} & = & \D{f_3}{v_2} +
\D{f_3}{v_3} * \D{v_3}{v_2}
& = 1.25
\end{array}
\]
\[
v_2 = 1 * v_1
\]
We define the function
f_1 ( v_1 )
as equal to
f_2
except that
v_2
is eliminated using this operation; i.e.,
\[
f_1 =
f_2 [ v_1 , v_2 ( v_1 ) ]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_1}{v_1} & = & \D{f_2}{v_1} +
\D{f_2}{v_2} * \D{v_2}{v_1}
& = 1.5
\end{array}
\]
Note that
v_1
is equal to
x
,
so the derivative of exp_eps(x, epsilon)
at x equal to .5 and epsilon equal .2 is
1.5 in the x direction and zero in the epsilon direction.
We also note that
3.3.4: forward
forward mode gave the
same result for the partial in the x direction.
f_j
that might not be equal to the corresponding
partials of
f_{j+1}
; i.e., the
other partials of
f_j
must be equal to the corresponding
partials of
f_{j+1}
.
x = .1
and we first preform a zero order forward mode sweep
for the operation sequence used above (in reverse order).
What are the results of a
first order reverse mode sweep; i.e.,
what are the corresponding values for
\D{f_j}{v_k}
for all
j, k
such that
\D{f_j}{v_k} \neq 0
.
# include <cstddef> // define size_t
# include <cmath> // for fabs function
extern bool exp_eps_for0(double *v0); // computes zero order forward sweep
bool exp_eps_rev1(void)
{ bool ok = true;
// set the value of v0[j] for j = 1 , ... , 7
double v0[8];
ok &= exp_eps_for0(v0);
// initial all partial derivatives as zero
double f_v[8];
size_t j;
for(j = 0; j < 8; j++)
f_v[j] = 0.;
// set partial derivative for f7
f_v[7] = 1.;
ok &= std::fabs( f_v[7] - 1. ) <= 1e-10; // f7_v7
// f6( v1 , v2 , v3 , v4 , v5 , v6 )
f_v[4] += f_v[7] * 1.;
f_v[6] += f_v[7] * 1.;
ok &= std::fabs( f_v[4] - 1. ) <= 1e-10; // f6_v4
ok &= std::fabs( f_v[6] - 1. ) <= 1e-10; // f6_v6
// f5( v1 , v2 , v3 , v4 , v5 )
f_v[5] += f_v[6] / 2.;
ok &= std::fabs( f_v[5] - 0.5 ) <= 1e-10; // f5_v5
// f4( v1 , v2 , v3 , v4 )
f_v[1] += f_v[5] * v0[3];
f_v[3] += f_v[5] * v0[1];
ok &= std::fabs( f_v[1] - 0.25) <= 1e-10; // f4_v1
ok &= std::fabs( f_v[3] - 0.25) <= 1e-10; // f4_v3
// f3( v1 , v2 , v3 )
f_v[3] += f_v[4] * 1.;
ok &= std::fabs( f_v[3] - 1.25) <= 1e-10; // f3_v3
// f2( v1 , v2 )
f_v[2] += f_v[3] / 1.;
ok &= std::fabs( f_v[2] - 1.25) <= 1e-10; // f2_v2
// f1( v1 )
f_v[1] += f_v[2] * 1.;
ok &= std::fabs( f_v[1] - 1.5 ) <= 1e-10; // f1_v2
return ok;
}
x(t)
and
\varepsilon(t) ]
near
t = 0
by the second order expansions
\[
\begin{array}{rcl}
x(t) & = & x^{(0)} + x^{(1)} * t + x^{(2)} * t^2 / 2
\\
\varepsilon(t) & = & \varepsilon^{(0)} + \varepsilon^{(1)} * t
+ \varepsilon^{(2)} * t^2 / 2
\end{array}
\]
It follows that for
k = 0 , 1 , 2
,
\[
\begin{array}{rcl}
x^{(k)} & = & \dpow{k}{t} x (0)
\\
\varepsilon^{(k)} & = & \dpow{k}{t} \varepsilon (0)
\end{array}
\]
exp_eps(x, epsilon)
with x is equal to .5
and epsilon is equal to .2.
For this case, the mathematical function for the operation sequence
corresponding to exp_eps is
\[
f ( x , \varepsilon ) = 1 + x + x^2 / 2
\]
The corresponding second partial derivative with respect to
x
,
and the value of the derivative, are
\[
\Dpow{2}{x} f ( x , \varepsilon ) = 1.
\]
t
,
at
t = 0
, for each variable in the sequence.
\[
v_i (t) = v_i^{(0)} + v_i^{(1)} * t + v_i^{(2)} * t^2 / 2
\]
We use
x^{(1)} = 1
,
x^{(2)} = 0
,
use
\varepsilon^{(1)} = 1
, and
\varepsilon^{(2)} = 0
so that second order differentiation
with respect to
t
, at
t = 0
,
is the same as the second partial differentiation
with respect to
x
at
x = x^{(0)}
.
| Index |
| Zero |
| Operation |
| First |
| Derivative |
| Second |
| 1 | 0.5 |
v_1^{(1)} = x^{(1)}
| 1 |
v_2^{(2)} = x^{(2)}
| 0 | |||||
| 2 | 0.5 |
v_2^{(1)} = 1 * v_1^{(1)}
| 1 |
v_2^{(2)} = 1 * v_1^{(2)}
| 0 | |||||
| 3 | 0.5 |
v_3^{(1)} = v_2^{(1)} / 1
| 1 |
v_3^{(2)} = v_2^{(2)} / 1
| 0 | |||||
| 4 | 1.5 |
v_4^{(1)} = v_3^{(1)}
| 1 |
v_4^{(2)} = v_3^{(2)}
| 0 | |||||
| 5 | 0.25 |
v_5^{(1)} = v_3^{(1)} * v_1^{(0)} + v_3^{(0)} * v_1^{(1)}
| 1 |
v_5^{(2)} = v_3^{(2)} * v_1^{(0)} + 2 * v_3^{(1)} * v_1^{(1)}
| 2 | |||||
| 6 | 0.125 |
v_6^{(1)} = v_5^{(1)} / 2
| 0.5 |
v_6^{(2)} = v_5^{(2)} / 2
| 1 | |||||
| 7 | 1.625 |
v_7^{(1)} = v_4^{(1)} + v_6^{(1)}
| 1.5 |
v_7^{(2)} = v_4^{(2)} + v_6^{(2)}
| 1 |
\[
\begin{array}{rcl}
1
& = &
v_7^{(2)} =
\left[ \Dpow{2}{t} v_7 \right]_{t=0} =
\left[ \Dpow{2}{t} f( x^{(0)} + x^{(1)} * t , \varepsilon^{(0)} ) \right]_{t=0}
\\
& = &
x^{(1)} * \Dpow{2}{x} f ( x^{(0)} , \varepsilon^{(0)} ) * x^{(1)} =
\Dpow{2}{x} f ( x^{(0)} , \varepsilon^{(0)} )
\end{array}
\]
(We have used the fact that
x^{(1)} = 1
,
x^{(2)} = 0
,
\varepsilon^{(1)} = 1
, and
\varepsilon^{(2)} = 0
.)
x = .1
,
what are the results of a zero, first, and second order forward sweep for
the operation sequence above;
i.e., what are the corresponding values for
v_i^{(k)}
for
i = 1, \ldots , 7
and
k = 0, 1, 2
.
# include <cmath> // for fabs function
extern bool exp_eps_for0(double *v0); // computes zero order forward sweep
extern bool exp_eps_for1(double *v1); // computes first order forward sweep
bool exp_eps_for2(void)
{ bool ok = true;
double v0[8], v1[8], v2[8];
// set the value of v0[j], v1[j] for j = 1 , ... , 7
ok &= exp_eps_for0(v0);
ok &= exp_eps_for1(v1);
v2[1] = 0.; // v1 = x
ok &= std::fabs( v2[1] - 0. ) <= 1e-10;
v2[2] = 1. * v2[1]; // v2 = 1 * v1
ok &= std::fabs( v2[2] - 0. ) <= 1e-10;
v2[3] = v2[2] / 1.; // v3 = v2 / 1
ok &= std::fabs( v2[3] - 0. ) <= 1e-10;
v2[4] = v2[3]; // v4 = 1 + v3
ok &= std::fabs( v2[4] - 0. ) <= 1e-10;
v2[5] = v2[3] * v0[1] + 2. * v1[3] * v1[1] // v5 = v3 * v1
+ v0[3] * v2[1];
ok &= std::fabs( v2[5] - 2. ) <= 1e-10;
v2[6] = v2[5] / 2.; // v6 = v5 / 2
ok &= std::fabs( v2[6] - 1. ) <= 1e-10;
v2[7] = v2[4] + v2[6]; // v7 = v4 + v6
ok &= std::fabs( v2[7] - 1. ) <= 1e-10;
return ok;
}
exp_eps(x, epsilon)
with x is equal to .5
and epsilon is equal to .2.
For this case, the mathematical function for the operation sequence
corresponding to exp_eps is
\[
f ( x , \varepsilon ) = 1 + x + x^2 / 2
\]
The corresponding derivative of the
partial derivative with respect to
x
is
\[
\begin{array}{rcl}
\Dpow{2}{x} f ( x , \varepsilon ) & = & 1
\\
\partial_\varepsilon \partial_x f ( x , \varepsilon ) & = & 0
\end{array}
\]
\varepsilon
is an independent variable,
it could included as an argument to all of the
f_j
functions below.
The result would be that all the partials with respect to
\varepsilon
would be zero and hence we drop it to simplify
the presentation.
v_7
.
We begin with the function
f_7
where
v_7
is both an argument and the value of the function; i.e.,
\[
\begin{array}{rcl}
f_7 \left(
v_1^{(0)} , v_1^{(1)} , \ldots , v_7^{(0)} , v_7^{(1)}
\right)
& = & v_7^{(1)}
\\
\D{f_7}{v_7^{(1)}} & = & 1
\end{array}
\]
All the other partial derivatives of
f_7
are zero.
\[
\begin{array}{rcl}
v_7^{(0)} & = & v_4^{(0)} + v_6^{(0)}
\\
v_7^{(1)} & = & v_4^{(1)} + v_6^{(1)}
\end{array}
\]
We define the function
f_6 \left( v_1^{(0)} , \ldots , v_6^{(1)} \right)
as equal to
f_7
except that
v_7^{(0)}
and
v_7^{(1)}
are eliminated using
this operation; i.e.
\[
f_6 =
f_7 \left[ v_1^{(0)} , \ldots , v_6^{(1)} ,
v_7^{(0)} \left( v_4^{(0)} , v_6^{(0)} \right) ,
v_7^{(1)} \left( v_4^{(1)} , v_6^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_6}{v_4^{(1)}}
& = & \D{f_7}{v_4^{(1)}} +
\D{f_7}{v_7^{(1)}} * \D{v_7^{(1)}}{v_4^{(1)}}
& = 1
\\
\D{f_6}{v_6^{(1)}}
& = & \D{f_7}{v_6^{(1)}} +
\D{f_7}{v_7^{(1)}} * \D{v_7^{(1)}}{v_6^{(1)}}
& = 1
\end{array}
\]
All the other partial derivatives of
f_6
are zero.
\[
\begin{array}{rcl}
v_6^{(0)} & = & v_5^{(0)} / 2
\\
v_6^{(1)} & = & v_5^{(1)} / 2
\end{array}
\]
We define the function
f_5 \left( v_1^{(0)} , \ldots , v_5^{(1)} \right)
as equal to
f_6
except that
v_6^{(0)}
and
v_6^{(1)}
are eliminated using
this operation; i.e.
\[
f_5 =
f_6 \left[ v_1^{(0)} , \ldots , v_5^{(1)} ,
v_6^{(0)} \left( v_5^{(0)} \right) ,
v_6^{(1)} \left( v_5^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_5}{v_4^{(1)}}
& = & \D{f_6}{v_4^{(1)}}
& = 1
\\
\D{f_5}{v_5^{(1)}}
& = & \D{f_6}{v_5} +
\D{f_6}{v_6^{(1)}} * \D{v_6^{(1)}}{v_5^{(1)}}
& = 0.5
\end{array}
\]
All the other partial derivatives of
f_5
are zero.
\[
\begin{array}{rcl}
v_5^{(0)} & = & v_3^{(0)} * v_1^{(0)}
\\
v_5^{(1)} & = & v_3^{(1)} * v_1^{(0)} + v_3^{(0)} * v_1^{(1)}
\end{array}
\]
We define the function
f_4 \left( v_1^{(0)} , \ldots , v_4^{(1)} \right)
as equal to
f_5
except that
v_5^{(0)}
and
v_5^{(1)}
are eliminated using
this operation; i.e.
\[
f_4 =
f_5 \left[ v_1^{(0)} , \ldots , v_4^{(1)} ,
v_5^{(0)} \left( v_1^{(0)}, v_3^{(0)} \right) ,
v_5^{(1)} \left( v_1^{(0)}, v_1^{(1)}, v_3^{(0)} , v_3^{(1)} \right) ,
\right]
\]
Given the information from the forward sweep, we have
v_1^{(0)} = 0.5
,
v_3^{(0)} = 0.5
,
v_1^{(1)} = 1
,
v_3^{(1)} = 1
,
and the fact that the partial of
f_5
with respect to
v_5^{(0)}
is zero, we have
\[
\begin{array}{rcll}
\D{f_4}{v_1^{(0)}}
& = & \D{f_5}{v_1^{(0)}}
+ \D{f_5}{v_5^{(1)}} * \D{v_5^{(1)}}{v_1^{(0)}}
& = 0.5
\\
\D{f_4}{v_1^{(1)}}
& = & \D{f_5}{v_1^{(1)}}
+ \D{f_5}{v_5^{(1)}} * \D{v_5^{(1)}}{v_1^{(1)}}
& = 0.25
\\
\D{f_4}{v_3^{(0)}}
& = & \D{f_5}{v_3^{(0)}}
+ \D{f_5}{v_5^{(1)}} * \D{v_5^{(1)}}{v_3^{(0)}}
& = 0.5
\\
\D{f_4}{v_3^{(1)}}
& = & \D{f_3}{v_1^{(1)}}
+ \D{f_5}{v_5^{(1)}} * \D{v_5^{(1)}}{v_3^{(1)}}
& = 0.25
\\
\D{f_4}{v_4^{(1)}}
& = & \D{f_5}{v_4^{(1)}}
& = 1
\end{array}
\]
All the other partial derivatives of
f_5
are zero.
\[
\begin{array}{rcl}
v_4^{(0)} = 1 + v_3^{(0)}
\\
v_4^{(1)} = v_3^{(1)}
\end{array}
\]
We define the function
f_3 \left( v_1^{(0)} , \ldots , v_3^{(1)} \right)
as equal to
f_4
except that
v_4^{(0)}
and
v_4^{(1)}
are eliminated using
this operation; i.e.
\[
f_3 =
f_4 \left[ v_1^{(0)} , \ldots , v_3^{(1)} ,
v_4^{(0)} \left( v_3^{(0)} \right) ,
v_4^{(1)} \left( v_3^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_3}{v_1^{(0)}}
& = & \D{f_4}{v_1^{(0)}}
& = 0.5
\\
\D{f_3}{v_1^{(1)}}
& = & \D{f_4}{v_1^{(1)}}
& = 0.25
\\
\D{f_3}{v_2^{(0)}}
& = & \D{f_4}{v_2^{(0)}}
& = 0
\\
\D{f_3}{v_2^{(1)}}
& = & \D{f_4}{v_2^{(1)}}
& = 0
\\
\D{f_3}{v_3^{(0)}}
& = & \D{f_4}{v_3^{(0)}}
+ \D{f_4}{v_4^{(0)}} * \D{v_4^{(0)}}{v_3^{(0)}}
& = 0.5
\\
\D{f_3}{v_3^{(1)}}
& = & \D{f_4}{v_3^{(1)}}
+ \D{f_4}{v_4^{(1)}} * \D{v_4^{(1)}}{v_3^{(1)}}
& = 1.25
\end{array}
\]
\[
\begin{array}{rcl}
v_3^{(0)} & = & v_2^{(0)} / 1
\\
v_3^{(1)} & = & v_2^{(1)} / 1
\end{array}
\]
We define the function
f_2 \left( v_1^{(0)} , \ldots , v_2^{(1)} \right)
as equal to
f_3
except that
v_3^{(0)}
and
v_3^{(1)}
are eliminated using
this operation; i.e.
\[
f_2 =
f_3 \left[ v_1^{(0)} , \ldots , v_2^{(1)} ,
v_3^{(0)} \left( v_2^{(0)} \right) ,
v_3^{(1)} \left( v_2^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_2}{v_1^{(0)}}
& = & \D{f_3}{v_1^{(0)}}
& = 0.5
\\
\D{f_2}{v_1^{(1)}}
& = & \D{f_3}{v_1^{(1)}}
& = 0.25
\\
\D{f_2}{v_2^{(0)}}
& = & \D{f_3}{v_2^{(0)}}
+ \D{f_3}{v_3^{(0)}} * \D{v_3^{(0)}}{v_2^{(0)}}
& = 0.5
\\
\D{f_2}{v_2^{(1)}}
& = & \D{f_3}{v_2^{(1)}}
+ \D{f_3}{v_3^{(1)}} * \D{v_3^{(1)}}{v_2^{(0)}}
& = 1.25
\end{array}
\]
\[
\begin{array}{rcl}
v_2^{(0)} & = & 1 * v_1^{(0)}
\\
v_2^{(1)} & = & 1 * v_1^{(1)}
\end{array}
\]
We define the function
f_1 \left( v_1^{(0)} , v_1^{(1)} \right)
as equal to
f_2
except that
v_2^{(0)}
and
v_2^{(1)}
are eliminated using
this operation; i.e.
\[
f_1 =
f_2 \left[ v_1^{(0)} , v_1^{(1)} ,
v_2^{(0)} \left( v_1^{(0)} \right) ,
v_2^{(1)} \left( v_1^{(1)} \right)
\right]
\]
It follows that
\[
\begin{array}{rcll}
\D{f_1}{v_1^{(0)}}
& = & \D{f_2}{v_1^{(0)}}
+ \D{f_2}{v_2^{(0)}} * \D{v_2^{(0)}}{v_1^{(0)}}
& = 1
\\
\D{f_1}{v_1^{(1)}}
& = & \D{f_2}{v_1^{(1)}}
+ \D{f_2}{v_2^{(1)}} * \D{v_2^{(1)}}{v_1^{(1)}}
& = 1.5
\end{array}
\]
Note that
v_1
is equal to
x
,
so the second partial derivative of
exp_eps(x, epsilon)
at x equal to .5 and epsilon equal .2 is
\[
\Dpow{2}{x} v_7^{(0)}
= \D{v_7^{(1)}}{x}
= \D{f_1}{v_1^{(0)}}
= 1
\]
There is a theorem about algorithmic differentiation that explains why
the other partial of
f_1
is equal to the first partial of
exp_eps(x, epsilon)
with respect to
x
.
f_j
that might not be equal to the corresponding
partials of
f_{j+1}
; i.e., the
other partials of
f_j
must be equal to the corresponding
partials of
f_{j+1}
.
x = .1
and we first preform a zero order forward mode sweep
for the operation sequence used above (in reverse order).
What are the results of a
first order reverse mode sweep; i.e.,
what are the corresponding values for
\D{f_j}{v_k}
for all
j, k
such that
\D{f_j}{v_k} \neq 0
.
# include <cstddef> // define size_t
# include <cmath> // for fabs function
extern bool exp_eps_for0(double *v0); // computes zero order forward sweep
extern bool exp_eps_for1(double *v1); // computes first order forward sweep
bool exp_eps_rev2(void)
{ bool ok = true;
// set the value of v0[j], v1[j] for j = 1 , ... , 7
double v0[8], v1[8];
ok &= exp_eps_for0(v0);
ok &= exp_eps_for1(v1);
// initial all partial derivatives as zero
double f_v0[8], f_v1[8];
size_t j;
for(j = 0; j < 8; j++)
{ f_v0[j] = 0.;
f_v1[j] = 0.;
}
// set partial derivative for f_7
f_v1[7] = 1.;
ok &= std::fabs( f_v1[7] - 1. ) <= 1e-10; // partial f_7 w.r.t. v_7^1
// f_6 = f_7( v_1^0 , ... , v_6^1 , v_4^0 + v_6^0, v_4^1 , v_6^1 )
f_v0[4] += f_v0[7];
f_v0[6] += f_v0[7];
f_v1[4] += f_v1[7];
f_v1[6] += f_v1[7];
ok &= std::fabs( f_v0[4] - 0. ) <= 1e-10; // partial f_6 w.r.t. v_4^0
ok &= std::fabs( f_v0[6] - 0. ) <= 1e-10; // partial f_6 w.r.t. v_6^0
ok &= std::fabs( f_v1[4] - 1. ) <= 1e-10; // partial f_6 w.r.t. v_4^1
ok &= std::fabs( f_v1[6] - 1. ) <= 1e-10; // partial f_6 w.r.t. v_6^1
// f_5 = f_6( v_1^0 , ... , v_5^1 , v_5^0 / 2 , v_5^1 / 2 )
f_v0[5] += f_v0[6] / 2.;
f_v1[5] += f_v1[6] / 2.;
ok &= std::fabs( f_v0[5] - 0. ) <= 1e-10; // partial f_5 w.r.t. v_5^0
ok &= std::fabs( f_v1[5] - 0.5 ) <= 1e-10; // partial f_5 w.r.t. v_5^1
// f_4 = f_5( v_1^0 , ... , v_4^1 , v_3^0 * v_1^0 ,
// v_3^1 * v_1^0 + v_3^0 * v_1^1 )
f_v0[1] += f_v0[5] * v0[3] + f_v1[5] * v1[3];
f_v0[3] += f_v0[5] * v0[1] + f_v1[5] * v1[1];
f_v1[1] += f_v1[5] * v0[3];
f_v1[3] += f_v1[5] * v0[1];
ok &= std::fabs( f_v0[1] - 0.5 ) <= 1e-10; // partial f_4 w.r.t. v_1^0
ok &= std::fabs( f_v0[3] - 0.5 ) <= 1e-10; // partial f_4 w.r.t. v_3^0
ok &= std::fabs( f_v1[1] - 0.25 ) <= 1e-10; // partial f_4 w.r.t. v_1^1
ok &= std::fabs( f_v1[3] - 0.25 ) <= 1e-10; // partial f_4 w.r.t. v_3^1
// f_3 = f_4( v_1^0 , ... , v_3^1 , 1 + v_3^0 , v_3^1 )
f_v0[3] += f_v0[4];
f_v1[3] += f_v1[4];
ok &= std::fabs( f_v0[3] - 0.5 ) <= 1e-10; // partial f_3 w.r.t. v_3^0
ok &= std::fabs( f_v1[3] - 1.25) <= 1e-10; // partial f_3 w.r.t. v_3^1
// f_2 = f_3( v_1^0 , ... , v_2^1 , v_2^0 , v_2^1 )
f_v0[2] += f_v0[3];
f_v1[2] += f_v1[3];
ok &= std::fabs( f_v0[2] - 0.5 ) <= 1e-10; // partial f_2 w.r.t. v_2^0
ok &= std::fabs( f_v1[2] - 1.25) <= 1e-10; // partial f_2 w.r.t. v_2^1
// f_1 = f_2 ( v_1^0 , v_2^0 , v_1^0 , v_2^0 )
f_v0[1] += f_v0[2];
f_v1[1] += f_v1[2];
ok &= std::fabs( f_v0[1] - 1. ) <= 1e-10; // partial f_1 w.r.t. v_1^0
ok &= std::fabs( f_v1[1] - 1.5 ) <= 1e-10; // partial f_1 w.r.t. v_1^1
return ok;
}
x
,
at the point
x = .5
and
\varepsilon = .2
,
of the function
exp_eps(x, epsilon)
as defined by the 3.3.1: exp_eps.hpp
include file.
x
,
at the point
x = .1
and
\varepsilon = .2
,
of the function
exp_eps(x, epsilon)
x
,
at the point
x = .1
and
\varepsilon = .2
,
of the function corresponding to the operation sequence
for
x = .5
and
\varepsilon = .2
.
Hint: you could define a vector u with two components and use
f.Forward(0, u)
to run zero order forward mode at a point different
form the point where the operation sequence corresponding to
f was recorded.
# include <cppad/cppad.hpp> // http://www.coin-or.org/CppAD/
# include "exp_eps.hpp" // our example exponential function approximation
bool exp_eps_cppad(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::vector; // can use any simple vector template class
using CppAD::NearEqual; // checks if values are nearly equal
// domain space vector
size_t n = 2; // dimension of the domain space
vector< AD<double> > U(n);
U[0] = .5; // value of x for this operation sequence
U[1] = .2; // value of e for this operation sequence
// declare independent variables and start recording operation sequence
CppAD::Independent(U);
// evaluate our exponential approximation
AD<double> x = U[0];
AD<double> epsilon = U[1];
AD<double> apx = exp_eps(x, epsilon);
// range space vector
size_t m = 1; // dimension of the range space
vector< AD<double> > Y(m);
Y[0] = apx; // variable that represents only range space component
// Create f: U -> Y corresponding to this operation sequence
// and stop recording. This also executes a zero order forward
// mode sweep using values in U for x and e.
CppAD::ADFun<double> f(U, Y);
// first order forward mode sweep that computes partial w.r.t x
vector<double> du(n); // differential in domain space
vector<double> dy(m); // differential in range space
du[0] = 1.; // x direction in domain space
du[1] = 0.;
dy = f.Forward(1, du); // partial w.r.t. x
double check = 1.5;
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// first order reverse mode sweep that computes the derivative
vector<double> w(m); // weights for components of the range
vector<double> dw(n); // derivative of the weighted function
w[0] = 1.; // there is only one weight
dw = f.Reverse(1, w); // derivative of w[0] * exp_eps(x, epsilon)
check = 1.5; // partial w.r.t. x
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
check = 0.; // partial w.r.t. epsilon
ok &= NearEqual(dw[1], check, 1e-10, 1e-10);
// second order forward sweep that computes
// second partial of exp_eps(x, epsilon) w.r.t. x
vector<double> x2(n); // second order Taylor coefficients
vector<double> y2(m);
x2[0] = 0.; // evaluate partial w.r.t x
x2[1] = 0.;
y2 = f.Forward(2, x2);
check = 0.5 * 1.; // Taylor coef is 1/2 second derivative
ok &= NearEqual(y2[0], check, 1e-10, 1e-10);
// second order reverse sweep that computes
// derivative of partial of exp_eps(x, epsilon) w.r.t. x
dw.resize(2 * n); // space for first and second derivative
dw = f.Reverse(2, w);
check = 1.; // result should be second derivative
ok &= NearEqual(dw[0*2+1], check, 1e-10, 1e-10);
return ok;
}
// system include files used for I/O
# include <iostream>
// external complied tests
extern bool exp_2(void);
extern bool exp_2_cppad(void);
extern bool exp_2_for1(void);
extern bool exp_2_for2(void);
extern bool exp_2_rev1(void);
extern bool exp_2_rev2(void);
extern bool exp_2_for0(void);
extern bool exp_eps(void);
extern bool exp_eps_cppad(void);
extern bool exp_eps_for1(void);
extern bool exp_eps_for2(void);
extern bool exp_eps_for0(void);
extern bool exp_eps_rev1(void);
extern bool exp_eps_rev2(void);
namespace {
static size_t Run_ok_count = 0;
static size_t Run_error_count = 0;
bool Run(bool TestOk(void), std::string name)
{ bool ok = true;
std::streamsize width = 20;
std::cout.width( width );
std::cout.setf( std::ios_base::left );
std::cout << name.c_str();
//
ok &= name.size() < size_t(width);
ok &= TestOk();
if( ok )
{ std::cout << "OK" << std::endl;
Run_ok_count++;
}
else
{ std::cout << "Error" << std::endl;
Run_error_count++;
}
return ok;
}
}
// main program that runs all the tests
int main(void)
{ bool ok = true;
using namespace std;
// This comment is used by OneTest
// external compiled tests
ok &= Run( exp_2, "exp_2" );
ok &= Run( exp_2_cppad, "exp_2_cppad" );
ok &= Run( exp_2_for0, "exp_2_for0" );
ok &= Run( exp_2_for1, "exp_2_for1" );
ok &= Run( exp_2_for2, "exp_2_for2" );
ok &= Run( exp_2_rev1, "exp_2_rev1" );
ok &= Run( exp_2_rev2, "exp_2_rev2" );
ok &= Run( exp_eps, "exp_eps" );
ok &= Run( exp_eps_cppad, "exp_eps_cppad" );
ok &= Run( exp_eps_for0, "exp_eps_for0" );
ok &= Run( exp_eps_for1, "exp_eps_for1" );
ok &= Run( exp_eps_for2, "exp_eps_for2" );
ok &= Run( exp_eps_rev1, "exp_eps_rev1" );
ok &= Run( exp_eps_rev2, "exp_eps_rev2" );
if( ok )
cout << "All " << int(Run_ok_count) << " tests passed." << endl;
else cout << int(Run_error_count) << " tests failed." << endl;
return static_cast<int>( ! ok );
}
float,
double,
std::complex<float>,
std::complex<double>.
Otherwise, see 4.7: base_require
.
| Default: 4.1 | AD Default Constructor |
| ad_copy: 4.2 | AD Copy Constructor and Assignment Operator |
| Convert: 4.3 | Conversion and Printing of AD Objects |
| ADValued: 4.4 | AD Valued Operations and Functions |
| BoolValued: 4.5 | Bool Valued Operations and Functions with AD Arguments |
| VecAD: 4.6 | AD Vectors that Record Index Operations |
| base_require: 4.7 | AD<Base> Requirements for Base Type |
AD<Base> x;
# include <cppad/cppad.hpp>
bool Default(void)
{ bool ok = true;
using CppAD::AD;
// default AD constructor
AD<double> x, y;
// check that they are parameters
ok &= Parameter(x);
ok &= Parameter(y);
// assign them values
x = 3.;
y = 4.;
// just check a simple operation
ok &= (x + y == 7.);
return ok;
}
AD<Base> y(x)
AD<Base> y = x
y = x
AD<Base> object y
and the assignment operator uses an existing y.
In either case,
y has the same value as x,
and the same dependence on the
9.4.j.c: independent variables
(y is a
9.4.l: variable
if and only if x is a variable).
const Type &x
where Type is
VecAD<Base>::reference,
AD<Base>,
Base, or
double.
AD<Base> &y
| 4.2.1: CopyAD.cpp | AD Copy Constructor: Example and Test |
| 4.2.2: CopyBase.cpp | AD Constructor From Base Type: Example and Test |
| 4.2.3: Eq.cpp | AD Assignment Operator: Example and Test |
# include <cppad/cppad.hpp>
bool CopyAD(void)
{ bool ok = true; // initialize test result flag
using CppAD::AD; // so can use AD in place of CppAD::AD
// domain space vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 2.;
// declare independent variables and start tape recording
CppAD::Independent(x);
// create an AD<double> that does not depend on x
AD<double> b = 3.;
// use copy constructor
AD<double> u(x[0]);
AD<double> v = b;
// check which are parameters
ok &= Variable(u);
ok &= Parameter(v);
// range space vector
size_t m = 2;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = u;
y[1] = v;
// create f: x -> y and vectors used for derivative calculations
CppAD::ADFun<double> f(x, y);
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
// check parameters flags
ok &= ! f.Parameter(0);
ok &= f.Parameter(1);
// check function values
ok &= ( y[0] == 2. );
ok &= ( y[1] == 3. );
// forward computation of partials w.r.t. x[0]
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= ( dy[0] == 1. ); // du / dx
ok &= ( dy[1] == 0. ); // dv / dx
return ok;
}
# include <cppad/cppad.hpp>
bool CopyBase(void)
{ bool ok = true; // initialize test result flag
using CppAD::AD; // so can use AD in place of CppAD::AD
// construct directly from Base where Base is double
AD<double> x(1.);
// construct from a type that converts to Base where Base is double
AD<double> y = 2;
// construct from a type that converts to Base where Base = AD<double>
AD< AD<double> > z(3);
// check that resulting objects are parameters
ok &= Parameter(x);
ok &= Parameter(y);
ok &= Parameter(z);
// check values of objects (compare AD<double> with double)
ok &= ( x == 1.);
ok &= ( y == 2.);
ok &= ( Value(z) == 3.);
// user constructor through the static_cast template function
x = static_cast < AD<double> >( 4 );
z = static_cast < AD< AD<double> > >( 5 );
ok &= ( x == 4. );
ok &= ( Value(z) == 5. );
return ok;
}
# include <cppad/cppad.hpp>
bool Eq(void)
{ bool ok = true;
using CppAD::AD;
// domain space vector
size_t n = 3;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 2; // AD<double> = int
x[1] = 3.; // AD<double> = double
x[2] = x[1]; // AD<double> = AD<double>
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 3;
CPPAD_TEST_VECTOR< AD<double> > y(m);
// assign an AD<Base> object equal to an independent variable
// (choose the first independent variable to check a special case)
// use the value returned by the assignment (for another assignment)
y[0] = y[1] = x[0];
// assign an AD<Base> object equal to an expression
y[1] = x[1] + 1.;
y[2] = x[2] + 2.;
// check that all the resulting components of y depend on x
ok &= Variable(y[0]); // y[0] = x[0]
ok &= Variable(y[1]); // y[1] = x[1] + 1
ok &= Variable(y[2]); // y[2] = x[2] + 2
// construct f : x -> y and stop the tape recording
CppAD::ADFun<double> f(x, y);
// check variable values
ok &= ( y[0] == 2.);
ok &= ( y[1] == 4.);
ok &= ( y[2] == 5.);
// compute partials w.r.t x[1]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 0.;
dx[1] = 1.;
dx[2] = 0.;
dy = f.Forward(1, dx);
ok &= (dy[0] == 0.); // dy[0] / dx[1]
ok &= (dy[1] == 1.); // dy[1] / dx[1]
ok &= (dy[2] == 0.); // dy[2] / dx[1]
// compute the derivative y[2]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 0.;
w[1] = 0.;
w[2] = 1.;
dw = f.Reverse(1, w);
ok &= (dw[0] == 0.); // dy[2] / dx[0]
ok &= (dw[1] == 0.); // dy[2] / dx[1]
ok &= (dw[2] == 1.); // dy[2] / dx[2]
// assign a VecAD<Base>::reference
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = 5.;
ok &= (v[0] == 5.);
return ok;
}
| 4.3.1: Value | Convert From an AD Type to its Base Type |
| 4.3.2: Integer | Convert From AD to Integer |
| 4.3.3: Output | AD Output Stream Operator |
| 4.3.4: PrintFor | Printing AD Values During Forward Mode |
| 4.3.5: Var2Par | Convert an AD Variable to a Parameter |
b = Value(x)
const AD<Base> &x
Base b
Value result (see above).
For this reason,
the argument x must be a 9.4.h: parameter
; i.e.,
it cannot depend on the current
9.4.j.c: independent variables
.
# include <cppad/cppad.hpp>
bool Value(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::Value;
// domain space vector
size_t n = 2;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 3.;
x[1] = 4.;
// check value before recording
ok &= (Value(x[0]) == 3.);
ok &= (Value(x[1]) == 4.);
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = - x[1];
// cannot call Value(x[j]) or Value(y[0]) here (currently variables)
AD<double> p = 5.; // p is a parameter (does not depend on x)
ok &= (Value(p) == 5.);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// can call Value(x[j]) or Value(y[0]) here (currently parameters)
ok &= (Value(x[0]) == 3.);
ok &= (Value(x[1]) == 4.);
ok &= (Value(y[0]) == -4.);
return ok;
}
i = Integer(x)
int i
const float &x
const double &x
the fractional part is dropped to form the integer value.
For example, if x is 1.5, i is 1.
In general, if
x \geq 0
, i is the
greatest integer less than or equal x.
If
x \leq 0
, i is the
smallest integer greater than or equal x.
const std::complex<float> &x
const std::complex<double> &x
The result i is given by
i = Integer(x.real())
const AD<Base> &x
const VecAD<Base>::reference &x
Base must support the Integer function and
the conversion has the same meaning as for Base.
# include <cppad/cppad.hpp>
bool Integer(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::Integer;
// domain space vector
size_t n = 2;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 3.5;
x[1] = 4.5;
// check integer before recording
ok &= (Integer(x[0]) == 3);
ok &= (Integer(x[1]) == 4);
// start recording
// declare independent variables and start tape recording
CppAD::Independent(x);
// check integer during recording
ok &= (Integer(x[0]) == 3);
ok &= (Integer(x[1]) == 4);
// check integer for VecAD element
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = 2;
ok &= (Integer(v[zero]) == 2);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = - x[1];
// create f: x -> y and stop recording
CppAD::ADFun<double> f(x, y);
// check integer after recording
ok &= (Integer(x[0]) == 3.);
ok &= (Integer(x[1]) == 4.);
ok &= (Integer(y[0]) == -4.);
return ok;
}
os << x
std::ostream &os
const AD<Base> &x
const VecAD<Base>::reference &x
AD<Base> y
then the syntax
os << x << y
will output the value corresponding to x
followed by the value corresponding to y.
# include <cppad/cppad.hpp>
# include <sstream> // std::ostringstream
# include <string> // std::string
# include <iomanip> // std::setprecision, setw, setfill, right
namespace {
template <class S>
void set_ostream(S &os)
{ os
<< std::setprecision(4) // 4 digits of precision
<< std::setw(6) // 6 characters per field
<< std::setfill(' ') // fill with spaces
<< std::right; // adjust value to the right
}
}
bool Output(void)
{ bool ok = true;
// This output stream is an ostringstream for testing purposes.
// You can use << with other types of streams; i.e., std::cout.
std::ostringstream stream;
// ouput an AD<double> object
CppAD::AD<double> pi = 4. * atan(1.); // 3.1415926536
set_ostream(stream);
stream << pi;
// ouput a VecAD<double>::reference object
CppAD::VecAD<double> v(1);
CppAD::AD<double> zero(0);
v[zero] = exp(1.); // 2.7182818285
set_ostream(stream);
stream << v[zero];
// convert output from stream to string
std::string str = stream.str();
// check the output
ok &= (str == " 3.142 2.718");
return ok;
}
PrintFor(text, y)
f.Forward(0, x)
AD<Base>
object y is the result of an AD of Base operation.
This operation may be part of the
9.4.g.b: operation sequence
that is transferred to an 5: ADFun
object f.
The ADFun object can be evaluated at different values for the
9.4.j.c: independent variables
.
This may result in a corresponding value for y
that is different from when the operation sequence was recorded.
The routine PrintFor requests a printing,
when f.Forward(0, x) is executed,
of the value for y that corresponds to the
independent variable values specified by x.
const char *text
The corresponding text is written to std::cout before the
value of y.
const AD<Base> &y
const VecAD<Base>::reference &y
The value of y that corresponds to x
is written to std::cout during the execution of
f.Forward(0, x)
Nan.
# include <cppad/cppad.hpp>
int main(void)
{
using namespace CppAD;
using std::cout;
using std::endl;
// independent variable vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > X(n);
X[0] = 1.;
Independent(X);
// print a VecAD<double>::reference object that is a parameter
VecAD<double> V(1);
AD<double> Zero(0);
V[Zero] = 0.;
PrintFor("v[0] = ", V[Zero]);
// dependent variable vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > Y(m);
Y[0] = V[Zero] + X[0];
// First print a newline to separate this from previous output,
// then print an AD<double> object that is a variable.
PrintFor( "\nv[0] + x[0] = ", Y[0]);
// define f: x -> y and stop tape recording
ADFun<double> f(X, Y);
// zero order forward with x[0] = 2
CPPAD_TEST_VECTOR<double> x(n);
x[0] = 2.;
cout << "v[0] = 0" << endl;
cout << "v[0] + x[0] = 2" << endl;
// Developer Note: ./makefile.am "Test passes" to begin next output line
cout << "Test passes if two lines above repeat below:" << endl;
f.Forward(0, x);
// print a new line after output
std::cout << std::endl;
return 0;
}
v[0] = 0
v[0] + x[0] = 2
Test passes if two lines above repeat below:
v[0] = 0
v[0] + x[0] = 2
y = Var2Par(x)
const AD<Base> &x
The argument x may be a variable or parameter.
AD<Base> &y
The return value y will be a parameter.
# include <cppad/cppad.hpp>
bool Var2Par(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::Value;
using CppAD::Var2Par;
// domain space vector
size_t n = 2;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 3.;
x[1] = 4.;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = - x[1] * Var2Par(x[0]); // same as y[0] = -x[1] * 3.;
// cannot call Value(x[j]) or Value(y[0]) here (currently variables)
ok &= ( Value( Var2Par(x[0]) ) == 3. );
ok &= ( Value( Var2Par(x[1]) ) == 4. );
ok &= ( Value( Var2Par(y[0]) ) == -12. );
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// can call Value(x[j]) or Value(y[0]) here (currently parameters)
ok &= (Value(x[0]) == 3.);
ok &= (Value(x[1]) == 4.);
ok &= (Value(y[0]) == -12.);
// evaluate derivative of y w.r.t x
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= (dw[0] == 0.); // derivative of y[0] w.r.t x[0] is zero
ok &= (dw[1] == -3.); // derivative of y[0] w.r.t x[1] is 3
return ok;
}
| Arithmetic: 4.4.1 | AD Arithmetic Operators and Computed Assignments |
| std_math_ad: 4.4.2 | AD Standard Math Unary Functions |
| MathOther: 4.4.3 | Other AD Math Functions |
| CondExp: 4.4.4 | AD Conditional Expressions |
| Discrete: 4.4.5 | Discrete AD Functions |
| UnaryPlus: 4.4.1.1 | AD Unary Plus Operator |
| UnaryMinus: 4.4.1.2 | AD Unary Minus Operator |
| ad_binary: 4.4.1.3 | AD Binary Arithmetic Operators |
| compute_assign: 4.4.1.4 | AD Computed Assignment Operators |
y = + x
const AD<Base> &x
const VecAD<Base>::reference &x
AD<Base> y
It is equal to the operand x.
f
is a
9.4.d: Base function
,
\[
\D{[ + f(x) ]}{x} = \D{f(x)}{x}
\]
# include <cppad/cppad.hpp>
bool UnaryPlus(void)
{ bool ok = true;
using CppAD::AD;
// domain space vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 3.;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = + x[0];
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check values
ok &= ( y[0] == 3. );
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
size_t p = 1;
dx[0] = 1.;
dy = f.Forward(p, dx);
ok &= ( dy[0] == 1. ); // dy[0] / dx[0]
// reverse computation of dertivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(p, w);
ok &= ( dw[0] == 1. ); // dy[0] / dx[0]
// use a VecAD<Base>::reference object with unary plus
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x[0];
AD<double> result = + v[zero];
ok &= (result == y[0]);
return ok;
}
y = - x
const Base object.
const AD<Base> &x
const VecAD<Base>::reference &x
AD<Base> y
It is equal to the negative of the operand x.
f
is a
9.4.d: Base function
,
\[
\D{[ - f(x) ]}{x} = - \D{f(x)}{x}
\]
# include <cppad/cppad.hpp>
bool UnaryMinus(void)
{ bool ok = true;
using CppAD::AD;
// domain space vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 3.;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = - x[0];
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check values
ok &= ( y[0] == -3. );
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
size_t p = 1;
dx[0] = 1.;
dy = f.Forward(p, dx);
ok &= ( dy[0] == -1. ); // dy[0] / dx[0]
// reverse computation of dertivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(p, w);
ok &= ( dw[0] == -1. ); // dy[0] / dx[0]
// use a VecAD<Base>::reference object with unary minus
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x[0];
AD<double> result = - v[zero];
ok &= (result == y[0]);
return ok;
}
z = x Op y
AD<Base> or
4.6.d: VecAD<Base>::reference
.
| Op | Meaning |
+ | z is x plus y |
- | z is x minus y |
* | z is x times y |
/ | z is x divided by y |
AD<Base> or VecAD<Base>::reference.
const Type &x
where Type is
VecAD<Base>::reference,
AD<Base>,
Base, or
double.
const Type &y
where Type is
VecAD<Base>::reference,
AD<Base>,
Base, or
double.
Type z
where Type is
AD<Base>.
| 4.4.1.3.1: Add.cpp | AD Binary Addition: Example and Test |
| 4.4.1.3.2: Sub.cpp | AD Binary Subtraction: Example and Test |
| 4.4.1.3.3: Mul.cpp | AD Binary Multiplication: Example and Test |
| 4.4.1.3.4: Div.cpp | AD Binary Division: Example and Test |
f
and
g
are
9.4.d: Base functions
\[
\D{[ f(x) + g(x) ]}{x} = \D{f(x)}{x} + \D{g(x)}{x}
\]
\[
\D{[ f(x) - g(x) ]}{x} = \D{f(x)}{x} - \D{g(x)}{x}
\]
\[
\D{[ f(x) * g(x) ]}{x} = g(x) * \D{f(x)}{x} + f(x) * \D{g(x)}{x}
\]
\[
\D{[ f(x) / g(x) ]}{x} =
[1/g(x)] * \D{f(x)}{x} - [f(x)/g(x)^2] * \D{g(x)}{x}
\]
# include <cppad/cppad.hpp>
bool Add(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// some binary addition operations
AD<double> a = x[0] + 1.; // AD<double> + double
AD<double> b = a + 2; // AD<double> + int
AD<double> c = 3. + b; // double + AD<double>
AD<double> d = 4 + c; // int + AD<double>
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = d + x[0]; // AD<double> + AD<double>
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , 2. * x0 + 10, 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 2., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 2., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with addition
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = a;
AD<double> result = v[zero] + 2;
ok &= (result == b);
return ok;
}
# include <cppad/cppad.hpp>
bool Sub(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = .5;
CPPAD_TEST_VECTOR< AD<double> > x(1);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
AD<double> a = 2. * x[0] - 1.; // AD<double> - double
AD<double> b = a - 2; // AD<double> - int
AD<double> c = 3. - b; // double - AD<double>
AD<double> d = 4 - c; // int - AD<double>
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = x[0] - d; // AD<double> - AD<double>
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0], x0-4.+3.+2.-2.*x0+1., 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], -1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], -1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with subtraction
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = b;
AD<double> result = 3. - v[zero];
ok &= (result == c);
return ok;
}
# include <cppad/cppad.hpp>
bool Mul(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = .5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// some binary multiplication operations
AD<double> a = x[0] * 1.; // AD<double> * double
AD<double> b = a * 2; // AD<double> * int
AD<double> c = 3. * b; // double * AD<double>
AD<double> d = 4 * c; // int * AD<double>
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = x[0] * d; // AD<double> * AD<double>
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0*(4.*3.*2.*1.)*x0, 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], (4.*3.*2.*1.)*2.*x0, 1e-10 , 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], (4.*3.*2.*1.)*2.*x0, 1e-10 , 1e-10);
// use a VecAD<Base>::reference object with multiplication
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = c;
AD<double> result = 4 * v[zero];
ok &= (result == d);
return ok;
}
# include <cppad/cppad.hpp>
bool Div(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// some binary division operations
AD<double> a = x[0] / 1.; // AD<double> / double
AD<double> b = a / 2; // AD<double> / int
AD<double> c = 3. / b; // double / AD<double>
AD<double> d = 4 / c; // int / AD<double>
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = (x[0] * x[0]) / d; // AD<double> / AD<double>
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0], x0*x0*3.*2.*1./(4.*x0), 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 3.*2.*1./4., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 3.*2.*1./4., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with division
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = d;
AD<double> result = (x[0] * x[0]) / v[zero];
ok &= (result == y[0]);
return ok;
}
x Op y
AD<Base>.
| Op | Meaning |
+= | x is assigned x plus y |
-= | x is assigned x minus y |
*= | x is assigned x times y |
/= | x is assigned x divided by y |
AD<Base> &x
const Type &y
where Type is
VecAD<Base>::reference,
AD<Base>,
Base, or
double.
AD<Base> z
then the syntax
z = x += y
will compute x plus y
and then assign this value to both x and z.
| 4.4.1.4.1: AddEq.cpp | AD Computed Assignment Addition: Example and Test |
| 4.4.1.4.2: SubEq.cpp | AD Computed Assignment Subtraction: Example and Test |
| 4.4.1.4.3: MulEq.cpp | AD Computed Assignment Multiplication: Example and Test |
| 4.4.1.4.4: DivEq.cpp | AD Computed Assignment Division: Example and Test |
f
and
g
are
9.4.d: Base functions
\[
\D{[ f(x) + g(x) ]}{x} = \D{f(x)}{x} + \D{g(x)}{x}
\]
\[
\D{[ f(x) - g(x) ]}{x} = \D{f(x)}{x} - \D{g(x)}{x}
\]
\[
\D{[ f(x) * g(x) ]}{x} = g(x) * \D{f(x)}{x} + f(x) * \D{g(x)}{x}
\]
\[
\D{[ f(x) / g(x) ]}{x} =
[1/g(x)] * \D{f(x)}{x} - [f(x)/g(x)^2] * \D{g(x)}{x}
\]
# include <cppad/cppad.hpp>
bool AddEq(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = .5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 2;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = x[0]; // initial value
y[0] += 2; // AD<double> += int
y[0] += 4.; // AD<double> += double
y[1] = y[0] += x[0]; // use the result of a computed assignment
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0+2.+4.+x0, 1e-10 , 1e-10);
ok &= NearEqual(y[1] , y[0], 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 2., 1e-10, 1e-10);
ok &= NearEqual(dy[1], 2., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
w[1] = 0.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 2., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with computed addition
CppAD::VecAD<double> v(1);
AD<double> zero(0);
AD<double> result = 1;
v[zero] = 2;
result += v[zero];
ok &= (result == 3);
return ok;
}
# include <cppad/cppad.hpp>
bool SubEq(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = .5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 2;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = 3. * x[0]; // initial value
y[0] -= 2; // AD<double> -= int
y[0] -= 4.; // AD<double> -= double
y[1] = y[0] -= x[0]; // use the result of a computed assignment
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , 3.*x0-(2.+4.+x0), 1e-10 , 1e-10);
ok &= NearEqual(y[1] , y[0], 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 2., 1e-10, 1e-10);
ok &= NearEqual(dy[1], 2., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
w[1] = 0.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 2., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with computed subtraction
CppAD::VecAD<double> v(1);
AD<double> zero(0);
AD<double> result = 1;
v[zero] = 2;
result -= v[zero];
ok &= (result == -1);
return ok;
}
# include <cppad/cppad.hpp>
bool MulEq(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = .5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 2;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = x[0]; // initial value
y[0] *= 2; // AD<double> *= int
y[0] *= 4.; // AD<double> *= double
y[1] = y[0] *= x[0]; // use the result of a computed assignment
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0*2.*4.*x0, 1e-10 , 1e-10);
ok &= NearEqual(y[1] , y[0], 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 8.*2.*x0, 1e-10, 1e-10);
ok &= NearEqual(dy[1], 8.*2.*x0, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
w[1] = 0.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 8.*2.*x0, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with computed multiplication
CppAD::VecAD<double> v(1);
AD<double> zero(0);
AD<double> result = 1;
v[zero] = 2;
result *= v[zero];
ok &= (result == 2);
return ok;
}
# include <cppad/cppad.hpp>
bool DivEq(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = .5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 2;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = x[0] * x[0]; // initial value
y[0] /= 2; // AD<double> /= int
y[0] /= 4.; // AD<double> /= double
y[1] = y[0] /= x[0]; // use the result of a computed assignment
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0*x0/(2.*4.*x0), 1e-10 , 1e-10);
ok &= NearEqual(y[1] , y[0], 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1./8., 1e-10, 1e-10);
ok &= NearEqual(dy[1], 1./8., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
w[1] = 0.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1./8., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with computed division
CppAD::VecAD<double> v(1);
AD<double> zero(0);
AD<double> result = 2;
v[zero] = 1;
result /= v[zero];
ok &= (result == 2);
return ok;
}
y = fun(x)
const AD<Base> &x
const VecAD<Base>::reference &x
AD<Base> y
acos,
asin,
atan,
cos,
cosh,
exp,
log,
log10,
sin,
sinh,
sqrt,
tan,
tanh.
| 4.4.2.1: Acos.cpp | The AD acos Function: Example and Test |
| 4.4.2.2: Asin.cpp | The AD asin Function: Example and Test |
| 4.4.2.3: Atan.cpp | The AD atan Function: Example and Test |
| 4.4.2.4: Cos.cpp | The AD cos Function: Example and Test |
| 4.4.2.5: Cosh.cpp | The AD cosh Function: Example and Test |
| 4.4.2.6: Exp.cpp | The AD exp Function: Example and Test |
| 4.4.2.7: Log.cpp | The AD log Function: Example and Test |
| 4.4.2.8: Log10.cpp | The AD log10 Function: Example and Test |
| 4.4.2.9: Sin.cpp | The AD sin Function: Example and Test |
| 4.4.2.10: Sinh.cpp | The AD sinh Function: Example and Test |
| 4.4.2.11: Sqrt.cpp | The AD sqrt Function: Example and Test |
| 4.4.2.12: Tan.cpp | The AD tan Function: Example and Test |
| 4.4.2.13: Tanh.cpp | The AD tanh Function: Example and Test |
\[
\begin{array}{lcr}
\D{[ {\rm acos} (x) ]}{x} & = & - (1 - x * x)^{-1/2}
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ {\rm asin} (x) ]}{x} & = & (1 - x * x)^{-1/2}
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ {\rm atan} (x) ]}{x} & = & \frac{1}{1 + x^2}
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ \cos (x) ]}{x} & = & - \sin (x) \\
\D{[ \sin (x) ]}{x} & = & \cos (x)
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ \cosh (x) ]}{x} & = & \sinh (x) \\
\D{[ \sin (x) ]}{x} & = & \cosh (x)
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ \exp (x) ]}{x} & = & \exp (x)
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ \log (x) ]}{x} & = & \frac{1}{x}
\end{array}
\]
\[
\begin{array}{lcr}
{\rm log10} (x) & = & \log(x) / \log(10)
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ \sin (x) ]}{x} & = & \cos (x) \\
\D{[ \cos (x) ]}{x} & = & - \sin (x)
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ \sinh (x) ]}{x} & = & \cosh (x) \\
\D{[ \cosh (x) ]}{x} & = & \sinh (x)
\end{array}
\]
\[
\begin{array}{lcr}
\D{[ {\rm sqrt} (x) ]}{x} & = & \frac{1}{2 {\rm sqrt} (x) }
\end{array}
\]
\[
\begin{array}{lcr}
\tan (x) & = & \sin(x) / \cos(x)
\end{array}
\]
\[
\begin{array}{lcr}
\tanh (x) & = & \sinh(x) / \cosh(x)
\end{array}
\]
# include <cppad/cppad.hpp>
bool Acos(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// a temporary value
AD<double> cos_of_x0 = CppAD::cos(x[0]);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::acos(cos_of_x0);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with acos
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = cos_of_x0;
AD<double> result = CppAD::acos(v[zero]);
ok &= NearEqual(result, x0, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
bool Asin(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// a temporary value
AD<double> sin_of_x0 = CppAD::sin(x[0]);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::asin(sin_of_x0);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with asin
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = sin_of_x0;
AD<double> result = CppAD::asin(v[zero]);
ok &= NearEqual(result, x0, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
bool Atan(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// a temporary value
AD<double> tan_of_x0 = CppAD::tan(x[0]);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::atan(tan_of_x0);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with atan
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = tan_of_x0;
AD<double> result = CppAD::atan(v[zero]);
ok &= NearEqual(result, x0, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool Cos(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::cos(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::cos(x0);
ok &= NearEqual(y[0] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = - std::sin(x0);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with cos
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::cos(v[zero]);
check = std::cos(x0);
ok &= NearEqual(result, check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool Cosh(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::cosh(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::cosh(x0);
ok &= NearEqual(y[0] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = std::sinh(x0);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with cosh
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::cosh(v[zero]);
check = std::cosh(x0);
ok &= NearEqual(result, check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool Exp(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::exp(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::exp(x0);
ok &= NearEqual(y[0] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = std::exp(x0);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with exp
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::exp(v[zero]);
ok &= NearEqual(result, check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
bool Log(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// a temporary value
AD<double> exp_of_x0 = CppAD::exp(x[0]);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::log(exp_of_x0);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with log
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = exp_of_x0;
AD<double> result = CppAD::log(v[zero]);
ok &= NearEqual(result, x0, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
bool Log10(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// ten raised to the x0 power
AD<double> ten = 10.;
AD<double> pow_10_x0 = CppAD::pow(ten, x[0]);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::log10(pow_10_x0);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with log10
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = pow_10_x0;
AD<double> result = CppAD::log10(v[zero]);
ok &= NearEqual(result, x0, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool Sin(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::sin(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::sin(x0);
ok &= NearEqual(y[0] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = std::cos(x0);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with sin
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::sin(v[zero]);
check = std::sin(x0);
ok &= NearEqual(result, check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool Sinh(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::sinh(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::sinh(x0);
ok &= NearEqual(y[0] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = std::cosh(x0);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with sinh
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::sinh(v[zero]);
check = std::sinh(x0);
ok &= NearEqual(result, check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool Sqrt(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::sqrt(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::sqrt(x0);
ok &= NearEqual(y[0] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = 1. / (2. * std::sqrt(x0) );
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with sqrt
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::sqrt(v[zero]);
check = std::sqrt(x0);
ok &= NearEqual(result, check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
# include <limits>
bool Tan(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
double eps = 10. * std::numeric_limits<double>::epsilon();
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::tan(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::tan(x0);
ok &= NearEqual(y[0] , check, eps, eps);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = 1. + std::tan(x0) * std::tan(x0);
ok &= NearEqual(dy[0], check, eps, eps);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, eps, eps);
// use a VecAD<Base>::reference object with tan
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::tan(v[zero]);
check = std::tan(x0);
ok &= NearEqual(result, check, eps, eps);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
# include <limits>
bool Tanh(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
double eps = 10. * std::numeric_limits<double>::epsilon();
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::tanh(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check = std::tanh(x0);
ok &= NearEqual(y[0] , check, eps, eps);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
check = 1. - std::tanh(x0) * std::tanh(x0);
ok &= NearEqual(dy[0], check, eps, eps);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, eps, eps);
// use a VecAD<Base>::reference object with tan
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::tanh(v[zero]);
check = std::tanh(x0);
ok &= NearEqual(result, check, eps, eps);
return ok;
}
| 4.4.3.1: abs | AD Absolute Value Function |
| 4.4.3.2: atan2 | AD Two Argument Inverse Tangent Function |
| 4.4.3.3: erf | The AD Error Function |
| 4.4.3.4: pow | The AD Power Function |
y = abs(x)
const AD<Base> &x
const VecAD<Base>::reference &x
AD<Base> y
abs is not defined for the AD type sequences
above std::complex<float> or std::complex<double>
because the complex abs function is not complex differentiable
(see 9.1.d: complex types faq
).
x > 0
and minus one for
x < 0
.
The subtitle issue is
how to compute its directional derivative
what
x = 0
.
The function corresponding to the argument x
and the result y are represented
by their Taylor coefficients; i.e.,
\[
\begin{array}{rcl}
X(t) & = & x^{(0)} (t) + x^{(1)} t + \cdots + x^{(p)} t^p
\\
Y(t) & = & y^{(0)} (t) + y^{(1)} t + \cdots + y^{(p)} t^p
\end{array}
\]
Note that
x^{(0)} = X(0)
is the value of x and
y^{(0)} = Y(0)
is the value of y.
In the equations above, the order
p
is specified
by a call to 5.6.1: Forward
or 5.6.2: Reverse
as follows:
f.Forward(p, dx)
f.Reverse(p+1, w)
If all of the Taylor coefficients of
X(t)
are zero,
we define
k = p
.
Otherwise, we define
k
to be the minimal index such that
x^{(k)} \neq 0
.
Note that if
x \neq 0
,
k = 0
.
The Taylor coefficient representation of
Y(t)
(and hence it's derivatives) are computed as
\[
y^{(\ell)}
=
\left\{ \begin{array}{ll}
x^{(\ell)} & {\rm if} \; x^{(k)} > 0 \\
0 & {\rm if} \; x^{(k)} = 0 \\
- x^{(\ell)} & {\rm if} \; x^{(k)} < 0
\end{array} \right.
\]
# include <cppad/cppad.hpp>
bool Abs(void)
{ bool ok = true;
using CppAD::abs;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = 0.;
// declare independent variables and start tape recording
CppAD::Independent(x);
// range space vector
size_t m = 3;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = abs(x[0] - 1.);
y[1] = abs(x[0]);
y[2] = abs(x[0] + 1.);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check values
ok &= (y[0] == 1.);
ok &= (y[1] == 0.);
ok &= (y[2] == 1.);
// forward computation of partials w.r.t. a positive x[0] direction
size_t p = 1;
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(p, dx);
ok &= (dy[0] == - dx[0]);
ok &= (dy[1] == + dx[0]);
ok &= (dy[2] == + dx[0]);
// forward computation of partials w.r.t. a negative x[0] direction
dx[0] = -1.;
dy = f.Forward(p, dx);
ok &= (dy[0] == - dx[0]);
ok &= (dy[1] == - dx[0]);
ok &= (dy[2] == + dx[0]);
// reverse computation of derivative of y[0]
p = 0;
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.; w[1] = 0.; w[2] = 0.;
dw = f.Reverse(p+1, w);
ok &= (dw[0] == -1.);
// reverse computation of derivative of y[1]
w[0] = 0.; w[1] = 1.; w[2] = 0.;
dw = f.Reverse(p+1, w);
ok &= (dw[0] == 0.);
// reverse computation of derivative of y[2]
w[0] = 0.; w[1] = 0.; w[2] = 1.;
dw = f.Reverse(p+1, w);
ok &= (dw[0] == 1.);
// use a VecAD<Base>::reference object with abs
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = -1;
AD<double> result = abs(v[zero]);
ok &= NearEqual(result, 1., 1e-10, 1e-10);
return ok;
}
theta = atan2(y, x)
\theta \in [ - \pi , + \pi ]
such that
\[
\begin{array}{rcl}
\sin ( \theta ) & = & y / \sqrt{ x^2 + y^2 } \\
\cos ( \theta ) & = & x / \sqrt{ x^2 + y^2 }
\end{array}
\]
const AD<Base> &y
const VecAD<Base>::reference &y
const AD<Base> &x
const VecAD<Base>::reference &x
AD<Base> theta
# include <cppad/cppad.hpp>
bool Atan2(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// a temporary value
AD<double> sin_of_x0 = CppAD::sin(x[0]);
AD<double> cos_of_x0 = CppAD::cos(x[0]);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::atan2(sin_of_x0, cos_of_x0);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 1., 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 1., 1e-10, 1e-10);
// use a VecAD<Base>::reference object with atan2
CppAD::VecAD<double> v(2);
AD<double> zero(0);
AD<double> one(1);
v[zero] = sin_of_x0;
v[one] = cos_of_x0;
AD<double> result = CppAD::atan2(v[zero], v[one]);
ok &= NearEqual(result, x0, 1e-10, 1e-10);
return ok;
}
y = erf(x)
\[
{\rm erf} (x) = \frac{2}{ \sqrt{\pi} } \int_0^x \exp( - t * t ) \; {\bf d} t
\]
x
, and the result
y
have one of the following paris of prototypes:
const float &x, float y
const double &x, double y
const AD<Base> &x, AD<Base> y
const VecAD<Base>::reference &x, AD<Base> y
Base
operation sequence used to calculate
y
is
9.4.g.d: independent
of
x
.
4 \times 10^{-4}
; see
Vedder, J.D.,
Simple approximations for the error function and its inverse,
American Journal of Physics,
v 55,
n 8,
1987,
p 762-3.
# include <cppad/cppad.hpp>
# include <cmath>
# include <limits>
bool Erf(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
double eps = 10. * std::numeric_limits<double>::epsilon();
// domain space vector
size_t n = 1;
double x0 = 0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
// declare independent variables and start tape recording
CppAD::Independent(x);
// a temporary value
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = CppAD::erf(x[0]);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check relative erorr
double erf_x0 = 0.5205;
ok &= NearEqual(y[0] , erf_x0, 4e-4 , 0.);
// value of derivative of erf at x0
double pi = 4. * std::atan(1.);
double factor = 2. / sqrt(pi);
double check = factor * std::exp(-x0 * x0);
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], check, 4e-4, 0.);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], check, 4e-4, 0.);
// use a VecAD<Base>::reference object with erf
CppAD::VecAD<double> v(1);
AD<double> zero(0);
v[zero] = x0;
AD<double> result = CppAD::erf(v[zero]);
ok &= NearEqual(result, y[0], eps, eps);
// use a double with erf
ok &= NearEqual(CppAD::erf(x0), y[0], eps, eps);
return ok;
}
z = pow(x, y)
\[
{\rm pow} (x, y) = x^y
\]
This version of the pow function may use
logarithms and exponentiation to compute derivatives.
This will not work if x is less than or equal zero.
If the value of y is an integer,
the 6.10: pow_int
function is used to compute this value
using only multiplication (and division if y is negative).
(This will work even if x is less than or equal zero.)
const Type &x
where Type is
VecAD<Base>::reference,
AD<Base>,
Base,
double,
or
int.
const Type &y
where Type is
VecAD<Base>::reference,
AD<Base>,
Base,
double,
or
int.
AD<Base> z
pow function is included
in the CppAD namespace for the case where both x
and y have the same type and that type is
float or double.
# include <cppad/cppad.hpp>
# include <cmath>
bool Pow(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 2;
double x = 0.5;
double y = 2.;
CPPAD_TEST_VECTOR< AD<double> > XY(n);
XY[0] = x;
XY[1] = y;
// declare independent variables and start tape recording
CppAD::Independent(XY);
// range space vector
size_t m = 3;
CPPAD_TEST_VECTOR< AD<double> > Z(m);
Z[0] = CppAD::pow(XY[0], XY[1]); // pow(variable, variable)
Z[1] = CppAD::pow(XY[0], y); // pow(variable, parameter)
Z[2] = CppAD::pow(x, XY[1]); // pow(parameter, variable)
// create f: XY -> Z and stop tape recording
CppAD::ADFun<double> f(XY, Z);
// check value
double check = std::pow(x, y);
size_t i;
for(i = 0; i < m; i++)
ok &= NearEqual(Z[i] , check, 1e-10 , 1e-10);
// forward computation of first partial w.r.t. x
CPPAD_TEST_VECTOR<double> dxy(n);
CPPAD_TEST_VECTOR<double> dz(m);
dxy[0] = 1.;
dxy[1] = 0.;
dz = f.Forward(1, dxy);
check = y * std::pow(x, y-1.);
ok &= NearEqual(dz[0], check, 1e-10, 1e-10);
ok &= NearEqual(dz[1], check, 1e-10, 1e-10);
ok &= NearEqual(dz[2], 0., 1e-10, 1e-10);
// forward computation of first partial w.r.t. y
dxy[0] = 0.;
dxy[1] = 1.;
dz = f.Forward(1, dxy);
check = std::log(x) * std::pow(x, y);
ok &= NearEqual(dz[0], check, 1e-10, 1e-10);
ok &= NearEqual(dz[1], 0., 1e-10, 1e-10);
ok &= NearEqual(dz[2], check, 1e-10, 1e-10);
// reverse computation of derivative of z[0] + z[1] + z[2]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
w[1] = 1.;
w[2] = 1.;
dw = f.Reverse(1, w);
check = y * std::pow(x, y-1.);
ok &= NearEqual(dw[0], 2. * check, 1e-10, 1e-10);
check = std::log(x) * std::pow(x, y);
ok &= NearEqual(dw[1], 2. * check, 1e-10, 1e-10);
// use a VecAD<Base>::reference object with pow
CppAD::VecAD<double> v(2);
AD<double> zero(0);
AD<double> one(1);
v[zero] = XY[0];
v[one] = XY[1];
AD<double> result = CppAD::pow(v[zero], v[one]);
ok &= NearEqual(result, Z[0], 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cmath>
bool pow_int(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// declare independent variables and start tape recording
size_t n = 1;
double x0 = -0.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
CppAD::Independent(x);
// dependent variable vector
size_t m = 7;
CPPAD_TEST_VECTOR< AD<double> > y(m);
int i;
for(i = 0; i < int(m); i++)
y[i] = CppAD::pow(x[0], i - 3);
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
double check;
for(i = 0; i < int(m); i++)
{ check = std::pow(x0, double(i - 3));
ok &= NearEqual(y[i] , check, 1e-10 , 1e-10);
}
// forward computation of first partial w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dy = f.Forward(1, dx);
for(i = 0; i < int(m); i++)
{ check = double(i-3) * std::pow(x0, double(i - 4));
ok &= NearEqual(dy[i] , check, 1e-10 , 1e-10);
}
// reverse computation of derivative of y[i]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
for(i = 0; i < int(m); i++)
w[i] = 0.;
for(i = 0; i < int(m); i++)
{ w[i] = 1.;
dw = f.Reverse(1, w);
check = double(i-3) * std::pow(x0, double(i - 4));
ok &= NearEqual(dw[0] , check, 1e-10 , 1e-10);
w[i] = 0.;
}
return ok;
}
result = CondExpRel(left, right, exp_if_true, exp_if_false)
Base
9.4.g.b: operation sequence
,
the conditional result
if( left Cop right )
result = exp_if_true
else result = exp_if_false
The relational
Rel
and comparison operator
Cop
above have the following correspondence:
Rel
|
Lt
|
Le
|
Eq
|
Ge
|
Gt
|
Cop
|
<
|
<=
|
==
|
>=
|
>
|
f
is the 5: ADFun
object corresponding to the
AD operation sequence,
the assignment choice for
result
in an AD conditional expression is made each time
5.6.1: f.Forward
is used to evaluate the zero order Taylor
coefficients with new values for the
9.4.j.c: independent variables
.
This is in contrast to the 4.5.1: AD comparison operators
which are boolean valued and not included in the AD operation sequence.
Rel
represents one of the following
two characters: Lt, Le, Eq, Ge, Gt.
As in the table above,
Rel
determines which comparison operator
Cop
is used
when comparing
left
and
right
.
Type
is float , double, or any type of the form
AD<Base>
.
(Note that all four arguments must have the same type.)
left
has prototype
const Type &left
It specifies the value for the left side of the comparison operator.
right
has prototype
const Type &right
It specifies the value for the right side of the comparison operator.
exp_if_true
has prototype
const Type &exp_if_true
It specifies the return value if the result of the comparison is true.
exp_if_false
has prototype
const Type &exp_if_false
It specifies the return value if the result of the comparison is false.
result
has prototype
Type &exp_if_false
CondExp(flag, exp_if_true, exp_if_false)
for the same meaning as
CondExpGt(flag, Type(0), exp_if_true, exp_if_false)
Use of CondExp is deprecated, but continues to be supported.
Base
9.4.g.a: atomic operation
and hence is part of the current
AD of
Base
9.4.g.b: operation sequence
.
template <class Base>
AD<Base> atan2 (const AD<Base> &y, const AD<Base> &x)
{ AD<Base> alpha;
AD<Base> beta;
AD<Base> theta;
AD<Base> zero = 0;
AD<Base> pi2 = 2. * atan(1.);
AD<Base> pi = 2. * pi2;
AD<Base> ax = abs(x);
AD<Base> ay = abs(y);
// if( ax > ay )
// theta = atan(ay / ax);
// else theta = pi2 - atan(ax / ay);
alpha = atan(ay / ax);
beta = pi2 - atan(ax / ay);
theta = CondExpGt(ax, ay, alpha, beta); // use of CondExp
// if( x <= 0 )
// theta = pi - theta;
theta = CondExpLe(x, zero, pi - theta, theta); // use of CondExp
// if( y <= 0 )
// theta = - theta;
theta = CondExpLe(y, zero, -theta, theta); // use of CondExp
return theta;
}
CondExp to compute
\[
f(x) = \sum_{j=0}^{m-1} x_j \log( x_j )
\]
and its derivative at various argument values
( where
x_j \geq 0
)
with out having to re-tape; i.e.,
using only one 5: ADFun
object.
Note that
x_j \log ( x_j ) \rightarrow 0
as
x_j \downarrow 0
and
we need to handle the case
x_j = 0
in a special way to avoid multiplying zero by infinity.
# include <cppad/cppad.hpp>
# include <limits>
bool CondExp(void)
{ bool ok = true;
using CppAD::isnan;
using CppAD::AD;
using CppAD::NearEqual;
using CppAD::log;
using CppAD::abs;
double eps = 100. * std::numeric_limits<double>::epsilon();
double fmax = std::numeric_limits<double>::max();
// domain space vector
size_t n = 5;
CPPAD_TEST_VECTOR< AD<double> > X(n);
size_t j;
for(j = 0; j < n; j++)
X[j] = 1.;
// declare independent variables and start tape recording
CppAD::Independent(X);
AD<double> Sum = 0.;
AD<double> Zero = 0.;
for(j = 0; j < n; j++)
{ // if x_j > 0, add x_j * log( x_j ) to the sum
Sum += CppAD::CondExpGt(X[j], Zero, X[j] * log(X[j]), Zero);
}
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > Y(m);
Y[0] = Sum;
// create f: X -> Y and stop tape recording
CppAD::ADFun<double> f(X, Y);
// vectors for arguments to the function object f
CPPAD_TEST_VECTOR<double> x(n); // argument values
CPPAD_TEST_VECTOR<double> y(m); // function values
CPPAD_TEST_VECTOR<double> w(m); // function weights
CPPAD_TEST_VECTOR<double> dw(n); // derivative of weighted function
// a case where x[j] > 0 for all j
double check = 0.;
for(j = 0; j < n; j++)
{ x[j] = double(j + 1);
check += x[j] * log( x[j] );
}
// function value
y = f.Forward(0, x);
ok &= NearEqual(y[0], check, eps, eps);
// compute derivative of y[0]
w[0] = 1.;
dw = f.Reverse(1, w);
for(j = 0; j < n; j++)
ok &= NearEqual(dw[j], log(x[j]) + 1., eps, eps);
// a case where x[3] is equal to zero
check -= x[3] * log( x[3] );
x[3] = 0.;
// function value
y = f.Forward(0, x);
ok &= NearEqual(y[0], check, eps, eps);
// check derivative of y[0]
w[0] = 1.;
dw = f.Reverse(1, w);
for(j = 0; j < n; j++)
{ if( x[j] > 0 )
ok &= NearEqual(dw[j], log(x[j]) + 1., eps, eps);
else
{ // In this case computing dw[j] is computed using
// log(x[j]) + x[j] / x[j]
// which has limit minus infinity but computes as nan.
ok &= ( isnan( dw[j] ) || dw[j] <= -fmax );
}
}
return ok;
}
CPPAD_DISCRETE_FUNCTION(Base, name)
v = name(u)
y = name(x)
AD<Base>
9.4.g.b: operation sequence
.
The value of a discrete function can depend on the
9.4.j.c: independent variables
,
but its derivative is identically zero.
For example, suppose that the integer part of
a 9.4.l: variable
x is the
index into an array of values.
AD<Base> can be recorded in an operation sequence.
AD<Base>.
const Base &u
It is the value at which the user provided version of name
is to be evaluated.
Base v
It is the return value for the user provided version of name.
const AD<Base> &x
It is the value at which the CppAD provided version of name
is to be evaluated.
AD<Base> v
It is the return value for the CppAD provided version of name.
CPPAD_DISCRETE_FUNCTION(Base, name)
defines the AD<Base> version of name.
This can be with in a namespace (not the CppAD namespace)
but must be outside of any routine.
CppADCreateDiscrete
is defined to be the same as CPPAD_DISCRETE_FUNCTION
but its use is deprecated.
# include <cppad/cppad.hpp>
namespace {
double Array(const double &index)
{ static double array[] = {
5.,
4.,
3.,
2.,
1.
};
static size_t number = sizeof(array) / sizeof(array[0]);
if( index < 0. )
return array[0];
size_t i = static_cast<size_t>(index);
if( i >= number )
return array[number-1];
return array[i];
}
// in empty namespace and outside any other routine
CPPAD_DISCRETE_FUNCTION(double, Array)
}
bool TapeIndex(void)
{ bool ok = true;
using CppAD::AD;
// domain space vector
size_t n = 2;
CPPAD_TEST_VECTOR< AD<double> > X(n);
X[0] = 2.; // array index value
X[1] = 3.; // multiplier of array index value
// declare independent variables and start tape recording
CppAD::Independent(X);
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > Y(m);
Y[0] = X[1] * Array( X[0] );
// create f: X -> Y and stop tape recording
CppAD::ADFun<double> f(X, Y);
// vectors for arguments to the function object f
CPPAD_TEST_VECTOR<double> x(n); // argument values
CPPAD_TEST_VECTOR<double> y(m); // function values
CPPAD_TEST_VECTOR<double> w(m); // function weights
CPPAD_TEST_VECTOR<double> dw(n); // derivative of weighted function
// check function value
x[0] = Value(X[0]);
x[1] = Value(X[1]);
y[0] = Value(Y[0]);
ok &= y[0] == x[1] * Array(x[0]);
// evaluate f where x has different values
x[0] = x[0] + 1.; // new array index value
x[1] = x[1] + 1.; // new multiplier value
y = f.Forward(0, x);
ok &= y[0] == x[1] * Array(x[0]);
// evaluate derivaitve of y[0]
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= dw[0] == 0.; // partial w.r.t array index
ok &= dw[1] == Array(x[0]); // partial w.r.t multiplier
return ok;
}
# include <cppad/cppad.hpp>
# include <cassert>
# include <cmath>
namespace {
double ArgumentValue[] = {
.0 ,
.2 ,
.4 ,
.8 ,
1.
};
double FunctionValue[] = {
std::sin( ArgumentValue[0] ) ,
std::sin( ArgumentValue[1] ) ,
std::sin( ArgumentValue[2] ) ,
std::sin( ArgumentValue[3] ) ,
std::sin( ArgumentValue[4] )
};
size_t TableLength = 5;
size_t Index(const double &x)
{ // determine the index j such that x is between
// ArgumentValue[j] and ArgumentValue[j+1]
static size_t j = 0;
while ( x < ArgumentValue[j] && j > 0 )
j--;
while ( x > ArgumentValue[j+1] && j < TableLength - 2)
j++;
// assert conditions that must be true given logic above
assert( j >= 0 && j < TableLength - 1 );
return j;
}
double Argument(const double &x)
{ size_t j = Index(x);
return ArgumentValue[j];
}
double Function(const double &x)
{ size_t j = Index(x);
return FunctionValue[j];
}
double Slope(const double &x)
{ size_t j = Index(x);
double dx = ArgumentValue[j+1] - ArgumentValue[j];
double dy = FunctionValue[j+1] - FunctionValue[j];
return dy / dx;
}
CPPAD_DISCRETE_FUNCTION(double, Argument)
CPPAD_DISCRETE_FUNCTION(double, Function)
CPPAD_DISCRETE_FUNCTION(double, Slope)
}
bool interp_onetape(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > X(n);
X[0] = .4 * ArgumentValue[1] + .6 * ArgumentValue[2];
// declare independent variables and start tape recording
CppAD::Independent(X);
// evaluate piecewise linear interpolant at X[0]
AD<double> A = Argument(X[0]);
AD<double> F = Function(X[0]);
AD<double> S = Slope(X[0]);
AD<double> I = F + (X[0] - A) * S;
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > Y(m);
Y[0] = I;
// create f: X -> Y and stop tape recording
CppAD::ADFun<double> f(X, Y);
// vectors for arguments to the function object f
CPPAD_TEST_VECTOR<double> x(n); // argument values
CPPAD_TEST_VECTOR<double> y(m); // function values
CPPAD_TEST_VECTOR<double> dx(n); // differentials in x space
CPPAD_TEST_VECTOR<double> dy(m); // differentials in y space
// to check function value we use the fact that X[0] is between
// ArgumentValue[1] and ArgumentValue[2]
x[0] = Value(X[0]);
double delta = ArgumentValue[2] - ArgumentValue[1];
double check = FunctionValue[2] * (x[0] - ArgumentValue[1]) / delta
+ FunctionValue[1] * (ArgumentValue[2] - x[0]) / delta;
ok &= NearEqual(Y[0], check, 1e-10, 1e-10);
// evaluate f where x has different value
x[0] = .7 * ArgumentValue[2] + .3 * ArgumentValue[3];
y = f.Forward(0, x);
// check function value
delta = ArgumentValue[3] - ArgumentValue[2];
check = FunctionValue[3] * (x[0] - ArgumentValue[2]) / delta
+ FunctionValue[2] * (ArgumentValue[3] - x[0]) / delta;
ok &= NearEqual(y[0], check, 1e-10, 1e-10);
// evaluate partials w.r.t. x[0]
dx[0] = 1.;
dy = f.Forward(1, dx);
// check that the derivative is the slope
check = (FunctionValue[3] - FunctionValue[2])
/ (ArgumentValue[3] - ArgumentValue[2]);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
return ok;
}
# include <cppad/cppad.hpp>
# include <cassert>
# include <cmath>
namespace {
double ArgumentValue[] = {
.0 ,
.2 ,
.4 ,
.8 ,
1.
};
double FunctionValue[] = {
std::sin( ArgumentValue[0] ) ,
std::sin( ArgumentValue[1] ) ,
std::sin( ArgumentValue[2] ) ,
std::sin( ArgumentValue[3] ) ,
std::sin( ArgumentValue[4] )
};
size_t TableLength = 5;
size_t Index(const CppAD::AD<double> &x)
{ // determine the index j such that x is between
// ArgumentValue[j] and ArgumentValue[j+1]
static size_t j = 0;
while ( x < ArgumentValue[j] && j > 0 )
j--;
while ( x > ArgumentValue[j+1] && j < TableLength - 2)
j++;
// assert conditions that must be true given logic above
assert( j >= 0 && j < TableLength - 1 );
return j;
}
double Argument(const CppAD::AD<double> &x)
{ size_t j = Index(x);
return ArgumentValue[j];
}
double Function(const CppAD::AD<double> &x)
{ size_t j = Index(x);
return FunctionValue[j];
}
double Slope(const CppAD::AD<double> &x)
{ size_t j = Index(x);
double dx = ArgumentValue[j+1] - ArgumentValue[j];
double dy = FunctionValue[j+1] - FunctionValue[j];
return dy / dx;
}
}
bool interp_retape(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// domain space vector
size_t n = 1;
CPPAD_TEST_VECTOR< AD<double> > X(n);
// loop over argument values
size_t k;
for(k = 0; k < TableLength - 1; k++)
{
X[0] = .4 * ArgumentValue[k] + .6 * ArgumentValue[k+1];
// declare independent variables and start tape recording
// (use a different tape for each argument value)
CppAD::Independent(X);
// evaluate piecewise linear interpolant at X[0]
AD<double> A = Argument(X[0]);
AD<double> F = Function(X[0]);
AD<double> S = Slope(X[0]);
AD<double> I = F + (X[0] - A) * S;
// range space vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > Y(m);
Y[0] = I;
// create f: X -> Y and stop tape recording
CppAD::ADFun<double> f(X, Y);
// vectors for arguments to the function object f
CPPAD_TEST_VECTOR<double> x(n); // argument values
CPPAD_TEST_VECTOR<double> y(m); // function values
CPPAD_TEST_VECTOR<double> dx(n); // differentials in x space
CPPAD_TEST_VECTOR<double> dy(m); // differentials in y space
// to check function value we use the fact that X[0] is between
// ArgumentValue[k] and ArgumentValue[k+1]
double delta, check;
x[0] = Value(X[0]);
delta = ArgumentValue[k+1] - ArgumentValue[k];
check = FunctionValue[k+1] * (x[0]-ArgumentValue[k]) / delta
+ FunctionValue[k] * (ArgumentValue[k+1]-x[0]) / delta;
ok &= NearEqual(Y[0], check, 1e-10, 1e-10);
// evaluate partials w.r.t. x[0]
dx[0] = 1.;
dy = f.Forward(1, dx);
// check that the derivative is the slope
check = (FunctionValue[k+1] - FunctionValue[k])
/ (ArgumentValue[k+1] - ArgumentValue[k]);
ok &= NearEqual(dy[0], check, 1e-10, 1e-10);
}
return ok;
}
| 4.5.1: Compare | AD Binary Comparison Operators |
| 4.5.2: NearEqualExt | Compare AD and Base Objects for Nearly Equal |
| 4.5.3: BoolFun | AD Boolean Functions |
| 4.5.4: ParVar | Is an AD Object a Parameter or Variable |
| 4.5.5: EqualOpSeq | Check if Equal and Correspond to Same Operation Sequence |
b = x Op y
AD<Base> object.
The comparison has the same interpretation as for
the Base type.
Op | Meaning |
< | is x less than y |
<= | is x less than or equal y |
> | is x greater than y |
>= | is x greater than or equal y |
== | is x equal to y |
!= | is x not equal to y |
const Type &x
where Type is AD<Base>, Base, or int.
const Type &y
where Type is AD<Base>, Base, or int.
bool b
bool value
(not an 9.4.b: AD of Base
object).
Thus it will not be recorded as part of an
AD of Base
9.4.g.b: operation sequence
.
For example, suppose
x and y are AD<Base> objects,
the tape corresponding to AD<Base> is recording,
b is true,
and the subsequent code is
if( b )
y = cos(x);
else y = sin(x);
only the assignment y = cos(x) is recorded on the tape
(if x is a 9.4.h: parameter
,
nothing is recorded).
The 5.6.1.5: CompareChange
function can yield
some information about changes in comparison operation results.
You can use 4.4.4: CondExp
to obtain comparison operations
that depends on the
9.4.j.c: independent variable
values with out re-taping the AD sequence of operations.
AD<Base> object,
it is assumed that the same operator is supported by the base type
Base.
# include <cppad/cppad.hpp>
bool Compare(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
// declare independent variables and start tape recording
size_t n = 2;
double x0 = 0.5;
double x1 = 1.5;
CPPAD_TEST_VECTOR< AD<double> > x(n);
x[0] = x0;
x[1] = x1;
CppAD::Independent(x);
// some binary comparision operations
AD<double> p;
if( x[0] < x[1] )
p = x[0]; // values in x choose this case
else p = x[1];
if( x[0] <= x[1] )
p *= x[0]; // values in x choose this case
else p *= x[1];
if( x[0] > x[1] )
p *= x[0];
else p *= x[1]; // values in x choose this case
if( x[0] >= x[1] )
p *= x[0];
else p *= x[1]; // values in x choose this case
if( x[0] == x[1] )
p *= x[0];
else p *= x[1]; // values in x choose this case
if( x[0] != x[1] )
p *= x[0]; // values in x choose this case
else p *= x[1];
// dependent variable vector
size_t m = 1;
CPPAD_TEST_VECTOR< AD<double> > y(m);
y[0] = p;
// create f: x -> y and stop tape recording
CppAD::ADFun<double> f(x, y);
// check value
ok &= NearEqual(y[0] , x0*x0*x1*x1*x1*x0, 1e-10 , 1e-10);
// forward computation of partials w.r.t. x[0]
CPPAD_TEST_VECTOR<double> dx(n);
CPPAD_TEST_VECTOR<double> dy(m);
dx[0] = 1.;
dx[1] = 0.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 3.*x0*x0*x1*x1*x1, 1e-10, 1e-10);
// forward computation of partials w.r.t. x[1]
dx[0] = 0.;
dx[1] = 1.;
dy = f.Forward(1, dx);
ok &= NearEqual(dy[0], 3.*x0*x0*x1*x1*x0, 1e-10, 1e-10);
// reverse computation of derivative of y[0]
CPPAD_TEST_VECTOR<double> w(m);
CPPAD_TEST_VECTOR<double> dw(n);
w[0] = 1.;
dw = f.Reverse(1, w);
ok &= NearEqual(dw[0], 3.*x0*x0*x1*x1*x1, 1e-10, 1e-10);
ok &= NearEqual(dw[1], 3.*x0*x0*x1*x1*x0, 1e-10, 1e-10);
return ok;
}
b = NearEqual(x, y, r, a)
AD<Type> or
AD< std::complex<Type> >.
const Type &x
const AD<Type> &x
const AD< std::complex<Type> > &x
const Type &y
const AD<Type> &y
const AD< std::complex<Type> > &x
const Type &r
It must be greater than or equal to zero.
The relative error condition is defined as:
\[
\frac{ | x - y | } { |x| + |y| } \leq r
\]
const Type &a
It must be greater than or equal to zero.
The absolute error condition is defined as:
\[
| x - y | \leq a
\]
bool b
If either x or y is infinite or not a number,
the return value is false.
Otherwise, if either the relative or absolute error
condition (defined above) is satisfied, the return value is true.
Otherwise, the return value is false.
| Operation | Description |
a <= b |
less that or equal operator (returns a bool object)
|
# include <cppad/cppad.hpp>
# include <complex>
bool NearEqualExt(void)
{ bool ok = true;
using