mirror of https://github.com/CGAL/cgal
- finished MPS-output routine (and with this also data2mps)
This commit is contained in:
parent
efdecc2ffa
commit
7dd4a84585
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue