3b9fb216e9fa74108d4c4e17e26f1e1c8bc7a9c0
[libfirm] / ir / lpp / mps.c
1 /**
2  * Author:      Daniel Grund
3  * Date:        02.06.2005
4  * Copyright:   (c) Universitaet Karlsruhe
5  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  */
7
8 #include "config.h"
9 #include <stdarg.h>
10 #include <assert.h>
11 #include "mps.h"
12
13 /**
14  * These must comply to the enum cst_t in lpp.h
15  */
16 static const char *mps_cst_encoding[4] = {"N", "E", "L", "G"};
17
18 /**
19  * Diffferent line styles which can be used in a mps file
20  */
21 typedef enum _mps_line_t {l_raw,
22                                                   l_ind_name, l_ind_objs, l_ind_rows, l_ind_cols, l_ind_rhs, l_ind_end,
23                                                   l_data_row, l_data_col1, l_data_col2, l_data_mst, l_marker} mps_line_t;
24
25 static void mps_write_line(FILE *out, style_t style, mps_line_t line_type, ...) {
26         va_list args;
27         const char *fmt = "";
28
29         assert(style == s_mps_fixed || style == s_mps_free);
30         va_start(args, line_type);
31
32         if (style == s_mps_fixed) {
33                 /* white spaces are important! */
34                 switch (line_type) {
35                         case l_raw:       fmt = "%s\n"; break;
36                         case l_ind_name:  fmt = "NAME          %s\n"; break;
37                         case l_ind_objs:  fmt = "OBJSENSE\n"; break;
38                         case l_ind_rows:  fmt = "ROWS\n"; break;
39                         case l_ind_cols:  fmt = "COLUMNS\n"; break;
40                         case l_ind_rhs:   fmt = "RHS\n"; break;
41                         case l_ind_end:   fmt = "ENDATA\n"; break;
42                         case l_data_row:  fmt = " %-2s %-8s\n"; break; /* Field 1-2 */
43                         case l_data_col1: fmt = "    %-8s  %-8s  %12g\n"; break; /* Field 2-4 */
44                         case l_data_col2: fmt = "    %-8s  %-8s  %12g   %-8s  %12g\n"; break; /* Field 2-6 */
45                         case l_data_mst:  fmt = "    %-8s            %12g\n"; break; /* Field 3-4 */
46                         case l_marker:    fmt = "    M%-7d  'MARKER'                 '%s'\n"; break; /* Field 2,3,5 */
47                         default: assert(0);
48                 }
49         } else {
50                 switch (line_type) {
51                         case l_raw:       fmt = "%s\n"; break;
52                         case l_ind_name:  fmt = "NAME %s\n"; break;
53                         case l_ind_objs:  fmt = "OBJSENSE\n"; break;
54                         case l_ind_rows:  fmt = "ROWS\n"; break;
55                         case l_ind_cols:  fmt = "COLUMNS\n"; break;
56                         case l_ind_rhs:   fmt = "RHS\n"; break;
57                         case l_ind_end:   fmt = "ENDATA\n"; break;
58                         case l_data_row:  fmt = " %s\t%s\n"; break;
59                         case l_data_col1: fmt = " %s\t%s\t%g\n"; break;
60                         case l_data_col2: fmt = " %s\t%s\t%g\t%s\t%g\n"; break;
61                         case l_data_mst:  fmt = " %s\t%g\n"; break;
62                         case l_marker:    fmt = " M%d\t'MARKER'\t'%s'\n"; break;
63                         default: assert(0);
64                 }
65         }
66
67         vfprintf(out, fmt, args);
68         va_end(args);
69 }
70
71 static int mps_insert_markers(FILE *out, style_t style, lpp_var_t curr, lpp_var_t last, int marker_nr) {
72         assert(style == s_mps_fixed || style == s_mps_free);
73         if (last != curr) {
74                 /* print end-marker for last */
75                 if (last == lpp_binary)
76                         mps_write_line(out, style, l_marker, marker_nr++, "INTEND");
77
78                 /* print begin-marker for curr */
79                 if (curr == lpp_binary)
80                         mps_write_line(out, style, l_marker, marker_nr++, "INTORG");
81         }
82         return marker_nr;
83 }
84
85 void mps_write_mps(lpp_t *lpp, style_t style, FILE *out) {
86         int i, count, marker_nr = 0;
87         const lpp_name_t *curr;
88         const matrix_elem_t *elem, *before = NULL;
89         lpp_var_t last_type;
90         assert(style == s_mps_fixed || style == s_mps_free);
91
92         /* NAME */
93         mps_write_line(out, style, l_ind_name, lpp->name);
94
95         /* OBJSENSE */
96         if (lpp->opt_type == lpp_maximize) {
97                 mps_write_line(out, style, l_ind_objs);
98                 mps_write_line(out, style, l_raw, " MAX");
99         }
100
101         /* ROWS */
102         mps_write_line(out, style, l_ind_rows);
103         for(i=0; i<lpp->cst_next; ++i) {
104                 curr = lpp->csts[i];
105                 mps_write_line(out, style, l_data_row, mps_cst_encoding[curr->type.cst_type], curr->name);
106         }
107
108         /* COLUMNS */
109         mps_write_line(out, style, l_ind_cols);
110         last_type = lpp_invalid;
111         for(i=1; i<lpp->var_next; ++i) { /* column 0 is rhs */
112                 curr = lpp->vars[i];
113
114                 /* markers */
115                 marker_nr = mps_insert_markers(out, style, curr->type.var_type, last_type, marker_nr);
116                 last_type = curr->type.var_type;
117
118                 /* participation in constraints */
119                 count = 0;
120                 matrix_foreach_in_col(lpp->m, curr->nr, elem) {
121                         if (count == 0) {
122                                 before = elem;
123                                 count = 1;
124                         } else {
125                                 mps_write_line(out, style, l_data_col2, curr->name, lpp->csts[before->row]->name, (double)before->val, lpp->csts[elem->row]->name, (double)elem->val);
126                                 count = 0;
127                         }
128                 }
129                 if (count == 1)
130                         mps_write_line(out, style, l_data_col1, curr->name, lpp->csts[before->row]->name, (double)before->val);
131         }
132         mps_insert_markers(out, style, lpp_invalid, last_type, marker_nr); /* potential end-marker */
133
134         /* RHS */
135         mps_write_line(out, style, l_ind_rhs);
136         count = 0;
137         matrix_foreach_in_col(lpp->m, 0, elem) {
138                 if (count == 0) {
139                         before = elem;
140                         count = 1;
141                 } else {
142                         mps_write_line(out, style, l_data_col2, "rhs", lpp->csts[before->row]->name, (double)before->val, lpp->csts[elem->row]->name, (double)elem->val);
143                         count = 0;
144                 }
145         }
146         if (count == 1)
147                 mps_write_line(out, style, l_data_col1, "rhs", lpp->csts[before->row]->name, (double)before->val);
148
149         /* ENDATA */
150         mps_write_line(out, style, l_ind_end);
151 }
152
153 void mps_write_mst(lpp_t *lpp, style_t style, FILE *out) {
154         int i;
155         mps_write_line(out, style, l_ind_name, "");
156         for (i=0; i<lpp->var_next; ++i) {
157                 const lpp_name_t *var = lpp->vars[i];
158                 if (var->value_kind == lpp_value_start)
159                         mps_write_line(out, style, l_data_mst, var->name, (double)var->value);
160         }
161         mps_write_line(out, style, l_ind_end);
162 }