|
Prev
| Next
|
|
|
|
|
|
atomic_four_mat_mul_forward.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 Forward Mode: Example and Test
Purpose
This example demonstrates using forward mode with
the atomic_four_mat_mul
class.
f(x)
For this example, the function @(@
f(x)
@)@ is
@[@
f(x) =
\left( \begin{array}{cc}
x_0 & x_1 \\
x_2 & x_3 \\
x_4 & x_5
\end{array} \right)
\left( \begin{array}{c}
x_6 \\
x_7
\end{array} \right)
=
\left( \begin{array}{c}
x_0 x_6 + x_1 x_7 \\
x_2 x_6 + x_3 x_7 \\
x_4 x_6 + x_5 x_7
\end{array} \right)
@]@
Jacobian of f(x)
The Jacobian of @(@
f(x)
@)@ is
@[@
f^{(1)} (x) = \left( \begin{array}{cccccccc}
x_6 & x_7 & 0 & 0 & 0 & 0 & x_0 & x_1 \\
0 & 0 & x_6 & x_7 & 0 & 0 & x_2 & x_3 \\
0 & 0 & 0 & 0 & x_6 & x_7 & x_4 & x_5
\end{array} \right)
@]@
g(x)
We define the function @(@
g(x) = f_1^{(1)} (x)^\R{T}
@)@; i.e.,
@[@
g(x) = ( 0, 0, x_6, x_7, 0, 0, x_2, x_3 )^\R{T}
@]@
Hessian
The Hessian of @(@
f_1(x)
@)@ is the Jacobian
of @(@
g(x)
@)@; i.e.,
@[@
f_1^{(2)} (x)
=
g^{(1)} (x)
=
\left( \begin{array}{cccccccc}
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\
0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\
\end{array} \right)
@]@
Source
# include <cppad/cppad.hpp>
# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
bool forward(void)
{ // ok, eps
bool ok = true;
//
// AD, NearEqual
using CppAD::AD;
using CppAD::NearEqual;
// -----------------------------------------------------------------------
// Record f
// -----------------------------------------------------------------------
//
// afun
CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
//
// nleft, n_middle, n_right
size_t n_left = 3, n_middle = 2, n_right = 1;
//
// nx, ax
size_t nx = n_middle * (n_left + n_right);
CPPAD_TESTVECTOR( AD<double> ) ax(nx);
for(size_t j = 0; j < nx; ++j)
ax[j] = AD<double>(j + 2);
CppAD::Independent(ax);
//
// ny, ay
size_t ny = n_left * n_right;
CPPAD_TESTVECTOR( AD<double> ) ay(ny);
//
// ay
size_t call_id = afun.set(n_left, n_middle, n_right);
afun(call_id, ax, ay);
//
// f
CppAD::ADFun<double> f(ax, ay);
// -----------------------------------------------------------------------
// Forward mode on f
// -----------------------------------------------------------------------
//
// x
CPPAD_TESTVECTOR(double) x(nx);
for(size_t j = 0; j < nx; ++j)
x[j] = double(3 + nx - j);
//
// y
// zero order forward mode computation of f(x)
CPPAD_TESTVECTOR(double) y(ny);
y = f.Forward(0, x);
//
// check_y
double check_y[] = {
x[0] * x[6] + x[1] * x[7],
x[2] * x[6] + x[3] * x[7],
x[4] * x[6] + x[5] * x[7]
};
for(size_t i = 0; i < ny; ++i)
ok &= y[i] == check_y[i];
//
// J
// first order forward mode computation of f'(x)
CPPAD_TESTVECTOR(double) x1(nx), y1(ny), J(ny * nx);
for(size_t j = 0; j < nx; ++j)
x1[j] = 0.0;
for(size_t j = 0; j < nx; ++j)
{ x1[j] = 1.0;
y1 = f.Forward(1, x1);
x1[j] = 0.0;
for(size_t i = 0; i < ny; ++i)
J[i * nx + j] = y1[i];
}
//
// check_J
double check_J[] = {
x[6], x[7], 0.0, 0.0, 0.0, 0.0, x[0], x[1],
0.0, 0.0, x[6], x[7], 0.0, 0.0, x[2], x[3],
0.0, 0.0, 0.0, 0.0, x[6], x[7], x[4], x[5]
};
for(size_t ij = 0; ij < ny * nx; ij++)
ok &= J[ij] == check_J[ij];
//
// H_1
// Second order forward mode computaiton of f_1^2 (x)
// (use the fact that the diagonal of this Hessian is zero).
CPPAD_TESTVECTOR(double) x2(nx), y2(nx), H_1(nx * nx);
for(size_t j = 0; j < nx; ++j)
x2[j] = 0.0;
for(size_t i = 0; i < nx; ++i)
{ for(size_t j = 0; j < nx; ++j)
{ x1[i] = 1.0;
x1[j] = 1.0;
f.Forward(1, x1);
x1[i] = 0.0;
x1[j] = 0.0;
y2 = f.Forward(2, x2);
H_1[i * nx + j] = y2[1];
}
}
//
// check_H_1
double check_H_1[] = {
0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 1., 0.,
0., 0., 0., 0., 0., 0., 0., 1.,
0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 1., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 0., 0., 0.
};
for(size_t ij = 0; ij < nx * nx; ij++)
ok &= H_1[ij] == check_H_1[ij];
// -----------------------------------------------------------------------
// Record g
// -----------------------------------------------------------------------
//
// af
CppAD::ADFun< AD<double>, double> af = f.base2ad();
//
// az
CppAD::Independent(ax);
CPPAD_TESTVECTOR( AD<double> ) ax1(nx), ay1(ny), az(nx);
af.Forward(0, ax);
for(size_t j = 0; j < nx; ++j)
ax1[j] = 0.0;
for(size_t j = 0; j < nx; ++j)
{ ax1[j] = 1.0;
ay1 = af.Forward(1, ax1);
ax1[j] = 0.0;
az[j] = ay1[1];
}
// g
CppAD::ADFun<double> g(ax, az);
// -----------------------------------------------------------------------
// Forward mode on g
// -----------------------------------------------------------------------
//
// z
// zero order forward mode computation of g(x)
CPPAD_TESTVECTOR(double) z(nx);
z = g.Forward(0, x);
//
// check z
for(size_t j = 0; j < nx; ++j)
ok &= z[j] == J[1 * nx + j];
//
// z1
CPPAD_TESTVECTOR(double) z1(nx);
for(size_t j = 0; j < nx; ++j)
{ x1[j] = 1.0;
z1 = g.Forward(1, x1);
x1[j] = 0.0;
for(size_t i = 0; i < nx; ++i)
ok &= z1[i] == check_H_1[i * nx + j];
}
// ----------------------------------------------------------------
return ok;
}
Input File: example/atomic_four/mat_mul/forward.cpp