- some more manual fixes

- made partial pricing also work for high constraint/variable ratio (needs to
  be properly tested)
- added QSCORPIO as interesting additional example 
- switched to quotient output in iteration log to avoid nans
- removed filter_failure example (after all, this particular example
  was just an artifact of the bad to_double() routine of Gmpzf that I
  fixed earlier
This commit is contained in:
Bernd Gärtner 2007-04-20 12:31:57 +00:00
parent 66378f5a45
commit 6a79d4f45d
14 changed files with 2142 additions and 1946 deletions

3
.gitattributes vendored
View File

@ -1914,8 +1914,6 @@ QP_solver/examples/QP_solver/cycling.cpp -text
QP_solver/examples/QP_solver/cycling.mps -text
QP_solver/examples/QP_solver/double_qp_solver.cin -text
QP_solver/examples/QP_solver/double_qp_solver.data -text
QP_solver/examples/QP_solver/filter_failure.cpp -text
QP_solver/examples/QP_solver/filter_failure.mps -text
QP_solver/examples/QP_solver/first_lp.cpp -text
QP_solver/examples/QP_solver/first_lp.mps -text
QP_solver/examples/QP_solver/first_lp_from_mps.cpp -text
@ -1949,6 +1947,7 @@ QP_solver/test/QP_solver/debug_bug.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
QP_solver/test/QP_solver/test_solver_data/masters/additional/QSCORPIO.QPS -text
Qt_widget/demo/Qt_widget/hellosegment.vcproj eol=crlf
Qt_widget/demo/Qt_widget/layer.vcproj eol=crlf
Qt_widget/demo/Qt_widget/standard_toolbar.vcproj eol=crlf

View File

@ -52,13 +52,14 @@ provides a number of easy-to-use and flexible models, see Section
\ref{sec:QP-first} below. The input data may be of any given number
type, such as \ccc{double}, \ccc{int}, or any exact type.
Then the program is solved using the function \ccc{solve_quadratic_program}
(or some specialized other functions, e.g.\ for linear programs). For this,
you also have to provide a suitable \emph{exact} number type \ccc{ET} used
in the solution process. In case of input type \ccc{double}, solution
methods that use floating-point-filtering are chosen by default (in some
cases, this is not appropriate, and the default should be changed;
see Section \ref{sec:QP-customization} for details).
Then the program is solved using the function
\ccc{solve_quadratic_program} (or some specialized other functions,
e.g.\ for linear programs). For this, you also have to provide a
suitable \emph{exact} number type \ccc{ET} used in the solution
process. In case of input type \ccc{double}, solution methods that use
floating-point-filtering are chosen by default for certain programs
(in some cases, this is not appropriate, and the default should be
changed; see Section \ref{sec:QP-customization} for details).
The output of this is an object of \ccc{Quadratic_program_solution<ET>}
which you can in turn query for various things: what is the status of
@ -153,13 +154,13 @@ convex quadratic program. It may fail to compute a solution only if
on efficiency).
\item The quadratic objective function matrix $D$ is not
positive-semidefinite (see the discussion below).
\item The floating-point filter used by default for input type
\ccc{double} fails due to a \emph{double} exponent overflow. This
happens in rare cases only, and it does not pay off to sacrifice
the efficiency of the filtered approach in order to cope with these
rare cases. There are means, however, to avoid such
problems by switching to a slower non-filtered variant, see
Section \ref{sec:QP-customization-filtering}.
\item The floating-point filter used by default for certain programs
and input type \ccc{double} fails due to a \emph{double} exponent
overflow. This happens in rare cases only, and it does not pay off
to sacrifice the efficiency of the filtered approach in order to
cope with these rare cases. There are means, however, to avoid such
problems by switching to a slower non-filtered variant, see Section
\ref{sec:QP-customization-filtering}.
\item The solver internally cycles. This also happens in rare
cases only. However, if
you have a hunch that the solver cycles on your problem,
@ -190,7 +191,7 @@ using the \cgal\ program models and solution functions.
There are two essentially different ways to proceed,
and we will discuss them in turn. In short,
\begin{itemize}
\item you can let the model take care of yor program data; you start
\item you can let the model take care of your program data; you start
from an empty program and then simply insert the non-zero entries, or
read them from a file (more generally, any input stream) in
\ccc{MPSFormat}. You can also change program entries at any time.
@ -198,7 +199,7 @@ This is usually the most convenient way if you don't want to care
about representation issues;
\item you can maintain the data yourself and only supply suitable
random-access iterators over the matrices and vectors. This is
advantageous if you already have the data (explicitly, or implictly
advantageous if you already have the data (explicitly, or implicitly
encoded, for example through iterators) and want to avoid copying
of data. Typically, this happens if you write generic iterator-based
code.
@ -249,7 +250,7 @@ function at this optimal solution is $2^2 + 4(3-4)^2 = 8$.
Here is how this quadratic program can be solved in \cgal\
according to the first way (letting the model take care of
the data). We use \ccc{int} as the entry type, and
\ccc{MP_Float} or \ccc{Gmpz} (which is faster and preferrable if
\ccc{MP_Float} or \ccc{Gmpz} (which is faster and preferable if
\texttt{GMP} is installed) as the exact type for the
internal computations. For examples
how to work with the input type \ccc{double}, we refer to
@ -286,7 +287,7 @@ The following program again solves our running example from above,
with the same output, but this time with iterators over data stored
in suitable containers. You can see that we also store zero
entries here (in $D$). For this toy problem, the previous two
approaches (program from data/stream) are clearly preferrable,
approaches (program from data/stream) are clearly preferable,
but Section \ref{sec:QP-iterators} shows an
example where it makes sense to use the iterator-based approach.
@ -668,29 +669,25 @@ for the performance (see the class \ccc{Quadratic_program_pricing_strategy}
for a discussion).
\subsection{Exponent overflow in double using floating-point filters\label{sec:QP-customization-filtering}}
The filtered version of the solver that is used by default on input
The filtered version of the solver that is used for some problems
by default on input
type \ccc{double} internally constructs double-approximations of exact
multiprecision values. If these exact values are extremely large, this
may lead to \emph{infinite} \ccc{double} values and incorrect results.
In debug mode, the solver will notice this through a certificate
cross-check in the end (or even earlier). In this case, it is advisable
to switch to a non-filtered \emph{pricing strategy}, see
to explicitly switch to a non-filtered \emph{pricing strategy}, see
\ccc{Quadratic_program_pricing_strategy}.
Consider the following program. It reads a nonnegative linear program from
the file \texttt{filter\_failure.mps} (which is in the example directory as
well), and then solves it using \emph{Dantzig's rule}.
\ccIncludeExampleCode{QP_solver/filter_failure.cpp}
If your comment the line
\begin{verbatim}
options.set_pricing_strategy(CGAL::QP_DANTZIG); // Dantzig's rule
\end{verbatim}
you will see that the solver fails (in debug mode, it will run into
an assertion, and in non-debug mode, the objective value is simply
wrong). This is due to a filter failure, and switching to a non-filtered
variant like \ccc{QP_DANTZIG} solves the problem.
{\bf Hint:}
If you have a program where the number of variables $n$ and the number of
constraints $m$ have the same order of
magnitude, the filtering will usually have
no dramatic effect on the performance, so in that case you might as well
switch to \ccc{QP_PARTIAL_DANTZIG}
to be safe from the issue described here (see
\ccReferToExampleCode{QP_solver/cycling.cpp}
for an example that shows how to change the pricing strategy).
\subsection{The solver internally cycles\label{sec:QP-customization-cycling}}
Consider the following program. It reads a nonnegative linear program from
@ -722,9 +719,8 @@ typical in your case, and we make no claims whatsoever about the
performance in other applications.
Still, the example shows that the performance can be dramatically
affected by switching between pricing strategies, and this message
is important to know if you want to achieve good performance in
general.
affected by switching between pricing strategies, and we give some
hints on how to achieve good performance in general.
The application is the one already discussed in Section \ref{sec:QP-iterators}
above: testing whether a point is in the convex hull of other points.
@ -748,9 +744,9 @@ If you compile with the macros \texttt{NDEBUG} or
\texttt{CGAL\_QP\_NO\_ASSERTIONS} set (this is essential for good
performance!!), you will see runtimes that qualitatively look as
follows (on your machine, the actual runtimes will roughly be some
fixed multiples of the numbers in the table below). The default
choice of the pricing strategy in that case is
\ccc{QP_PARTIAL_FILTERED_DANTZIG}.
fixed multiples of the numbers in the table below, and they might
vary with the random choices). The default choice of the pricing
strategy in that case is \ccc{QP_PARTIAL_FILTERED_DANTZIG}.
\begin{tabular}{lcl}
strategy & &runtime in seconds \\ \hline
@ -780,10 +776,15 @@ strategy & &runtime in seconds \\ \hline
\ccc{CGAL::QP_PARTIAL_FILTERED_DANTZIG}& | & 1.34
\end{tabular}
In general, if your problem has a high variable/constraint or
constraint/variable ratio, then filtering will typically pay off.
In such cases, it might be beneficial to encode your problem using
input type \ccc{double} in order to profit from the filtering (but
see the issue discussed in Section \ref{sec:QP-customization-filtering}).
\subsection{$d=100$, $n=100,000$}
Increasing the dimension to $100$ compared to the above example clearly
shows that the filtering effect deteriorates with higher dimension but
is still noticeable.
Conversely, the filtering effect deteriorates if the points/dimension ratio
becomes smaller.
\begin{tabular}{lcl}
strategy & &runtime in seconds \\ \hline
@ -797,9 +798,9 @@ strategy & &runtime in seconds \\ \hline
\subsection{$d=500$, $n=1,000$}
If the points/dimension ratio tends to a constant, filtering is no
longer a clear winner. The reason is that the numbers involved in the
necessary exact calculations are so large that the overall performance is
dominated by them.
longer a clear winner. The reason is that in this case,
the necessary exact calculations with multiprecision numbers
dominate the overall runtime.
\begin{tabular}{lcl}
strategy & &runtime in seconds \\ \hline
@ -810,3 +811,10 @@ strategy & &runtime in seconds \\ \hline
\ccc{CGAL::QP_FILTERED_DANTZIG} & | & 2.65 \\
\ccc{CGAL::QP_PARTIAL_FILTERED_DANTZIG}& | & 2.61
\end{tabular}
In general, if you have a program where the number of variables
and the number of constraints have the same order of magnitude, then
the saving gained from using the filtered approach is typically
small. In such a situation, you should consider switching to
a non-filtered variant in order to avoid the rare issue discussed
in Section \ref{sec:QP-customization-filtering} altogether.

View File

@ -5,8 +5,12 @@
\ccDefinition
This is a class used for passing options to the linear and
quadratic programming solvers. Currently, we support only
two types of options, but the idea is that this list
grows in the future.
options referring to
\begin{enumerate}
\item the verbosity,
\item the pricing strategy (see \ccc{Quadratic_program_pricing_strategy}).
\end{enumerate}
The idea is that this list grows in the futurex.
\ccCreation
\ccIndexClassCreation

View File

@ -9,8 +9,11 @@ This is an enumeration type containing the values
\ccc{QP_PARTIAL_FILTERED_DANTZIG}, and\ccc{QP_BLAND}.
It indicates the pricing strategy to be used in
solving a linear or quadratic program. Here we describe when to
choose which strategy.
solving a linear or quadratic program. This strategy determines
how the solver gets from one intermediate solution to the next
during any of its iterations.
Here we briefly describe when to choose which strategy.
\ccHeading{\ccc{QP_CHOOSE_DEFAULT}}
This is the default value of the pricing strategy in
@ -19,41 +22,45 @@ strategy that it thinks is most appropriate for the problem at hand.
There are only few reasons to deviate from this default, but you are
free to experiment, of course.
\ccHeading{\ccc{QP_DANTZIG}}
If the input type is \textbf{not} \ccc{double}, this is usually the best choice
for `''typical'' sparse linear and quadratic programs of medium size,
where the number of variables has roughly the same order of magnitude
as the number of constraints.
\ccHeading{\ccc{QP_PARTIAL_DANTZIG}}
If the input type is \textbf{not} \ccc{double}, this is usually the
best choice for linear and quadratic programs of medium size.
\ccHeading{\ccc{QP_PARTIAL_DANTZIG}}
If the input type is \textbf{not} \ccc{double}, this is usually the best choice
for linear and quadratic programs with few (up to 100, say), constraints,
but a possibly large number of variables, or the other way around
(few variables, but possibly many constraints)
\ccHeading{\ccc{QP_DANTZIG}}
If the input type is \textbf{not} \ccc{double}, this can sometimes
make a difference (be faster or slowe) than \ccc{QP_PARTIAL_DANTZIG}
for problems with a high variable/constraint or constraint/variable ratio.
\ccHeading{\ccc{QP_FILTERED_DANTZIG}}
\ccHeading{\ccc{QP_PARTIAL_FILTERED_DANTZIG}}
If the input type \textbf{is} \ccc{double}, this is usually the best choice
for `''typical'' sparse linear and quadratic programs of medium size,
where the number of variables has roughly the same order of magnitude
as the number of constraints.
for linear and quadratic programs of medium size.
If the input type is not \ccc{double}, this choice is equivalent
to \ccc{QP_PARTIAL_DANTZIG}.
{\bf Note:} filtered strategies may occasionally fail due to double
exponent overflows. In this case, the slower fallback option is
the non-filtered variant \ccc{QP_DANTZIG} of this strategy.
\ccHeading{\ccc{QP_PARTIAL_FILTERED_DANTZIG}}
If the input type \textbf{is} \ccc{double}, this is usually the best choice
for linear and quadratic programs with few (up to 100, say), constraints,
but a possibly large number of variables, or the other way around
(few variables, but possibly many constraints).
{\bf Note:} filtered strategies may occasionally fail due to double
exponent overflows. In this case, the slower fallback option is
{\bf Note:} filtered strategies may in rare cases fail due to double
exponent overflows, see
Section \ref{sec:QP-customization-filtering}.
In this case, the slower fallback option is
the non-filtered variant \ccc{QP_PARTIAL_DANTZIG} of this strategy.
\ccHeading{\ccc{QP_FILTERED_DANTZIG}}
If the input type \textbf{is} \ccc{double}, this can sometimes
make a difference (be faster or slowe) than \ccc{QP_PARTIAL_FILTERED_DANTZIG}
for problems with a high variable/constraint or constraint/variable ratio.
If the input type is not \ccc{double}, this choice is equivalent
to \ccc{QP_DANTZIG}.
{\bf Note:} filtered strategies may in rare cases fail due to double
exponent overflows, see
Section \ref{sec:QP-customization-filtering}.
In this case, the slower fallback option is
the non-filtered variant \ccc{QP_DANTZIG} of this strategy.
\ccHeading{\ccc{QP_BLAND}}
This is hardly ever the most efficient choice, but it is guaranteed
to avoid internal cycling of the solution algorithm.
to avoid internal cycling of the solution algorithm, see
Section \ref{sec:QP-customization-cycling}.
\ccSeeAlso

View File

@ -77,6 +77,10 @@ concept.
\ccRefIdfierPage{solve_nonnegative_quadratic_program}\\
\ccRefIdfierPage{solve_nonnegative_linear_program}
The solution process can customized by passing an object of the class
\ccRefIdfierPage{Quadratic_program_options}
Programs can be written to an output stream in \ccc{MPSFormat}, using
one of the following four functions.

View File

@ -1,7 +1,6 @@
// Example: assess the solver performance under any of the available
// pricing strategies, in the convex-hull-containment problem
// NOTE: in order to see meaningful results, compile with -DNDEBUG
#include <cassert>
#include <vector>
#include <CGAL/Cartesian_d.h>
#include <CGAL/MP_Float.h>

View File

@ -1,36 +0,0 @@
// example: solve a nonnegative quadratic program that by default leads
// to double overflows, using Dantzig pricing
#include <iostream>
#include <fstream>
#include <CGAL/basic.h>
#include <CGAL/QP_models.h>
#include <CGAL/QP_functions.h>
// choose exact floating-point type
#ifdef CGAL_USE_GMP
#include <CGAL/Gmpzf.h>
typedef CGAL::Gmpzf ET;
#else
#include <CGAL/MP_Float.h>
typedef CGAL::MP_Float ET;
#endif
// program and solution types
typedef CGAL::Quadratic_program_from_mps<double> Program;
typedef CGAL::Quadratic_program_solution<ET> Solution;
int main() {
std::ifstream in ("filter_failure.mps");
Program qp(in); // read program from file
assert (qp.is_valid()); // we should have a valid mps file
assert (qp.is_nonnegative()); // .. and it should be nonnegative
// solve the program, using ET as the exact type
// choose verbose mode and non-filtered Dantzig pricing
CGAL::Quadratic_program_options options;
options.set_pricing_strategy(CGAL::QP_DANTZIG); // Dantzig's rule
Solution s = CGAL::solve_nonnegative_quadratic_program(qp, ET(), options);
// output solution
std::cout << s;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -125,19 +125,21 @@ set(const Q& qp)
<< "Set-Up" << std::endl
<< "======" << std::endl;
}
vout.out() << "[ " << (is_LP ? "LP" : "QP")
<< ", " << qp_n << " variables, " << qp_m << " constraints";
}
}
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)";
}
vout.out() << " ]" << std::endl;
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:

View File

@ -142,6 +142,8 @@ init( )
// initialize size of active set
int n = this->solver().number_of_variables();
int m = this->solver().number_of_constraints();
// we also want to cover the high constraints/variable ratio
if (n < m) (std::swap)(n,m);
s = (std::min)( static_cast< unsigned int>( m*std::sqrt( n/2.0)),
static_cast< unsigned int>(N.size()));

View File

@ -2949,14 +2949,16 @@ set_pricing_strategy
if (strategy == QP_DANTZIG)
strategyP = new QP_full_exact_pricing<Q, ET, Tags>;
else if (strategy == QP_FILTERED_DANTZIG)
else if (strategy == QP_FILTERED_DANTZIG)
// choose between FF (double) and FE (anything else)
strategyP =
new typename QP_solver_impl::Filtered_pricing_strategy_selector
<Q, ET, Tags, C_entry>::FF;
else if (strategy == QP_PARTIAL_DANTZIG)
strategyP = new QP_partial_exact_pricing<Q, ET, Tags>;
else if (strategy == QP_PARTIAL_FILTERED_DANTZIG
|| strategy == QP_CHOOSE_DEFAULT)
|| strategy == QP_CHOOSE_DEFAULT)
// choose between PF (double) and PE (anything else)
strategyP =
new typename QP_solver_impl::Filtered_pricing_strategy_selector
<Q, ET, Tags, C_entry>::PF;
@ -3184,7 +3186,8 @@ print_solution( ) const
<< "solution: "
<< solution_numerator() << " / " << solution_denominator()
<< " ~= "
<< to_double(solution_numerator())/to_double(solution_denominator())
<< to_double
(CGAL::Quotient<ET>(solution_numerator(), solution_denominator()))
<< std::endl;
CGAL_qpe_debug {
vout2 << std::endl;

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,6 @@
#include <cstdlib>
#include <CGAL/basic.h>
#include <CGAL/Timer.h>
#ifndef CGAL_USE_GMP
#include <CGAL/Gmpq.h> // Quotient<MP_Float> is too slow, even
@ -293,8 +292,6 @@ bool process(const std::string& filename,
using std::cout;
using std::endl;
CGAL::Timer timer;
// extract verbosity:
const int verbosity = options.find("Verbosity")->second;
@ -425,13 +422,10 @@ bool process(const std::string& filename,
(static_cast<CGAL::Quadratic_program_pricing_strategy>
(options.find("Strategy")->second));
timer.reset();
timer.start();
CGAL::QP_solver<QP_instance, ET, Tags> solver(qp, solver_options);
timer.stop();
// output solution + number of iterations + time
cout << CGAL::to_double(solver.solution()) << " (it: "
<< solver.iterations() << ",time: " << timer.time() << ") ";
// output solution + number of iterations
cout << CGAL::to_double(solver.solution()) << "("
<< solver.iterations() << ") ";
// the solver previously checked itself through an assertion
const bool is_valid = true;

File diff suppressed because it is too large Load Diff