Scippy

SoPlex

Sequential object-oriented simPlex

mpsinput.cpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the class library */
4 /* SoPlex --- the Sequential object-oriented simPlex. */
5 /* */
6 /* Copyright (C) 1996-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file mpsinput.cpp
17  * @brief Read MPS format files.
18  */
19 
20 #include <assert.h>
21 #include <ctype.h>
22 #include <string.h>
23 
24 #include "soplex/spxdefines.h"
25 #include "soplex/mpsinput.h"
26 #include "soplex/spxout.h"
27 
28 #define PATCH_CHAR '_'
29 #define BLANK ' '
30 
31 namespace soplex
32 {
33 
34 /// fill the line from \p pos up to column 80 with blanks.
35 static void clear_from(char* buf, int pos)
36 {
37  for(int i = pos; i < 80; i++)
38  buf[i] = BLANK;
39 
40  buf[80] = '\0';
41 }
42 
43 /// change all blanks inside a field to #PATCH_CHAR.
44 static void patch_field(char* buf, int beg, int end)
45 {
46  while((beg <= end) && (buf[end] == BLANK))
47  end--;
48 
49  while((beg <= end) && (buf[beg] == BLANK))
50  beg++;
51 
52  for(int i = beg; i <= end; i++)
53  if(buf[i] == BLANK)
54  buf[i] = PATCH_CHAR;
55 }
56 
57 /// read a MPS format data line and parse the fields.
59 {
60  int len;
61  int space;
62  char* s;
63  bool is_marker;
64  bool is_comment;
65 
66  do
67  {
68  m_f0 = m_f1 = m_f2 = m_f3 = m_f4 = m_f5 = 0;
69  is_marker = false;
70 
71  // Read until we have a non-empty, non-comment line.
72  do
73  {
74  if(!m_input.getline(m_buf, sizeof(m_buf)).good() && !m_input.eof())
75  return false;
76 
77  m_lineno++;
78 
79  MSG_DEBUG(std::cout << "DMPSIN01 Line " << m_lineno
80  << " " << m_buf << std::endl;)
81 
82  /* check if comment line */
83  is_comment = true;
84 
85  if(m_buf[0] == '*')
86  continue;
87 
88  /* normalize line and check if it is empty */
89  len = int(strlen(m_buf));
90 
91  for(int i = 0; i < len; i++)
92  {
93  if(m_buf[i] == '\t' || m_buf[i] == '\n' || m_buf[i] == '\r')
94  m_buf[i] = BLANK;
95  else if(m_buf[i] != BLANK)
96  is_comment = false;
97  }
98  }
99  while(is_comment);
100 
101  len = int(strlen(m_buf));
102 
103  if(len < 80)
104  clear_from(m_buf, len);
105 
106  assert(strlen(m_buf) >= 80);
107 
108  /* Look for new section
109  */
110  if(*m_buf != BLANK)
111  {
112  m_f0 = strtok(&m_buf[0], " ");
113 
114  assert(m_f0 != 0);
115 
116  m_f1 = strtok(0, " ");
117 
118  return true;
119  }
120 
121  if(!m_is_new_format)
122  {
123  /* Test for fixed format comments
124  */
125  if((m_buf[14] == '$') && (m_buf[13] == ' '))
126  clear_from(m_buf, 14);
127  else if((m_buf[39] == '$') && (m_buf[38] == ' '))
128  clear_from(m_buf, 39);
129 
130  /* Test for fixed format
131  */
132  space = m_buf[12] | m_buf[13]
133  | m_buf[22] | m_buf[23]
134  | m_buf[36] | m_buf[37] | m_buf[38]
135  | m_buf[47] | m_buf[48]
136  | m_buf[61] | m_buf[62] | m_buf[63];
137 
138  if(space == BLANK || len < 13)
139  {
140  /* Now we have space at the right positions.
141  * But are there also the non space where they
142  * should be ?
143  */
144  bool number = isdigit(m_buf[24]) || isdigit(m_buf[25])
145  || isdigit(m_buf[26]) || isdigit(m_buf[27])
146  || isdigit(m_buf[28]) || isdigit(m_buf[29])
147  || isdigit(m_buf[30]) || isdigit(m_buf[31])
148  || isdigit(m_buf[32]) || isdigit(m_buf[33])
149  || isdigit(m_buf[34]) || isdigit(m_buf[35]);
150 
151  /* len < 13 is handle ROW lines with embedded spaces
152  * in the names correctly
153  */
154  if(number || len < 13)
155  {
156  /* Now we assume fixed format, so we patch possible embedded spaces.
157  */
158  patch_field(m_buf, 4, 12);
159  patch_field(m_buf, 14, 22);
160  patch_field(m_buf, 39, 47);
161  }
162  else
163  {
164  if(m_section == COLUMNS || m_section == RHS
165  || m_section == RANGES || m_section == BOUNDS)
166  m_is_new_format = true;
167  }
168  }
169  else
170  {
171  m_is_new_format = true;
172  }
173  }
174 
175  s = &m_buf[1];
176 
177  /* At this point it is not clear if we have a indicator field.
178  * If there is none (e.g. empty) f1 will be the first name field.
179  * If there is one, f2 will be the first name field.
180  *
181  * Initially comment marks '$' ar only allowed in the beginning
182  * of the 2nd and 3rd name field. We test all fields but the first.
183  * This makes no difference, since if the $ is at the start of a value
184  * field, the line will be errornous anyway.
185  */
186  do
187  {
188  if(0 == (m_f1 = strtok(s, " ")))
189  break;
190 
191  if((0 == (m_f2 = strtok(0, " "))) || (*m_f2 == '$'))
192  {
193  m_f2 = 0;
194  break;
195  }
196 
197  if(!strcmp(m_f2, "'MARKER'"))
198  is_marker = true;
199 
200  if((0 == (m_f3 = strtok(0, " "))) || (*m_f3 == '$'))
201  {
202  m_f3 = 0;
203  break;
204  }
205 
206  if(is_marker)
207  {
208  if(!strcmp(m_f3, "'INTORG'"))
209  m_is_integer = true;
210  else if(!strcmp(m_f3, "'INTEND'"))
211  m_is_integer = false;
212  else
213  break; // unknown marker
214  }
215 
216  if(!strcmp(m_f3, "'MARKER'"))
217  is_marker = true;
218 
219  if((0 == (m_f4 = strtok(0, " "))) || (*m_f4 == '$'))
220  {
221  m_f4 = 0;
222  break;
223  }
224 
225  if(is_marker)
226  {
227  if(!strcmp(m_f4, "'INTORG'"))
228  m_is_integer = true;
229  else if(!strcmp(m_f4, "'INTEND'"))
230  m_is_integer = false;
231  else
232  break; // unknown marker
233  }
234 
235  if((0 == (m_f5 = strtok(0, " "))) || (*m_f5 == '$'))
236  m_f5 = 0;
237  }
238  while(false);
239  }
240  while(is_marker);
241 
242  MSG_DEBUG(std::cerr
243  << "DMPSIN02 -----------------------------------------------"
244  << std::endl
245  << "DMPSIN03 f0=" << ((m_f0 == 0) ? "nil" : m_f0) << std::endl
246  << "DMPSIN04 f1=" << ((m_f1 == 0) ? "nil" : m_f1) << std::endl
247  << "DMPSIN05 f2=" << ((m_f2 == 0) ? "nil" : m_f2) << std::endl
248  << "DMPSIN06 f3=" << ((m_f3 == 0) ? "nil" : m_f3) << std::endl
249  << "DMPSIN07 f4=" << ((m_f4 == 0) ? "nil" : m_f4) << std::endl
250  << "DMPSIN08 f5=" << ((m_f5 == 0) ? "nil" : m_f5) << std::endl
251  << "DMPSIN09 -----------------------------------------------"
252  << std::endl;
253  )
254 
255  return true;
256 }
257 
258 /// Insert \p name as field 1 and shift all other fields up.
259 void MPSInput::insertName(const char* name, bool second)
260 {
261  m_f5 = m_f4;
262  m_f4 = m_f3;
263  m_f3 = m_f2;
264 
265  if(second)
266  m_f2 = name;
267  else
268  {
269  m_f2 = m_f1;
270  m_f1 = name;
271  }
272 }
273 
274 } // namespace soplex
Section m_section
Definition: mpsinput.h:66
Read MPS format files.
const char * m_f0
first field in a line
Definition: mpsinput.h:78
const char * m_f5
sixth field in a line
Definition: mpsinput.h:88
bool m_is_new_format
new MPS format?
Definition: mpsinput.h:96
char m_buf[MAX_LINE_LEN]
the line buffer
Definition: mpsinput.h:76
#define BLANK
Definition: mpsinput.cpp:29
const char * m_f4
fifth field in a line
Definition: mpsinput.h:86
Wrapper for different output streams and verbosity levels.
bool readLine()
reads an MPS format data line and parse the fields.
Definition: mpsinput.cpp:58
#define MSG_DEBUG(x)
Definition: spxdefines.h:132
#define PATCH_CHAR
Definition: mpsinput.cpp:28
const char * m_f3
fourth field in a line
Definition: mpsinput.h:84
Debugging, floating point type and parameter definitions.
bool m_is_integer
Definition: mpsinput.h:94
Everything should be within this namespace.
std::istream & m_input
the input stream from which the file is read
Definition: mpsinput.h:68
const char * m_f2
third field in a line
Definition: mpsinput.h:82
int m_lineno
line number
Definition: mpsinput.h:70
static void patch_field(char *buf, int beg, int end)
change all blanks inside a field to PATCH_CHAR.
Definition: mpsinput.cpp:44
void insertName(const char *name, bool second=false)
Inserts name as field 1 and shifts all other fields up.
Definition: mpsinput.cpp:259
const char * m_f1
second field in a line
Definition: mpsinput.h:80
static void clear_from(char *buf, int pos)
fill the line from pos up to column 80 with blanks.
Definition: mpsinput.cpp:35