Prev Next atomic_four_mat_mul_rev_depend.cpp

@(@\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 .
Atomic Matrix Multiply Reverse Dependency: Example and Test

Purpose
This example uses the atomic matrix multiply rev_depend function to reduce the number of variables in the recording of @(@ g(u) @)@.

f(u)
@[@ f(u) = \left( \begin{array}{cc} 2 u_0 & 2 u_1 \\ 2 u_2 & 2 u_3 \\ \end{array} \right) \left( \begin{array}{cc} 2 u_4 & 2 u_5 \\ 2 u_6 & 2 u_7 \end{array} \right) = \left( \begin{array}{cc} 4( u_0 u_4 + u_1 u_6 ) & 4( u_0 u_5 + u_1 u_7 ) \\ 4( u_2 u_4 + u_3 u_6 ) & 4( u_2 u_5 + u_3 u_7 ) \\ \end{array} \right) @]@@[@ f_{0,0} (u) = 4 ( u_0 u_4 + u_1 u_6 ) @]@
Forward Analysis
Forward dependency analysis determines that there is a new variable for each of the 8 multiplications by 2.0. It also determines, using for_type that each of the 4 elements in the matrix product result is a new variable.

Reverse Analysis
Reverse analysis detect that only 1 of the 4 elements in the matrix product is used. In addition it determines, using rev_depend , that only 4 of the 8 multiplications by 2.0 are used.

size_var
The difference in size_var is the difference between only using forward dependency and using both; i.e., (8 - 4) + (4 - 1) = 7.

Source

# include <cppad/cppad.hpp>
# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>

bool rev_depend(void)
{   // ok, eps
    bool ok = true;
    //
    // AD
    using CppAD::AD;
    using CppAD::sparse_rc;
    // -----------------------------------------------------------------------
    // Record g
    // -----------------------------------------------------------------------
    //
    // afun
    CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
    //
    // nleft, n_middle, n_right
    size_t n_left = 2, n_middle = 2, n_right = 2;
    //
    // nu, au
    size_t nu = n_middle * (n_left + n_right);
    CPPAD_TESTVECTOR( AD<double> ) au(nu);
    for(size_t j = 0; j < nu; ++j)
        au[j] = AD<double>(j + 2);
    CppAD::Independent(au);
    //
    // nx, ax
    CPPAD_TESTVECTOR( AD<double> ) ax(nu);
    for(size_t j = 0; j < nu; ++j)
        ax[j] = 2.0 * au[j];
    //
    // ny, ay
    size_t ny = n_left * n_right;
    CPPAD_TESTVECTOR( AD<double> ) ay(ny);
    size_t call_id = afun.set(n_left, n_middle, n_right);
    afun(call_id, ax, ay);
    //
    // az = f_{0,0} (x)
    CPPAD_TESTVECTOR( AD<double> ) az(1);
    az[0] = ay[ 0 * n_right + 0 ];
    //
    // g
    CppAD::ADFun<double> g(au, az);
    //
    // size_var_before
    size_t size_var_before = g.size_var();
    //
    //
    // optimize
    g.optimize();
    //
    // size_var_after
    size_t size_var_after = g.size_var();
    //
    // ok
    ok &= size_var_before - size_var_after == 7;
    //
    return ok;
}

Input File: example/atomic_four/mat_mul/rev_depend.cpp