diff --git a/QP_solver/include/CGAL/QP_solver/MPS.C b/QP_solver/include/CGAL/QP_solver/MPS.C index 702dc8f5d2a..70c2dd3a649 100644 --- a/QP_solver/include/CGAL/QP_solver/MPS.C +++ b/QP_solver/include/CGAL/QP_solver/MPS.C @@ -21,6 +21,8 @@ // Kaspar Fischer #include +#include + #include #include @@ -745,5 +747,130 @@ const typename MPS::Row_type QP_solver_MPS_traits_d::GREATER_EQUAL; +// Routines to output to MPS format: + +namespace QP_MPS_detail { + + template + struct Write_MPS_type_name { + static const char *name() { return 0; } + }; + + template<> + struct Write_MPS_type_name { + static const char *name() { return "floating-point"; } + }; + + template<> + struct Write_MPS_type_name { + static const char *name() { return "integer"; } + }; + + template<> + struct Write_MPS_type_name { + static const char *name() { return "rational"; } + }; + +} // QP_MPS_detail + +template +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::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(-1)) + out << " L"; + else if (rt[i] == static_cast(0)) + out << " E"; + else if (rt[i] == static_cast(1)) + out << " G"; + else + CGAL_qpe_assertion_msg(false, "incorrect row-type"); + out << " c" << i << "\n"; + } + + // output COLUMNS section: + for (int i=0; i=". +template +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 diff --git a/QP_solver/test/QP_solver/data2mps.C b/QP_solver/test/QP_solver/data2mps.C index 450329e51f3..68e10953cfe 100644 --- a/QP_solver/test/QP_solver/data2mps.C +++ b/QP_solver/test/QP_solver/data2mps.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 // @@ -10,9 +10,14 @@ #include #include #include +#include #include +namespace CGAL { + bool is_zero(const boost::any& a); +} + #include #include #include @@ -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(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(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(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(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(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(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; }