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