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