/* nag::ad::c05au Adjoint Example Program.
*/
#include <dco.hpp>
#include <iostream>
#include <nagad.h>
// Function which calls NAG AD Library routines.
template <typename T> void func(T r, T &x);
// Driver with the adjoint calls.
// Finds the zero point f(xv) = 0 for the function
// f(x) = x - exp(-r*x) using an initial approximation of xv.
// Also, computes the gradient dxdr = dxv/dr.
void driver(const double &rv, double &xv, double &dxdr);
// The function f
template <typename T>
void NAG_CALL f(void *&ad_handle, const T &x, T &z, Integer iuser[], T ruser[]);
int main()
{
std::cout << " nag::ad::c05au Adjoint Example Program Results\n";
// Set problem parameters
double rv = 1.0;
// Solution x
double xv;
// Derivative of x
double dxdr;
// Call driver
driver(rv, xv, dxdr);
// Print outputs
std::cout << "\n Derivatives calculated: First order adjoints\n";
std::cout << " Computational mode : algorithmic\n";
std::cout.setf(std::ios::scientific, std::ios::floatfield);
std::cout.precision(12);
std::cout << "\n Solution:\n";
std::cout << " x = " << xv << std::endl;
std::cout << "\n Derivative of solution x w.r.t. parameter r:\n";
std::cout << " dx/dr(x) = " << dxdr << std::endl;
return 0;
}
// Driver with the adjoint calls.
// Finds the zero point f(xv) = 0 for the function
// f(x) = x - exp(-r*x) using an initial approximation of xv.
// Also, computes the gradient dxdr = dxv/dr.
void driver(const double &rv, double &xv, double &dxdr)
{
using T = dco::ga1s<double>::type;
// Create the AD tape
dco::ga1s<double>::global_tape = dco::ga1s<double>::tape_t::create();
// Function parameter r
T r = rv;
// Register variable to differentiate w.r.t.
dco::ga1s<double>::global_tape->register_variable(r);
// Variable to differentiate
T x;
// Call the NAG AD Lib functions
func(r, x);
// Extract the computed solution
xv = dco::value(x);
dco::ga1s<double>::global_tape->register_output_variable(x);
dco::derivative(x) = 1.0;
dco::ga1s<double>::global_tape->interpret_adjoint();
// Extract the derivatives
dxdr = dco::derivative(r);
// Remove tape
dco::ga1s<double>::tape_t::remove(dco::ga1s<double>::global_tape);
}
// Function which calls NAG AD Library routines.
template <typename T> void func(T r, T &x)
{
// Active variables
T a, b, h = 0.1;
T eps = 1.0e-5, eta = 0.0;
// Initial guess to the zero
dco::passive_value(x) = 1.0;
// Create AD configuration data object
Integer ifail = 0;
void * ad_handle = 0;
nag::ad::x10aa(ad_handle, ifail);
// Routine for computing an approximation to a simple zero of the continuous
// function f using an initial approximation.
ifail = 0;
nag::ad::c05au(ad_handle, x, h, eps, eta, f<T>, a, b, 0, nullptr, 1, &r,
ifail);
// Remove computational data object
ifail = 0;
nag::ad::x10ab(ad_handle, ifail);
}
// Callback that evaluates the non-linear function
template <typename T>
void NAG_CALL f(void *&ad_handle, const T &x, T &z, Integer iuser[], T ruser[])
{
T r = ruser[0];
z = x - exp(-r * x);
}