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