SoPlex
Toggle main menu visibility
Loading...
Searching...
No Matches
src
soplex
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-2026 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.
67
bool
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
=
nullptr
;
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
!=
nullptr
);
123
124
m_f1
= strtok(
nullptr
,
" "
);
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
[3]
141
|
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
)
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
((
m_section
!=
ROWS
&& number) || (
m_section
==
ROWS
&& 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
m_is_new_format
=
true
;
174
}
175
}
176
else
177
{
178
m_is_new_format
=
true
;
179
}
180
}
181
182
s = &
m_buf
[1];
183
184
/* At this point it is not clear if we have a indicator field.
185
* If there is none (e.g. empty) f1 will be the first name field.
186
* If there is one, f2 will be the first name field.
187
*
188
* Initially comment marks '$' ar only allowed in the beginning
189
* of the 2nd and 3rd name field. We test all fields but the first.
190
* This makes no difference, since if the $ is at the start of a value
191
* field, the line will be errornous anyway.
192
*/
193
do
194
{
195
if
(
nullptr
== (
m_f1
= strtok(s,
" "
)))
196
break
;
197
198
if
((
nullptr
== (
m_f2
= strtok(
nullptr
,
" "
))) || (*
m_f2
==
'$'
))
199
{
200
m_f2
=
nullptr
;
201
break
;
202
}
203
204
if
(!strcmp(
m_f2
,
"'MARKER'"
))
205
is_marker =
true
;
206
207
if
((
nullptr
== (
m_f3
= strtok(
nullptr
,
" "
))) || (*
m_f3
==
'$'
))
208
{
209
m_f3
=
nullptr
;
210
break
;
211
}
212
213
if
(is_marker)
214
{
215
if
(!strcmp(
m_f3
,
"'INTORG'"
))
216
m_is_integer
=
true
;
217
else
if
(!strcmp(
m_f3
,
"'INTEND'"
))
218
m_is_integer
=
false
;
219
else
220
break
;
// unknown marker
221
}
222
223
if
(!strcmp(
m_f3
,
"'MARKER'"
))
224
is_marker =
true
;
225
226
if
((
nullptr
== (
m_f4
= strtok(
nullptr
,
" "
))) || (*
m_f4
==
'$'
))
227
{
228
m_f4
=
nullptr
;
229
break
;
230
}
231
232
if
(is_marker)
233
{
234
if
(!strcmp(
m_f4
,
"'INTORG'"
))
235
m_is_integer
=
true
;
236
else
if
(!strcmp(
m_f4
,
"'INTEND'"
))
237
m_is_integer
=
false
;
238
else
239
break
;
// unknown marker
240
}
241
242
if
((
nullptr
== (
m_f5
= strtok(
nullptr
,
" "
))) || (*
m_f5
==
'$'
))
243
m_f5
=
nullptr
;
244
}
245
while
(
false
);
246
}
247
while
(is_marker);
248
249
SPxOut::debug
(
this
,
"DMPSIN02 -----------------------------------------------\n"
250
"DMPSIN03 f0={}\n"
251
"DMPSIN04 f1={}\n"
252
"DMPSIN05 f2={}\n"
253
"DMPSIN07 f4={}\n"
254
"DMPSIN06 f3={}\n"
255
"DMPSIN08 f5={}\n"
256
"DMPSIN09 -----------------------------------------------\n"
,
257
((
m_f0
==
nullptr
) ?
"nil"
:
m_f0
),
258
((
m_f1
==
nullptr
) ?
"nil"
:
m_f1
),
259
((
m_f2
==
nullptr
) ?
"nil"
:
m_f2
),
260
((
m_f3
==
nullptr
) ?
"nil"
:
m_f3
),
261
((
m_f4
==
nullptr
) ?
"nil"
:
m_f4
),
262
((
m_f5
==
nullptr
) ?
"nil"
:
m_f5
));
263
return
true
;
264
}
265
266
/// Insert \p name as field 1 and shift all other fields up.
267
void
MPSInput::insertName
(
const
char
* name,
bool
second)
268
{
269
m_f5
=
m_f4
;
270
m_f4
=
m_f3
;
271
m_f3
=
m_f2
;
272
273
if
(second)
274
m_f2
= name;
275
else
276
{
277
m_f2
=
m_f1
;
278
m_f1
= name;
279
}
280
}
281
282
}
// namespace soplex
soplex::MPSInput::m_buf
char m_buf[MAX_LINE_LEN]
the line buffer
Definition
mpsinput.h:85
soplex::MPSInput::m_f5
const char * m_f5
sixth field in a line
Definition
mpsinput.h:97
soplex::MPSInput::m_f1
const char * m_f1
second field in a line
Definition
mpsinput.h:89
soplex::MPSInput::m_section
Section m_section
Definition
mpsinput.h:75
soplex::MPSInput::m_input
std::istream & m_input
the input stream from which the file is read
Definition
mpsinput.h:77
soplex::MPSInput::m_is_new_format
bool m_is_new_format
new MPS format?
Definition
mpsinput.h:105
soplex::MPSInput::m_lineno
int m_lineno
line number
Definition
mpsinput.h:79
soplex::MPSInput::m_is_integer
bool m_is_integer
Definition
mpsinput.h:103
soplex::MPSInput::m_f0
const char * m_f0
first field in a line
Definition
mpsinput.h:87
soplex::MPSInput::insertName
void insertName(const char *name, bool second=false)
Inserts name as field 1 and shifts all other fields up.
Definition
mpsinput.cpp:267
soplex::MPSInput::readLine
bool readLine()
reads an MPS format data line and parse the fields.
Definition
mpsinput.cpp:67
soplex::MPSInput::ROWS
@ ROWS
Definition
mpsinput.h:54
soplex::MPSInput::m_f2
const char * m_f2
third field in a line
Definition
mpsinput.h:91
soplex::MPSInput::m_f3
const char * m_f3
fourth field in a line
Definition
mpsinput.h:93
soplex::MPSInput::m_f4
const char * m_f4
fifth field in a line
Definition
mpsinput.h:95
soplex::SPxOut::debug
static void debug(const T *, Args &&... args)
Definition
spxout.h:203
BLANK
#define BLANK
Definition
mpsinput.cpp:38
PATCH_CHAR
#define PATCH_CHAR
Definition
mpsinput.cpp:37
mpsinput.h
Read MPS format files.
soplex
Everything should be within this namespace.
soplex::patch_field
static void patch_field(char *buf, int beg, int end)
change all blanks inside a field to PATCH_CHAR.
Definition
mpsinput.cpp:53
soplex::clear_from
static void clear_from(char *buf, int pos)
fill the line from pos up to column 80 with blanks.
Definition
mpsinput.cpp:44
spxdefines.h
Debugging, floating point type and parameter definitions.
spxout.h
Wrapper for different output streams and verbosity levels.
Generated by
1.17.0