672 lines
21 KiB
C
672 lines
21 KiB
C
|
// Copyright (c) 1997-2007 ETH Zurich (Switzerland).
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// This file is part of CGAL (www.cgal.org).
|
||
|
// You can redistribute it and/or modify it under the terms of the GNU
|
||
|
// General Public License as published by the Free Software Foundation,
|
||
|
// either version 3 of the License, or (at your option) any later version.
|
||
|
//
|
||
|
// Licensees holding a valid commercial license may use this file in
|
||
|
// accordance with the commercial license agreement provided with the software.
|
||
|
//
|
||
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
//
|
||
|
// $URL$
|
||
|
// $Id$
|
||
|
// SPDX-License-Identifier: GPL-3.0+
|
||
|
//
|
||
|
//
|
||
|
// Author(s) : Sven Schoenherr
|
||
|
// Bernd Gaertner <gaertner@inf.ethz.ch>
|
||
|
// Franz Wessendorp
|
||
|
// Kaspar Fischer
|
||
|
|
||
|
#include<CGAL/QP_functions.h>
|
||
|
|
||
|
namespace CGAL {
|
||
|
|
||
|
// creation & initialization
|
||
|
// -------------------------
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
QP_solver<Q, ET, Tags>::
|
||
|
QP_solver(const Q& qp, const Quadratic_program_options& options)
|
||
|
: et0(0), et1(1), et2(2),
|
||
|
strategyP(0),
|
||
|
inv_M_B(vout4),
|
||
|
d(inv_M_B.denominator()),
|
||
|
m_phase(-1), is_phaseI(false), is_phaseII(false),
|
||
|
is_RTS_transition(false),
|
||
|
is_LP(check_tag(Is_linear())), is_QP(!is_LP),
|
||
|
//no_ineq(check_tag(Has_equalities_only_and_full_rank())),
|
||
|
no_ineq(QP_functions_detail::is_in_equational_form(qp)),
|
||
|
// may change after phase I
|
||
|
has_ineq(!no_ineq),
|
||
|
is_nonnegative(check_tag(Is_nonnegative()))
|
||
|
{
|
||
|
// init diagnostics
|
||
|
diagnostics.redundant_equations = false;
|
||
|
|
||
|
// initialization as in the standard-form case:
|
||
|
set_verbosity(options.get_verbosity());
|
||
|
// only if C_entry is double, we actually get filtered strategies,
|
||
|
// otherwise we fall back to the respective non-filtered ones
|
||
|
set_pricing_strategy(options.get_pricing_strategy());
|
||
|
|
||
|
// Note: we first set the bounds and then call set() because set()
|
||
|
// accesses qp_fl, qp_l, etc.
|
||
|
set_explicit_bounds(qp);
|
||
|
set(qp);
|
||
|
|
||
|
// initialize and solve immediately:
|
||
|
init();
|
||
|
solve();
|
||
|
}
|
||
|
|
||
|
// set-up of QP
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set_D(const Q& /*qp*/, Tag_true /*is_linear*/)
|
||
|
{
|
||
|
// dummy value, never used
|
||
|
qp_D = 0;
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set_D(const Q& qp, Tag_false /*is_linear*/)
|
||
|
{
|
||
|
qp_D = qp.get_d();
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set(const Q& qp)
|
||
|
{
|
||
|
// assertions:
|
||
|
CGAL_qpe_assertion(qp.get_n() >= 0);
|
||
|
CGAL_qpe_assertion(qp.get_m() >= 0);
|
||
|
|
||
|
// store QP
|
||
|
qp_n = qp.get_n(); qp_m = qp.get_m();
|
||
|
qp_A = qp.get_a(); qp_b = qp.get_b(); qp_c = qp.get_c(); qp_c0 = qp.get_c0();
|
||
|
|
||
|
set_D(qp, Is_linear());
|
||
|
qp_r = qp.get_r();
|
||
|
|
||
|
// set up slack variables and auxiliary problem
|
||
|
// --------------------------------------------
|
||
|
|
||
|
// reserve memory for slack and artificial part of `A':
|
||
|
if (has_ineq) {
|
||
|
const unsigned int eq = static_cast<unsigned int>(std::count(qp_r, qp_r+qp_m, CGAL::EQUAL));
|
||
|
slack_A.reserve(qp_m - eq);
|
||
|
art_A.reserve ( eq);
|
||
|
art_s.insert(art_s.end(), qp_m, A_entry(0));
|
||
|
} else
|
||
|
art_A.reserve( qp_m);
|
||
|
|
||
|
// decide on which bound the variables sit initially:
|
||
|
if (!check_tag(Is_nonnegative()))
|
||
|
init_x_O_v_i();
|
||
|
|
||
|
set_up_auxiliary_problem();
|
||
|
|
||
|
e = static_cast<int>(qp_m-slack_A.size()); // number of equalities
|
||
|
l = (std::min)(qp_n+e+1, qp_m); // maximal size of basis in phase I
|
||
|
|
||
|
// diagnostic output:
|
||
|
CGAL_qpe_debug {
|
||
|
if (vout.verbose()) {
|
||
|
if (vout2.verbose()) {
|
||
|
vout2.out() << "======" << std::endl
|
||
|
<< "Set-Up" << std::endl
|
||
|
<< "======" << std::endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
vout << "[ " << (is_LP ? "LP" : "QP")
|
||
|
<< ", " << qp_n << " variables, " << qp_m << " constraints"
|
||
|
<< " ]" << std::endl;
|
||
|
CGAL_qpe_debug {
|
||
|
if (vout2.verbose() && (!slack_A.empty())) {
|
||
|
vout2.out() << " (" << slack_A.size() << " inequalities)";
|
||
|
}
|
||
|
if (vout2.verbose()) {
|
||
|
if (has_ineq)
|
||
|
vout2.out() << "flag: has inequalities or rank not full"
|
||
|
<< std::endl;
|
||
|
if (vout4.verbose()) print_program();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set up pricing strategy:
|
||
|
if (strategyP != static_cast< Pricing_strategy*>(0))
|
||
|
strategyP->set(*this, vout2);
|
||
|
|
||
|
// set up basis inverse:
|
||
|
inv_M_B.set(qp_n, qp_m, e);
|
||
|
|
||
|
// set phase:
|
||
|
m_phase = 0;
|
||
|
is_phaseI = false;
|
||
|
is_phaseII = false;
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set_explicit_bounds(const Q& qp)
|
||
|
{
|
||
|
set_explicit_bounds (qp, Is_nonnegative());
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set_explicit_bounds(const Q& /*qp*/, Tag_true) {
|
||
|
// dummy values, never used
|
||
|
qp_fl = 0;
|
||
|
qp_l = 0;
|
||
|
qp_fu = 0;
|
||
|
qp_u = 0;
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set_explicit_bounds(const Q& qp, Tag_false) {
|
||
|
qp_fl = qp.get_fl();
|
||
|
qp_l = qp.get_l();
|
||
|
qp_fu = qp.get_fu();
|
||
|
qp_u = qp.get_u();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_x_O_v_i()
|
||
|
{
|
||
|
// allocate storage:
|
||
|
x_O_v_i.reserve(qp_n);
|
||
|
x_O_v_i.resize (qp_n);
|
||
|
|
||
|
// constants for comparisions:
|
||
|
const L_entry l0(0);
|
||
|
const U_entry u0(0);
|
||
|
|
||
|
// our initial solution will have all original variables nonbasic,
|
||
|
// and so we initialize them to zero (if the bound on the variable
|
||
|
// allows it), or to the variable's lower or upper bound:
|
||
|
for (int i = 0; i < qp_n; ++i) {
|
||
|
CGAL_qpe_assertion( !*(qp_fl+i) || !*(qp_fu+i) || *(qp_l+i)<=*(qp_u+i));
|
||
|
|
||
|
if (*(qp_fl+i)) // finite lower bound?
|
||
|
if (*(qp_fu+i)) // finite lower and finite upper bound?
|
||
|
if (*(qp_l+i) == *(qp_u+i)) // fixed variable?
|
||
|
x_O_v_i[i] = FIXED;
|
||
|
else // finite lower and finite upper?
|
||
|
if (*(qp_l+i) <= l0 && u0 <= *(qp_u+i))
|
||
|
x_O_v_i[i] = ZERO;
|
||
|
else
|
||
|
x_O_v_i[i] = LOWER;
|
||
|
else // finite lower and infinite upper?
|
||
|
if (*(qp_l+i) <= l0)
|
||
|
x_O_v_i[i] = ZERO;
|
||
|
else
|
||
|
x_O_v_i[i] = LOWER;
|
||
|
else // infinite lower bound?
|
||
|
if (*(qp_fu+i)) // infinite lower and finite upper?
|
||
|
if (u0 <= *(qp_u+i))
|
||
|
x_O_v_i[i] = ZERO;
|
||
|
else
|
||
|
x_O_v_i[i] = UPPER;
|
||
|
else // infinite lower and infinite upper?
|
||
|
x_O_v_i[i] = ZERO;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
set_up_auxiliary_problem()
|
||
|
{
|
||
|
ET b_max(et0);
|
||
|
const C_entry c1(1);
|
||
|
int i_max = -1; // i_max-th inequality is the most infeasible one
|
||
|
int i_max_absolute = -1; // absolute index of most infeasible ineq
|
||
|
|
||
|
// TAG: TODO using variable i here, which is also the index of the entering
|
||
|
// variable.
|
||
|
for (int i = 0; i < qp_m; ++i) {
|
||
|
// Note: For nonstandard form problems, our initial solution is not the
|
||
|
// zero vector (but the vector with values original_variable_value(i),
|
||
|
// 0<=i<qp_n), and therefore, rhs=b-Ax is not simply b as in the standard
|
||
|
// form case, but Ax_init-b:
|
||
|
const ET rhs = check_tag(Is_nonnegative())?
|
||
|
ET(*(qp_b+i)) : ET(*(qp_b+i)) - multiply__A_ixO(i);
|
||
|
|
||
|
if (has_ineq && (*(qp_r+i) != CGAL::EQUAL)) { // inequality constraint, so we
|
||
|
// add a slack variable, and (if
|
||
|
// needed) a special artificial
|
||
|
if (*(qp_r+i) == CGAL::SMALLER) { // '<='
|
||
|
|
||
|
// add special artificial ('< -0') in case the inequality is
|
||
|
// infeasible for our starting point (which is the origin):
|
||
|
if (rhs < et0) {
|
||
|
art_s[i] = -c1;
|
||
|
if (-rhs > b_max) {
|
||
|
i_max = static_cast<int>(slack_A.size());
|
||
|
i_max_absolute = i;
|
||
|
b_max = -rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// slack variable:
|
||
|
slack_A.push_back(std::make_pair(i, false));
|
||
|
} else { // '>='
|
||
|
|
||
|
// add special artificial ('> +0') in case the inequality is
|
||
|
// infeasible for our starting point (which is the origin):
|
||
|
if (rhs > et0) {
|
||
|
art_s[i] = c1;
|
||
|
if (rhs > b_max) {
|
||
|
i_max = static_cast<int>(slack_A.size());
|
||
|
i_max_absolute = i;
|
||
|
b_max = rhs;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// store slack column
|
||
|
slack_A.push_back(std::make_pair(i, true));
|
||
|
}
|
||
|
|
||
|
} else { // equality constraint, so we
|
||
|
// add an artificial variable
|
||
|
// (Note: if rhs==et0 here then the artificial variable is (at the
|
||
|
// moment!) not needed. However, we nonetheless add it, for the following
|
||
|
// reason. If we did and were given an equality problem with the zero
|
||
|
// vector as the right-hand side then NO artificials would be added at
|
||
|
// all; so our initial basis would be empty, something we do not want.)
|
||
|
art_A.push_back(std::make_pair(i, rhs < et0));
|
||
|
}
|
||
|
} // end for
|
||
|
|
||
|
// Note: in order to make our initial starting point (which is the origin) a
|
||
|
// feasible point of the auxiliary problem, we need to initialize the
|
||
|
// special artificial value correctly, namely to
|
||
|
//
|
||
|
// max { |b_i| | i is index of an infeasible inequality constraint }. (C1)
|
||
|
//
|
||
|
// The index of this "most infeasible" constraint is, at this point of the
|
||
|
// code, i_max (or i_max is -1 in which case all inequality constraints are
|
||
|
// feasible and hence no special artififial column is needed at all).
|
||
|
|
||
|
// prepare initialization of special artificial column:
|
||
|
// Note: the real work is done in init_basis() below.
|
||
|
if (i_max >= 0) {
|
||
|
art_s_i = i_max; // Note: the actual
|
||
|
art_basic = i_max_absolute; // initialization of art_s_i
|
||
|
// will be done in init_basis()
|
||
|
// below. We misuse art_s_i to
|
||
|
// remember i_max and art_basic
|
||
|
// to remember i_max_absolute
|
||
|
} else { // no special art col needed
|
||
|
art_s_i = -1;
|
||
|
art_s.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// initialization (phase I)
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init()
|
||
|
{
|
||
|
CGAL_qpe_debug {
|
||
|
vout2 << std::endl
|
||
|
<< "==============" << std::endl
|
||
|
<< "Initialization" << std::endl
|
||
|
<< "==============" << std::endl;
|
||
|
|
||
|
}
|
||
|
|
||
|
// set status:
|
||
|
m_phase = 1;
|
||
|
m_status = QP_UPDATE;
|
||
|
m_pivots = 0;
|
||
|
is_phaseI = true;
|
||
|
is_phaseII = false;
|
||
|
|
||
|
// initial basis and basis inverse
|
||
|
init_basis();
|
||
|
|
||
|
// initialize additional data members
|
||
|
init_additional_data_members();
|
||
|
|
||
|
// initial solution
|
||
|
init_solution();
|
||
|
|
||
|
// initialize pricing strategy
|
||
|
CGAL_qpe_assertion(strategyP != static_cast< Pricing_strategy*>(0));
|
||
|
strategyP->init(0);
|
||
|
|
||
|
// basic feasible solution already available?
|
||
|
if (art_basic == 0) {
|
||
|
|
||
|
// transition to phase II
|
||
|
CGAL_qpe_debug {
|
||
|
if (vout2.verbose()) {
|
||
|
vout2.out() << std::endl
|
||
|
<< "no artificial variables at all "
|
||
|
<< "--> skip phase I"
|
||
|
<< std::endl;
|
||
|
}
|
||
|
}
|
||
|
transition();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set up the initial basis and basis inverse.
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_basis()
|
||
|
{
|
||
|
int s_i = -1;
|
||
|
int s_i_absolute = -1;
|
||
|
const int s = static_cast<int>(slack_A.size());
|
||
|
|
||
|
// has special artificial column?
|
||
|
if (!art_s.empty()) {
|
||
|
|
||
|
// Note: we maintain the information about the special artificial column in
|
||
|
// the variable art_s_i and the vector s_art; in addition, however, we also
|
||
|
// add a special "fake" column to art_A. This "fake" column has (in
|
||
|
// constrast to the special artificial column) only one nonzero entry,
|
||
|
// namely a +-1 for the most infeasible row (see (C1) above).
|
||
|
|
||
|
// add "fake" column to art_A:
|
||
|
s_i = art_s_i; // s_i-th ineq. is most infeasible, see (C1)
|
||
|
s_i_absolute = art_basic; // absolute index of most infeasible ineq
|
||
|
art_s_i = static_cast<int>(qp_n+s+art_A.size()); // number of special artificial var
|
||
|
// BG: By construction of art_s_i (= i_max) in set_up_auxiliary_problem(),
|
||
|
// s_i conforms with the indexing of slack_A, and the sign of the +-1
|
||
|
// entry is just the negative of the corresponding slackie; this explains
|
||
|
// the second parameter of make_pair. But the index passed as the
|
||
|
// first parameter must refer to the ABSOLUTE index of the most
|
||
|
// infeasible row. Putting s_i here is therefore a mistake unless
|
||
|
// we only have equality constraints
|
||
|
|
||
|
// art_A.push_back(std::make_pair(s_i, !slack_A[s_i].second));
|
||
|
CGAL_qpe_assertion(s_i_absolute >= 0);
|
||
|
CGAL_qpe_assertion(s_i_absolute == slack_A[s_i].first);
|
||
|
art_A.push_back(std::make_pair(s_i_absolute, !slack_A[s_i].second));
|
||
|
}
|
||
|
|
||
|
// initialize indices of basic variables:
|
||
|
if (!in_B.empty()) in_B.clear();
|
||
|
in_B.reserve(qp_n+s+art_A.size());
|
||
|
in_B.insert(in_B.end(), qp_n, -1); // no original variable is basic
|
||
|
|
||
|
init_basis__slack_variables(s_i, no_ineq);
|
||
|
|
||
|
if (!B_O.empty()) B_O.clear();
|
||
|
B_O.reserve(qp_n); // all artificial variables are basic
|
||
|
for (int i = 0; i < static_cast<int>(art_A.size()); ++i) {
|
||
|
B_O .push_back(qp_n+s+i);
|
||
|
in_B.push_back(i);
|
||
|
}
|
||
|
art_basic = static_cast<int>(art_A.size());
|
||
|
|
||
|
// initialize indices of 'basic' and 'nonbasic' constraints:
|
||
|
if (!C.empty()) C.clear();
|
||
|
init_basis__constraints(s_i, no_ineq);
|
||
|
|
||
|
// diagnostic output:
|
||
|
CGAL_qpe_debug {
|
||
|
if (vout.verbose()) print_basis();
|
||
|
}
|
||
|
|
||
|
// initialize basis inverse (explain: 'art_s' not needed here (todo kf: don't
|
||
|
// understand this note)):
|
||
|
// BG: as we only look at the basic constraints, the fake column in art_A
|
||
|
// will do as nicely as the actual column arts_s
|
||
|
inv_M_B.init(static_cast<unsigned int>(art_A.size()), art_A.begin());
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags > inline // no ineq.
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_basis__slack_variables( int, Tag_true)
|
||
|
{
|
||
|
// nop
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags > // has ineq.
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_basis__slack_variables(int s_i, Tag_false) // Note: s_i-th inequality is
|
||
|
// the most infeasible one,
|
||
|
// see (C1).
|
||
|
{
|
||
|
const int s = static_cast<int>(slack_A.size());
|
||
|
|
||
|
// reserve memory:
|
||
|
if (!B_S.empty()) B_S.clear();
|
||
|
B_S.reserve(s);
|
||
|
|
||
|
// all slack variables are basic, except the slack variable corresponding to
|
||
|
// special artificial variable (which is nonbasic): (todo kf: I do not
|
||
|
// understand this)
|
||
|
// BG: the s_i-th inequality is the most infeasible one, and the i-th
|
||
|
// inequality corresponds to the slackie of index qp_n + i
|
||
|
for (int i = 0; i < s; ++i) // go through all inequalities
|
||
|
if (i != s_i) {
|
||
|
in_B.push_back(static_cast<typename Indices::value_type>(B_S.size()));
|
||
|
B_S .push_back(i+qp_n);
|
||
|
} else
|
||
|
in_B.push_back(-1);
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags > inline // no ineq.
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_basis__constraints( int, Tag_true)
|
||
|
{
|
||
|
// reserve memory:
|
||
|
C.reserve(qp_m);
|
||
|
in_C.reserve(qp_m);
|
||
|
|
||
|
// As there are no inequalities, C consists of all inequality constraints
|
||
|
// only, so we add them all:
|
||
|
for (int i = 0; i < qp_m; ++i) {
|
||
|
C.push_back(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags > // has ineq.
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_basis__constraints(int s_i, Tag_false) // Note: s_i-th inequality is the
|
||
|
// most infeasible one, see (C1).
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
// reserve memory:
|
||
|
if (!in_C.empty()) in_C.clear();
|
||
|
if (! S_B.empty()) S_B.clear();
|
||
|
C.reserve(l);
|
||
|
S_B.reserve(slack_A.size());
|
||
|
|
||
|
// store constraints' indices:
|
||
|
in_C.insert(in_C.end(), qp_m, -1);
|
||
|
if (s_i >= 0) s_i = slack_A[s_i].first; // now s_i is absolute index
|
||
|
// of most infeasible row
|
||
|
for (i = 0, j = 0; i < qp_m; ++i)
|
||
|
if (*(qp_r+i) == CGAL::EQUAL) { // equal. constraint basic
|
||
|
C.push_back(i);
|
||
|
in_C[i] = j;
|
||
|
++j;
|
||
|
} else { // ineq. constraint nonbasic
|
||
|
if (i != s_i) // unless it's most infeasible
|
||
|
S_B.push_back(i);
|
||
|
}
|
||
|
// now handle most infeasible inequality if any
|
||
|
if (s_i >= 0) {
|
||
|
C.push_back(s_i);
|
||
|
in_C[s_i] = j;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Initialize r_C.
|
||
|
template < typename Q, typename ET, typename Tags > // Standard form
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_r_C(Tag_true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Initialize r_C.
|
||
|
template < typename Q, typename ET, typename Tags > // Upper bounded
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_r_C(Tag_false)
|
||
|
{
|
||
|
r_C.resize(C.size());
|
||
|
multiply__A_CxN_O(r_C.begin());
|
||
|
}
|
||
|
|
||
|
// Initialize r_S_B.
|
||
|
template < typename Q, typename ET, typename Tags > // Standard form
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_r_S_B(Tag_true)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Initialize r_S_B.
|
||
|
template < typename Q, typename ET, typename Tags > // Upper bounded
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_r_S_B(Tag_false)
|
||
|
{
|
||
|
r_S_B.resize(S_B.size());
|
||
|
multiply__A_S_BxN_O(r_S_B.begin());
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags > inline // no ineq.
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_solution__b_C(Tag_true)
|
||
|
{
|
||
|
b_C.reserve(qp_m);
|
||
|
std::copy(qp_b, qp_b+qp_m, std::back_inserter(b_C));
|
||
|
}
|
||
|
|
||
|
template < typename Q, typename ET, typename Tags > inline // has ineq.
|
||
|
void QP_solver<Q, ET, Tags>::
|
||
|
init_solution__b_C(Tag_false)
|
||
|
{
|
||
|
b_C.insert(b_C.end(), l, et0);
|
||
|
B_by_index_accessor b_accessor(qp_b); // todo kf: is there some boost
|
||
|
// replacement for this accessor?
|
||
|
std::copy(B_by_index_iterator(C.begin(), b_accessor),
|
||
|
B_by_index_iterator(C.end (), b_accessor),
|
||
|
b_C.begin());
|
||
|
}
|
||
|
|
||
|
// initial solution
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void
|
||
|
QP_solver<Q, ET, Tags>::
|
||
|
init_solution()
|
||
|
{
|
||
|
// initialize exact version of `qp_b' restricted to basic constraints C
|
||
|
// (implicit conversion to ET):
|
||
|
if (!b_C.empty()) b_C.clear();
|
||
|
init_solution__b_C(no_ineq);
|
||
|
|
||
|
// initialize exact version of `aux_c' and 'minus_c_B', the
|
||
|
// latter restricted to basic variables B_O:
|
||
|
if (!minus_c_B.empty()) minus_c_B.clear();
|
||
|
minus_c_B.insert(minus_c_B.end(), l, -et1); // todo: what is minus_c_B?
|
||
|
CGAL_qpe_assertion(l >= static_cast<int>(art_A.size()));
|
||
|
if (art_s_i > 0)
|
||
|
minus_c_B[art_A.size()-1] *= ET(qp_n+qp_m); // Note: the idea here is to
|
||
|
// give more weight to the
|
||
|
// special artifical variable
|
||
|
// so that it gets removed very
|
||
|
// early, - todo kf: why?
|
||
|
|
||
|
// ...and now aux_c: as we want to make all artificial variables (including
|
||
|
// the special one) zero, we weigh these variables with >= 1 in the objective
|
||
|
// function (and leave the other entries in the objective function at zero):
|
||
|
aux_c.reserve(art_A.size());
|
||
|
aux_c.insert(aux_c.end(), art_A.size(), 0);
|
||
|
for (int col=static_cast<int>(qp_n+slack_A.size()); col<number_of_working_variables(); ++col)
|
||
|
if (col==art_s_i) // special artificial?
|
||
|
aux_c[col-qp_n-slack_A.size()]= qp_n+qp_m;
|
||
|
else // normal artificial
|
||
|
aux_c[col-qp_n-slack_A.size()]= 1;
|
||
|
|
||
|
// allocate memory for current solution:
|
||
|
if (!lambda.empty()) lambda.clear();
|
||
|
if (!x_B_O .empty()) x_B_O .clear();
|
||
|
if (!x_B_S .empty()) x_B_S .clear();
|
||
|
lambda.insert(lambda.end(), l, et0);
|
||
|
x_B_O .insert(x_B_O .end(), l, et0);
|
||
|
x_B_S .insert(x_B_S .end(), slack_A.size(), et0);
|
||
|
|
||
|
#if 0 // todo kf: I guess the following can be removed...
|
||
|
//TESTING the updates of r_C, r_S_B, r_B_O, w
|
||
|
// ratio_test_bound_index = LOWER;
|
||
|
//direction = 1;
|
||
|
#endif
|
||
|
|
||
|
// The following sets the pricing direction to "up" (meaning that
|
||
|
// the priced variable will be increased and not decreased); the
|
||
|
// statement is completely useless except that it causes debugging
|
||
|
// output to be consistent in case we are running in standard form.
|
||
|
// (If we are in standard form, the variable 'direction' is never
|
||
|
// touched; otherwise, it will be set to the correct value during
|
||
|
// each pricing step.)
|
||
|
direction = 1;
|
||
|
|
||
|
// initialization of vectors r_C, r_S_B:
|
||
|
init_r_C(Is_nonnegative());
|
||
|
init_r_S_B(Is_nonnegative());
|
||
|
|
||
|
// compute initial solution:
|
||
|
compute_solution(Is_nonnegative());
|
||
|
|
||
|
// diagnostic output:
|
||
|
CGAL_qpe_debug {
|
||
|
if (vout.verbose()) print_solution();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Initialize additional data members.
|
||
|
template < typename Q, typename ET, typename Tags >
|
||
|
void
|
||
|
QP_solver<Q, ET, Tags>::
|
||
|
init_additional_data_members()
|
||
|
{
|
||
|
// todo kf: do we really have to insert et0, or would it suffice to just
|
||
|
// resize() in the following statements?
|
||
|
// BG: no clue, but it's at least safe that way
|
||
|
|
||
|
if (!A_Cj.empty()) A_Cj.clear();
|
||
|
A_Cj.insert(A_Cj.end(), l, et0);
|
||
|
if (!two_D_Bj.empty()) two_D_Bj.clear();
|
||
|
two_D_Bj.insert(two_D_Bj.end(), l, et0);
|
||
|
|
||
|
if (!q_lambda.empty()) q_lambda.clear();
|
||
|
q_lambda.insert(q_lambda.end(), l, et0);
|
||
|
if (!q_x_O.empty()) q_x_O.clear();
|
||
|
q_x_O.insert(q_x_O.end(), l, et0);
|
||
|
if (!q_x_S.empty()) q_x_S.clear();
|
||
|
q_x_S.insert(q_x_S.end(), slack_A.size(), et0);
|
||
|
|
||
|
if (!tmp_l.empty()) tmp_l.clear();
|
||
|
tmp_l.insert(tmp_l.end(), l, et0);
|
||
|
if (!tmp_l_2.empty()) tmp_l_2.clear();
|
||
|
tmp_l_2.insert(tmp_l_2.end(), l, et0);
|
||
|
if (!tmp_x.empty()) tmp_x.clear();
|
||
|
tmp_x.insert(tmp_x.end(), l, et0);
|
||
|
if (!tmp_x_2.empty()) tmp_x_2.clear();
|
||
|
tmp_x_2.insert(tmp_x_2.end(), l, et0);
|
||
|
}
|
||
|
|
||
|
} //namespace CGAL
|
||
|
|
||
|
// ===== EOF ==================================================================
|