|
Prev
| Next
|
|
|
|
|
|
qp_interior.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
.
qp_interior Source Code
namespace {
// ------------------------------------------------------------------------
template <class Vector>
double qp_interior_max_abs(const Vector& v)
{ double max_abs = 0.0;
for(size_t j = 0; j < size_t(v.size()); j++)
max_abs = std::max( max_abs, std::fabs(v[j]) );
return max_abs;
}
// ------------------------------------------------------------------------
template <class Vector>
void qp_interior_split(
const Vector& v, Vector& v_x, Vector& v_y, Vector& v_s
)
{ size_t n = v_x.size();
size_t m = v_y.size();
CPPAD_ASSERT_UNKNOWN( size_t(v_s.size()) == m );
CPPAD_ASSERT_UNKNOWN( size_t(v.size()) == n + m + m );
for(size_t i = 0; i < n; i++)
v_x[i] = v[i];
for(size_t i = 0; i < m; i++)
{ v_y[i] = v[n + i];
v_s[i] = v[n + m + i];
}
return;
}
// ------------------------------------------------------------------------
template <class Vector>
void qp_interior_join(
Vector& v, const Vector& v_x, const Vector& v_y, const Vector& v_s
)
{ size_t n = v_x.size();
size_t m = v_y.size();
CPPAD_ASSERT_UNKNOWN( size_t(v_s.size()) == m );
CPPAD_ASSERT_UNKNOWN( size_t(v.size()) == n + m + m );
for(size_t i = 0; i < n; i++)
v[i] = v_x[i];
for(size_t i = 0; i < m; i++)
v[n + i] = v_y[i];
for(size_t i = 0; i < m; i++)
v[n + m + i] = v_s[i];
return;
}
// ------------------------------------------------------------------------
template <class Vector>
Vector qp_interior_F_0(
const Vector& c ,
const Vector& C ,
const Vector& g ,
const Vector& G ,
const Vector& x ,
const Vector& y ,
const Vector& s )
{ size_t n = g.size();
size_t m = c.size();
// compute r_x(x, y, s) = g + G x + y^T C
Vector r_x(n);
for(size_t j = 0; j < n; j++)
{ r_x[j] = g[j];
for(size_t i = 0; i < n; i++)
r_x[j] += G[j * n + i] * x[i];
for(size_t i = 0; i < m; i++)
r_x[j] += y[i] * C[i * n + j];
}
// compute r_y(x, y, s) = C x + c + s
Vector r_y(m);
for(size_t i = 0; i < m; i++)
{ r_y[i] = c[i] + s[i];
for(size_t j = 0; j < n; j++)
r_y[i] += C[i * n + j] * x[j];
}
// compute r_s(x, y, s) = D(s) * D(y) * 1_m - mu * 1_m
// where mu = 0
Vector r_s(m);
for(size_t i = 0; i < m; i++)
r_s[i] = s[i] * y[i];
//
// combine into one vector
Vector F_0(n + m + m);
qp_interior_join(F_0, r_x, r_y, r_s);
//
return F_0;
}
}
// BEGIN C++
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
// BEGIN PROTOTYPE
template <class Vector>
bool qp_interior(
size_t level ,
const Vector& c ,
const Vector& C ,
const Vector& g ,
const Vector& G ,
double epsilon ,
size_t maxitr ,
const Vector& xin ,
Vector& xout ,
Vector& yout ,
Vector& sout )
// END PROTOTYPE
{ size_t m = c.size();
size_t n = g.size();
CPPAD_ASSERT_KNOWN(
level <= 1,
"qp_interior: level is greater than one"
);
CPPAD_ASSERT_KNOWN(
size_t(C.size()) == m * n,
"qp_interior: size of C is not m * n"
);
CPPAD_ASSERT_KNOWN(
size_t(G.size()) == n * n,
"qp_interior: size of G is not n * n"
);
if( level > 0 )
{ std::cout << "start qp_interior\n";
CppAD::abs_print_mat("c", m, 1, c);
CppAD::abs_print_mat("C", m, n, C);
CppAD::abs_print_mat("g", n, 1, g);
CppAD::abs_print_mat("G", n, n, G);
CppAD::abs_print_mat("xin", n, 1, xin);
}
//
// compute the maximum absolute element of the problem vectors and matrices
double max_element = 0.0;
for(size_t i = 0; i < size_t(C.size()); i++)
max_element = std::max(max_element , std::fabs(C[i]) );
for(size_t i = 0; i < size_t(c.size()); i++)
max_element = std::max(max_element , std::fabs(c[i]) );
for(size_t i = 0; i < size_t(G.size()); i++)
max_element = std::max(max_element , std::fabs(G[i]) );
for(size_t i = 0; i < size_t(g.size()); i++)
max_element = std::max(max_element , std::fabs(g[i]) );
//
double mu = 1e-1 * max_element;
//
if( max_element == 0.0 )
{ if( level > 0 )
std::cout << "end qp_interior: line_search failed\n";
return false;
}
//
// initialize x, y, s
xout = xin;
for(size_t i = 0; i < m; i++)
{ double sum = c[i];
for(size_t j = 0; j < n; j++)
sum += C[ i * n + j ] * xout[j];
if( sum > 0.0 )
{ if( level > 0 ) std::cout <<
"end qp_interior: xin is not in interior of feasible set\n";
return false;
}
//
sout[i] = std::sqrt(mu);
yout[i] = std::sqrt(mu);
}
// ----------------------------------------------------------------------
// initialie F_0(xout, yout, sout)
Vector F_0 = qp_interior_F_0(c, C, g, G, xout, yout, sout);
double F_max_abs = qp_interior_max_abs( F_0 );
for(size_t itr = 0; itr <= maxitr; itr++)
{
// check for convergence
if( F_max_abs <= epsilon )
{ if( level > 0 )
std::cout << "end qp_interior: ok = true\n";
return true;
}
if( itr == maxitr )
{ if( level > 0 ) std::cout <<
"end qp_interior: max # iterations without convergence\n";
return false;
}
//
// compute F_mu(xout, yout, sout)
Vector F_mu = F_0;
for(size_t i = 0; i < m; i++)
F_mu[n + m + i] -= mu;
//
// r_x, r_y, r_s (xout, yout, sout)
Vector r_x(n), r_y(m), r_s(m);
qp_interior_split(F_mu, r_x, r_y, r_s);
//
// tmp_m = D(s)^{-1} * [ r_s - D(y) r_y ]
Vector tmp_m(m);
for(size_t i = 0; i < m; i++)
tmp_m[i] = ( r_s[i] - yout[i] * r_y[i] ) / sout[i];
//
// right_x = C^T * D(s)^{-1} * [ r_s - D(y) r_y ] - r_x
Vector right_x(n);
for(size_t j = 0; j < n; j++)
{ right_x[j] = 0.0;
for(size_t i = 0; i < m; i++)
right_x[j] += C[ i * n + j ] * tmp_m[i];
right_x[j] -= r_x[j];
}
//
// Left_x = G + C^T * D(y / s) * C
Vector Left_x = G;
for(size_t i = 0; i < n; i++)
{ for(size_t j = 0; j < n; j++)
{ for(size_t k = 0; k < m; k++)
{ double y_s = yout[k] / sout[k];
Left_x[ i * n + j] += C[k * n + j] * y_s * C[k * n + i];
}
}
}
// delta_x
Vector delta_x(n);
double logdet;
LuSolve(n, 1, Left_x, right_x, delta_x, logdet);
//
// C_delta_x = C * delta_x
Vector C_delta_x(m);
for(size_t i = 0; i < m; i++)
{ C_delta_x[i] = 0.0;
for(size_t j = 0; j < n; j++)
C_delta_x[i] += C[ i * n + j ] * delta_x[j];
}
//
// delta_y = D(s)^-1 * [D(y) * r_y - r_s + D(y) * C * delta_x]
Vector delta_y(m);
for(size_t i = 0; i < m; i++)
{ delta_y[i] = yout[i] * r_y[i] - r_s[i] + yout[i] * C_delta_x[i];
delta_y[i] /= sout[i];
}
// delta_s = - r_y - C * delta_x
Vector delta_s(m);
for(size_t i = 0; i < m; i++)
delta_s[i] = - r_y[i] - C_delta_x[i];
//
// delta_xys
Vector delta_xys(n + m + m);
qp_interior_join(delta_xys, delta_x, delta_y, delta_s);
// -------------------------------------------------------------------
//
// The initial derivative in direction Delta_xys is equal to
// the negative of the norm square of F_mu
//
// line search parameter lam
Vector x(n), y(m), s(m);
double lam = 2.0;
bool lam_ok = false;
while( ! lam_ok && lam > 1e-5 )
{ lam = lam / 2.0;
for(size_t j = 0; j < n; j++)
x[j] = xout[j] + lam * delta_xys[j];
lam_ok = true;
for(size_t i = 0; i < m; i++)
{ y[i] = yout[i] + lam * delta_xys[n + i];
s[i] = sout[i] + lam * delta_xys[n + m + i];
lam_ok &= s[i] > 0.0 && y[i] > 0.0;
}
if( lam_ok )
{ Vector F_mu_tmp = qp_interior_F_0(c, C, g, G, x, y, s);
for(size_t i = 0; i < m; i++)
F_mu_tmp[n + m + i] -= mu;
// avoid cancellation roundoff in difference of norm squared
// |v + dv|^2 = v^T * v + 2 * v^T * dv + dv^T * dv
// |v + dv|^2 - |v|^2 = 2 * v^T * dv + dv^T * dv
double F_norm_sq = 0.0;
double diff_norm_sq = 0.0;
for(size_t i = 0; i < n + m + m; i++)
{ double dv = F_mu_tmp[i] - F_mu[i];
F_norm_sq += F_mu[i] * F_mu[i];
diff_norm_sq += 2.0 * F_mu[i] * dv + dv * dv;
}
lam_ok &= diff_norm_sq < - lam * F_norm_sq / 4.0;
}
}
if( ! lam_ok )
{ if( level > 0 )
std::cout << "end qp_interior: line search failed\n";
return false;
}
//
// update current solution
xout = x;
yout = y;
sout = s;
//
// updage F_0
F_0 = qp_interior_F_0(c, C, g, G, xout, yout, sout);
F_max_abs = qp_interior_max_abs( F_0 );
//
// update mu
if( F_max_abs <= 1e1 * mu )
mu = mu / 1e2;
if( level > 0 )
{ std::cout << "itr = " << itr
<< ", mu = " << mu
<< ", lam = " << lam
<< ", F_max_abs = " << F_max_abs << "\n";
abs_print_mat("xout", 1, n, xout);
}
}
if( level > 0 )
std::cout << "end qp_interior: progam error\n";
return false;
}
} // END_CPPAD_NAMESPACE
Input File: example/abs_normal/qp_interior.omh