dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/QP_solution.h

846 lines
24 KiB
C++
Executable File

// 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.
//
// Licenseges 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) : Kaspar Fischer
// : Bernd Gaertner <gaertner@inf.ethz.ch>
// : Sven Schoenherr
// : Franz Wessendorp
#ifndef CGAL_QP_SOLUTION_H
#define CGAL_QP_SOLUTION_H
#include <CGAL/license/QP_solver.h>
#include <CGAL/disable_warnings.h>
#include <iostream>
#include <vector>
#include <CGAL/basic.h>
#include <CGAL/Handle_for.h>
#include <CGAL/function_objects.h>
#include <CGAL/Algebraic_structure_traits.h>
#include <CGAL/QP_solver/assertions.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <CGAL/boost/iterator/transform_iterator.hpp>
namespace CGAL {
// forward references
template <typename Q, typename ET, typename Tags>
class QP_solver;
namespace QP_solution_detail {
template <typename ET>
class Quotient_normalizer;
template <typename ET>
class Value_by_index;
template <typename ET>
class Unbounded_direction_by_index;
template <typename ET>
class Lambda_by_index;
}
// global status type
enum Quadratic_program_status
{
QP_UPDATE,
QP_INFEASIBLE,
QP_UNBOUNDED,
QP_OPTIMAL
};
// abstract base class of all QP-solvers
// -------------------------------------
template <class ET>
class QP_solver_base
{
public:
// types
typedef CGAL::Creator_2< ET, ET, Quotient<ET> >
U_Quotient_creator; // unnormalized quotient creator ET x ET -> (ET, ET)
typedef QP_solution_detail::Quotient_normalizer<ET>
Quotient_normalizer; // normalizer (ET, ET) -> (ET, ET)
typedef boost::function1< Quotient<ET>, ET >
Quotient_maker;
typedef std::vector<int>
Indices;
typedef Indices::iterator
Index_mutable_iterator;
typedef Indices::const_iterator
Index_const_iterator;
typedef typename QP_solution_detail::Value_by_index<ET> Value_by_index;
typedef typename boost::transform_iterator
<Value_by_index, boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t> >
Variable_numerator_iterator;
typedef boost::transform_iterator
<Quotient_maker, Variable_numerator_iterator>
Variable_value_iterator;
typedef typename QP_solution_detail::Unbounded_direction_by_index<ET>
Unbounded_direction_by_index;
typedef boost::transform_iterator
<Unbounded_direction_by_index, boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t> >
Unbounded_direction_iterator;
typedef typename QP_solution_detail::Lambda_by_index<ET>
Lambda_by_index;
typedef boost::transform_iterator
<Lambda_by_index, boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t> >
Lambda_numerator_iterator;
typedef boost::transform_iterator
<Quotient_maker,Lambda_numerator_iterator>
Lambda_iterator;
public:
// virtual access functions to solution that will
// be overridden by QP_solver below
// Solution
// --------
virtual ET solution_numerator() const = 0;
virtual ET solution_denominator() const = 0;
Quotient<ET> solution( ) const
{
// workaround to please Boost 1.33.1:
ET n = solution_numerator();
ET d = solution_denominator();
return
boost::bind
(Quotient_normalizer(), boost::bind
(U_Quotient_creator(), _1, _2))
(n, d);
// (solution_numerator(), solution_denominator());
}
virtual Quadratic_program_status status() const = 0;
virtual int iterations() const = 0;
// Variable values
// ---------------
virtual ET variable_numerator_value (int i) const = 0;
virtual const ET& variables_common_denominator( ) const = 0;
virtual int number_of_variables() const = 0;
// value type ET
Variable_numerator_iterator
original_variables_numerator_begin( ) const
{ return Variable_numerator_iterator
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
Value_by_index(this));}
Variable_numerator_iterator
original_variables_numerator_end ( ) const
{ return Variable_numerator_iterator
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(number_of_variables()) ,
Value_by_index(this));}
// value type Quotient<ET>
Variable_value_iterator
original_variable_values_begin( ) const
{ return Variable_value_iterator
(original_variables_numerator_begin(),
boost::bind
(boost::bind
(Quotient_normalizer(), boost::bind
(U_Quotient_creator(), _1, _2)), _1, variables_common_denominator()));
}
Variable_value_iterator
original_variable_values_end ( ) const
{ return Variable_value_iterator
(original_variables_numerator_end(),
boost::bind
(boost::bind
(Quotient_normalizer(), boost::bind
(U_Quotient_creator(), _1, _2)), _1, variables_common_denominator()));
}
// Basic variables and constraints
// -------------------------------
virtual Index_const_iterator
basic_original_variable_indices_begin() const = 0;
virtual Index_const_iterator
basic_original_variable_indices_end() const = 0;
virtual int number_of_basic_original_variables() const = 0;
virtual Index_const_iterator
basic_constraint_indices_begin() const = 0;
virtual Index_const_iterator
basic_constraint_indices_end() const = 0;
virtual int number_of_basic_constraints() const = 0;
// Unboundedness
// -------------
virtual ET unbounded_direction_value(int i) const = 0;
Unbounded_direction_iterator unbounded_direction_begin() const
{ return Unbounded_direction_iterator
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
Unbounded_direction_by_index(this));}
// Returns the past-the-end iterator corresponding to
// unbounded_direction_begin().
Unbounded_direction_iterator unbounded_direction_end() const
{ return Unbounded_direction_iterator
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(number_of_variables()),
Unbounded_direction_by_index(this));}
// Optimality
// ----------
virtual ET lambda_numerator(int i) const = 0;
virtual int number_of_constraints() const = 0;
// value type ET
Lambda_numerator_iterator
lambda_numerator_begin() const
{ return Lambda_numerator_iterator
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
Lambda_by_index(this));}
Lambda_numerator_iterator
lambda_numerator_end() const
{ return Lambda_numerator_iterator
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(number_of_constraints()),
Lambda_by_index(this));}
// value type Quotient<ET>
Lambda_iterator
lambda_begin() const
{
return Lambda_iterator
(lambda_numerator_begin(),
boost::bind
(boost::bind
(Quotient_normalizer(), boost::bind
(U_Quotient_creator(), _1, _2)), _1, variables_common_denominator()));
}
Lambda_iterator
lambda_end() const
{
return Lambda_iterator
(lambda_numerator_end(),
boost::bind
(boost::bind
(Quotient_normalizer(), boost::bind
(U_Quotient_creator(), _1, _2)), _1, variables_common_denominator()));
}
// destruction
// -----------
virtual ~QP_solver_base() {}
};
// Quadratic_program_solution class: a handle for QP_solver_base<ET>
// -----------------------------------------------------------------
template <class ET_>
class Quadratic_program_solution: Handle_for<const QP_solver_base<ET_>*>
{
public:
typedef ET_ ET;
// interface types
// ===============
// variable values / indices
// -------------------------
typedef typename QP_solver_base<ET>::Variable_value_iterator
Variable_value_iterator;
typedef typename QP_solver_base<ET>::Variable_numerator_iterator
Variable_numerator_iterator;
typedef typename QP_solver_base<ET>::Index_const_iterator
Index_iterator;
// certificates
// ------------
typedef typename QP_solver_base<ET>::Unbounded_direction_iterator
Unboundedness_certificate_iterator;
typedef
typename QP_solver_base<ET>::Lambda_numerator_iterator
Optimality_certificate_numerator_iterator;
typedef typename QP_solver_base<ET>::Lambda_iterator
Optimality_certificate_iterator;
typedef typename QP_solver_base<ET>::Lambda_numerator_iterator
Infeasibility_certificate_iterator;
// methods
// -------
Quadratic_program_solution ()
: Handle_for<const QP_solver_base<ET>*>(), et0(0)
{
*(this->ptr()) = 0; // unitialized solution
}
Quadratic_program_solution (const QP_solver_base<ET>* s)
: Handle_for<const QP_solver_base<ET>*>(s), et0(0)
{}
Quadratic_program_solution&
operator= (const Quadratic_program_solution& sol)
{
if (this != &sol) {
// delete the old solver if necessary
if (!this->is_shared()) delete *(this->ptr());
this->Handle_for<const QP_solver_base<ET>*>::operator=(sol);
}
return *this;
}
~Quadratic_program_solution()
{
if (!this->is_shared()) delete *(this->ptr());
}
private:
const QP_solver_base<ET>* solver() const
{
return *(this->Ptr());
}
public:
bool is_void() const
{
return solver() == 0;
}
Quotient<ET> objective_value() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->solution();
}
ET objective_value_numerator() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->solution_numerator();
}
ET objective_value_denominator() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->solution_denominator();
}
Quadratic_program_status status() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->status();
}
bool is_optimal() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return status() == QP_OPTIMAL;
}
bool is_infeasible() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return status() == QP_INFEASIBLE;
}
bool is_unbounded() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return status() == QP_UNBOUNDED;
}
int number_of_iterations() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->iterations();
}
Variable_value_iterator variable_values_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->original_variable_values_begin();
}
Variable_value_iterator variable_values_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->original_variable_values_end();
}
Variable_numerator_iterator variable_numerators_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->original_variables_numerator_begin();
}
Variable_numerator_iterator variable_numerators_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->original_variables_numerator_end();
}
const ET& variables_common_denominator() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->variables_common_denominator();
}
Index_iterator basic_variable_indices_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->basic_original_variable_indices_begin();
}
Index_iterator basic_variable_indices_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->basic_original_variable_indices_end();
}
int number_of_basic_variables() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->number_of_basic_original_variables();
}
Index_iterator basic_constraint_indices_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->basic_constraint_indices_begin();
}
Index_iterator basic_constraint_indices_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->basic_constraint_indices_end();
}
int number_of_basic_constraints() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
return solver()->number_of_basic_constraints();
}
Optimality_certificate_numerator_iterator
optimality_certificate_numerators_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_OPTIMAL);
return solver()->lambda_numerator_begin();
}
Optimality_certificate_numerator_iterator
optimality_certificate_numerators_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_OPTIMAL);
return solver()->lambda_numerator_end();
}
Optimality_certificate_iterator
optimality_certificate_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_OPTIMAL);
return solver()->lambda_begin();
}
Optimality_certificate_iterator
optimality_certificate_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_OPTIMAL);
return solver()->lambda_end();
}
// infeasibility
// -------------
Infeasibility_certificate_iterator
infeasibility_certificate_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_INFEASIBLE);
return solver()->lambda_numerator_begin();
}
Infeasibility_certificate_iterator
infeasibility_certificate_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_INFEASIBLE);
return solver()->lambda_numerator_end();
}
// unboundedness
// -------------
Unboundedness_certificate_iterator unboundedness_certificate_begin() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_UNBOUNDED);
return solver()->unbounded_direction_begin();
}
Unboundedness_certificate_iterator unboundedness_certificate_end() const
{
CGAL_qpe_assertion_msg(!is_void(), "Solution not initialized");
CGAL_qpe_assertion(status() == QP_UNBOUNDED);
return solver()->unbounded_direction_end();
}
private:
ET et0; // 0
// validity
// --------
// error message returned by failing validation
std::string err_msg;
// the error message is set by the following function
bool error (const std::string& message)
{
err_msg = message;
return false;
}
public:
bool is_valid() const
{
return err_msg.empty();
}
const std::string& get_error() const
{
return err_msg;
}
// these four methods use the certificates to validate the solution
// of all four program types; in case this fails, the solution becomes
// invalid (and this explains why the methods are non-const)
template <class QuadraticProgram>
bool solves_quadratic_program
(const QuadraticProgram& qp)
{ return solves_program(qp, Tag_false(), Tag_false()); }
template <class LinearProgram>
bool solves_linear_program
(const LinearProgram& lp)
{ return solves_program(lp, Tag_true(), Tag_false()); }
template <class NonnegativeQuadraticProgram>
bool solves_nonnegative_quadratic_program
(const NonnegativeQuadraticProgram& qp)
{ return solves_program(qp, Tag_false(), Tag_true()); }
template <class NonnegativeLinearProgram>
bool solves_nonnegative_linear_program
(const NonnegativeLinearProgram& lp)
{ return solves_program(lp, Tag_true(), Tag_true()); }
// helper used by all four validation methods above; see
// QP_solver/QP_solution_impl.h for its implementation
template <class Program, typename Is_linear, typename Is_nonnegative>
bool solves_program (const Program& p,
Is_linear is_linear, Is_nonnegative is_nonnegative);
private:
// helpers used by the previous method
template <typename Program>
bool is_feasible (const Program& p,
typename std::vector<ET>& ax_minus_b,
Tag_true /*is_nonnegative*/);
template <typename Program>
bool is_feasible (const Program& p,
typename std::vector<ET>& ax_minus_b,
Tag_false /*is_nonnegative*/);
template <typename Program>
bool is_optimal_1 (const Program& p);
template <typename Program>
bool is_optimal_2 (const Program& p,
const typename std::vector<ET>& ax_minus_b);
template <typename Program>
bool is_optimal_3 (const Program& p, typename std::vector<ET>& two_Dx,
Tag_true /*is_linear*/, Tag_true /*is_nonnegative*/);
template <typename Program>
bool is_optimal_3 (const Program& p, typename std::vector<ET>& two_Dx,
Tag_false /*is_linear*/, Tag_true /*is_nonnegative*/);
template <typename Program>
bool is_optimal_3 (const Program& p, typename std::vector<ET>& two_Dx,
Tag_true /*is_linear*/, Tag_false /*is_nonnegative*/);
template <typename Program>
bool is_optimal_3 (const Program& p, typename std::vector<ET>& two_Dx,
Tag_false /*is_linear*/, Tag_false /*is_nonnegative*/);
template <typename Program>
bool is_infeasible_1 (const Program& p);
template <typename Program>
bool is_infeasible_2 (const Program& p,
typename std::vector<ET>& lambda_a,
Tag_true /*is_nonnegative*/);
template <typename Program>
bool is_infeasible_2 (const Program& p,
typename std::vector<ET>& lambda_a,
Tag_false /*is_nonnegative*/);
template <typename Program>
bool is_infeasible_3 (const Program& p,
const typename std::vector<ET>& /*lambda_a*/,
Tag_true /*is_nonnegative*/);
template <typename Program>
bool is_infeasible_3 (const Program& p,
const typename std::vector<ET>& lambda_a,
Tag_false /*is_nonnegative*/);
template <typename Program>
bool is_unbounded_1 (const Program& p);
template <typename Program>
bool is_unbounded_2 (const Program& p, Tag_true /*is_nonnegative*/);
template <typename Program>
bool is_unbounded_2 (const Program& p, Tag_false /*is_nonnegative*/);
template <typename Program>
bool is_unbounded_3 (const Program& p, Tag_true /*is_linear*/);
template <typename Program>
bool is_unbounded_3 (const Program& p, Tag_false /*is_linear*/);
template <typename Program>
bool is_value_correct
(const Program& p, typename std::vector<ET>& /*two_Dx*/,
Tag_true /*is_linear*/);
template <typename Program>
bool is_value_correct
(const Program& p, typename std::vector<ET>& two_Dx,
Tag_false /*is_linear*/);
template <typename Program>
bool are_constraints_feasible
(const Program& p, typename std::vector<ET>& ax);
template <typename Program>
bool are_bounds_feasible (const Program& p, Tag_true /*is_nonnegative*/);
template <typename Program>
bool are_bounds_feasible (const Program& p, Tag_false /*is_nonnegative*/);
template <typename Program, typename Z_iterator >
void add_Az
(const Program& p, Z_iterator z, typename std::vector<ET>& v);
template <typename Program, typename Z_iterator >
void add_two_Dz
(const Program& p, Z_iterator z, typename std::vector<ET>& v);
template <typename Program, typename Z_iterator >
void add_zA
(const Program& p, Z_iterator z, typename std::vector<ET>& v);
template <typename Program>
void add_c
(const Program& p, typename std::vector<ET>& v);
};
// output
template <typename ET>
std::ostream& operator<<
(std::ostream& o, const Quadratic_program_solution<ET>& s)
{
o << "status: ";
switch (s.status()) {
case QP_INFEASIBLE:
return o << "INFEASIBLE\n";
case QP_UNBOUNDED:
return o << "UNBOUNDED\n";
case QP_OPTIMAL:
o << "OPTIMAL\n";
break;
default:
CGAL_qpe_assertion(false);
}
o << "objective value: " << s.objective_value() << "\n";
o << "variable values:\n";
int j=0;
for ( typename Quadratic_program_solution<ET>::Variable_value_iterator
it = s.variable_values_begin();
it < s.variable_values_end(); ++it, ++j)
o << " " << j << ": " << *it << "\n";
return o;
}
// Details
namespace QP_solution_detail {
// Quotient_normalizer
// -------------------
template < typename ET>
class Quotient_normalizer {
public:
typedef CGAL::Quotient<ET> result_type;
private:
typedef CGAL::Algebraic_structure_traits<ET> AST;
typedef typename AST::Algebraic_category Category;
public:
typedef CGAL::Boolean_tag<
CGAL::is_same_or_derived<CGAL::Unique_factorization_domain_tag,Category>::value>
Has_gcd;
typedef CGAL::Boolean_tag<
CGAL::is_same_or_derived<CGAL::Integral_domain_tag,Category>::value>
Has_exact_division;
CGAL::Quotient<ET> normalize
(const CGAL::Quotient<ET>& q,
Tag_true /*has_gcd*/,
Tag_true /*has_exact_division*/) const
{
if (CGAL::is_zero (q.numerator()))
return CGAL::Quotient<ET>(ET(0), ET(1));
ET gcd = CGAL::gcd (q.numerator(), q.denominator());
return CGAL::Quotient<ET>
(CGAL::integral_division (q.numerator(), gcd),
CGAL::integral_division (q.denominator(), gcd));
}
CGAL::Quotient<ET> normalize
(const CGAL::Quotient<ET>& q,
Tag_true /*has_gcd*/,
Tag_false /*has_exact_division*/) const
{
return q;
}
CGAL::Quotient<ET> normalize
(const CGAL::Quotient<ET>& q,
Tag_false /*has_gcd*/,
Tag_true /*has_exact_division*/) const
{
return q;
}
CGAL::Quotient<ET> normalize
(const CGAL::Quotient<ET>& q,
Tag_false /*has_gcd*/,
Tag_false /*has_exact_division*/) const
{
return q;
}
CGAL::Quotient<ET> operator() (const CGAL::Quotient<ET>& q) const
{
return normalize (q, Has_gcd(), Has_exact_division());
}
};
// Value_by_index
// --------------
template < typename ET>
class Value_by_index : public CGAL::cpp98::unary_function< std::size_t, ET>
{
public:
typedef QP_solver_base<ET> QP;
typedef ET result_type;
Value_by_index(const QP* solver)
: s (solver)
{}
// returns value * denominator
result_type operator () ( std::size_t i) const
{
return s->variable_numerator_value(static_cast<int>(i));
}
const QP* s;
};
// Unbounded_direction_by_index
// ----------------------------
template < typename ET>
class Unbounded_direction_by_index : public CGAL::cpp98::unary_function< std::size_t, ET>
{
public:
typedef QP_solver_base<ET> QP;
typedef ET result_type;
Unbounded_direction_by_index(const QP* solver)
: s (solver)
{}
result_type operator () ( std::size_t i) const
{
return s->unbounded_direction_value(static_cast<int>(i));
}
const QP* s;
};
// Lambda_by_index
// ---------------
template < typename ET>
class Lambda_by_index : public CGAL::cpp98::unary_function< std::size_t, ET>
{
public:
typedef QP_solver_base<ET> QP;
typedef ET result_type;
Lambda_by_index(const QP* solver)
: s (solver)
{}
result_type operator () ( std::size_t i) const
{
return s->lambda_numerator(static_cast<int>(i));
}
const QP* s;
};
}
} //namespace CGAL
#include <CGAL/QP_solver/QP_solution_impl.h>
#include <CGAL/enable_warnings.h>
#endif// CGAL_QP_SOLUTION_H