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