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