|
Prev
| Next
|
|
|
|
|
|
abs_min_linear.hpp |
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
.
abs_min_linear Source Code
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
// BEGIN PROTOTYPE
template <class DblVector, class SizeVector>
bool abs_min_linear(
size_t level ,
size_t n ,
size_t m ,
size_t s ,
const DblVector& g_hat ,
const DblVector& g_jac ,
const DblVector& bound ,
const DblVector& epsilon ,
const SizeVector& maxitr ,
DblVector& delta_x )
// END PROTOTYPE
{ using std::fabs;
bool ok = true;
double inf = std::numeric_limits<double>::infinity();
//
CPPAD_ASSERT_KNOWN(
level <= 4,
"abs_min_linear: level is not less that or equal 4"
);
CPPAD_ASSERT_KNOWN(
size_t(epsilon.size()) == 2,
"abs_min_linear: size of epsilon not equal to 2"
);
CPPAD_ASSERT_KNOWN(
size_t(maxitr.size()) == 2,
"abs_min_linear: size of maxitr not equal to 2"
);
CPPAD_ASSERT_KNOWN(
m == 1,
"abs_min_linear: m is not equal to 1"
);
CPPAD_ASSERT_KNOWN(
size_t(delta_x.size()) == n,
"abs_min_linear: size of delta_x not equal to n"
);
CPPAD_ASSERT_KNOWN(
size_t(bound.size()) == n,
"abs_min_linear: size of bound not equal to n"
);
CPPAD_ASSERT_KNOWN(
size_t(g_hat.size()) == m + s,
"abs_min_linear: size of g_hat not equal to m + s"
);
CPPAD_ASSERT_KNOWN(
size_t(g_jac.size()) == (m + s) * (n + s),
"abs_min_linear: size of g_jac not equal to (m + s)*(n + s)"
);
CPPAD_ASSERT_KNOWN(
size_t(bound.size()) == n,
"abs_min_linear: size of bound is not equal to n"
);
if( level > 0 )
{ std::cout << "start abs_min_linear\n";
CppAD::abs_print_mat("bound", n, 1, bound);
CppAD::abs_print_mat("g_hat", m + s, 1, g_hat);
CppAD::abs_print_mat("g_jac", m + s, n + s, g_jac);
}
// partial y(x, u) w.r.t x (J in reference)
DblVector py_px(n);
for(size_t j = 0; j < n; j++)
py_px[ j ] = g_jac[ j ];
//
// partial y(x, u) w.r.t u (Y in reference)
DblVector py_pu(s);
for(size_t j = 0; j < s; j++)
py_pu[ j ] = g_jac[ n + j ];
//
// partial z(x, u) w.r.t x (Z in reference)
DblVector pz_px(s * n);
for(size_t i = 0; i < s; i++)
{ for(size_t j = 0; j < n; j++)
{ pz_px[ i * n + j ] = g_jac[ (n + s) * (i + m) + j ];
}
}
// partial z(x, u) w.r.t u (L in reference)
DblVector pz_pu(s * s);
for(size_t i = 0; i < s; i++)
{ for(size_t j = 0; j < s; j++)
{ pz_pu[ i * s + j ] = g_jac[ (n + s) * (i + m) + n + j ];
}
}
// initailize delta_x
for(size_t j = 0; j < n; j++)
delta_x[j] = 0.0;
//
// value of approximation for g(x, u) at current delta_x
DblVector g_tilde = CppAD::abs_eval(n, m, s, g_hat, g_jac, delta_x);
//
// value of sigma at delta_x = 0; i.e., sign( z(x, u) )
CppAD::vector<double> sigma(s);
for(size_t i = 0; i < s; i++)
sigma[i] = CppAD::sign( g_tilde[m + i] );
//
// current set of cutting planes
DblVector C(maxitr[0] * n), c(maxitr[0]);
//
//
size_t n_plane = 0;
for(size_t itr = 0; itr < maxitr[0]; itr++)
{
// Equation (5), Propostion 3.1 of reference
// dy_dx = py_px + py_pu * Sigma * (I - pz_pu * Sigma)^-1 * pz_px
//
// tmp_ss = I - pz_pu * Sigma
DblVector tmp_ss(s * s);
for(size_t i = 0; i < s; i++)
{ for(size_t j = 0; j < s; j++)
tmp_ss[i * s + j] = - pz_pu[i * s + j] * sigma[j];
tmp_ss[i * s + i] += 1.0;
}
// tmp_sn = (I - pz_pu * Sigma)^-1 * pz_px
double logdet;
DblVector tmp_sn(s * n);
LuSolve(s, n, tmp_ss, pz_px, tmp_sn, logdet);
//
// tmp_sn = Sigma * (I - pz_pu * Sigma)^-1 * pz_px
for(size_t i = 0; i < s; i++)
{ for(size_t j = 0; j < n; j++)
tmp_sn[i * n + j] *= sigma[i];
}
// dy_dx = py_px + py_pu * Sigma * (I - pz_pu * Sigma)^-1 * pz_px
DblVector dy_dx(n);
for(size_t j = 0; j < n; j++)
{ dy_dx[j] = py_px[j];
for(size_t k = 0; k < s; k++)
dy_dx[j] += py_pu[k] * tmp_sn[ k * n + j];
}
//
// check for case where derivative of hyperplane is zero
// (in convex case, this is the minimizer)
bool near_zero = true;
for(size_t j = 0; j < n; j++)
near_zero &= std::fabs( dy_dx[j] ) < epsilon[1];
if( near_zero )
{ if( level > 0 )
std::cout << "end abs_min_linear: local derivative near zero\n";
return true;
}
// value of hyperplane at delta_x
double plane_at_zero = g_tilde[0];
// value of hyperplane at 0
for(size_t j = 0; j < n; j++)
plane_at_zero -= dy_dx[j] * delta_x[j];
//
// add a cutting plane with value g_tilde[0] at delta_x
// and derivative dy_dx
c[n_plane] = plane_at_zero;
for(size_t j = 0; j < n; j++)
C[n_plane * n + j] = dy_dx[j];
++n_plane;
//
// variables for cutting plane problem are (dx, w)
// c[i] + C[i,:]*dx <= w
DblVector b_box(n_plane), A_box(n_plane * (n + 1));
for(size_t i = 0; i < n_plane; i++)
{ b_box[i] = c[i];
for(size_t j = 0; j < n; j++)
A_box[i * (n+1) + j] = C[i * n + j];
A_box[i *(n+1) + n] = -1.0;
}
// w is the objective
DblVector c_box(n + 1);
for(size_t i = 0; i < size_t(c_box.size()); i++)
c_box[i] = 0.0;
c_box[n] = 1.0;
//
// d_box
DblVector d_box(n+1);
for(size_t j = 0; j < n; j++)
d_box[j] = bound[j];
d_box[n] = inf;
//
// solve the cutting plane problem
DblVector xout_box(n + 1);
size_t level_box = 0;
if( level > 0 )
level_box = level - 1;
ok &= CppAD::lp_box(
level_box,
A_box,
b_box,
c_box,
d_box,
maxitr[1],
xout_box
);
if( ! ok )
{ if( level > 0 )
{ CppAD::abs_print_mat("delta_x", n, 1, delta_x);
std::cout << "end abs_min_linear: lp_box failed\n";
}
return false;
}
//
// check for convergence
double max_diff = 0.0;
for(size_t j = 0; j < n; j++)
{ double diff = delta_x[j] - xout_box[j];
max_diff = std::max( max_diff, std::fabs(diff) );
}
//
// check for descent in value of approximation objective
DblVector delta_new(n);
for(size_t j = 0; j < n; j++)
delta_new[j] = xout_box[j];
DblVector g_new = CppAD::abs_eval(n, m, s, g_hat, g_jac, delta_new);
if( level > 0 )
{ std::cout << "itr = " << itr << ", max_diff = " << max_diff
<< ", y_cur = " << g_tilde[0] << ", y_new = " << g_new[0]
<< "\n";
CppAD::abs_print_mat("delta_new", n, 1, delta_new);
}
//
g_tilde = g_new;
delta_x = delta_new;
//
// value of sigma at new delta_x; i.e., sign( z(x, u) )
for(size_t i = 0; i < s; i++)
sigma[i] = CppAD::sign( g_tilde[m + i] );
//
if( max_diff < epsilon[0] )
{ if( level > 0 )
std::cout << "end abs_min_linear: change in delta_x near zero\n";
return true;
}
}
if( level > 0 )
std::cout << "end abs_min_linear: maximum number of iterations exceeded\n";
return false;
}
} // END_CPPAD_NAMESPACE
Input File: example/abs_normal/abs_min_linear.omh