1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
on-restart-benchmarks/solvers/nl/nl_solreader.cpp
Jip J. Dekker f2a1c4e389 Squashed 'software/mza/' content from commit f970a59b17
git-subtree-dir: software/mza
git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
2021-07-11 16:34:30 +10:00

276 lines
7.8 KiB
C++

#include <minizinc/solvers/nl/nl_solreader.hh>
namespace MiniZinc {
// *** *** *** NLSol *** *** ***
// Parse a string into a NLSol object
NLSol NLSol::parse_sol(istream& in) {
string buffer;
string msg;
vector<double> vec;
NL_Solver_Status st;
try {
// Read the message
while (getline(in, buffer) && !buffer.empty()) {
msg += buffer + '\n';
}
if (in.bad()) {
return NLSol("Error reading the solver message", NL_Solver_Status::PARSE_ERROR, {});
}
// Check if we have 'Options', and skip them
if (getline(in, buffer)) {
if (buffer == "Options") {
if (getline(in, buffer)) {
int nb_options = stoi(buffer);
while (nb_options > 0) {
getline(in, buffer);
nb_options--;
}
}
}
}
if (in.bad()) {
return NLSol("Error reading the solver Options", NL_Solver_Status::PARSE_ERROR, {});
}
// Check the dual: we ignore the first, read the second. If non zero, some lines are to be
// skipped
(getline(in, buffer) && getline(in, buffer));
if (in.bad()) {
return NLSol("Error reading the number of dual", NL_Solver_Status::PARSE_ERROR, {});
}
int nb_duals = stoi(buffer);
// Check the primal: we ignore the first, read the second
getline(in, buffer) && getline(in, buffer);
if (in.bad()) {
return NLSol("Error reading the number of primal", NL_Solver_Status::PARSE_ERROR, {});
}
int nb_vars = stoi(buffer);
// Skip the duals
while (nb_duals > 0 && getline(in, buffer)) {
nb_duals--;
}
if (in.bad()) {
return NLSol("Error reading the dual values", NL_Solver_Status::PARSE_ERROR, {});
}
// Read the vars
while (nb_vars > 0 && getline(in, buffer)) {
double d = stod(buffer);
vec.push_back(d);
nb_vars--;
}
if (in.bad()) {
return NLSol("Error reading the primal values", NL_Solver_Status::PARSE_ERROR, {});
}
// Reading status code
// objno 0 EXIT
// ........
// 8 char
getline(in, buffer);
string sub = buffer.substr(8, buffer.length() - 8);
int resultCode = stoi(sub);
st = NL_Solver_Status::UNKNOWN;
// Not this case, this one is our own: case -2: st = NL_Solver_Status::PARSE_ERROR;
if (resultCode == -1) {
st = NL_Solver_Status::UNKNOWN;
} else if (resultCode >= 0 && resultCode < 100) {
st = NL_Solver_Status::SOLVED;
} else if (resultCode >= 100 && resultCode < 200) {
st = NL_Solver_Status::UNCERTAIN;
} else if (resultCode >= 200 && resultCode < 300) {
st = NL_Solver_Status::INFEASIBLE;
} else if (resultCode >= 300 && resultCode < 400) {
st = NL_Solver_Status::UNBOUNDED;
} else if (resultCode >= 400 && resultCode < 500) {
st = NL_Solver_Status::LIMIT;
} else if (resultCode >= 500 && resultCode < 600) {
st = NL_Solver_Status::FAILURE;
} else if (resultCode == 600) {
st = NL_Solver_Status::INTERRUPTED;
}
} catch (...) {
return NLSol("Parsing error (probably a bad number)", NL_Solver_Status::PARSE_ERROR, vec);
}
return NLSol(msg, st, vec);
}
// *** *** *** NLSolns2Out *** *** ***
/** Our "feedrawdatachunk" directly gets the solver's output, which is not the result.
* The result is written in the .sol file.
* Get the solver output and add a comment % in front of the lines
* We may be in a middle of a line!
*/
bool NLSolns2Out::feedRawDataChunk(const char* data) {
if (data != NULL) {
std::stringstream ss(data);
string to;
while (getline(ss, to)) {
if (ss.eof()) {
if (in_line) { // Must complete a line, and the line is not over yet
getLog() << to << endl;
} else { // Start an incomple line
getLog() << "% " << to;
in_line = true;
}
} else {
if (in_line) { // Must complete a line, and the line is over.
getLog() << to << endl;
in_line = false;
} else { // Full line
getLog() << "% " << to << endl;
}
}
}
}
return true;
}
void NLSolns2Out::parse_sol(const string& filename) {
ifstream f(filename);
NLSol sol = NLSol::parse_sol(f);
switch (sol.status) {
case NL_Solver_Status::PARSE_ERROR: {
DEBUG_MSG("NL_Solver_Status: PARSE ERROR" << endl);
out->feedRawDataChunk(out->_opt.error_msg_00);
break;
}
case NL_Solver_Status::UNKNOWN: {
DEBUG_MSG("NL_Solver_Status: UNKNOWN" << endl);
out->feedRawDataChunk(out->_opt.unknown_msg_00);
break;
}
case NL_Solver_Status::SOLVED: {
DEBUG_MSG("NL_Solver_Status: SOLVED" << endl);
stringstream sb;
// sb << std::hexfloat; // Use hexadecimal format for FP
sb << std::showpoint; // Always shows the decimal point, so we have e.g. '256.0' when 256 is
// the answer for a fp value.
sb.precision(numeric_limits<double>::digits10 + 2);
for (int i = 0; i < nl_file.variables.size(); ++i) {
string n = nl_file.vnames[i];
NLVar v = nl_file.variables[n];
if (v.to_report) {
sb << v.name << " = ";
if (v.is_integer) {
long value = sol.values[i];
sb << value;
} else {
double value = sol.values[i];
sb << value;
}
sb << ";\n";
}
}
// Output the arrays
for (int i = 0; i < nl_file.output_arrays.size(); ++i) {
NLArray& a = nl_file.output_arrays.at(i);
sb << a.name << " = array" << a.dimensions.size() << "d( ";
for (const string& s : a.dimensions) {
sb << s << ", ";
}
sb << "[";
for (int j = 0; j < a.items.size(); ++j) {
const NLArray::Item& item = a.items.at(j);
// Case of the literals
if (item.variable.empty()) {
if (a.is_integer) {
long value = item.value;
sb << value;
} else {
double value = item.value;
sb << value;
}
} else {
int index = nl_file.variable_indexes.at(item.variable);
if (a.is_integer) {
long value = sol.values[index];
sb << value;
} else {
double value = sol.values[index];
sb << value;
}
}
if (j < a.items.size() - 1) {
sb << ", ";
}
}
sb << "]);\n";
}
string s = sb.str();
out->feedRawDataChunk(s.c_str());
out->feedRawDataChunk(out->_opt.solution_separator_00);
if (nl_file.objective.is_optimisation()) {
out->feedRawDataChunk("\n");
out->feedRawDataChunk(out->_opt.search_complete_msg_00);
}
break;
}
case NL_Solver_Status::UNCERTAIN: {
DEBUG_MSG("NL_Solver_Status: UNCERTAIN" << endl);
out->feedRawDataChunk(out->_opt.unknown_msg_00);
break;
}
case NL_Solver_Status::INFEASIBLE: {
DEBUG_MSG("NL_Solver_Status: INFEASIBLE" << endl);
out->feedRawDataChunk(out->_opt.unsatisfiable_msg_00);
break;
}
case NL_Solver_Status::UNBOUNDED: {
DEBUG_MSG("NL_Solver_Status: UNBOUNDED" << endl);
out->feedRawDataChunk(out->_opt.unbounded_msg_00);
break;
}
case NL_Solver_Status::LIMIT: {
DEBUG_MSG("NL_Solver_Status: LIMIT" << endl);
out->feedRawDataChunk(out->_opt.unknown_msg_00);
break;
}
case NL_Solver_Status::INTERRUPTED: {
DEBUG_MSG("NL_Solver_Status: INTERRUPTED" << endl);
out->feedRawDataChunk(out->_opt.unknown_msg_00);
break;
}
default:
should_not_happen("parse_sol: switch on status with unknown code: " << sol.status);
}
// "Finish" the feed
out->feedRawDataChunk("\n");
}
ostream& NLSolns2Out::getLog(void) { return verbose ? out->getLog() : dummy_ofstream; }
} // namespace MiniZinc