# ifndef CPPAD_CORE_FUN_CHECK_HPP
# define CPPAD_CORE_FUN_CHECK_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell

CppAD is distributed under the terms of the
             Eclipse Public License Version 2.0.

This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
      GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */

/*
$begin FunCheck$$
$spell
    exp
    bool
    const
    Taylor
$$


$section Check an ADFun Sequence of Operations$$

$head Syntax$$
$icode%ok% = FunCheck(%f%, %g%, %x%, %r%, %a%)%$$
$pre
$$
$bold See Also$$
$cref CompareChange$$


$head Purpose$$
We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the
$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$.
We use $latex G : \B{R}^n \rightarrow \B{R}^m$$ to denote the
function corresponding to the C++ function object $icode g$$.
This routine check if
$latex \[
    F(x) = G(x)
\]$$
If $latex F(x) \neq G(x)$$, the
$cref/operation sequence/glossary/Operation/Sequence/$$
corresponding to $icode f$$ does not represents the algorithm used
by $icode g$$ to calculate values for $latex G$$
(see $cref/Discussion/FunCheck/Discussion/$$ below).

$head f$$
The $code FunCheck$$ argument $icode f$$ has prototype
$codei%
    ADFun<%Base%> %f%
%$$
Note that the $cref ADFun$$ object $icode f$$ is not $code const$$
(see $cref/Forward/FunCheck/FunCheck Uses Forward/$$ below).

$head g$$
The $code FunCheck$$ argument $icode g$$ has prototype
$codei%
    %Fun% &%g%
%$$
($icode Fun$$ is defined the properties of $icode g$$).
The C++ function object $icode g$$ supports the syntax
$codei%
    %y% = %g%(%x%)
%$$
which computes $latex y = G(x)$$.

$subhead x$$
The $icode g$$ argument $icode x$$ has prototype
$codei%
    const %Vector% &%x%
%$$
(see $cref/Vector/FunCheck/Vector/$$ below)
and its size
must be equal to $icode n$$, the dimension of the
$cref/domain/fun_property/Domain/$$ space for $icode f$$.

$head y$$
The $icode g$$ result $icode y$$ has prototype
$codei%
    %Vector% %y%
%$$
and its value is $latex G(x)$$.
The size of $icode y$$
is equal to $icode m$$, the dimension of the
$cref/range/fun_property/Range/$$ space for $icode f$$.

$head x$$
The $code FunCheck$$ argument $icode x$$ has prototype
$codei%
    const %Vector% &%x%
%$$
and its size
must be equal to $icode n$$, the dimension of the
$cref/domain/fun_property/Domain/$$ space for $icode f$$.
This specifies that point at which to compare the values
calculated by $icode f$$ and $icode G$$.

$head r$$
The $code FunCheck$$ argument $icode r$$ has prototype
$codei%
    const %Base% &%r%
%$$
It specifies the relative error the element by element
comparison of the value of $latex F(x)$$ and $latex G(x)$$.

$head a$$
The $code FunCheck$$ argument $icode a$$ has prototype
$codei%
    const %Base% &%a%
%$$
It specifies the absolute error the element by element
comparison of the value of $latex F(x)$$ and $latex G(x)$$.

$head ok$$
The $code FunCheck$$ result $icode ok$$ has prototype
$codei%
    bool %ok%
%$$
It is true, if for $latex i = 0 , \ldots , m-1$$
either the relative error bound is satisfied
$latex \[
| F_i (x) - G_i (x) |
\leq
r ( | F_i (x) | + | G_i (x) | )
\] $$
or the absolute error bound is satisfied
$latex \[
    | F_i (x) - G_i (x) | \leq a
\] $$
It is false if for some $latex (i, j)$$ neither
of these bounds is satisfied.

$head Vector$$
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
$icode Base$$.
The routine $cref CheckSimpleVector$$ will generate an error message
if this is not the case.

$head FunCheck Uses Forward$$
After each call to $cref Forward$$,
the object $icode f$$ contains the corresponding
$cref/Taylor coefficients/glossary/Taylor Coefficient/$$.
After $code FunCheck$$,
the previous calls to $cref Forward$$ are undefined.

$head Discussion$$
Suppose that the algorithm corresponding to $icode g$$ contains
$codei%
    if( %x% >= 0 )
        %y% = exp(%x%)
    else
        %y% = exp(-%x%)
%$$
where $icode x$$ and $icode y$$ are $codei%AD<double>%$$ objects.
It follows that the
AD of $code double$$ $cref/operation sequence/glossary/Operation/Sequence/$$
depends on the value of $icode x$$.
If the sequence of operations stored in $icode f$$ corresponds to
$icode g$$ with $latex x \geq 0$$,
the function values computed using $icode f$$ when $latex x < 0$$
will not agree with the function values computed by $latex g$$.
This is because the operation sequence corresponding to $icode g$$ changed
(and hence the object $icode f$$ does not represent the function
$latex G$$ for this value of $icode x$$).
In this case, you probably want to re-tape the calculations
performed by $icode g$$ with the
$cref/independent variables/glossary/Tape/Independent Variable/$$
equal to the values in $icode x$$
(so AD operation sequence properly represents the algorithm
for this value of independent variables).


$head Example$$
$children%
    example/general/fun_check.cpp
%$$
The file
$cref fun_check.cpp$$
contains an example and test of this function.

$end
---------------------------------------------------------------------------
*/

namespace CppAD {
    template <class Base, class RecBase, class Fun, class Vector>
    bool FunCheck(
        ADFun<Base, RecBase>  &f ,
        Fun                   &g ,
        const Vector          &x ,
        const Base            &r ,
        const Base            &a )
    {   bool ok = true;

        size_t m   = f.Range();
        Vector yf  = f.Forward(0, x);
        Vector yg  = g(x);

        size_t i;
        for(i = 0; i < m; i++)
            ok  &= NearEqual(yf[i], yg[i], r, a);
        return ok;
    }
}

# endif
