Skip to content

Commit c397316

Browse files
committed
Initial commit
1 parent 1d0aa41 commit c397316

File tree

13 files changed

+345
-1
lines changed

13 files changed

+345
-1
lines changed

.github/dependabot.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2+
version: 2
3+
enable-beta-ecosystems: true # Julia ecosystem
4+
updates:
5+
- package-ecosystem: "github-actions"
6+
directory: "/" # Location of package manifests
7+
schedule:
8+
interval: "weekly"
9+
- package-ecosystem: "julia"
10+
directories: # Location of Julia projects
11+
- "/"
12+
- "/docs"
13+
- "/test"
14+
schedule:
15+
interval: "weekly"
16+
groups:
17+
# Group all Julia package updates into a single PR:
18+
all-julia-packages:
19+
patterns:
20+
- "*"

.github/workflows/format.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Runic formatting
2+
on:
3+
push:
4+
branches:
5+
- 'master'
6+
- 'release-'
7+
tags:
8+
- '*'
9+
pull_request:
10+
jobs:
11+
runic:
12+
name: Runic
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
# - uses: julia-actions/setup-julia@v2
17+
# with:
18+
# version: '1'
19+
# - uses: julia-actions/cache@v2
20+
- uses: fredrikekre/runic-action@v1
21+
with:
22+
version: '1'

.github/workflows/test.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Run tests
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
- main
8+
pull_request:
9+
10+
# needed to allow julia-actions/cache to delete old caches that it has created
11+
permissions:
12+
actions: write
13+
contents: read
14+
15+
jobs:
16+
test:
17+
runs-on: ubuntu-latest
18+
strategy:
19+
matrix:
20+
julia-version: ['lts', '1']
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
- uses: julia-actions/setup-julia@v2
25+
with:
26+
version: ${{ matrix.julia-version }}
27+
- uses: julia-actions/cache@v2
28+
- uses: julia-actions/julia-buildpkg@v1
29+
- uses: julia-actions/julia-runtest@v1

Project.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name = "MathProgBenchmarks"
2+
uuid = "f7f8d0a1-fd34-491e-a7ac-a4cf52f91fe5"
3+
version = "0.1.0"
4+
authors = ["Guillaume Dalle"]
5+
6+
[workspace]
7+
projects = ["test"]
8+
9+
[deps]
10+
DataDeps = "124859b0-ceae-595e-8997-d05f6a7a8dfe"
11+
GZip = "92fee26a-97fe-5a0c-ad85-20a5f3185b63"
12+
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
13+
QPSReader = "10f199a5-22af-520b-b891-7ce84a7b1bd0"
14+
15+
[compat]
16+
DataDeps = "0.7.13"
17+
GZip = "0.6.2"
18+
Logging = "1.11.0"
19+
QPSReader = "0.2.1"
20+
julia = "1.10"

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,20 @@
11
# MathProgBenchmarks.jl
2-
Automatic download and parsing of linear, quadratic and integer programming instances
2+
3+
A Julia package for automatic download and parsing of linear, quadratic and integer programming instances.
4+
5+
## Details
6+
7+
Supported datasets:
8+
9+
- [x] [Netlib](https://www.netlib.org/lp/data/index.html)
10+
- [x] [MIPLIB 2017](https://miplib.zib.de/index.html)
11+
- [ ] [Mittelman benchmark](https://plato.asu.edu/ftp/lptestset/)
12+
13+
The source files are downloaded automatically thanks to [DataDeps.jl](https://github.com/oxinabox/DataDeps.jl).
14+
The returned problem format is `QPSData` from [QPSReader.jl](https://github.com/JuliaSmoothOptimizers/QPSReader.jl).
15+
16+
## Getting started
17+
18+
To see which instances are available, call `list_instance(dataset, name)`.
19+
20+
To read a specific instance, call `read_instance(dataset, name)`.

src/MathProgBenchmarks.jl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
module MathProgBenchmarks
2+
3+
using DataDeps
4+
using GZip
5+
using Logging
6+
using QPSReader
7+
8+
include("datasets.jl")
9+
include("instances.jl")
10+
include("lists.jl")
11+
12+
export Dataset, MIPLIB2017, MIPLIB2017Benchmark, Netlib
13+
export read_instance
14+
export list_instances
15+
16+
function __init__()
17+
register(
18+
DataDep(
19+
"miplib2017-collection",
20+
"""
21+
All instances in the MIPLIB 2017 collection set (size: 3.5 GB).
22+
Source: https://miplib.zib.de/index.html.""",
23+
"https://miplib.zib.de/downloads/collection.zip",
24+
post_fetch_method = unpack,
25+
),
26+
)
27+
register(
28+
DataDep(
29+
"miplib2017-benchmark",
30+
"""
31+
All instances in the MIPLIB 2017 benchmark set (size: 317 MB).
32+
Source: https://miplib.zib.de/index.html.""",
33+
"https://miplib.zib.de/downloads/benchmark.zip",
34+
post_fetch_method = unpack,
35+
"c756eefd544d83b31809306b45d3549a1a5b9378e6aa78b68738b1a3b6a418fa"
36+
),
37+
)
38+
register(
39+
DataDep(
40+
"miplib2017-collection-list",
41+
"""
42+
List of instances in the MIPLIB 2017 collection.
43+
Source: https://miplib.zib.de/index.html.""",
44+
"https://miplib.zib.de/downloads/collection-v1.test",
45+
"c416f857083e2b7ec6edad87acc80437e2ea4be65debdbe7c4f3072881981c3f"
46+
),
47+
)
48+
register(
49+
DataDep(
50+
"miplib2017-benchmark-list",
51+
"""
52+
List of instances in the MIPLIB 2017 benchmark.
53+
Source: https://miplib.zib.de/index.html.""",
54+
"https://miplib.zib.de/downloads/benchmark-v2.test",
55+
"0ee9758dba64bb1689cc121c794ee547992a046bcabe1cce9ea79158375dabd5"
56+
),
57+
)
58+
return nothing
59+
end
60+
61+
end # module MathProgBenchmarks

src/datasets.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Dataset
3+
4+
Enum type for mathematical programming datasets.
5+
6+
Possible values:
7+
8+
- [`MIPLIB2017`](@ref), [`MIPLIB2017Benchmark`](@ref)
9+
- [`Netlib`](@ref)
10+
"""
11+
@enum Dataset MIPLIB2017 MIPLIB2017Benchmark Netlib
12+
13+
"""
14+
MIPLIB2017
15+
16+
Mixed Integer Linear Programs from the MIPLIB2017 collection dataset.
17+
18+
Source: <https://miplib.zib.de/>.
19+
"""
20+
MIPLIB2017
21+
22+
"""
23+
MIPLIB2017Benchmark
24+
25+
Mixed Integer Linear Programs from the MIPLIB2017 benchmark dataset (much smaller than the collection dataset).
26+
27+
Source: <https://miplib.zib.de/>.
28+
"""
29+
MIPLIB2017Benchmark
30+
31+
"""
32+
Netlib
33+
34+
Linear Programs from the Netlib dataset.
35+
36+
Source: <https://www.netlib.org/lp/data/index.html>.
37+
"""
38+
Netlib

src/instances.jl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""
2+
read_instance(dataset::Dataset, name::String)
3+
4+
Read the instance identified by `name` from a given `dataset` and return a `QPSReader.QPSData` object.
5+
6+
# See also
7+
8+
- [`Dataset`](@ref)
9+
"""
10+
function read_instance(dataset::Dataset, name::String)
11+
if dataset == MIPLIB2017 || dataset == MIPLIB2017Benchmark
12+
return read_miplib2017_instance(dataset, name)
13+
elseif dataset == Netlib
14+
return read_netlib_instance(name)
15+
end
16+
end
17+
18+
function read_miplib2017_instance(dataset::Dataset, name::String)
19+
folder = if dataset == MIPLIB2017Benchmark
20+
datadep"miplib2017-benchmark"
21+
else
22+
datadep"miplib2017-collection"
23+
end
24+
name = lowercase(name)
25+
mps_gz_path = joinpath(folder, "$name.mps.gz")
26+
return read_mps(mps_gz_path)
27+
end
28+
29+
function read_netlib_instance(name::String)
30+
name = uppercase(name)
31+
if name in ("BLEND", "DFL001", "FORPLAN", "GFRD-PNC", "SIERRA")
32+
# https://github.com/JuliaSmoothOptimizers/QPSReader.jl/issues/58
33+
mpsformat = :fixed
34+
else
35+
mpsformat = :free
36+
end
37+
netlib_path = fetch_netlib()
38+
sif_path = joinpath(netlib_path, "$name.SIF")
39+
return read_mps(sif_path; mpsformat)
40+
end
41+
42+
function read_mps(path::String; mpsformat::Symbol = :free)
43+
if endswith(path, ".mps.gz")
44+
contents = GZip.open(path, "r") do f
45+
read(f, String)
46+
end
47+
mps_path = string(tempname(), ".mps")
48+
open(mps_path, "w") do f
49+
write(f, contents)
50+
end
51+
else
52+
@assert endswith(path, ".mps") || endswith(path, ".SIF")
53+
mps_path = path
54+
end
55+
56+
qps_data = with_logger(NullLogger()) do
57+
readqps(mps_path; mpsformat)
58+
end
59+
return qps_data
60+
end

src/lists.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
list_instances(dataset::Dataset)
3+
4+
Return the names of all available instances in a given `dataset`.
5+
6+
# See also
7+
8+
- [`Dataset`](@ref)
9+
"""
10+
function list_instances(dataset::Dataset)
11+
if dataset == MIPLIB2017 || dataset == MIPLIB2017Benchmark
12+
return list_miplib2017_instances(dataset)
13+
elseif dataset == Netlib
14+
return list_netlib_instances()
15+
end
16+
end
17+
18+
function list_miplib2017_instances(dataset::Dataset)
19+
list_path = if dataset == MIPLIB2017Benchmark
20+
joinpath(datadep"miplib2017-benchmark-list", "benchmark-v2.test")
21+
else
22+
joinpath(datadep"miplib2017-collection-list", "collection-v1.test")
23+
end
24+
lines = open(list_path, "r") do file
25+
readlines(file)
26+
end
27+
return map(n -> string(chopsuffix(n, ".mps.gz")), lines)
28+
end
29+
30+
function list_netlib_instances()
31+
netlib_path = fetch_netlib()
32+
valid_instances = filter(n -> endswith(n, ".SIF"), readdir(netlib_path))
33+
return map(n -> lowercase(chopsuffix(n, ".SIF")), valid_instances)
34+
end

test/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[deps]
2+
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
3+
MathProgBenchmarks = "f7f8d0a1-fd34-491e-a7ac-a4cf52f91fe5"
4+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

0 commit comments

Comments
 (0)