# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
# SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
# SPDX-FileContributor: 2003-24 Bradley M. Bell
# ----------------------------------------------------------------------------
{xrst_begin reverse_any}
{xrst_spell
   dw
}

Any Order Reverse Mode
######################

Syntax
******
| *dw* = *f* . ``Reverse`` ( *q* , *w* )

Purpose
*******
We use :math:`F : \B{R}^n \rightarrow \B{R}^m` to denote the
:ref:`glossary@AD Function` corresponding to *f* .
Reverse mode computes the derivative of the :ref:`Forward-name` mode
:ref:`Taylor coefficients<glossary@Taylor Coefficient>`
with respect to the domain variable :math:`x`.
To be specific, it computes the derivative
:math:`W^{(1)} (u)` at :math:`u = x`
which is specified by the following notation:

Notation
********

u^(k)
=====
For :math:`k = 0, \ldots , q-1`,
the vector :math:`u^{(k)} \in \B{R}^n` is defined as the value of
*x_k* in the previous calls of the form

   *f* . ``Forward`` ( *k* , *x_k* )

If there is no previous call with :math:`k = 0`,
:math:`u^{(0)}` is the value of the independent variables when the
corresponding
AD of *Base*
:ref:`operation sequence<glossary@Operation@Sequence>` was recorded.

X(t, u)
=======
The function
:math:`X : \B{R} \times \B{R}^{n \times q} \rightarrow \B{R}^n` is defined by

.. math::

   X ( t , u ) = u^{(0)} + u^{(1)} * t + \cdots + u^{(q-1)} * t^{q-1}

Note that for :math:`k = 0 , \ldots , q-1`,
:math:`u^{(k)}` is related to the *k*-th partial of :math:`X(t, u)`
with respect to :math:`t` by

.. math::

   u^{(k)} = \frac{1}{k !} \Dpow{k}{t} X(0, u)

Y(t, u)
=======
The function
:math:`Y : \B{R} \times \B{R}^{n \times q} \rightarrow \B{R}^m` is defined by

.. math::

   Y(t, u) = F [ X(t,u) ]

w^(k)
=====
If the argument *w* has size *m* * *q* ,
for :math:`k = 0 , \ldots , q-1` and :math:`i = 0, \ldots , m-1`,

.. math::

   w_i^{(k)} = w [ i * q + k ]

If the argument *w* has size *m* ,
for :math:`k = 0 , \ldots , q-1` and :math:`i = 0, \ldots , m-1`,

.. math::

   w_i^{(k)} = \left\{ \begin{array}{ll}
      w [ i ] & {\rm if} \; k = q-1
      \\
      0       & {\rm otherwise}
   \end{array} \right.

W(u)
====
The function :math:`W : \B{R}^{n \times q} \rightarrow \B{R}` is defined by

.. math::

   W(u) = \sum_{k=0}^{q-1} ( w^{(k)} )^\R{T} \frac{1}{k !} \Dpow{k}{t} Y(0, u)

f
*
The object *f* has prototype

   ``const ADFun`` < *Base* > *f*

Before this call to ``Reverse`` , the value returned by

   *f* . ``size_order`` ()

must be greater than or equal *q*
(see :ref:`size_order-name` ).

q
*
The argument *q* has prototype

   ``size_t`` *q*

and specifies the number of Taylor coefficient orders to be differentiated
(for each variable).

w
*
The argument *w* has prototype

   ``const`` *Vector* & *w*

(see :ref:`reverse_any@Vector` below)
and its size
must be equal to *m* or *m* * *q* ,
It specifies the weighting vector *w*
in the definition of
:ref:`reverse_any@Notation@W(u)` .

dw
**
The return value *dw* has prototype

   *Vector* *dw*

(see :ref:`reverse_any@Vector` below).
It is a vector with size :math:`n \times q`.
For :math:`j = 0, \ldots, n-1` and :math:`k = 0 , \ldots , q-1`
If the argument *w* has size *m* * *q* ,

.. math::

   dw[ j * q + k ] = W^{(1)} ( x )_{j,k}

where :math:`u = x` is value of the Taylor coefficients where the
derivative is evaluated.

If the argument *w* has size *m* ,

.. math::

   dw[ j * q + q - k - 1 ] = W^{(1)} ( x )_{j,k}

where :math:`u = x` is value of the Taylor coefficients where the
derivative is evaluated.
Note the reverse order in which the order indices are stored.
This is an unfortunate consequence of keeping ``Reverse`` backward
compatible.

First Order
***********
We consider the case where
*q*  = 1 and *w* . ``size`` () == *m* .
In this case

.. math::
   :nowrap:

   \begin{eqnarray}
   W(u) & = & w_0 Y_0 (0, u) + \cdots + w_m Y_m (0, u)
   \\
   W(u) & = & w_0 F_0 [ X(0, u) ] + \cdots + w_m F_m [ X(0, u) ]
   \\
   W^{(1)} (x) & = &
      w_0 F_0^{(1)} ( x^{(0)} ) + \cdots + w_m F_m^{(1)} ( x^{(0)} )
   \end{eqnarray}

This is the same as the result documented in :ref:`reverse_one-name` .

Second Order
************
We consider the case where
*q*  = 2 and *w* . ``size`` () == *m* .
In this case

.. math::
   :nowrap:

   \begin{eqnarray}
   W(u) & = & w_0 \partial_t Y_0 (0, u) + \cdots + w_m \partial_t Y_m (0, u)
   \\
   W(u) & = &
      w_0 \partial_t \{ F_0 [ X(t, u) ] \}_{t = 0}
        + \cdots +
      w_m \partial_t \{ F_m [ X(t, u) ] \}_{t = 0}
   \\
   W(u) & = &
      w_0 F_0^{(1)} ( u^{(0)} ) u^{(1)}
        + \cdots +
      w_0 F_m^{(1)} ( u^{(0)} ) u^{(1)}
   \\
   \partial_{u(0)} W(x) & = &
      w_0 (  x^{(1)} )^\R{T} F_0^{(2)} ( x^{(0)} )
      + \cdots +
      w_m (  x^{(1)} )^\R{T} F_m^{(2)} ( x^{(0)} )
   \\
   \partial_{u(1)} W(x) & = &
      w_0 F_0^{(1)} ( x^{(0)} )
      + \cdots +
      w_m F_m^{(1)} ( x^{(0)} )
   \end{eqnarray}

where :math:`\partial{u(0)}`
denotes partial with respect to :math:`u^{(0)}`.
These are the same as the result documented in :ref:`reverse_two-name` .

Vector
******
The type *Vector* must be a :ref:`SimpleVector-name` class with
:ref:`elements of type<SimpleVector@Elements of Specified Type>`
*Base* .
The routine :ref:`CheckSimpleVector-name` will generate an error message
if this is not the case.

Example
*******
{xrst_toc_hidden
   example/general/reverse_three.cpp
   example/general/rev_checkpoint.cpp
}

#. The file :ref:`reverse_three.cpp-name`
   contains an example and test of using reverse mode
   to compute third order derivatives.
#. The file :ref:`rev_checkpoint.cpp-name`
   contains an example and test of the general reverse mode case.

{xrst_end reverse_any}
