[comment {-*- flibs -*- doctools manpage}]
[manpage_begin automatic_differentiation n 1.0]
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
[moddesc flibs]
[titledesc {Implement the "automatic differentation" technique}]

[description]

The [strong automatic_differentiation] module defines a derived
type that enables you (via overloading common mathematical
functions and operators) to:

[list_begin bullet]
[bullet]
Define a mathematical function in the usual way

[bullet]
Evaluate that function [strong and] its first derivative at the same
time

[list_end]

without having to program that first derivative.

[para]

The module uses real numbers of the kind "wp" as defined in the
auxiliary module [strong select_precision].

[para]

(I was pointed to this technique by Simon Geard, a couple of years ago,
in the context of one of the many language shootouts on the Internet.)


[section "EXAMPLE"]

In numerical methods like Newton-Raphson for finding a root of the
equation "f(x) = 0", you need the first derivative:

[example {
    x(k+1)  =  x(k)  - f(x(k)) / f'(x(k))
}]

Rather than implementing the function and its first derivatives as
separate functions, using this module you can dispense with manually
determining the first derivative:

[example {
program root
    use automatic_differentation

    type(AUTODERIV) :: x
    type(AUTODERIV) :: res
    integer         :: i

    !
    ! First estimate
    !
    x = derivvar( 1.0_wp )

    do i = 1,10
        res = f(x)
        x = x - res.v / res.dv
    enddo

    write(*,*) 'Root: ', x.v
contains

type(AUTODERIV) function f(x)
    type(AUTODERIV) :: x

    f = x + cos(x)

end function f
end program
}]


[section "DATA TYPES AND ROUTINES"]
The module defines a single data type, AUTODERIV, and one specific
function, derivvar().

[list_begin definitions]

[call [cmd "use automatic_differentiation"]]
The name of the module

[call [cmd "type(AUTODERIV)"]]
The type has two fields:

[list_begin arg]

[arg_def "real(wp)" v]
The value of the variable/function (or any intermediate result)

[arg_def "real(wp)" dv]
The first derivative

[list_end]
[nl]


[call [cmd "x = derivvar( value )"]]
Use this function to properly initialise the program
variable x as a "mathematical" variable. (It sets the derivative
of x to 1, because otherwise it would be regarded as a constant).

[list_begin arg]

[arg_def "real(wp)" value]
The value of the "mathematical" variable.

[list_end]

[call [cmd "call find_root( f, xinit, tolerance, root, found )"]]
This subroutine is a simple implementation of the Newton-Raphson
method to find roots. The function f takes one argument, x.

[list_begin arg]
[arg_def "type(AUTODERIV) function" f(x)]
The function must have the interface:
[example {
    interface
        function f(x)
            use automatic_differentiation_type
            type(AUTODERIV), intent(in) :: x
            type(AUTODERIV)             :: f
        end function
    end interface
}]

Its return value is the function value at point x and its first
derivative.


[arg_def "type(AUTODERIV), intent(in)" xinit]
Initial estimate of the root - the end result may depend on this choice.

[arg_def "real(wp)" tolerance]
Maximum allowable error in the absolute value of the root. If the
difference between the old and the new estimate is smaller than this
value, the iteration stops.

[arg_def "type(AUTODERIV), intent(out)" root]
Final estimate of the root.

[arg_def "logical" found]
Indicator whether a root was found or not. There is a maximum
number of iterations and the root must not grow too large.

[list_end]


[call [cmd "call find_root_iter( fvalue, root, tolerance, found )"]]
This subroutine performs a single iteration in the Newton-Raphson
method to find roots. It can be used to implement a more general version
of [strong find_root], for instance if the interface to the function
contains one or more asjustable parameters.

[list_begin arg]
[arg_def "type(AUTODERIV)" fvalue]
The value of the function (plus its first derivative)

[arg_def "type(AUTODERIV), intent(in)" root]
Current estimate of the root

[arg_def "real(wp)" tolerance]
Maximum allowable error in the absolute value of the root. If the
difference between the old and the new estimate is smaller than this
value, the indicator [strong found] is set to true.

[arg_def "logical" found]
Indicator whether a root was found or not.

[list_end]


[list_end]


[section "POSSIBLE EXTENSIONS"]
You can extend the module in at least two ways:

[list_begin bullet]
[bullet]
Determine the second derivative, the third and so on. This is
straightforward enough, but the formulae will get fairly complex after
the second derivative.

[bullet]
Determine the derivative of a function of two or more variables. This
will require a bit more: such functions have a vector-valued
derivative and each independent variable will have to have a
vector-valued derivative as well. For instance:
[nl]
A function f(x,y) evaluated at (1,2), would take as the actual arguments
x = (1,1,0) (so no variation in the second direction) and y = (2,0,1)
(no variation in the first direction).

[list_end]

[manpage_end]
