# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
# SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
# SPDX-FileContributor: 2003-23 Bradley M. Bell
# ----------------------------------------------------------------------------

{xrst_begin mul_level}

Using Multiple Levels of AD
###########################

Alternative
***********
Often it is easier to use
:ref:`base2ad-name` and :ref:`dynamic<new_dynamic-name>` parameters
to accomplish the objective below.

Background
**********
If *f* is an ``ADFun`` < *Base* > object,
the vectors returned by
:ref:`f.Forward<Forward-name>` ,
and
:ref:`f.Reverse<Reverse-name>` ,
have values of type *Base* and not
``AD`` < *Base* > .
This reflects the fact that operations used to calculate
these function values are not recorded by the tape corresponding to
``AD`` < *Base* > operations.

Motivation
**********
Suppose that you use derivatives of one or more inner functions
as part of the operations
needed to compute an outer function.
For example,
the derivatives returned by *f* . ``Forward``
might be used as part of
Taylor's method for solving ordinary
differential equations.
In addition, we might want to differentiate the
solution of a differential equation with respect to parameters
in the equation.
This can be accomplished in the following way:

#. The function defining the
   differential equation could be calculated using the class
   ``AD< AD<double> >`` .

#. The operations during the calculation of Taylor's method
   could be done using the ``AD<double>`` class.

#. Derivatives of the solution of the differential equation
   could then be calculated using the ``double`` class.

Procedure
*********

First Start AD<double>
======================
If some of the :ref:`parameters<glossary@Parameter>`
in the ``AD< AD<double> >`` recording depend on the
:ref:`variables<glossary@Variable>`
in the ``AD<double>`` recording,
we must first declaring these variables; i.e.,

   ``Independent`` ( *a1x* )

where *a1x* is
a :ref:`SimpleVector-name` with elements of type ``AD<double>`` .
This will start recording a new tape of
operations performed using ``AD<double>`` class objects.

Start AD< AD<double> > Recording
================================
The next step is to declare the independent variables using

   ``Independent`` ( *a2x* )

where *a2x* is
a :ref:`SimpleVector-name` with elements of type
``AD< AD<double> >`` .
This will start recording a new tape of
operations performed using ``AD< AD<double> >`` class objects.

Inner Function
==============
The next step is to calculate the inner function
using ``AD< AD<double> >`` class objects.
We then stop the recording using

   *a1f* . ``Dependent`` ( *a2x* , *a2y* )

where *a2y* is
a :ref:`SimpleVector-name` with elements of type
``AD< AD<double> >``
and *a1f* is an ``ADFun< AD<double> >`` object.

Second Start AD< AD<double> >
=============================
If none of the :ref:`parameters<glossary@Parameter>`
in the ``AD< AD<double> >`` recording depend on the
:ref:`variables<glossary@Variable>`
in the ``AD<double>`` recording,
it is preferred to delay declaring these variables to this point; i.e.,

   ``Independent`` ( *a1x* )

where *a1x* is
a :ref:`SimpleVector-name` with elements of type ``AD<double>`` .
This will start recording a new tape of
operations performed using ``AD<double>`` class objects.

Outer Function
==============
The next step is to calculate the outer function
using ``AD<double>`` class objects.
Note that derivatives of the inner function can be included
in the calculation of the outer function using *a1f* .
We then stop the recording of ``AD<double>`` operations using

   *g* . ``Dependent`` ( *a1x* , *a1y* )

where *a1y* is
a :ref:`SimpleVector-name` with elements of type
``AD<double>``
and *g* is an ``ADFun<double>`` object.

Derivatives of Outer Function
=============================
The AD function object *g* can then be used to calculate
the derivatives of the outer function.
{xrst_toc_hidden
   example/general/mul_level.cpp
   example/general/change_param.cpp
}

Example
*******
The files
:ref:`mul_level.cpp-name` and :ref:`change_param.cpp-name`
contain an examples and tests of this procedure.
They return true if they succeed and false otherwise.
The file :ref:`mul_level_ode.cpp-name` is a more complex example
use of multiple tapes.

{xrst_end mul_level}
