# 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 forward_order}
{xrst_spell
   cout
   dx
   ostream
   xk
   xq
   yq
}

Multiple Order Forward Mode
###########################

Syntax
******

| *yq* = *f* . ``Forward`` ( *q* , *xq*  )
| *yq* = *f* . ``Forward`` ( *q* , *xq* , *s* )

Purpose
*******
We use :math:`F : \B{R}^n \rightarrow \B{R}^m` to denote the
:ref:`glossary@AD Function` corresponding to *f* .
Given a function :math:`X : \B{R} \rightarrow \B{R}^n`,
defined by its
:ref:`Taylor coefficients<glossary@Taylor Coefficient>` ,
forward mode computes the Taylor coefficients for the function

.. math::

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

Function Values
===============
If you are using forward mode to compute values for :math:`F(x)`,
:ref:`forward_zero-name` is simpler to understand
than this explanation of the general case.

Derivative Values
=================
If you are using forward mode to compute values for :math:`F^{(1)} (x) * dx`,
:ref:`forward_one-name` is simpler to understand
than this explanation of the general case.

Notation
********

n
=
We use *n* to denote the dimension of the
:ref:`fun_property@Domain` space for *f* .

m
=
We use *m* to denote the dimension of the
:ref:`fun_property@Range` space for *f* .

f
*
The :ref:`ADFun-name` object *f* has prototype

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

Note that the :ref:`ADFun-name` object *f* is not ``const`` .
After this call we will have

| |tab| *f* . ``size_order`` ()     == *q*  + 1
| |tab| *f* . ``size_direction`` () == 1

One Order
*********
If *xq* . ``size`` () == *n* ,
then we are only computing one order.
In this case, before this call we must have

| |tab| *f* . ``size_order`` ()     >= *q*
| |tab| *f* . ``size_direction`` () == 1

q
*
The argument *q* has prototype

   ``size_t`` *q*

and specifies the highest order of the Taylor coefficients to be calculated.

xq
**
The argument *xq* has prototype

   ``const`` *BaseVector* & *xq*

(see :ref:`forward_order@BaseVector` below).
As above, we use *n* to denote the dimension of the
:ref:`fun_property@Domain` space for *f* .
The size of *xq* must be either *n* or
*n* * ( *q* +1) .
After this call we will have

   *f* . ``size_order`` ()     == *q*  + 1

One Order
=========
If *xq* . ``size`` () == *n* ,
the *q*-th order Taylor coefficient for :math:`X(t)`
is defined by

|tab| :math:`x^{(q)} =` *xq* .
For :math:`k = 0 , \ldots , q-1`,
the Taylor coefficient :math:`x^{(k)}`
is defined by *xk* in the previous call to

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

Multiple Orders
===============
If *xq* . ``size`` () == *n* * ( *q* +1) ,
For :math:`k = 0 , \ldots , q`,
:math:`j = 0 , \ldots , n-1`,
the *j*-th component of the *k*-th order Taylor coefficient
for :math:`X(t)` is defined by

|tab| :math:`x_j^{(k)} =` *xq* [ ( *q* +1) * *j* + *k*  ]

Restrictions
============
Note if *f* uses :ref:`atomic_one-name` functions,
the size of *xq* must be *n* .

s
*
If the argument *s* is not present, ``std::cout``
is used in its place.
Otherwise, this argument has prototype

   ``std::ostream&`` *s*

If order zero is begin calculated,
*s* specifies where the output corresponding to :ref:`PrintFor-name`
will be written.
If order zero is not being calculated,
*s* is not used

X(t)
****
The function
:math:`X : \B{R} \rightarrow \B{R}^n` is defined using
the Taylor coefficients :math:`x^{(k)} \in \B{R}^n`:

.. math::

   X(t) = x^{(0)} * t^0 + x^{(1)} * t^1 + \cdots + x^{(q)} * t^q

Note that for :math:`k = 0 , \ldots , q`,
the *k*-th derivative of :math:`X(t)` is related to the
Taylor coefficients by the equation

.. math::

   x^{(k)} = \frac{1}{k !} X^{(k)} (0)

Y(t)
****
The function
:math:`Y : \B{R} \rightarrow \B{R}^m` is defined by
:math:`Y(t) = F[ X(t) ]`.
We use :math:`y^{(k)} \in \B{R}^m`
to denote the *k*-th order Taylor coefficient of :math:`Y(t)`; i.e.,

.. math::

   Y(t) = y^{(0)} * t^0 + y^{(1)} * t^1 + \cdots + y^{(q)} * t^q + o( t^q )

where :math:`o( t^q ) * t^{-q} \rightarrow 0` as :math:`t \rightarrow 0`.
Note that :math:`y^{(k)}` is related to
the *k*-th derivative of :math:`Y(t)` by the equation

.. math::

   y^{(k)} = \frac{1}{k !} Y^{(k)} (0)

yq
**
The return value *yq* has prototype

   *BaseVector* *yq*

(see :ref:`forward_order@BaseVector` below).

One Order
=========
If *xq* . ``size`` () == *n* ,
the vector *yq* has size *m* .
The *q*-th order Taylor coefficient for :math:`Y(t)`
is returned as

   *yq*

:math:`= y^{(q)}`.

Multiple Orders
===============
If *xq* . ``size`` () == *n* * ( *q* +1) ,
the vector *yq* has size *m* * ( *q* +1) .
For :math:`k = 0 , \ldots , q`,
for :math:`i = 0 , \ldots , m-1`,
the *i*-th component of the *k*-th order Taylor coefficient
for :math:`Y(t)` is returned as

   ``yq`` [ ( ``q`` +1) * ``i`` + ``k``  ]

:math:`= y_i^{(k)}`

BaseVector
**********
The type *BaseVector* 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.

Zero Order
**********
The case where
:math:`q = 0` and *xq* . ``size`` () == *n* ,
corresponds to the zero order
:ref:`forward_zero@Special Case` .

First Order
***********
The case where
:math:`q = 1` and *xq* . ``size`` () == *n* ,
corresponds to the first order
:ref:`forward_one@Special Case` .

Second Order
************
The case where
:math:`q = 2` and *xq* . ``size`` () == *n* ,
corresponds to the second order
:ref:`forward_two@Special Case` .
{xrst_toc_hidden
   example/general/forward.cpp
   example/general/forward_order.cpp
}
Example
*******
The files
:ref:`forward.cpp-name` and :ref:`forward_order.cpp-name`
contain examples and tests of using forward mode with
one order and multiple orders respectively.
They return true if they succeed and false otherwise.

{xrst_end forward_order}
