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