diff --git a/src/FileFormats/SDPA/SDPA.jl b/src/FileFormats/SDPA/SDPA.jl index 8c73e04fa8..2bf3c67456 100644 --- a/src/FileFormats/SDPA/SDPA.jl +++ b/src/FileFormats/SDPA/SDPA.jl @@ -302,18 +302,15 @@ function _dim_to_set(s::AbstractString) end end -function _parse_dimensions(dims::AbstractString) - isvalid(char) = isdigit(char) || char == '-' - is_delimiter(char) = isspace(char) || char == ',' - start = findfirst(isvalid, dims) - if start === nothing - return Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}[] - end - stop = findlast(isvalid, dims)::Int - s = split(dims[start:stop], is_delimiter) - return Union{MOI.PositiveSemidefiniteConeTriangle,MOI.Nonnegatives}[ - _dim_to_set(dim) for dim in filter!(!isempty, s) - ] +function _split(line) + # In some variations of SDPA, there is the comment: + # + # The special characters `,`, `(`, `)`, `{`, and `}` can be used as + # punctuation and are ignored. + # + # As one example, see https://github.com/vsdp/SDPLIB + line = replace(line, r"[,{}\(\)]"=>' ') + return split(line) end """ @@ -365,19 +362,20 @@ function Base.read!(io::IO, model::Model{T}) where {T<:Real} num_variables_read = true # According to http://plato.asu.edu/ftp/sdpa_format.txt, # additional text after the number of variables should be ignored. - scalar_vars = MOI.add_variables(model, parse(Int, split(line)[1])) + scalar_vars = + MOI.add_variables(model, parse(Int, first(_split(line)))) elseif num_blocks === nothing if isempty(line) continue end # According to http://plato.asu.edu/ftp/sdpa_format.txt, # additional text after the number of blocks should be ignored. - num_blocks = parse(Int, split(line)[1]) + num_blocks = parse(Int, first(_split(line))) elseif !block_sets_read if isempty(line) && !iszero(num_blocks) continue end - block_sets = _parse_dimensions(line) + block_sets = _dim_to_set.(_split(line)) block_sets_read = true if length(block_sets) != num_blocks error( @@ -399,7 +397,7 @@ function Base.read!(io::IO, model::Model{T}) where {T<:Real} continue end objective_read = true - c = parse.(T, split(line)) + c = parse.(T, _split(line)) if length(c) != num_vars error( "The number of variables ($num_vars) does not match the length of the list of coefficients for the objective function vector of coefficients ($(length(c))).", @@ -416,7 +414,7 @@ function Base.read!(io::IO, model::Model{T}) where {T<:Real} if isempty(line) continue end - values = split(line) + values = _split(line) if length(values) != 5 error( "Invalid line specifying entry: $line. There are $(length(values)) values instead of 5.", diff --git a/test/FileFormats/SDPA/SDPA.jl b/test/FileFormats/SDPA/SDPA.jl index 4e3dcd4c8f..bd0777f58e 100644 --- a/test/FileFormats/SDPA/SDPA.jl +++ b/test/FileFormats/SDPA/SDPA.jl @@ -323,26 +323,19 @@ function test_examples() end # See https://github.com/jump-dev/MathOptInterface.jl/issues/1541 -function _spacer(char) - return [" ", "$char", " $char", "$char ", " $char "] -end +_spacer(char) = [" ", "$char", " $char", "$char ", " $char "] function test_dim_reader() - for before in _spacer('{') - for sep in _spacer(',') - for after in _spacer('}') - line = string(before, "-4", sep, "2", after) - exp = [ - MOI.Nonnegatives(4), - MOI.PositiveSemidefiniteConeTriangle(2), - ] - @test MOI.FileFormats.SDPA._parse_dimensions(line) == exp - line = string(before, "2", sep, "-4", after) - @test MOI.FileFormats.SDPA._parse_dimensions(line) == - exp[2:-1:1] - end + fn(line) = SDPA._dim_to_set.(SDPA._split(line)) + for (a, b) in ['{' => '}', '(' => ')'] + for pre in _spacer(a), sep in _spacer(','), suf in _spacer(b) + @test fn("$(pre)-4$(sep)2$suf") == + [MOI.Nonnegatives(4), MOI.PositiveSemidefiniteConeTriangle(2)] + @test fn("$(pre)2$(sep)-4$suf") == + [MOI.PositiveSemidefiniteConeTriangle(2), MOI.Nonnegatives(4)] end end + return end function test_integer_before_variables() diff --git a/test/FileFormats/SDPA/models/issue_1541.dat-s b/test/FileFormats/SDPA/models/issue_1541.dat-s index 01fe412015..db61d88134 100644 --- a/test/FileFormats/SDPA/models/issue_1541.dat-s +++ b/test/FileFormats/SDPA/models/issue_1541.dat-s @@ -1,7 +1,7 @@ 3 =mdim 2 =nblocks {-4, 2} --0.0 -1 -2 +{-0.0,-1e+0, -2} 0 1 1 1 -1 1 1 1 1 -1 1 1 2 2 1