diff --git a/QP_solver/include/CGAL/QP_solver.h b/QP_solver/include/CGAL/QP_solver.h index 273346e4c0e..e77661f10cf 100644 --- a/QP_solver/include/CGAL/QP_solver.h +++ b/QP_solver/include/CGAL/QP_solver.h @@ -1340,7 +1340,8 @@ private: // validity checks: bool is_solution_feasible_for_auxiliary_problem() const; bool is_solution_optimal_for_auxiliary_problem() const; - bool is_solution_feasible() const; + bool is_solution_feasible() const; + bool is_solution_infeasible() const; bool is_solution_optimal() const; bool is_value_correct() const; bool is_solution_unbounded() const; diff --git a/QP_solver/include/CGAL/QP_solver/Initialization.h b/QP_solver/include/CGAL/QP_solver/Initialization.h index dd43a3aeadd..fb5ac2cac14 100644 --- a/QP_solver/include/CGAL/QP_solver/Initialization.h +++ b/QP_solver/include/CGAL/QP_solver/Initialization.h @@ -195,7 +195,7 @@ init_x_O_v_i() // 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_l[i]<=qp_u[i] || !*(qp_fl+i) || !*(qp_fu+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? diff --git a/QP_solver/include/CGAL/QP_solver/QP_functions_impl.h b/QP_solver/include/CGAL/QP_solver/QP_functions_impl.h index e74fa8e9dbe..0bbad36bee5 100644 --- a/QP_solver/include/CGAL/QP_solver/QP_functions_impl.h +++ b/QP_solver/include/CGAL/QP_solver/QP_functions_impl.h @@ -135,7 +135,8 @@ namespace QP_functions_detail { int n = p.n(); bool empty_D = true; for (int i=0; i et0) && (k < qp_n) && *(qp_fu+k)) { ET diff = (d * ET(qp_u[k])) - x_k; if (diff * q_min < d_min * q_k) { i_min = k; diff --git a/QP_solver/include/CGAL/QP_solver/QP_solver_validity_impl.h b/QP_solver/include/CGAL/QP_solver/QP_solver_validity_impl.h index d76cdd11a90..59675389394 100644 --- a/QP_solver/include/CGAL/QP_solver/QP_solver_validity_impl.h +++ b/QP_solver/include/CGAL/QP_solver/QP_solver_validity_impl.h @@ -75,6 +75,7 @@ bool QP_solver::is_valid() const { const bool f = this->is_solution_feasible_for_auxiliary_problem(); const bool o = this->is_solution_optimal_for_auxiliary_problem(); + const bool i = this->is_solution_infeasible(); const bool aux_positive = ( (this->solution_numerator() > et0) && (d > et0) ); CGAL_qpe_debug { @@ -85,9 +86,10 @@ bool QP_solver::is_valid() const vout << " is in phase I: " << is_phaseI << std::endl; vout << " feasible_aux: " << f << std::endl; vout << " optimal_aux: " << o << std::endl; + vout << " infeasible: " << i << std::endl; vout << " obj. val. positive: " << aux_positive << std::endl; } - return is_phaseI && f && o && aux_positive; + return is_phaseI && f && o && i && aux_positive; } case QP_UNBOUNDED: { @@ -127,16 +129,30 @@ bool QP_solver::is_solution_feasible_for_auxiliary_problem() const if (*i_it < qp_n) { // original variable? if ((has_finite_lower_bound(*i_it) && (*v_it < lower_bound(*i_it) * d))|| (has_finite_upper_bound(*i_it) && (*v_it > upper_bound(*i_it) * d))) - return false; + { + CGAL_qpe_debug { + vout4 << "variable " << *i_it << " out of bounds" << std::endl; + } + return false; + } } else // artificial variable? if (*v_it < et0) - return false; + { + CGAL_qpe_debug { + vout4 << "artificial variable negative" << std::endl; + } + return false; + } } // check nonegativity of slack variables (the basic ones suffice): for (Value_const_iterator v_it = x_B_S.begin(); v_it != x_B_S.end(); ++v_it) - if (*v_it < et0) + if (*v_it < et0) { + CGAL_qpe_debug { + vout4 << "slack variable out of bounds" << std::endl; + } return false; + } // Check whether the current solution is feasible for the auxiliary // problem. For this, we use the fact that the auxiliary problem @@ -192,11 +208,75 @@ bool QP_solver::is_solution_feasible_for_auxiliary_problem() const // check equality (C1); for (int i=0; i +bool QP_solver::is_solution_infeasible() const +{ + // checks whether we have a proof of infeasibilty according + // to Farkas Lemma. Namely, the system is infeasible iff + // \tau^T = \lambda^T A (A) + // \lambda^T b - \sum{j: \tau_j < 0} \tau_j u_j + // - \sum{j: \tau_j > 0} \tau_j l_j < 0 (B) + // \lambda_i >= 0 for <=-constraints i, (C) + // \lambda_i <= 0 for >=-constraints i, (D) + + // get \lambda: + // Note: as the \lambda' we have access to is actual d times the \lambda + // we will not compute \tau but \tau * d. + Optimality_certificate_numerator_iterator + itb = optimality_certificate_numerator_begin(); + Optimality_certificate_numerator_iterator + ite = optimality_certificate_numerator_end(); + Optimality_certificate_iterator + itq = optimality_certificate_begin(); + Values lambda_prime; + int row = 0; + for (Optimality_certificate_numerator_iterator + it = itb; it != ite; ++it, ++itq, ++row) { + // simply check whether numerator/denominator gives correct value + CGAL_qpe_assertion (*it * (*itq).denominator() == (*itq).numerator() * d); + lambda_prime.push_back(*it); + // check sign (C) (D) + if (qp_r[row] == CGAL::SMALLER) + if (lambda_prime[row] < et0) return false; + if (qp_r[row] == CGAL::LARGER) + if (lambda_prime[row] > et0) return false; + } + + // compute \tau^T = \lambda^T A (A): + Values tau(qp_n,et0); + for (int col = 0; col < qp_n; ++col) + for (int i=0; i et0) { + CGAL_qpe_assertion(has_finite_lower_bound(col)); + sum -= tau[col] * lower_bound(col); // tau carries factor of d + } + } + return sum < et0; +} + + template < typename Q, typename ET, typename Tags > bool QP_solver::is_value_correct() const { @@ -443,8 +523,12 @@ bool QP_solver::is_solution_feasible() const if (var != *it) return false; // original_variables_numerator_begin() inconsistent if ((has_finite_lower_bound(i) && var < lower_bound(i) * d) || - (has_finite_upper_bound(i) && var > upper_bound(i) * d)) + (has_finite_upper_bound(i) && var > upper_bound(i) * d)) { + CGAL_qpe_debug { + vout4 << "variable " << i << " out of bounds" << std::endl; + } return false; + } // compute A x times d: for (int j=0; j::is_solution_feasible() const const ET rhs = ET(qp_b[row])*d; if ((qp_r[row] == CGAL::EQUAL && lhs_col[row] != rhs) || (qp_r[row] == CGAL::SMALLER && lhs_col[row] > rhs) || - (qp_r[row] == CGAL::LARGER && lhs_col[row] < rhs)) + (qp_r[row] == CGAL::LARGER && lhs_col[row] < rhs)) { + CGAL_qpe_debug { + vout4 << "row " << row << " infeasible" << std::endl; + } return false; + } } return true; diff --git a/QP_solver/test/QP_solver/master_mps_to_derivatives.cpp b/QP_solver/test/QP_solver/master_mps_to_derivatives.cpp index 77ddd972ac2..7ff6314fb9f 100644 --- a/QP_solver/test/QP_solver/master_mps_to_derivatives.cpp +++ b/QP_solver/test/QP_solver/master_mps_to_derivatives.cpp @@ -191,7 +191,7 @@ void create_shifted_instance(CGAL::QP_from_mps for (int i=0; i #else -#include +#include #endif #include @@ -49,11 +49,11 @@ int main(const int argNr,const char **args) { const int verbosity = argNr < 2? 1 : std::atoi(args[1]); // construct QP instance: - typedef double IT; + typedef int IT; #ifndef CGAL_USE_GMP typedef CGAL::MP_Float ET; #else - typedef CGAL::Gmpzf ET; + typedef CGAL::Gmpz ET; #endif typedef CGAL::QP_from_mps QP; QP qp(std::cin,true,verbosity); @@ -69,7 +69,7 @@ int main(const int argNr,const char **args) { CGAL::print_quadratic_program (cout, qp); cout << std::endl; } - typedef CGAL::QP_solver_impl::QP_tags Tags; + typedef CGAL::QP_solver_impl::QP_tags Tags; CGAL::QP_pricing_strategy *pricing_strategy = new CGAL::QP_full_exact_pricing; typedef CGAL::QP_solver Solver;