diff --git a/QP_solver/examples/QP_solver/data_to_mps.C b/QP_solver/examples/QP_solver/data_to_mps.C deleted file mode 100644 index ab6f593cde9..00000000000 --- a/QP_solver/examples/QP_solver/data_to_mps.C +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright (c) 1997-2001 ETH Zurich (Switzerland). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org); you may redistribute it under -// the terms of the Q Public License version 1.0. -// See the file LICENSE.QPL distributed with CGAL. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL: $ -// $Id: $ -// -// -// Author(s) : Kaspar Fischer -// Bernd Gaertner - -#include -#include -#include -#include - -#include - -namespace CGAL { - bool is_zero(const boost::any& a); -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // should to into QP_solver.h (?) - -class Data_reader { -public: // types: - typedef boost::any ANT; - typedef CGAL::Gmpq Rational; - enum Row_type { LESS_EQUAL = -1, EQUAL, GREATER_EQUAL}; - -private: // types: - enum Input_number_type { INTEGER, RATIONAL, DOUBLE, YET_UNKOWN_NUMBER_TYPE }; - - typedef std::vector Vector; - typedef std::vector Matrix; - typedef CGAL::QP_MPS_detail::Begin Beginner; - typedef CGAL::Join_input_iterator_1 Vector_iterator; - typedef Vector::const_iterator Entry_iterator; - typedef std::vector F_vector; - typedef F_vector::const_iterator F_vector_iterator; - typedef std::vector Row_type_vector; - -public: // types: - - // iterators over the input matrices and vectors: - typedef Vector_iterator A_iterator; - typedef Entry_iterator B_iterator; - typedef Entry_iterator C_iterator; - typedef Vector_iterator D_iterator; - typedef CGAL::Const_oneset_iterator< CGAL::Const_oneset_iterator > - Zero_D_iterator; - typedef F_vector_iterator FU_iterator; - typedef F_vector_iterator FL_iterator; - typedef Entry_iterator U_iterator; - typedef Entry_iterator L_iterator; - - typedef Row_type_vector::const_iterator Row_type_iterator; - -private: // members: - std::istream& in; // input stream containing .data format - bool good_; // whether or not we have successfully - // parsed the input - std::string error_message_; // error message, see error_message() - - // arguments read from the HEADER section: - Input_number_type nt; // what kind of numbers we are going to read - ANT any_zero; // the number 0 - int n, m; // number of variables and constraints - bool default_fl, default_fu; // "is lower/upper bound finite" flags for - // default bounds - ANT default_l, default_u; // default lower/upper bound - - // data: - Matrix A_, D_; - Vector b_, c_; - F_vector fl_, fu_; - Vector l_, u_; - Row_type_vector row_type_; - -public: - Data_reader(std::istream& in) : in(in), good_(false), - nt(YET_UNKOWN_NUMBER_TYPE), - n(-1), m(-1) - { - if (!read_initial_comments()) { - err("Unexpected EOF before HEADER"); - return; - } - - if (!read_HEADER()) - return; - - // allocate storage: - A_.resize(n, Vector(m, any_zero)); - D_.resize(n, Vector(n, any_zero)); - fl_.resize(n, default_fl); - fu_.resize(n, default_fu); - l_.resize(n, default_l); - u_.resize(n, default_u); - b_.resize(m); - c_.resize(n); - row_type_.resize(m); - - if (!read_CONSTRAINTS()) - return; - - std::string tk; - if (!read_D_MATRIX(tk)) - return; - - if (!read_C_VECTOR_AND_BOUNDS(tk)) - return; - - whitespace(); - if (token() != "END") { - err("Expected END after C-VECTOR-AND-BOUNDS section"); - return; - } - - // having survived everything till here, we mark the input as valid: - good_ = true; - } - - bool good() const - { - return good_; - } - - std::string& error_message() - { - CGAL_qpe_assertion(!good()); - 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... - - template - std::string tostr(const T& t) { - std::stringstream strm; - strm << t; - return strm.str(); - } - - // Replaces the first occurrence of '%' in msg by replacement. - std::string replace1(const std::string& msg,const std::string& replacement) - { - std::string result(msg); - const std::string::size_type pos = result.find('%'); - CGAL_qpe_assertion(pos < result.size()); - result.replace(pos,1,replacement); - return result; - } - - bool err(const char* msg) - { - error_message_ = msg; - return false; - } - - bool err1(const char* msg, - const std::string& parameter1) - { - error_message_ = replace1(msg,parameter1); - return false; - } - - bool err2(const char* msg, - const std::string& parameter1, - const std::string& parameter2) - { - error_message_ = replace1(replace1(msg,parameter1),parameter2); - return false; - } - - bool err3(const char* msg, - const std::string& parameter1, - const std::string& parameter2, - const std::string& parameter3) - { - error_message_ = replace1(replace1(replace1(msg,parameter1),parameter2), - parameter3); - return false; - } - - void warn(const std::string& msg) - { - std::cerr << "Parser warning: " << msg << '.' << std::endl; - } - - void warn1(const std::string& msg,const std::string& parameter1) - { - warn(replace1(msg,parameter1)); - } - -private: // parsing helpers: - - // Eats whitespace and returns true iff the end of the file has not yet been - // reached. - bool whitespace() - { - std::ws(in); - return !in.eof(); - } - - // Returns the next token, i.e., string of consecutive non-whitespace - // characters. - std::string token() { - whitespace(); - std::string token; - char c; - while (in.get(c)) { - if (isspace(c)) { - in.putback(c); - break; - } - token.push_back(c); - } - - // std::cout << "[token: '" << token << "']\n"; - return token; - } - - bool read_number(ANT& val) - { - if (nt == INTEGER) { - int v; - in >> v; - val = v; - } else if (nt == RATIONAL) { - Rational v; - in >> v; - val = v; - } else if (nt == DOUBLE) { - double v; - in >> v; - val = v; - } else - CGAL_qpe_assertion(false); - return in.good(); - } - -private: // parsing routines: - - // Reads the comments preceeding HEADER, returning false in case of an error. - // Note: this method does not touch error_message_. - bool read_initial_comments() - { - do { - // obtain first (real) charactor of the line: - whitespace(); - int first_char = in.peek(); - if (first_char != '#') - return in.good(); - - // skip this line: - while (in.good() && in.get() != '\n') - ; - } while (in.good()); - return false; - } - - // Reads the header, returning false in case of an error. - // Note: this method sets error_message_ appropriately in case of errors. - bool read_HEADER() { - // safety check: - std::string tk = token(); - if (tk != "HEADER") - return err1("Expected HEADER after initial comments but found '%'", tk); - - // read header tags: - tk = token(); - while (tk != "CONSTRAINTS") { - if (tk == "number-type:") { - std::string nts = token(); - if (nts == "integer") { - nt = INTEGER; - any_zero = int(0); - } else if (nts == "rational") { - nt = RATIONAL; - any_zero = Rational(0); - } else if (nts == "double") { - nt = DOUBLE; - any_zero = double(0); - } else - return err1("Unknown type '%' in 'number-type:' clause in " - "HEADER section", nts); - - // set default bound: - default_fl = true; - default_fu = false; - default_l = any_zero; - - } else if (tk == "number-of-variables:") { - in >> n; - if (!in.good()) - return err("Expected integer after 'number-of-variables:' in " - "in HEADER section"); - } else if (tk == "number-of-constraints:") { - in >> m; - if (!in.good()) - return err("Expected integer after 'number-of-variables:' in " - "in HEADER section"); - } else if (tk == "default-bound:") { - if (nt == YET_UNKOWN_NUMBER_TYPE) - return err("'default-bound:' must be preceded by 'number-type:' " - "in HEADER section"); - std::string bnd = token(); - if (bnd == "nonnegative") - ; // no need to do anything at all as this is the default - else if (bnd == "free") - default_fl = false; - else - return err1("Unknown bound type '%' in 'default-bound:' clause " - "in HEADER section", bnd); - } else - return err1("Unknown tag '%' in HEADER section", tk); - - tk = token(); - } - - if (nt == YET_UNKOWN_NUMBER_TYPE) - return err("No 'number-type:' given in HEADER"); - if (n < 0) - return err("No 'number-of-variables:' given in HEADER"); - if (m < 0) - return err("No 'number-of-constraints:' given in HEADER"); - return true; - } - - // Reads the constraints, returning false in case of an error. - // Note: this method sets error_message_ appropriately in case of errors. - bool read_CONSTRAINTS() { - // Note: "CONSTRAINTS" has already been parsed at this point. - - ANT val; - for (int i = 0; i < m; ++i) { - // read row of A: - for (int j = 0; j < n; ++j) { - if (!read_number(val)) - return err2("Expected number in CONSTRAINTS section at A[%,%]", - tostr(i), tostr(j)); - A_[j][i] = val; - } - - // read row-type: - std::string rt = token(); - if (rt == "<=") - row_type_[i] = LESS_EQUAL; - else if (rt == "=" || rt == "==") - row_type_[i] = EQUAL; - else if (rt == ">=") - row_type_[i] = GREATER_EQUAL; - else - return err2("Expected one of {'<=','=','>='} but found '%' in " - "row % of CONSTRAINTS section", rt, tostr(i)); - - // read b-entry: - if (!read_number(val)) - return err1("Expected number in CONSTRAINTS section at b[%]", - tostr(i)); - b_[i] = val; - } - - return true; - } - - // Reads the D-matrix, if need be, returning false in case of an error. - // Note: this method sets error_message_ appropriately in case of errors. - // Note: this method reads the next token into tk. - bool read_D_MATRIX(std::string& tk) { - // check if there is a D-MATRIX section at all: - tk = token(); - if (tk != "D-MATRIX") - return true; - - ANT val; - for (int i = 0; i < n; ++i) { - for (int j = 0; j < n; ++j) { - if (!read_number(val)) - return err2("Expected number in D-MATRIX section at D[%,%]", - tostr(i), tostr(j)); - D_[i][j] = val; - } - } - - tk = token(); - return true; - } - - // Reads the c-vector and the bounds, returning false in case of an error. - // Note: this method sets error_message_ appropriately in case of errors. - bool read_C_VECTOR_AND_BOUNDS(const std::string& tk) { - // safety check: - if (tk != "C-VECTOR-AND-BOUNDS") - return err1("Expected C-VECTOR-AND-BOUNDS but found '%'", tk); - - ANT val; - for (int i = 0; i < n; ++i) { - // read c-entry: - if (!read_number(val)) - return err1("Expected number in C-VECTOR-AND-BOUNDS section for " - "variable %", tostr(i)); - c_[i] = val; - - // read bounds, if need be: - whitespace(); - if (in.peek() == '(') { - in.get(); - whitespace(); - if (in.peek() == ',') { - in.get(); - fl_[i] = false; - } else { - 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() != ',') - return err1("Expected ',' in C-VECTOR-AND-BOUNDS section after " - "finite lower bound of variable %", tostr(i)); - } - whitespace(); - if (in.peek() == ')') { - in.get(); - fu_[i] = false; - } else { - 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() != ')') - return err1("Expected ')' in C-VECTOR-AND-BOUNDS section after " - "finite upper bound of variable %", tostr(i)); - } - } - } - - return true; - } -}; - -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 > 3) { - 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\"problem-name\" should not contain " - << "white-space.\n\n" - << "See data2mps.cin for an example 'datafile.data' file.\n"; - return 1; - } - const char *desc = (argnr > 1? argv[1] : "Test"); - const char *name = (argnr > 2? argv[2] : desc); - - // read data-file from standard in: - Data_reader data(std::cin); - if (!data.good()) { - std::cerr << "An error occurred while parsing the input data file: \n" - << data.error_message() << "\n"; - 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 = "default"; // just to kill warnings - 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, desc, "data2mps", name, - 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; -} diff --git a/QP_solver/examples/QP_solver/data_to_mps.C b/QP_solver/examples/QP_solver/data_to_mps.C new file mode 120000 index 00000000000..3056d7f8790 --- /dev/null +++ b/QP_solver/examples/QP_solver/data_to_mps.C @@ -0,0 +1 @@ +../../test/QP_solver/data_to_mps.C \ No newline at end of file