NAG Library Manual, Mark 28.4
```/* nag::ad::d02pq Adjoint Example Program.
*/

#include <dco.hpp>
#include <iostream>

// Function which calls NAG AD routines.
template <typename T> void func(std::vector<T> &r, std::vector<T> &y);

// Driver with the adjoint calls.
// Solves the equation y''=-y, y0(=y(0))=0, y0'(=y'(0))=1 by solving the ODE
// system:
//    y1'=r1*y2,  y2'=-r2*y1
// over the range [0,2*pi] with initial conditions y1=0, y2=1.
// Also computes the sum of all Jacobian elements dy/dr.
void driver(const std::vector<double> &rv,
std::vector<double> &      yv,
double &                   dy_dr);

int main()
{

// Set problem parameters
std::vector<double> rv{1.0, 1.0};
// Solution y
std::vector<double> yv{0.0, 1.0};
// Sum of Jacobian elements
double dy_dr;

// Call driver
driver(rv, yv, dy_dr);

// 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(6);
std::cout << "\n Solution computed with required tolerance " << 1e-4
<< std::endl;
for (std::size_t i = 0; i < yv.size(); i++)
{
std::cout << " y" << i + 1 << " = " << yv[i] << std::endl;
}

// Print derivatives
std::cout
<< "\n Sum of all Jacobian elements of solution vector y w.r.t. problem parameters :\n";
std::cout << " sum_ij [dy/dr]_ij = " << dy_dr << std::endl;

return 0;
}

// Driver with the adjoint calls.
// Solves the equation y''=-y, y0(=y(0))=0, y0'(=y'(0))=1 by solving the ODE
// system:
//    y1'=r1*y2,  y2'=-r2*y1
// over the range [0,2*pi] with initial conditions y1=0, y2=1.
// Also computes the sum of all Jacobian elements dy/dr.
void driver(const std::vector<double> &rv,
std::vector<double> &      yv,
double &                   dy_dr)
{
using mode = dco::ga1s<double>;
using T    = mode::type;

mode::global_tape = mode::tape_t::create();

// Size of system of ODEs
Integer n = rv.size();
// Variables to differentiate w.r.t.
std::vector<T> r(begin(rv), end(rv));

// Register variables to differentiate w.r.t.
mode::global_tape->register_variable(r);

// Solution y, variable to differentiate
std::vector<T> y(begin(yv), end(yv));

// Call the NAG AD Lib functions
func(r, y);

// Extract the computed solutions
yv = dco::passive_value(y);
mode::global_tape->register_output_variable(y);
dco::derivative(y) = std::vector<double>(n, 1.0);

// Interpret the tape

// Sum the adjoints of r
dy_dr = 0;
for (T const &ri : r)
{
dy_dr += dco::derivative(ri);
}

// Remove tape
mode::tape_t::remove(mode::global_tape);
}

// function which calls NAG AD Library routines
template <typename T> void func(std::vector<T> &r, std::vector<T> &y)
{
// Active variables
const Integer n      = y.size();
const Integer liwsav = 130, lrwsav = 350 + 32 * n;

std::vector<T>       thresh(n, 1e-8), ypnow(n), rwsav(lrwsav);
std::vector<Integer> iwsav(liwsav);

// Set parameters for the integrator.
Integer method = 2;
T       tol = 1e-4, hstart = 0.0, tend = 2.0 * nag_math_pi, tstart = 0.0;
// Create AD configuration data object
Integer           ifail = 0;

// Initialize Runge-Kutta method for integrating ODE
ifail = 0;
method, hstart, iwsav.data(), rwsav.data(), ifail);

T tnow = tstart;

const T &          t,
const Integer &    n,
const T            y[],
T                  yp[])
{
yp[0] = r[0] * y[1];
yp[1] = -r[1] * y[0];
};
do
{
ifail = 0;
// Solve an initial value problem for a 1st order system of ODEs