this repo has no description
at develop 8.2 kB view raw
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7#include <minizinc/solvers/nl/nl_solreader.hh> 8 9using namespace std; 10 11namespace MiniZinc { 12 13// *** *** *** NLSol *** *** *** 14 15// Parse a string into a NLSol object 16NLSol NLSol::parseSolution(istream& in) { 17 string buffer; 18 string msg; 19 vector<double> vec; 20 NL_Solver_Status st; 21 22 try { 23 // Read the message 24 while (getline(in, buffer) && !buffer.empty()) { 25 msg += buffer + '\n'; 26 } 27 28 if (in.bad()) { 29 return NLSol("Error reading the solver message", NL_Solver_Status::PARSE_ERROR, {}); 30 } 31 32 // Check if we have 'Options', and skip them 33 if (getline(in, buffer)) { 34 if (buffer == "Options") { 35 if (getline(in, buffer)) { 36 int nb_options = stoi(buffer); 37 while (nb_options > 0) { 38 getline(in, buffer); 39 nb_options--; 40 } 41 } 42 } 43 } 44 45 if (in.bad()) { 46 return NLSol("Error reading the solver Options", NL_Solver_Status::PARSE_ERROR, {}); 47 } 48 49 // Check the dual: we ignore the first, read the second. If non zero, some lines are to be 50 // skipped 51 (getline(in, buffer) && getline(in, buffer)); 52 if (in.bad()) { 53 return NLSol("Error reading the number of dual", NL_Solver_Status::PARSE_ERROR, {}); 54 } 55 int nb_duals = stoi(buffer); 56 57 // Check the primal: we ignore the first, read the second 58 getline(in, buffer) && getline(in, buffer); 59 if (in.bad()) { 60 return NLSol("Error reading the number of primal", NL_Solver_Status::PARSE_ERROR, {}); 61 } 62 int nb_vars = stoi(buffer); 63 64 // Skip the duals 65 while (nb_duals > 0 && getline(in, buffer)) { 66 nb_duals--; 67 } 68 69 if (in.bad()) { 70 return NLSol("Error reading the dual values", NL_Solver_Status::PARSE_ERROR, {}); 71 } 72 73 // Read the vars 74 while (nb_vars > 0 && getline(in, buffer)) { 75 double d = stod(buffer); 76 vec.push_back(d); 77 nb_vars--; 78 } 79 80 if (in.bad()) { 81 return NLSol("Error reading the primal values", NL_Solver_Status::PARSE_ERROR, {}); 82 } 83 84 // Reading status code 85 // objno 0 EXIT 86 // ........ 87 // 8 char 88 getline(in, buffer); 89 string sub = buffer.substr(8, buffer.length() - 8); 90 int resultCode = stoi(sub); 91 st = NL_Solver_Status::UNKNOWN; 92 // Not this case, this one is our own: case -2: st = NL_Solver_Status::PARSE_ERROR; 93 if (resultCode == -1) { 94 st = NL_Solver_Status::UNKNOWN; 95 } else if (resultCode >= 0 && resultCode < 100) { 96 st = NL_Solver_Status::SOLVED; 97 } else if (resultCode >= 100 && resultCode < 200) { 98 st = NL_Solver_Status::UNCERTAIN; 99 } else if (resultCode >= 200 && resultCode < 300) { 100 st = NL_Solver_Status::INFEASIBLE; 101 } else if (resultCode >= 300 && resultCode < 400) { 102 st = NL_Solver_Status::UNBOUNDED; 103 } else if (resultCode >= 400 && resultCode < 500) { 104 st = NL_Solver_Status::LIMIT; 105 } else if (resultCode >= 500 && resultCode < 600) { 106 st = NL_Solver_Status::FAILURE; 107 } else if (resultCode == 600) { 108 st = NL_Solver_Status::INTERRUPTED; 109 } 110 111 } catch (...) { 112 return NLSol("Parsing error (probably a bad number)", NL_Solver_Status::PARSE_ERROR, vec); 113 } 114 115 return NLSol(msg, st, vec); 116} 117 118// *** *** *** NLSolns2Out *** *** *** 119 120/** Our "feedrawdatachunk" directly gets the solver's output, which is not the result. 121 * The result is written in the .sol file. 122 * Get the solver output and add a comment % in front of the lines 123 * We may be in a middle of a line! 124 */ 125bool NLSolns2Out::feedRawDataChunk(const char* data) { 126 if (data != nullptr) { 127 std::stringstream ss(data); 128 string to; 129 130 while (getline(ss, to)) { 131 if (ss.eof()) { 132 if (_inLine) { // Must complete a line, and the line is not over yet 133 getLog() << to << endl; 134 } else { // Start an incomple line 135 getLog() << "% " << to; 136 _inLine = true; 137 } 138 } else { 139 if (_inLine) { // Must complete a line, and the line is over. 140 getLog() << to << endl; 141 _inLine = false; 142 } else { // Full line 143 getLog() << "% " << to << endl; 144 } 145 } 146 } 147 } 148 return true; 149} 150 151void NLSolns2Out::parseSolution(const string& filename) { 152 ifstream f(FILE_PATH(filename)); 153 NLSol sol = NLSol::parseSolution(f); 154 155 switch (sol.status) { 156 case NL_Solver_Status::PARSE_ERROR: { 157 DEBUG_MSG("NL_Solver_Status: PARSE ERROR" << endl); 158 _out->feedRawDataChunk(_out->opt.errorMsgDef); 159 break; 160 } 161 162 case NL_Solver_Status::UNKNOWN: { 163 DEBUG_MSG("NL_Solver_Status: UNKNOWN" << endl); 164 _out->feedRawDataChunk(_out->opt.unknownMsgDef); 165 break; 166 } 167 168 case NL_Solver_Status::SOLVED: { 169 DEBUG_MSG("NL_Solver_Status: SOLVED" << endl); 170 171 stringstream sb; 172 // sb << std::hexfloat; // Use hexadecimal format for FP 173 sb << std::showpoint; // Always shows the decimal point, so we have e.g. '256.0' when 256 is 174 // the answer for a fp value. 175 sb.precision(numeric_limits<double>::digits10 + 2); 176 177 for (int i = 0; i < _nlFile.variables.size(); ++i) { 178 string n = _nlFile.vnames[i]; 179 NLVar v = _nlFile.variables[n]; 180 if (v.toReport) { 181 sb << v.name << " = "; 182 if (v.isInteger) { 183 long value = sol.values[i]; 184 sb << value; 185 } else { 186 double value = sol.values[i]; 187 sb << value; 188 } 189 sb << ";\n"; 190 } 191 } 192 193 // Output the arrays 194 for (auto& a : _nlFile.outputArrays) { 195 sb << a.name << " = array" << a.dimensions.size() << "d( "; 196 for (const string& s : a.dimensions) { 197 sb << s << ", "; 198 } 199 sb << "["; 200 for (int j = 0; j < a.items.size(); ++j) { 201 const NLArray::Item& item = a.items.at(j); 202 203 // Case of the literals 204 if (item.variable.empty()) { 205 if (a.isInteger) { 206 sb << static_cast<long long int>(item.value); 207 } else { 208 sb << item.value; 209 } 210 } else { 211 int index = _nlFile.variableIndexes.at(item.variable); 212 if (a.isInteger) { 213 long value = sol.values[index]; 214 sb << value; 215 } else { 216 double value = sol.values[index]; 217 sb << value; 218 } 219 } 220 221 if (j < a.items.size() - 1) { 222 sb << ", "; 223 } 224 } 225 226 sb << "]);\n"; 227 } 228 229 string s = sb.str(); 230 _out->feedRawDataChunk(s.c_str()); 231 _out->feedRawDataChunk(_out->opt.solutionSeparatorDef); 232 if (_nlFile.objective.isOptimisation()) { 233 _out->feedRawDataChunk("\n"); 234 _out->feedRawDataChunk(_out->opt.searchCompleteMsgDef); 235 } 236 237 break; 238 } 239 240 case NL_Solver_Status::UNCERTAIN: { 241 DEBUG_MSG("NL_Solver_Status: UNCERTAIN" << endl); 242 _out->feedRawDataChunk(_out->opt.unknownMsgDef); 243 break; 244 } 245 246 case NL_Solver_Status::INFEASIBLE: { 247 DEBUG_MSG("NL_Solver_Status: INFEASIBLE" << endl); 248 _out->feedRawDataChunk(_out->opt.unsatisfiableMsgDef); 249 break; 250 } 251 252 case NL_Solver_Status::UNBOUNDED: { 253 DEBUG_MSG("NL_Solver_Status: UNBOUNDED" << endl); 254 _out->feedRawDataChunk(_out->opt.unboundedMsgDef); 255 break; 256 } 257 258 case NL_Solver_Status::LIMIT: { 259 DEBUG_MSG("NL_Solver_Status: LIMIT" << endl); 260 _out->feedRawDataChunk(_out->opt.unknownMsgDef); 261 break; 262 } 263 264 case NL_Solver_Status::INTERRUPTED: { 265 DEBUG_MSG("NL_Solver_Status: INTERRUPTED" << endl); 266 _out->feedRawDataChunk(_out->opt.unknownMsgDef); 267 break; 268 } 269 270 default: 271 should_not_happen("parseSolution: switch on status with unknown code: " << sol.status); 272 } 273 274 // "Finish" the feed 275 _out->feedRawDataChunk("\n"); 276} 277 278ostream& NLSolns2Out::getLog() { return _verbose ? _out->getLog() : _dummyOfstream; } 279 280} // namespace MiniZinc