this repo has no description
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