- finished MPS-output routine (and with this also data2mps)

This commit is contained in:
Kaspar Fischer 2006-02-23 17:36:59 +00:00
parent efdecc2ffa
commit 7dd4a84585
3 changed files with 298 additions and 4 deletions

View File

@ -21,6 +21,8 @@
// Kaspar Fischer <fischerk@inf.ethz.ch>
#include <iomanip>
#include <fstream>
#include <CGAL/QP_partial_filtered_pricing.h>
#include <CGAL/QP_partial_exact_pricing.h>
@ -745,5 +747,130 @@ const typename MPS::Row_type QP_solver_MPS_traits_d<MPS,
Has_equalities_only_and_full_rank_,
Is_in_standard_form_,IT_,ET_,D_iterator_>::GREATER_EQUAL;
// Routines to output to MPS format:
namespace QP_MPS_detail {
template<typename T>
struct Write_MPS_type_name {
static const char *name() { return 0; }
};
template<>
struct Write_MPS_type_name<double> {
static const char *name() { return "floating-point"; }
};
template<>
struct Write_MPS_type_name<int> {
static const char *name() { return "integer"; }
};
template<>
struct Write_MPS_type_name<Gmpq> {
static const char *name() { return "rational"; }
};
} // QP_MPS_detail
template<typename A_iterator,
typename B_iterator,
typename C_iterator,
typename D_iterator,
typename FU_iterator,
typename FL_iterator,
typename U_iterator,
typename L_iterator,
typename Row_type_iterator>
void write_MPS(std::ostream& out,
const std::string& number_type, // pass "" to deduce
// the number-type from
// U_iterator::value_type
const std::string& description,
const std::string& generator_name,
const std::string& problem_name,
const int n,
const int m,
A_iterator A,
B_iterator b,
C_iterator c,
D_iterator D,
FU_iterator fu,
FL_iterator fl,
U_iterator u,
L_iterator l,
Row_type_iterator rt)
{
typedef typename Row_type_iterator::value_type Row_type;
// output header:
if (number_type.length() == 0) {
const char *tn = QP_MPS_detail::Write_MPS_type_name<typename U_iterator::
value_type>::name();
if (tn != 0)
out << "* Number-type: " << tn << "\n";
} else
out << "* Number-type: " << number_type << "\n";
out << "* Description: " << description << "\n"
<< "* Generated-by: " << generator_name << "\n"
<< "NAME " << problem_name << "\n";
// write ROWS section:
out << "ROWS\n"
<< " N obj\n"; // a row for the objective function
for (int i=0; i<m; ++i) {
if (rt[i] == static_cast<Row_type>(-1))
out << " L";
else if (rt[i] == static_cast<Row_type>(0))
out << " E";
else if (rt[i] == static_cast<Row_type>(1))
out << " G";
else
CGAL_qpe_assertion_msg(false, "incorrect row-type");
out << " c" << i << "\n";
}
// output COLUMNS section:
for (int i=0; i<n; ++i) {
out << " x" << i << " obj " << c[i] << "\n";
for (int j=0; j<m; ++j) {
out << " x" << i << " c" << j << " " << A[i][j] << "\n";
}
}
// output RHS section:
out << "RHS\n";
for (int i=0; i<m; ++i)
out << " rhs c" << i << " " << b[i] << "\n";
// output BOUNDS section:
out << "BOUNDS\n";
for (int i=0; i<n; ++i) {
#if 0 // debugging
std::cout << "fl" << i << ": " << *(fl+i) << " ";
if (*(fl+i))
std::cout << "l=" << l[i] << " ";
std::cout << "fu" << i << ": " << *(fu+i) << " ";
if (*(fu+i))
std::cout << "l=" << u[i] << " ";
#endif
if (!*(fl+i) || !CGAL::is_zero(l[i]))
if (*(fl+i))
out << " LO BND x" << i << " " << l[i] << "\n";
else
out << " MI BND x" << i << "\n";
if (*(fu+i))
out << " UP BND x" << i << " " << u[i] << "\n";
}
// output QMATRIX section:
out << "QMATRIX\n";
for (int i=0; i<n; ++i)
for (int j=0; j<n; ++j)
out << " x" << i << " x" << j << " " << 2*D[i][j] << "\n";
// output end:
out << "ENDATA\n";
}
CGAL_END_NAMESPACE

View File

@ -602,6 +602,38 @@ public:
typedef Is_in_standard_form_ Is_in_standard_form;
};
// helper routine to write an MPS from given A, b, c, D, fl, fu, l, u
// and row-types; notice that the value type of Row_type_iterator is
// assumed (todo: remove this hard-coding) to be int and -1
// corresponds to "<=", 0 to "=", and 1 to ">=".
template<typename A_iterator,
typename B_iterator,
typename C_iterator,
typename D_iterator,
typename FU_iterator,
typename FL_iterator,
typename U_iterator,
typename L_iterator,
typename Row_type_iterator>
void write_MPS(std::ostream& out,
const std::string& number_type, // pass "" to deduce
// the number-type from
// U_iterator::value_type
const std::string& description,
const std::string& generator_name,
const std::string& problem_name,
const int n,
const int m,
A_iterator A,
B_iterator b,
C_iterator c,
D_iterator D,
FU_iterator fu,
FL_iterator fl,
U_iterator u,
L_iterator l,
Row_type_iterator rt);
CGAL_END_NAMESPACE
#include <CGAL/QP_solver/MPS.C>

View File

@ -1,6 +1,6 @@
// Synopsis: converts a .data-file to a MPS-file
//
// Usage: ./data2mps < data-file
// Usage: ./data2mps description < data-file
//
// Author: Kaspar Fischer <fischerk@inf.ethz.ch>
//
@ -10,9 +10,14 @@
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include <boost/any.hpp>
namespace CGAL {
bool is_zero(const boost::any& a);
}
#include <CGAL/QP_solver/gmp_double.h>
#include <CGAL/QP_solver.h>
#include <CGAL/QP_full_exact_pricing.h>
@ -135,6 +140,70 @@ public:
return error_message_;
}
int number_of_variables()
{
CGAL_qpe_assertion(good());
return n;
}
int number_of_constraints()
{
CGAL_qpe_assertion(good());
return m;
}
public: // access:
A_iterator A()
{
CGAL_qpe_assertion(good());
return Vector_iterator(A_.begin(),Beginner());
}
B_iterator b()
{
CGAL_qpe_assertion(good());
return b_.begin();
}
C_iterator c()
{
CGAL_qpe_assertion(good());
return c_.begin();
}
D_iterator D()
{
CGAL_qpe_assertion(good());
return Vector_iterator(D_.begin(),Beginner());
}
Row_type_iterator row_types()
{
CGAL_qpe_assertion(good());
return row_type_.begin();
}
FL_iterator fl() {
CGAL_qpe_assertion(good());
return fl_.begin();
}
FU_iterator fu() {
CGAL_qpe_assertion(good());
return fu_.begin();
}
U_iterator u() {
CGAL_qpe_assertion(good());
return u_.begin();
}
L_iterator l() {
CGAL_qpe_assertion(good());
return l_.begin();
}
private: // error handling helpers:
// Note: alternatively, I could have used exceptions to handle errors...
@ -418,6 +487,7 @@ private: // parsing routines:
if (!read_number(val))
return err1("Expected number in C-VECTOR-AND-BOUNDS section for "
"finite lower bound of variable %", tostr(i));
fl_[i] = true;
l_[i] = val;
whitespace();
if (in.get() != ',')
@ -432,6 +502,7 @@ private: // parsing routines:
if (!read_number(val))
return err1("Expected number in C-VECTOR-AND-BOUNDS section for "
"finite upper bound of variable %", tostr(i));
fu_[i] = true;
u_[i] = val;
whitespace();
if (in.get() != ')')
@ -445,13 +516,61 @@ private: // parsing routines:
}
};
namespace boost {
std::ostream& operator<<(std::ostream& o,const any& a)
{
if (a.type() == typeid(double))
o << std::setprecision(17) // 17 is enough, see D. Goldberg's
// "What Every Computer Scientist
// Should Know About
// Floating-Point Arithmetic", p. 237
<< any_cast<double>(a);
else if (a.type() == typeid(::Data_reader::Rational))
o << any_cast< ::Data_reader::Rational >(a);
else if (a.type() == typeid(int))
o << any_cast<int>(a);
else
CGAL_qpe_assertion(false);
return o;
}
any operator*(const int f,const any& a)
{
if (a.type() == typeid(double))
return 2.0 * any_cast<double>(a);
else if (a.type() == typeid(::Data_reader::Rational))
return 2 * any_cast< ::Data_reader::Rational >(a);
else if (a.type() == typeid(int))
return 2 * any_cast<int>(a);
else
CGAL_qpe_assertion(false);
return any();
}
}
namespace CGAL {
bool is_zero(const boost::any& a) {
if (a.type() == typeid(double))
return is_zero(boost::any_cast<double>(a));
else if (a.type() == typeid(::Data_reader::Rational))
return is_zero(boost::any_cast< ::Data_reader::Rational >(a));
else if (a.type() == typeid(int))
return is_zero(boost::any_cast<int>(a));
else
CGAL_qpe_assertion(false);
return false;
}
}
int main(int argnr, char **argv)
{
// output usage information:
if (argnr > 1) {
std::cerr << "Usage: " << argv[0] << " < datafile.data\n\n"
if (argnr > 3 || argnr <= 2) {
std::cerr << "Usage: " << argv[0] << " \"description\" \"problem-name\" "
"< datafile.data\n\n"
<< "The resulting MPS-file is written to standard-out, errors "
<< "go to standard-error.\n\n"
<< "go to standard-error.\n\"problem-name\" should not contain "
<< "white-space.\n\n"
<< "See data2mps.cin for an example 'datafile.data' file.\n";
return 1;
}
@ -464,6 +583,22 @@ int main(int argnr, char **argv)
return 2;
}
// determine number-type (test_solver needs this in order to know
// what the numbers look like):
Data_reader::ANT tmp = *data.c(); // any number
const char *number_type;
if (tmp.type() == typeid(double))
number_type = "floating-point";
else if (tmp.type() == typeid(::Data_reader::Rational))
number_type = "rational";
else if (tmp.type() == typeid(int))
number_type = "integer";
// write MPS-file to standard out:
CGAL::write_MPS(std::cout, number_type, argv[1], "data2mps", argv[2],
data.number_of_variables(), data.number_of_constraints(),
data.A(), data.b(), data.c(), data.D(), data.fu(),
data.fl(), data.u(), data.l(), data.row_types());
return 0;
}