Skip to content

Commit f0a2875

Browse files
blegatodow
andauthored
[FileFormats] robust reading of dimensions in SDPA file (#1789)
Co-authored-by: odow <[email protected]>
1 parent 70e34b5 commit f0a2875

File tree

3 files changed

+73
-9
lines changed

3 files changed

+73
-9
lines changed

src/FileFormats/SDPA/SDPA.jl

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,31 @@ function mat_to_vec_idx(i::Int, j::Int)
235235
end
236236
end
237237

238+
function _dim_to_set(s::AbstractString)
239+
block_dim = parse(Int, s)
240+
if block_dim > 0
241+
return MOI.PositiveSemidefiniteConeTriangle(block_dim)
242+
else
243+
return MOI.Nonnegatives(-block_dim)
244+
end
245+
end
246+
function _parse_dimensions(dims)
247+
isvalid(char) = isdigit(char) || char == '-'
248+
start = findfirst(isvalid, dims)
249+
stop = findlast(isvalid, dims)
250+
if isnothing(start)
251+
return Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}[]
252+
end
253+
function is_delimiter(char)
254+
return isspace(char) || char == ','
255+
end
256+
s = split(dims[start:stop], is_delimiter)
257+
s = filter(!isempty, s)
258+
return Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}[
259+
_dim_to_set(dim) for dim in s
260+
]
261+
end
262+
238263
"""
239264
Base.read!(io::IO, model::FileFormats.SDPA.Model)
240265
@@ -247,14 +272,6 @@ function Base.read!(io::IO, model::Model{T}) where {T}
247272
num_variables_read = false
248273
num_blocks = nothing
249274
block_sets = nothing
250-
function dim_to_set(s::AbstractString)
251-
block_dim = parse(Int, s)
252-
if block_dim > 0
253-
return MOI.PositiveSemidefiniteConeTriangle(block_dim)
254-
else
255-
return MOI.Nonnegatives(-block_dim)
256-
end
257-
end
258275
objective_read = false
259276
integer_read = false
260277
scalar_vars = nothing
@@ -303,7 +320,7 @@ function Base.read!(io::IO, model::Model{T}) where {T}
303320
if isempty(line) && !iszero(num_blocks)
304321
continue
305322
end
306-
block_sets = dim_to_set.(split(line))
323+
block_sets = _parse_dimensions(line)
307324
if length(block_sets) != num_blocks
308325
error(
309326
"The number of blocks ($num_blocks) does not match the length of the list of blocks dimensions ($(length(block_sets))).",

test/FileFormats/SDPA/SDPA.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,15 @@ const _EXAMPLE_MODELS = [
283283
x in Integer()
284284
y in Integer()
285285
z in Integer()
286+
""",
287+
),
288+
(
289+
"issue_1541.dat-s",
290+
"""
291+
variables: x, y, z
292+
minobjective: -1y + -2z
293+
c1: [-1x + -1y + -1z + 1, 1x, 1y, 1z] in Nonnegatives(4)
294+
c2: [1x + 3y, 4y + 2z, -1z] in PositiveSemidefiniteConeTriangle(2)
286295
""",
287296
),
288297
]
@@ -294,6 +303,28 @@ function test_examples()
294303
end
295304
end
296305

306+
# See https://github.com/jump-dev/MathOptInterface.jl/issues/1541
307+
function _spacer(char)
308+
return [" ", "$char", " $char", "$char ", " $char "]
309+
end
310+
function test_dim_reader()
311+
for before in _spacer('{')
312+
for sep in _spacer(',')
313+
for after in _spacer('}')
314+
line = string(before, "-4", sep, "2", after)
315+
exp = [
316+
MOI.Nonnegatives(4),
317+
MOI.PositiveSemidefiniteConeTriangle(2),
318+
]
319+
@test MOI.FileFormats.SDPA._parse_dimensions(line) == exp
320+
line = string(before, "2", sep, "-4", after)
321+
@test MOI.FileFormats.SDPA._parse_dimensions(line) ==
322+
exp[2:-1:1]
323+
end
324+
end
325+
end
326+
end
327+
297328
function runtests()
298329
for name in names(@__MODULE__, all = true)
299330
if startswith("$(name)", "test_")
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
3 =mdim
2+
2 =nblocks
3+
{-4, 2}
4+
-0.0 -1 -2
5+
0 1 1 1 -1
6+
1 1 1 1 -1
7+
1 1 2 2 1
8+
2 1 1 1 -1
9+
2 1 3 3 1
10+
3 1 1 1 -1
11+
3 1 4 4 1
12+
1 2 1 1 1.0
13+
2 2 1 1 3.0
14+
2 2 1 2 4.0
15+
3 2 1 2 2.0
16+
3 2 2 2 -1.0

0 commit comments

Comments
 (0)