Line data Source code
1 : /*
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2017 Pantelis Sopasakis (https://alphaville.github.io),
5 : * Krina Menounou (https://www.linkedin.com/in/krinamenounou),
6 : * Panagiotis Patrinos (http://homes.esat.kuleuven.be/~ppatrino)
7 : * Copyright (c) 2012 Brendan O'Donoghue (bodonoghue85@gmail.com)
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : * of this software and associated documentation files (the "Software"), to deal
11 : * in the Software without restriction, including without limitation the rights
12 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : * copies of the Software, and to permit persons to whom the Software is
14 : * furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included in all
17 : * copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 : * SOFTWARE.
26 : *
27 : */
28 : #include "scs_parser.h"
29 : #include <stdio.h>
30 :
31 : #if(defined _WIN32 || defined _WIN64 || defined _WINDLL)
32 : #define SCS_FORMAT_ZU "%Iu"
33 : #else
34 : #define SCS_FORMAT_ZU "%zu"
35 : #endif
36 :
37 : static const char SCS_EOL = '\n';
38 : #define SCS_YAML_CHAR_LEN 64
39 : static const char scs_yaml_meta[] = "meta";
40 : static const char scs_yaml_meta_id[] = "id";
41 : static const char scs_yaml_meta_creator[] = "creator";
42 : static const char scs_yaml_meta_license[] = "license";
43 : static const char scs_yaml_meta_date[] = "date";
44 : static const char scs_yaml_meta_yaml_version[] = "yamlVersion";
45 : static const char scs_yaml_problem[] = "problem";
46 : static const char scs_yaml_problem_name[] = "name";
47 : static const char scs_yaml_m[] = "m";
48 : static const char scs_yaml_n[] = "n";
49 : static const char scs_yaml_nnz[] = "nnz";
50 : static const char scs_yaml_matrix_A[] = "A";
51 : static const char scs_yaml_matrix_A_a[] = "a";
52 : static const char scs_yaml_matrix_A_I[] = "I";
53 : static const char scs_yaml_matrix_A_J[] = "J";
54 : static const char scs_yaml_vector_b[] = "b";
55 : static const char scs_yaml_vector_c[] = "c";
56 : static const char scs_yaml_cone_K[] = "K";
57 : static const char scs_yaml_cone_field_ep[] = "ep";
58 : static const char scs_yaml_cone_field_ed[] = "ed";
59 : static const char scs_yaml_cone_field_f[] = "f";
60 : static const char scs_yaml_cone_field_l[] = "l";
61 : static const char scs_yaml_cone_field_p[] = "p";
62 : static const char scs_yaml_cone_field_q[] = "q";
63 : static const char scs_yaml_cone_field_s[] = "s";
64 : static const char scs_yaml_cone_field_psize[] = "psize";
65 : static const char scs_yaml_cone_field_qsize[] = "qsize";
66 : static const char scs_yaml_cone_field_ssize[] = "ssize";
67 :
68 : static char scs_yaml_variable_name[SCS_YAML_CHAR_LEN];
69 :
70 : static void scs_yaml_clear_char_array(void) {
71 : memset(scs_yaml_variable_name, 0, SCS_YAML_CHAR_LEN * sizeof (char));
72 : }
73 :
74 : static void scs_yaml_skip_to_end_of_line(FILE * fp) {
75 : int c;
76 3143046 : while ((c = fgetc(fp)) != EOF && c != SCS_EOL);
77 : }
78 :
79 1560 : static char * scs_yaml_get_variable_name(FILE * fp) {
80 : int c;
81 1560 : size_t k = 0;
82 1560 : char colon = ':';
83 1560 : char hash = '#';
84 1560 : char begin_yaml[] = "---";
85 1560 : char end_yaml[] = "...";
86 :
87 : scs_yaml_clear_char_array();
88 :
89 : /* read the first three characters (unless a hash is found - then stop) */
90 13430 : while (k < 3 && (c = fgetc(fp)) != EOF && c != colon && c != hash)
91 11870 : if (c != ' ' && c != '\n') scs_yaml_variable_name[k++] = (char) c;
92 :
93 : /* check whether the first three chars are --- or ... */
94 1560 : if (strcmp(begin_yaml, scs_yaml_variable_name) == 0
95 1510 : || strcmp(end_yaml, scs_yaml_variable_name) == 0) {
96 : scs_yaml_skip_to_end_of_line(fp); /* skip to the end of the line */
97 : return SCS_NULL;
98 : }
99 :
100 1460 : if (c == hash) {
101 : scs_yaml_skip_to_end_of_line(fp); /* skip to the end of the line */
102 : return SCS_NULL;
103 : }
104 1384 : if (c == colon) return scs_yaml_variable_name;
105 :
106 : /* read the rest */
107 1980 : while ((c = fgetc(fp)) != EOF && c != colon)
108 1438 : if (c != ' ') scs_yaml_variable_name[k++] = (char) c;
109 :
110 : return scs_yaml_variable_name; /* variable name */
111 : }
112 :
113 50 : static void scs_yaml_skip_to_problem(FILE * fp) {
114 474 : while (!feof(fp)) {
115 : char * var_name;
116 424 : var_name = scs_yaml_get_variable_name(fp);
117 424 : if (var_name != SCS_NULL) {
118 : scs_yaml_skip_to_end_of_line(fp);
119 350 : if (strcmp(var_name, scs_yaml_problem) == 0) break;
120 : }
121 : }
122 50 : }
123 :
124 261 : static size_t scs_yaml_read_size_t(FILE * fp) {
125 : size_t value_in_yaml;
126 : int status;
127 261 : status = fscanf(fp, SCS_FORMAT_ZU, &value_in_yaml);
128 261 : if (status <= 0) value_in_yaml = 0;
129 261 : return value_in_yaml;
130 : }
131 :
132 1 : static scs_float scs_yaml_read_numeric(FILE * fp) {
133 : scs_float value_in_yaml;
134 : int status;
135 1 : status = fscanf(fp, "%lf", &value_in_yaml);
136 1 : if (status <= 0) value_in_yaml = 0;
137 1 : return value_in_yaml;
138 : }
139 :
140 25 : static void scs_yaml_discover_matrix_sizes(FILE * fp, ScsData * data, scs_int * nnz) {
141 : size_t k = 0;
142 187 : while (k++ < 6 && !feof(fp)) {
143 : char * var_name;
144 162 : var_name = scs_yaml_get_variable_name(fp);
145 162 : if (var_name == SCS_NULL) {
146 12 : k--;
147 12 : continue;
148 : }
149 150 : if (strcmp(var_name, scs_yaml_m) == 0) {
150 25 : data->m = scs_yaml_read_size_t(fp);
151 125 : } else if (strcmp(var_name, scs_yaml_n) == 0) {
152 25 : data->n = scs_yaml_read_size_t(fp);
153 100 : } else if (strcmp(var_name, scs_yaml_nnz) == 0) {
154 25 : *nnz = scs_yaml_read_size_t(fp);
155 : }
156 : scs_yaml_skip_to_end_of_line(fp);
157 : }
158 25 : }
159 :
160 25 : static void scs_yaml_discover_cone_sizes(FILE * fp, ScsCone * cone) {
161 25 : size_t k = 0;
162 306 : while (k++ < 10 && !feof(fp)) {
163 : char * var_name;
164 256 : var_name = scs_yaml_get_variable_name(fp);
165 256 : if (var_name == SCS_NULL) {
166 12 : k--;
167 12 : continue;
168 : }
169 244 : if (strcmp(var_name, scs_yaml_cone_field_psize) == 0) {
170 23 : cone->psize = scs_yaml_read_size_t(fp);
171 221 : } else if (strcmp(var_name, scs_yaml_cone_field_qsize) == 0) {
172 25 : cone->qsize = scs_yaml_read_size_t(fp);
173 196 : } else if (strcmp(var_name, scs_yaml_cone_field_ssize) == 0) {
174 25 : cone->ssize = scs_yaml_read_size_t(fp);
175 : }
176 : scs_yaml_skip_to_end_of_line(fp);
177 : }
178 25 : }
179 :
180 25 : static int scs_yaml_discover_sizes(
181 : FILE * fp,
182 : ScsData * data,
183 : ScsCone * cone,
184 : scs_int * nnz) {
185 25 : int checkpoints = 0;
186 : /* fast-forward to the problem */
187 25 : scs_yaml_skip_to_problem(fp);
188 :
189 : /* parse the problem */
190 200 : while (!feof(fp)) {
191 : char * variable_name;
192 150 : variable_name = scs_yaml_get_variable_name(fp);
193 : scs_yaml_skip_to_end_of_line(fp);
194 150 : if (variable_name == SCS_NULL) continue;
195 123 : if (strcmp(variable_name, scs_yaml_matrix_A) == 0) {
196 25 : checkpoints++;
197 25 : scs_yaml_discover_matrix_sizes(fp, data, nnz);
198 98 : } else if (strcmp(variable_name, scs_yaml_cone_K) == 0) {
199 25 : checkpoints++;
200 25 : scs_yaml_discover_cone_sizes(fp, cone);
201 : }
202 : }
203 25 : return checkpoints == 2 ? 0 : 1;
204 : }
205 :
206 25 : static int scs_yaml_initialise_data_and_cone(ScsData * data, ScsCone * cone, scs_int nnz) {
207 25 : if (data == SCS_NULL || cone == SCS_NULL) return 700;
208 25 : if (data->m <= 0) return 701;
209 25 : if (data->n <= 0) return 702;
210 25 : if (cone->psize < 0) return 703;
211 25 : if (cone->qsize < 0) return 704;
212 25 : if (cone->ssize < 0) return 705;
213 :
214 : /* initialise matrix `A` */
215 25 : data->A = scs_malloc(sizeof (ScsAMatrix));
216 25 : if (data->A == SCS_NULL) goto yaml_init_error_0;
217 25 : data->A->m = data->m;
218 25 : data->A->n = data->n;
219 25 : data->A->i = scs_malloc(nnz * sizeof (scs_int));
220 25 : if (data->A->i == SCS_NULL) goto yaml_init_error_1;
221 25 : data->A->p = scs_malloc((data->n + 1) * sizeof (scs_int));
222 25 : if (data->A->p == SCS_NULL) goto yaml_init_error_2;
223 25 : data->A->x = scs_malloc(nnz * sizeof (scs_float));
224 25 : if (data->A->x == SCS_NULL) goto yaml_init_error_3;
225 :
226 : /* initialise `b` and `c` */
227 25 : data->b = scs_malloc(data->m * sizeof (scs_float));
228 25 : if (data->b == SCS_NULL) goto yaml_init_error_4;
229 25 : data->c = scs_malloc(data->n * sizeof (scs_float));
230 25 : if (data->c == SCS_NULL) goto yaml_init_error_5;
231 :
232 : /* initialise `cone` */
233 25 : cone->p = scs_malloc(cone->psize * sizeof (scs_float));
234 25 : if (cone->psize > 0 && cone->p == SCS_NULL) goto yaml_init_error_6;
235 25 : cone->q = scs_malloc(cone->qsize * sizeof (scs_int));
236 25 : if (cone->qsize > 0 && cone->q == SCS_NULL) goto yaml_init_error_7;
237 25 : cone->s = scs_malloc(cone->ssize * sizeof (scs_int));
238 25 : if (cone->ssize && cone->s == SCS_NULL) goto yaml_init_error_8;
239 :
240 : return 0;
241 :
242 : /* LCOV_EXCL_START */
243 : yaml_init_error_8:
244 : scs_free(cone->q);
245 : yaml_init_error_7:
246 : scs_free(cone->p);
247 : yaml_init_error_6:
248 : scs_free(data->c);
249 : yaml_init_error_5:
250 : scs_free(data->b);
251 : yaml_init_error_4:
252 : scs_free(data->A->x);
253 : yaml_init_error_3:
254 : scs_free(data->A->p);
255 : yaml_init_error_2:
256 : scs_free(data->A->i);
257 : yaml_init_error_1:
258 : scs_free(data->A);
259 : yaml_init_error_0:
260 : return 1;
261 : /* LCOV_EXCL_STOP */
262 : }
263 :
264 59 : static int scs_yaml_parse_int_array(FILE * fp, scs_int * array, size_t len) {
265 : int temp;
266 : size_t i;
267 59 : if (fscanf(fp, " [ %d", &temp) == 0) return 1;
268 59 : array[0] = temp;
269 129612 : for (i = 0; i < len - 1; ++i) {
270 129553 : if (fscanf(fp, " , %d", &temp) == 0) return 1;
271 129553 : array[i + 1] = temp;
272 : }
273 : return 0;
274 : }
275 :
276 78 : static int scs_yaml_parse_float_array(FILE * fp, scs_float * array, size_t len) {
277 : size_t i;
278 78 : if (fscanf(fp, " [ %lf ", array) == 0) return 1;
279 173446 : for (i = 0; i < len - 1; ++i)
280 173368 : if (fscanf(fp, " , %lf ", array + i + 1) == 0) return 1;
281 : return 0;
282 : }
283 :
284 25 : static int scs_yaml_parse_matrix_A(FILE * fp, ScsData * data, scs_int nonzeroes) {
285 : /* parse matrix A */
286 : size_t k = 0;
287 : int checkpoints = 0;
288 187 : while (k++ < 6 && !feof(fp)) {
289 : char * var_name;
290 162 : var_name = scs_yaml_get_variable_name(fp);
291 162 : if (var_name == SCS_NULL) {
292 12 : k--;
293 12 : continue;
294 : }
295 150 : if (strcmp(var_name, scs_yaml_matrix_A_I) == 0) {
296 25 : checkpoints++;
297 25 : if (scs_yaml_parse_int_array(fp, data->A->p, data->n + 1)) return 1;
298 125 : } else if (strcmp(var_name, scs_yaml_matrix_A_J) == 0) {
299 25 : checkpoints++;
300 25 : if (scs_yaml_parse_int_array(fp, data->A->i, nonzeroes)) return 1;
301 100 : } else if (strcmp(var_name, scs_yaml_matrix_A_a) == 0) {
302 25 : checkpoints++;
303 25 : if (scs_yaml_parse_float_array(fp, data->A->x, nonzeroes)) return 1;
304 : }
305 : scs_yaml_skip_to_end_of_line(fp);
306 : }
307 25 : return checkpoints == 3 ? 0 : 2;
308 : }
309 :
310 25 : static int scs_yaml_parse_cone_K(FILE * fp, ScsCone * cone) {
311 25 : size_t k = 0;
312 25 : char * var_name = SCS_NULL;
313 306 : while (k++ < 10 && !feof(fp)) {
314 256 : var_name = scs_yaml_get_variable_name(fp);
315 256 : if (var_name == SCS_NULL) {
316 12 : k--;
317 12 : continue;
318 : }
319 244 : if (strcmp(var_name, scs_yaml_cone_field_f) == 0) {
320 23 : cone->f = scs_yaml_read_size_t(fp);
321 221 : } else if (strcmp(var_name, scs_yaml_cone_field_l) == 0) {
322 25 : cone->l = scs_yaml_read_size_t(fp);
323 196 : } else if (strcmp(var_name, scs_yaml_cone_field_ep) == 0) {
324 25 : cone->ep = scs_yaml_read_size_t(fp);
325 171 : } else if (strcmp(var_name, scs_yaml_cone_field_ed) == 0) {
326 23 : cone->ed = scs_yaml_read_size_t(fp);
327 148 : } else if (strcmp(var_name, scs_yaml_cone_field_q) == 0) {
328 25 : if (cone->qsize == 1) {
329 16 : cone->q[0] = (scs_int) scs_yaml_read_size_t(fp);
330 9 : } else if (cone->qsize > 1) {
331 3 : if (scs_yaml_parse_int_array(fp, cone->q, cone->qsize)) return 1;
332 : }
333 123 : } else if (strcmp(var_name, scs_yaml_cone_field_p) == 0) {
334 25 : if (cone->psize == 1) {
335 1 : cone->p[0] = scs_yaml_read_numeric(fp);
336 24 : } else if (cone->psize > 1) {
337 3 : if (scs_yaml_parse_float_array(fp, cone->p, cone->psize)) return 1;
338 : }
339 98 : } else if (strcmp(var_name, scs_yaml_cone_field_s) == 0) {
340 25 : if (cone->ssize == 1) {
341 1 : cone->s[0] = (scs_int) scs_yaml_read_size_t(fp);
342 24 : } else if (cone->ssize > 1) {
343 6 : if (scs_yaml_parse_int_array(fp, cone->s, cone->ssize)) return 1;
344 : }
345 : }
346 : scs_yaml_skip_to_end_of_line(fp);
347 : }
348 : return 0;
349 : }
350 :
351 25 : static int scs_yaml_parse_data_and_cone(
352 : FILE * fp,
353 : ScsData * data,
354 : ScsCone * cone,
355 : scs_int nonzeroes) {
356 : /* fast-forward to the problem */
357 25 : scs_yaml_skip_to_problem(fp);
358 :
359 : /* parse the problem */
360 200 : while (!feof(fp)) {
361 150 : scs_yaml_get_variable_name(fp);
362 150 : if (strcmp(scs_yaml_variable_name, scs_yaml_matrix_A) == 0) {
363 : scs_yaml_skip_to_end_of_line(fp);
364 25 : if (scs_yaml_parse_matrix_A(fp, data, nonzeroes)) return 1;
365 125 : } else if (strcmp(scs_yaml_variable_name, scs_yaml_cone_K) == 0) {
366 : scs_yaml_skip_to_end_of_line(fp);
367 25 : if (scs_yaml_parse_cone_K(fp, cone)) return 1;
368 100 : } else if (strcmp(scs_yaml_variable_name, scs_yaml_vector_b) == 0) {
369 25 : if (scs_yaml_parse_float_array(fp, data->b, data->m)) return 1;
370 : scs_yaml_skip_to_end_of_line(fp);
371 75 : } else if (strcmp(scs_yaml_variable_name, scs_yaml_vector_c) == 0) {
372 25 : if (scs_yaml_parse_float_array(fp, data->c, data->n)) return 1;
373 : scs_yaml_skip_to_end_of_line(fp);
374 : } else {
375 : scs_yaml_skip_to_end_of_line(fp);
376 : }
377 : }
378 : return 0;
379 :
380 : }
381 :
382 : static void scs_reset_cone(ScsCone * cone) {
383 25 : cone->ssize = 0;
384 25 : cone->ed = 0;
385 25 : cone->ep = 0;
386 25 : cone->f = 0;
387 25 : cone->l = 0;
388 25 : cone->psize = 0;
389 : cone->ssize = 0;
390 25 : cone->qsize = 0;
391 25 : cone->q = SCS_NULL;
392 25 : cone->p = SCS_NULL;
393 25 : cone->s = SCS_NULL;
394 : }
395 :
396 25 : scs_int scs_from_YAML(
397 : const char * filepath,
398 : ScsData ** data,
399 : ScsCone ** cone) {
400 :
401 25 : FILE *fp = SCS_NULL;
402 : scs_int status;
403 : scs_int nonzeroes;
404 :
405 25 : nonzeroes = 0;
406 25 : status = 0;
407 :
408 25 : *data = scs_init_data();
409 25 : if (data == SCS_NULL) {
410 : status = 501;
411 : goto exit_error_1;
412 : }
413 :
414 25 : *cone = scs_malloc(sizeof (ScsCone));
415 25 : scs_reset_cone(*cone);
416 25 : if (cone == SCS_NULL) {
417 : status = 502;
418 : goto exit_error_2;
419 : }
420 :
421 25 : fp = fopen(filepath, "r");
422 :
423 25 : if (fp == NULL) {
424 : status = 1000;
425 : goto exit_error_2;
426 : }
427 :
428 :
429 : /* first we need to know the sizes */
430 25 : if (scs_yaml_discover_sizes(fp, *data, *cone, &nonzeroes)) {
431 : status = 101;
432 : goto exit_error_2;
433 : }
434 :
435 : /* we know the dimensions - initialise `data` and `cone` */
436 25 : if ((status = scs_yaml_initialise_data_and_cone(*data, *cone, nonzeroes)))
437 : goto exit_error_2;
438 :
439 : /* rewind file */
440 25 : rewind(fp);
441 :
442 : /* parse `data` and `cone` */
443 25 : if (scs_yaml_parse_data_and_cone(fp, *data, *cone, nonzeroes)) {
444 : status = 103;
445 : goto exit_error_2;
446 : }
447 :
448 25 : if (fp != SCS_NULL) {
449 25 : if (0 != fclose(fp)) {
450 0 : status = 224;
451 : }
452 : }
453 25 : return status;
454 :
455 : /* LCOV_EXCL_START */
456 : exit_error_2:
457 : scs_free_data_cone(*data, *cone);
458 : exit_error_1:
459 : if (fp != SCS_NULL)
460 : fclose(fp);
461 : return status;
462 : /* LCOV_EXCL_STOP */
463 : }
464 :
465 : static int scs_double_num_digits = 17;
466 : static char scs_yaml_space[] = " ";
467 : static char scs_yaml_double_space[] = " ";
468 :
469 64 : static void scs_serialize_array_to_YAML(
470 : FILE * RESTRICT fp,
471 : void * array,
472 : scs_int len,
473 : scs_int is_array_int
474 : ) {
475 : fprintf(fp, "[");
476 64 : if (len > 0) {
477 : size_t i;
478 49 : if (is_array_int) {
479 : scs_int * int_array = (scs_int *) array;
480 9859 : for (i = 0; i < len - 1; ++i) {
481 9859 : fprintf(fp, "%d,", (int) int_array[i]);
482 : }
483 21 : fprintf(fp, "%d", (int) int_array[len - 1]);
484 : } else {
485 : scs_float * float_array = (scs_float *) array;
486 11132 : for (i = 0; i < len - 1; ++i) {
487 11132 : fprintf(fp, "%.*g,", scs_double_num_digits, (double) float_array[i]);
488 : }
489 28 : fprintf(fp, "%.*g", scs_double_num_digits, (double) float_array[len - 1]);
490 : }
491 : }
492 : fprintf(fp, "]\n");
493 64 : }
494 :
495 9 : static void scs_serialize_sparse_matrix_to_YAML(
496 : FILE * RESTRICT fp,
497 : const ScsAMatrix * RESTRICT matrix) {
498 9 : scs_int num_nonzeroes = matrix->p[matrix->n];
499 : fprintf(fp, "%s%s:\n", scs_yaml_space, scs_yaml_matrix_A);
500 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_m, (int) matrix->m);
501 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_n, (int) matrix->n);
502 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_nnz, (int) num_nonzeroes);
503 : fprintf(fp, "%s%s: ", scs_yaml_double_space, scs_yaml_matrix_A_a);
504 9 : scs_serialize_array_to_YAML(fp, matrix->x, num_nonzeroes, 0);
505 : fprintf(fp, "%s%s: ", scs_yaml_double_space, scs_yaml_matrix_A_I);
506 9 : scs_serialize_array_to_YAML(fp, matrix->p, matrix->n + 1, 1);
507 : fprintf(fp, "%s%s: ", scs_yaml_double_space, scs_yaml_matrix_A_J);
508 9 : scs_serialize_array_to_YAML(fp, matrix->i, num_nonzeroes, 1);
509 9 : }
510 :
511 9 : static void scs_serialize_vectors_to_YAML(
512 : FILE * RESTRICT fp,
513 : const ScsData * RESTRICT data) {
514 : fprintf(fp, "%s%s: ", scs_yaml_space, scs_yaml_vector_b);
515 9 : scs_serialize_array_to_YAML(fp, data->b, data->m, 0);
516 : fprintf(fp, "%s%s: ", scs_yaml_space, scs_yaml_vector_c);
517 9 : scs_serialize_array_to_YAML(fp, data->c, data->n, 0);
518 9 : }
519 :
520 9 : static void scs_serialize_cone_to_YAML(
521 : FILE * RESTRICT fp,
522 : const ScsCone * RESTRICT cone) {
523 : fprintf(fp, "%s%s:\n", scs_yaml_space, scs_yaml_cone_K);
524 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_psize, (int) cone->psize);
525 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_qsize, (int) cone->qsize);
526 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_ssize, (int) cone->ssize);
527 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_f, (int) cone->f);
528 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_l, (int) cone->l);
529 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_ep, (int) cone->ep);
530 9 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_ed, (int) cone->ed);
531 9 : if (cone->qsize == 1) {
532 6 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space, scs_yaml_cone_field_q, (int) cone->q[0]);
533 : } else {
534 : fprintf(fp, "%s%s: ", scs_yaml_double_space, scs_yaml_cone_field_q);
535 3 : scs_serialize_array_to_YAML(fp, cone->q, cone->qsize, 1);
536 : }
537 9 : if (cone->psize == 1) {
538 1 : fprintf(fp, "%s%s: %.*g\n", scs_yaml_double_space,
539 : scs_yaml_cone_field_p, scs_double_num_digits,
540 1 : (double) cone->p[0]);
541 : } else {
542 : fprintf(fp, "%s%s: ", scs_yaml_double_space, scs_yaml_cone_field_p);
543 8 : scs_serialize_array_to_YAML(fp, cone->p, cone->psize, 0);
544 : }
545 9 : if (cone->ssize == 1) {
546 1 : fprintf(fp, "%s%s: %d\n", scs_yaml_double_space,
547 1 : scs_yaml_cone_field_s, (int) cone->s[0]);
548 : } else {
549 : fprintf(fp, "%s%s: ", scs_yaml_double_space, scs_yaml_cone_field_s);
550 8 : scs_serialize_array_to_YAML(fp, cone->s, cone->ssize, 1);
551 : }
552 9 : }
553 :
554 9 : scs_int scs_to_YAML(
555 : const char * RESTRICT filepath,
556 : ScsConicProblemMetadata * metadata,
557 : const ScsData * RESTRICT data,
558 : const ScsCone * RESTRICT cone) {
559 9 : scs_int status = 0;
560 9 : FILE *fp = SCS_NULL;
561 9 : scs_int should_free_metadata = 0;
562 :
563 9 : if (data == SCS_NULL) return 501;
564 9 : if (cone == SCS_NULL) return 502;
565 9 : if (filepath == SCS_NULL) return 503;
566 :
567 9 : if (metadata == SCS_NULL) {
568 1 : metadata = scs_init_conic_problem_metadata("anonymous-conic-problem");
569 1 : if (metadata == SCS_NULL) return 600;
570 : should_free_metadata = 1;
571 : }
572 :
573 9 : fp = fopen(filepath, "w");
574 :
575 9 : if (fp == NULL) {
576 : status = 101;
577 : goto to_yaml_exit_0;
578 : }
579 : fprintf(fp, "--- # SuperSCS Problem\n%s:\n", scs_yaml_meta);
580 9 : fprintf(fp, "%s%s: '%s'\n", scs_yaml_space, scs_yaml_meta_id, metadata->id);
581 9 : fprintf(fp, "%s%s: '%s'\n", scs_yaml_space, scs_yaml_meta_creator, metadata->creator);
582 9 : fprintf(fp, "%s%s: '%s'\n", scs_yaml_space, scs_yaml_meta_yaml_version, metadata->yamlVersion);
583 9 : fprintf(fp, "%s%s: '%s'\n", scs_yaml_space, scs_yaml_meta_license, metadata->license);
584 9 : fprintf(fp, "%s%s: '%s'\n", scs_yaml_space, scs_yaml_meta_date, metadata->date);
585 : fprintf(fp, "%s:\n", scs_yaml_problem);
586 9 : fprintf(fp, "%s%s: '%s'\n", scs_yaml_space, scs_yaml_problem_name, metadata->problemName);
587 9 : scs_serialize_sparse_matrix_to_YAML(fp, data->A);
588 9 : scs_serialize_vectors_to_YAML(fp, data);
589 9 : scs_serialize_cone_to_YAML(fp, cone);
590 : fprintf(fp, "...");
591 :
592 : to_yaml_exit_0:
593 9 : if (fp != SCS_NULL) {
594 9 : if (fclose(fp) != 0) {
595 0 : status = 250;
596 : }
597 : }
598 9 : if (should_free_metadata) {
599 1 : scs_free(metadata);
600 : }
601 9 : return status;
602 : }
603 :
604 4 : static int scs_time_offset(void) {
605 4 : time_t gmt, rawtime = time(NULL);
606 : struct tm *ptm;
607 : #if !defined(WIN32)
608 : struct tm gbuf;
609 4 : ptm = gmtime_r(&rawtime, &gbuf);
610 : #else
611 : ptm = gmtime(&rawtime);
612 : #endif
613 : // Request that mktime() looksup dst in timezone database
614 4 : ptm->tm_isdst = -1;
615 4 : gmt = mktime(ptm);
616 4 : return (int) difftime(rawtime, gmt) / 3600;
617 : }
618 :
619 4 : ScsConicProblemMetadata * scs_init_conic_problem_metadata(const char * problemName) {
620 4 : ScsConicProblemMetadata * metadata = SCS_NULL;
621 4 : time_t t = time(NULL);
622 4 : struct tm date_time_now = *localtime(&t);
623 :
624 4 : metadata = scs_malloc(sizeof (*metadata));
625 4 : if (metadata == SCS_NULL) return SCS_NULL;
626 4 : strncpy(metadata->license,
627 : "https://github.com/kul-forbes/scs/blob/master/LICENSE.txt",
628 : SCS_METADATA_TEXT_SIZE);
629 4 : strncpy(metadata->problemName, problemName, SCS_METADATA_TEXT_SIZE);
630 4 : snprintf(metadata->id, SCS_METADATA_TEXT_SIZE, "http://superscs.org/problem/%s", problemName);
631 4 : snprintf(metadata->creator, SCS_METADATA_TEXT_SIZE, "%s", scs_version());
632 4 : snprintf(metadata->date, SCS_METADATA_TEXT_SIZE,
633 : "%d-%d-%d %d:%d:%d [GMT+%d]",
634 : date_time_now.tm_year + 1900,
635 : date_time_now.tm_mon + 1,
636 : date_time_now.tm_mday,
637 : date_time_now.tm_hour,
638 : date_time_now.tm_min,
639 : date_time_now.tm_sec,
640 : scs_time_offset());
641 :
642 4 : snprintf(metadata->yamlVersion, SCS_METADATA_TEXT_SIZE, "1.2");
643 4 : return metadata;
644 : }
|