Prev Next bender_quad.cpp Headings

@(@\newcommand{\W}[1]{ \; #1 \; } \newcommand{\R}[1]{ {\rm #1} } \newcommand{\B}[1]{ {\bf #1} } \newcommand{\D}[2]{ \frac{\partial #1}{\partial #2} } \newcommand{\DD}[3]{ \frac{\partial^2 #1}{\partial #2 \partial #3} } \newcommand{\Dpow}[2]{ \frac{\partial^{#1}}{\partial {#2}^{#1}} } \newcommand{\dpow}[2]{ \frac{ {\rm d}^{#1}}{{\rm d}\, {#2}^{#1}} }@)@ This is cppad-20221105 documentation. Here is a link to its current documentation .
BenderQuad: Example and Test
Define @(@ F : \B{R} \times \B{R} \rightarrow \B{R} @)@ by @[@ F(x, y) = \frac{1}{2} \sum_{i=1}^N [ y * \sin ( x * t_i ) - z_i ]^2 @]@ where @(@ z \in \B{R}^N @)@ is a fixed vector. It follows that @[@ \begin{array}{rcl} \partial_y F(x, y) & = & \sum_{i=1}^N [ y * \sin ( x * t_i ) - z_i ] \sin( x * t_i ) \\ \partial_y \partial_y F(x, y) & = & \sum_{i=1}^N \sin ( x t_i )^2 \end{array} @]@ Furthermore if we define @(@ Y(x) @)@ as the argmin of @(@ F(x, y) @)@ with respect to @(@ y @)@, @[@ \begin{array}{rcl} Y(x) & = & y - [ \partial_y \partial_y F(x, y) ]^{-1} \partial_y F[x, y] \\ & = & \left. \sum_{i=1}^N z_i \sin ( x t_i ) \right/ \sum_{i=1}^N z_i \sin ( x * t_i )^2 \end{array} @]@

# include <cppad/cppad.hpp>

namespace {
    using CppAD::AD;
    typedef CPPAD_TESTVECTOR(double)         BAvector;
    typedef CPPAD_TESTVECTOR(AD<double>)   ADvector;

    class Fun {
    private:
        BAvector t_; // measurement times
        BAvector z_; // measurement values
    public:
        // constructor
        Fun(const BAvector &t, const BAvector &z)
        : t_(t), z_(z)
        { }
        // Fun.f(x, y) = F(x, y)
        ADvector f(const ADvector &x, const ADvector &y)
        {   size_t i;
            size_t N = size_t(z_.size());

            ADvector F(1);
            F[0] = 0.;

            AD<double> residual;
            for(i = 0; i < N; i++)
            {   residual = y[0] * sin( x[0] * t_[i] ) - z_[i];
                F[0]    += .5 * residual * residual;
            }
            return F;
        }
        // Fun.h(x, y) = H(x, y) = F_y (x, y)
        ADvector h(const ADvector &x, const BAvector &y)
        {   size_t i;
            size_t N = size_t(z_.size());

            ADvector fy(1);
            fy[0] = 0.;

            AD<double> residual;
            for(i = 0; i < N; i++)
            {   residual = y[0] * sin( x[0] * t_[i] ) - z_[i];
                fy[0]   += residual * sin( x[0] * t_[i] );
            }
            return fy;
        }
        // Fun.dy(x, y, h) = - H_y (x,y)^{-1} * h
        //                 = - F_yy (x, y)^{-1} * h
        ADvector dy(
            const BAvector &x ,
            const BAvector &y ,
            const ADvector &H )
        {   size_t i;
            size_t N = size_t(z_.size());

            ADvector Dy(1);
            AD<double> fyy = 0.;

            for(i = 0; i < N; i++)
            {   fyy += sin( x[0] * t_[i] ) * sin( x[0] * t_[i] );
            }
            Dy[0] = - H[0] / fyy;

            return Dy;
        }
    };

    // Used to test calculation of Hessian of G
    AD<double> G(const ADvector& x, const BAvector& t, const BAvector& z)
    {   // compute Y(x)
        AD<double> numerator = 0.;
        AD<double> denominator = 0.;
        size_t k;
        for(k = 0; k < size_t(t.size()); k++)
        {   numerator   += sin( x[0] * t[k] ) * z[k];
            denominator += sin( x[0] * t[k] ) * sin( x[0] * t[k] );
        }
        AD<double> y = numerator / denominator;

        // V(x) = F[x, Y(x)]
        AD<double> sum = 0;
        for(k = 0; k < size_t(t.size()); k++)
        {   AD<double> residual = y * sin( x[0] * t[k] ) - z[k];
            sum += .5 * residual * residual;
        }
        return sum;
    }
}

bool BenderQuad(void)
{   bool ok = true;
    using CppAD::AD;
    using CppAD::NearEqual;

    // temporary indices
    size_t i, j;

    // x space vector
    size_t n = 1;
    BAvector x(n);
    x[0] = 2. * 3.141592653;

    // y space vector
    size_t m = 1;
    BAvector y(m);
    y[0] = 1.;

    // t and z vectors
    size_t N = 10;
    BAvector t(N);
    BAvector z(N);
    for(i = 0; i < N; i++)
    {   t[i] = double(i) / double(N);       // time of measurement
        z[i] = y[0] * sin( x[0] * t[i] );   // data without noise
    }

    // construct the function object
    Fun fun(t, z);

    // evaluate the G(x), G'(x) and G''(x)
    BAvector g(1), gx(n), gxx(n * n);
    CppAD::BenderQuad(x, y, fun, g, gx, gxx);


    // create ADFun object Gfun corresponding to G(x)
    ADvector a_x(n), a_g(1);
    for(j = 0; j < n; j++)
        a_x[j] = x[j];
    Independent(a_x);
    a_g[0] = G(a_x, t, z);
    CppAD::ADFun<double> Gfun(a_x, a_g);

    // accuracy for checks
    double eps = 10. * CppAD::numeric_limits<double>::epsilon();

    // check Jacobian
    BAvector check_gx = Gfun.Jacobian(x);
    for(j = 0; j < n; j++)
        ok &= NearEqual(gx[j], check_gx[j], eps, eps);

    // check Hessian
    BAvector check_gxx = Gfun.Hessian(x, 0);
    for(j = 0; j < n*n; j++)
        ok &= NearEqual(gxx[j], check_gxx[j], eps, eps);

    return ok;
}

Input File: example/general/bender_quad.cpp