- in Quadratic_program model, default bounds can now be configured,

and there are some tests that cover this
This commit is contained in:
Bernd Gärtner 2007-04-13 16:12:08 +00:00
parent 7a80cfa1a3
commit 890c5d0fed
6 changed files with 249 additions and 52 deletions

2
.gitattributes vendored
View File

@ -1871,7 +1871,7 @@ QP_solver/examples/QP_solver/unboundedness_certificate.cpp -text
QP_solver/maintainer -text
QP_solver/test/QP_solver/create_test_solver_cin -text
QP_solver/test/QP_solver/debug_bug.cpp -text
QP_solver/test/QP_solver/test_empty_qp.cpp -text
QP_solver/test/QP_solver/test_default_bounds.cpp -text
QP_solver/test/QP_solver/test_random_qp.cpp -text
QP_solver/test/QP_solver/test_solver.cout -text
Qt_widget/demo/Qt_widget/hellosegment.vcproj eol=crlf

View File

@ -52,13 +52,22 @@ the model \ccc{Quadratic_program_from_mps<NT>}.
\ccCreationVariable{qp}
\ccConstructor{
Quadratic_program(CGAL::Comparison_result default_r = CGAL::EQUAL);}
Quadratic_program
(CGAL::Comparison_result default_r = CGAL::EQUAL,
bool default_fl = true,
const NT& default_l = 0,
bool default_fu = false,
const NT& default_u = 0);}
{constructs a quadratic program with no variables and no constraints, ready
for data to be added. Unless
bounds are explicitly set using one of the methods below, bounds will be
$x\geq 0$. Unless relations are explicitly set, relations will be of type
\ccc{default_r}. Numerical entries that are not explicitly set will
default to $0$.}
for data to be added. Unless relations are explicitly set, they will
be of type \ccc{default_r}. Unless bounds are explicitly set, they
will be as specified by \ccc{default_fl} (finite lower bound?),
\ccc{default_l} (lower bound value if lower bound is finite),
\ccc{default_fu} (finite upper bound?), and
\ccc{default_l} (upper bound value if upper bound is finite). If all
parameters take their default values, we thus get equality constraints
and bounds $x\geq 0$ by default. Numerical entries that are not
explicitly set will default to $0$.}
\ccOperations
@ -96,9 +105,10 @@ of \ccVar\ to \ccc{val}. An existing entry is overwritten.
\ccMethod{void set_c0 (const NT& val);}{sets the entry $c_0$
of \ccVar\ to \ccc{val}. An existing entry is overwritten.}
\ccMethod{void set_d (int i, int j, const NT& val);}{sets the entry
$2D_{ij}$ of \ccVar\ to \ccc{val}. An existing entry is overwritten.
\ccVar\ is enlarged if necessary to accomodate this entry.}
\ccMethod{void set_d (int i, int j, const NT& val);}{sets the entries
$2D_{ij}$ and $2D_{ji}$ of \ccVar\ to \ccc{val}. Existing entries are
overwritten. \ccVar\ is enlarged if necessary to accomodate these entries.
\ccPrecond \ccc{j <= i}}
\ccSeeAlso

View File

@ -97,9 +97,10 @@ of \ccVar\ to \ccc{val}. An existing entry is overwritten.
\ccMethod{void set_c0 (const NT& val);}{sets the entry $c_0$
of \ccVar\ to \ccc{val}. An existing entry is overwritten.}
\ccMethod{void set_d (int i, int j, const NT& val);}{sets the entry
$2D_{ij}$ of \ccVar\ to \ccc{val}. An existing entry is overwritten.
\ccVar\ is enlarged if necessary to accomodate this entry.}
\ccMethod{void set_d (int i, int j, const NT& val);}{sets the entries
$2D_{ij}$ and $2D_{ji}$ of \ccVar\ to \ccc{val}. Existing entries are
overwritten. \ccVar\ is enlarged if necessary to accomodate these entries.
\ccPrecond \ccc{j <= i}}
\ccSeeAlso
\ccc{Quadratic_program<NT>}\\

View File

@ -643,7 +643,7 @@ public:
FL_iterator get_fl() const
{
CGAL_qpe_assertion(is_valid());
return FL_iterator (&fl_vector, default_fl); // default bound: >= 0
return FL_iterator (&fl_vector, default_fl);
}
L_iterator get_l() const
{
@ -688,10 +688,16 @@ public:
}
// default constructor
Quadratic_program (CGAL::Comparison_result relation = CGAL::EQUAL)
Quadratic_program
(CGAL::Comparison_result relation = CGAL::EQUAL,
bool finite_lower = true,
NT lower = 0,
bool finite_upper = false,
NT upper = 0)
: n_(0), m_(0), c0_(0),
default_r(relation), default_fl(true),
default_l(0), default_fu(false), default_u(0), is_valid_(true)
default_r(relation), default_fl(finite_lower),
default_l(lower), default_fu(finite_upper),
default_u(upper), is_valid_(true)
{}
// constructor from iterators
template <typename A_it, typename B_it, typename R_it, typename FL_it,
@ -741,14 +747,62 @@ public:
return true;
}
private:
// helpers to determine bound status
// checks whether all bounds in flu are as given by the parameter "finite"
// default_flu is the default-value of the underlying map that is not
// stored
bool all_bounds_are
(bool finite, const Sparse_f_vector& flu, bool default_flu) const
{
if (finite == default_flu)
return flu.empty();
else
// are there exactly n non-default values "finite"?
return flu.size() == (unsigned int)(n_);
}
bool all_bounds_are_zero
// checks whether all bounds in lu are 0. default_lu is the default-value
// of the underlying map that is not stored
(const Sparse_vector& lu, const NT& default_lu) const
{
if (CGAL::is_zero(default_lu))
return lu.empty();
else {
// are there exactly n non-default values?
if (lu.size() != (unsigned int)(n_)) return false;
// ok, we have to test each of the non-default values against zero
for (typename Sparse_vector::const_iterator
j = lu.begin(); j != lu.end(); ++j)
if (!CGAL::is_zero(j->second)) return false;
return true;
}
}
public:
bool is_nonnegative() const
{
CGAL_qpe_assertion(default_fl);
CGAL_qpe_assertion(CGAL::is_zero(default_l));
CGAL_qpe_assertion(!default_fu);
// bounds must be at their defaults:
// >= 0 inf
return (fl_vector.empty() && l_vector.empty() && fu_vector.empty());
return
all_bounds_are (true, fl_vector, default_fl) &&
all_bounds_are_zero (l_vector, default_l) &&
all_bounds_are (false, fu_vector, default_fu);
}
bool is_nonpositive() const
{
return
all_bounds_are (false, fl_vector, default_fl) &&
all_bounds_are_zero (u_vector, default_u) &&
all_bounds_are (true, fu_vector, default_fu);
}
bool is_free() const
{
return
all_bounds_are (false, fl_vector, default_fl) &&
all_bounds_are (false, fu_vector, default_fu);
}
// set methods

View File

@ -0,0 +1,161 @@
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <CGAL/basic.h>
#include <CGAL/QP_models.h>
#include <CGAL/QP_functions.h>
// choose exact integral type
#ifndef CGAL_USE_GMP
#include <CGAL/MP_Float.h>
typedef CGAL::MP_Float ET;
#else
#include <CGAL/Gmpz.h>
typedef CGAL::Gmpz ET;
#endif
int main()
{
for (bool fl = false; fl < true; ++fl)
for (bool fu = false; fu < true; ++fu)
for (int l = -2; l < 0; ++l)
for (int u = 0; u < 2; ++u)
for (int r = -1; r < 1; ++r) {
// generate empty program with all possible
// defaults, and test solver / bound status functions
CGAL::Quadratic_program<int> qp
(CGAL::Comparison_result(r), fl, l, fu, u);
assert (qp.is_valid());
// test solver
CGAL::Quadratic_program_solution<ET> s =
CGAL::solve_quadratic_program (qp, ET());
assert (CGAL::is_zero(s.objective_value()));
assert (s.is_optimal());
// test bounds (program is empty, so everything should hold)
assert (qp.is_nonnegative());
assert (qp.is_nonpositive());
assert (qp.is_free());
// now manipulate program
qp.set_c(0, 1); // min x_0
// l <= x_0 <= u
// test solver
s = CGAL::solve_quadratic_program (qp, ET());
if (fl) {
assert (s.is_optimal());
assert (s.objective_value() == l);
} else
assert (s.is_unbounded());
// test bounds
if (fl && fu) {
assert (!qp.is_nonnegative());
assert (!qp.is_nonpositive());
assert (!qp.is_free());
}
if (fl && !fu) {
if (l==0)
assert (qp.is_nonnegative());
else
assert (!qp.is_nonnegative());
assert (!qp.is_nonpositive());
assert (!qp.is_free());
}
if (!fl && fu) {
if (u==0)
assert (qp.is_nonpositive());
else
assert (!qp.is_nonpositive());
assert (!qp.is_nonnegative());
assert (!qp.is_free());
}
if (!fl && !fu) {
assert (qp.is_free());
assert (!qp.is_nonnegative());
assert (!qp.is_nonpositive());
}
// manipulate program
qp.set_l(0, true, 0); // 0 <= x_0 <= u
// test solver
s = CGAL::solve_quadratic_program (qp, ET());
assert (s.is_optimal());
assert (CGAL::is_zero(s.objective_value()));
// test bounds
if (!fu)
assert (qp.is_nonnegative());
else
assert (!qp.is_nonnegative());
assert (!qp.is_free());
assert (!qp.is_nonpositive());
// manipulate program
qp.set_l(0, false); // -infty <= x_0 <= u
// test solver
s = CGAL::solve_quadratic_program (qp, ET());
assert (s.is_unbounded());
// manipulate program
qp.set_c(0, -1); // max x_0
// test solver
s = CGAL::solve_quadratic_program (qp, ET());
if (fu) {
assert (s.is_optimal());
assert (s.objective_value() == u);
} else
assert (s.is_unbounded());
// test bounds
if (fu) {
if (u==0)
assert (qp.is_nonpositive());
else
assert (!qp.is_nonpositive());
assert (!qp.is_free());
} else {
assert (qp.is_free());
assert (!qp.is_nonpositive());
}
assert (!qp.is_nonnegative());
// manipulate program
qp.set_c0(5);
qp.set_u(0, true, 0); // -infty <= x_0 <= 0
// test solver
s = CGAL::solve_quadratic_program (qp, ET());
assert (s.is_optimal());
assert (s.objective_value() == 5);
// test bounds
assert (qp.is_nonpositive());
assert (!qp.is_nonnegative());
assert (!qp.is_free());
qp.set_u(0, false); // -infty <= x_0 <= infty
s = CGAL::solve_quadratic_program (qp, ET());
assert (s.is_unbounded());
assert (qp.is_free());
assert (!qp.is_nonnegative());
assert (!qp.is_nonpositive());
// test default_r: insert constraint 0x ~ 1; this is
// feasible iff <=
qp.set_a(0,0,0);
qp.set_b(0,1);
// test solver
s = CGAL::solve_quadratic_program (qp, ET());
if (r == -1)
assert (s.is_unbounded());
else
assert (s.is_infeasible());
}
return 0;
}

View File

@ -1,29 +0,0 @@
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <CGAL/basic.h>
#include <CGAL/QP_models.h>
#include <CGAL/QP_functions.h>
// choose exact integral type
#ifndef CGAL_USE_GMP
#include <CGAL/MP_Float.h>
typedef CGAL::MP_Float ET;
#else
#include <CGAL/Gmpz.h>
typedef CGAL::Gmpz ET;
#endif
int main()
{
CGAL::Quadratic_program<int> qp; // no variables, no constraints
assert (qp.is_valid());
CGAL::Quadratic_program_solution<ET> s =
CGAL::solve_quadratic_program (qp, ET());
std::cout << "Solution = " << s.objective_value() << std::endl;
std::cout << "Status = " << s.status() << std::endl;
return 0;
}