Skip to content

Commit f06c0f5

Browse files
authored
Merge pull request #76 from SCIP-Interfaces/rs/clang
Rewrite SCIP wrapper with Clang.jl to support a MIP solver through MOI
2 parents d6397cf + 3b4f087 commit f06c0f5

File tree

149 files changed

+16814
-1758
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+16814
-1758
lines changed

.gitignore

-5
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,4 @@
33
*.jl.*.cov
44
*.jl.mem
55
deps/deps.jl
6-
deps/downloads/
7-
deps/src/
8-
deps/usr/
96
deps/build.log
10-
/test/test.lp
11-
/test/test.mps

.travis.yml

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
1-
# Documentation: http://docs.travis-ci.com/user/languages/julia/
1+
## Documentation: http://docs.travis-ci.com/user/languages/julia/
22
language: julia
3-
os:
4-
- linux
3+
os: linux
4+
dist: xenial
5+
sudo: true
56
julia:
6-
- 0.7
77
- 1.0
8-
dist: trusty
9-
sudo: required
10-
services:
11-
- docker
12-
before_install:
13-
- echo "**** pulling Docker image"
14-
- docker pull leethargo/scip-julia
8+
- nightly
159
notifications:
1610
email: false
11+
git:
12+
depth: 99999999
13+
matrix:
14+
allow_failures:
15+
- julia: nightly
16+
before_install:
17+
- sudo apt-get install libblas-dev liblapack-dev gfortran
18+
- export VERSION=6.0.0
19+
- wget http://scip.zib.de/download/release/SCIPOptSuite-$VERSION-Linux.deb
20+
- sudo dpkg -i SCIPOptSuite-$VERSION-Linux.deb
1721
script:
18-
- echo "**** running Docker"
19-
- docker run --env-file travis_docker_env.list -t -a STDOUT -a STDIN -a STDERR -v $PWD:/mnt leethargo/scip-julia /mnt/travis_docker_test_script.sh $TRAVIS_JULIA_VERSION
22+
- julia -e 'using Pkg; Pkg.clone(pwd()); Pkg.build("SCIP"); Pkg.test("SCIP"; coverage=true)'
2023
after_success:
21-
# push coverage results to Coveralls, .cov files were copied back by script above
22-
- echo "**** submitting coverage information"
23-
- julia -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(Codecov.process_folder())'
24+
# push coverage results to Coveralls
25+
- julia -e 'using Pkg; cd(Pkg.dir("SCIP")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
26+
# push coverage results to Codecov
27+
- julia -e 'using Pkg; cd(Pkg.dir("SCIP")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2016 Robert Schwarz
3+
Copyright (c) 2018 Felipe Serrano, Miles Lubin, Robert Schwarz
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+84-57
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,91 @@
11
# SCIP.jl
2+
23
Julia interface to [SCIP](http://scip.zib.de) solver.
34

45
[![Build Status](https://travis-ci.org/SCIP-Interfaces/SCIP.jl.svg?branch=master)](https://travis-ci.org/SCIP-Interfaces/SCIP.jl)
56
[![Coverage Status](https://coveralls.io/repos/github/SCIP-Interfaces/SCIP.jl/badge.svg?branch=master)](https://coveralls.io/github/SCIP-Interfaces/SCIP.jl?branch=master)
67
[![codecov](https://codecov.io/gh/SCIP-Interfaces/SCIP.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/SCIP-Interfaces/SCIP.jl)
78

8-
## Related Projects
9-
10-
- [SCIP](http://scip.zib.de): actual solver (implemented in C) that is wrapped
11-
for Julia.
12-
- [CSIP](https://github.com/SCIP-Interfaces/CSIP): restricted and simplified C
13-
interface to SCIP which our wrapper is based on.
14-
- [SCIP.jl](https://github.com/ryanjoneil/SCIP.jl): previous attempt to
15-
interface SCIP from Julia, using autogenerated wrapper code for all public
16-
functions.
17-
- [MathProgBase](https://github.com/JuliaOpt/MathProgBase.jl): We aim to
18-
implement MPB's abstract solver interfaces, so that one can use SCIP.jl
19-
through [JuMP](https://github.com/JuliaOpt/JuMP.jl). For now, the
20-
`LinearQuadraticModel` interface is implemented, supporting lazy constraint
21-
and heuristic callbacks.
22-
23-
## Installation
24-
25-
**Note**: These instructions are meant for and only tested with GNU/Linux. OS X used to work,
26-
but there is an issue (#46) since the update to SCIP 4.0.0.
27-
28-
Follow the steps below to get SCIP.jl working. Unfortunately, these steps can not be automated as part of `Pkg.build("SCIP")`, because the academic license of SCIP does not allow distribution of the source code without tracking the download metadata. See the [license](http://scip.zib.de/academic.txt) for details.
29-
30-
1.The SCIP.jl package requires [SCIP](http://scip.zib.de/) to be installed in a recent version (e.g. 6.0.0).
31-
[Download](http://scip.zib.de) the SCIP Optimization Suite.
32-
```
33-
tar xzf scipoptsuite-6.0.0.tgz
34-
```
35-
36-
2.Choose an installation path and set the **environment variable `SCIPOPTDIR`** to point there.
37-
```
38-
export SCIPOPTDIR=`my/install/dir`
39-
```
40-
41-
3.Build and install the shared library with
42-
```
43-
mkdir build
44-
cd build
45-
cmake -DCMAKE_INSTALL_PREFIX=$SCIPOPTDIR ..
46-
make
47-
make install
48-
```
49-
50-
4.This package is registered in `METADATA.jl` and can be installed in Julia with
51-
```
52-
Pkg.add("SCIP")
53-
```
54-
55-
## Setting Parameters
56-
57-
SCIP has a [long list of parameters](http://scip.zib.de/doc/html/PARAMETERS.php)
58-
that can all be set through SCIP.jl, by passing them to the constructor of
59-
`SCIPSolver`. To set a value `val` to a parameter `name`, pass the two
60-
parameters `(name, val)`. For example, let's set two parameters, to disable
61-
output and increase the gap limit to 0.05:
62-
```
63-
solver = SCIPSolver("display/verblevel", 0, "limits/gap", 0.05)
64-
```
9+
## Update (December 2018)
10+
11+
We have completely rewritten the interface from scratch, using
12+
[Clang.jl](https://github.com/ihnorton/Clang.jl) to generate wrappers based on
13+
the headers of the SCIP library.
14+
The goal is to support [JuMP](https://github.com/JuliaOpt/JuMP.jl) (from version
15+
0.19 on) through
16+
[MathOptInterface](https://github.com/JuliaOpt/MathOptInterface.jl).
17+
18+
Currently, we support LP and MIP problems only.
19+
This means we still have a feature loss in the areas as nonlinear constraints as
20+
well as supported callbacks compared to previous versions (see below).
21+
22+
## Getting Started
23+
24+
To use SCIP.jl, you will need [SCIP](http://scip.zib.de) installed on your
25+
system. [SCIP's license](https://scip.zib.de/index.php#license) does not allow
26+
(automatic) redistribution, so please
27+
[download](https://scip.zib.de/index.php#download) and install it yourself.
28+
29+
Only Linux is tested and officially supported. Contributions to supporting other
30+
operating systems are welcome.
31+
32+
We recommend using one of the provided installers, e.g.,
33+
`SCIPOptSuite-6.0.0-Linux.deb` for systems based on Debian. Adding the SCIP.jl
34+
package should then work out of the box:
35+
36+
pkg> add SCIP
37+
38+
If you [build SCIP from source](https://scip.zib.de/doc-6.0.0/html/CMAKE.php)
39+
you should set the environment variable `SCIPOPTDIR` to point the the
40+
**installation path**. That is, `$SCIPOPTDIR/lib/libscip.so` should exist.
41+
42+
## Design Considerations
43+
44+
**Wrapper of Public API**: All of SCIP's public API methods are wrapped and
45+
available within the `SCIP` package. This includes the `scip_*.h` and `pub_*.h`
46+
headers that are collected in `scip.h`, as well as all default constraint
47+
handlers (`cons_*.h`.) But the wrapped functions do not transform any data
48+
structures and work on the *raw* pointers (e.g. `SCIP*` in C, `Ptr{SCIP_}` in
49+
Julia). Convenience wrapper functions based on Julia types are added as needed.
50+
51+
**Memory Management**: Programming with SCIP requires dealing with variable and
52+
constraints objects that use [reference
53+
counting](https://scip.zib.de/doc-6.0.0/html/OBJ.php) for memory management.
54+
SCIP.jl provides a wrapper type `ManagedSCIP` that collects lists of `SCIP_VAR*`
55+
and `SCIP_CONS*` under the hood, and releases all reference when it is garbage
56+
collected itself (via `finalize`). When adding a variable (`add_variable`) or a
57+
constraint (`add_linear_constraint`), an integer index is returned. This index
58+
can be used to retrieve the `SCIP_VAR*` or `SCIP_CONS*` pointer via `get_var`
59+
and `get_cons` respectively.
60+
61+
`ManagedSCIP` does not currently support deletion of variables or constraints.
62+
63+
**Supported Features for MathOptInterface**: We aim at exposing many of SCIP's
64+
features through MathOptInterface. However, the focus is on keeping the wrapper
65+
simple and avoiding duplicate storage of model data.
66+
67+
As a consequence, we do not currently support some features such as retrieving
68+
constraints by name (`SingleVariable`-set constraints are not stored as SCIP
69+
constraints explicitly).
70+
71+
Support for more constraint types (quadratic/SOC, SOS1/2, nonlinear expression)
72+
is planned, but SCIP itself only supports affine objective functions, so we will
73+
stick with that. More general objective functions could be implented via a
74+
[bridge](https://github.com/JuliaOpt/MathOptInterface.jl/issues/529).
75+
76+
## Old Interface Implementation
77+
78+
A previous implementation of SCIP.jl supported
79+
[JuMP](https://github.com/JuliaOpt/JuMP.jl) (up to version 0.18) through
80+
[MathProgBase](https://github.com/JuliaOpt/MathOptInterface.jl). It did not
81+
interface SCIP directly, but went through
82+
[CSIP](https://github.com/SCIP-Interfaces/CSIP), a simplified C wrapper.
83+
84+
Back then, the interface support MINLP problems as well as solver-indepentent
85+
callbacks for lazy constraints and heuristics.
86+
87+
To use that version, you need to pin the version of SCIP.jl to `v0.6.1` (the
88+
last release before the rewrite):
89+
90+
91+
pkg> pin SCIP

REQUIRE

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
julia 0.7
2-
BinDeps
3-
MathProgBase 0.5 0.8
1+
julia 1.0
2+
MathOptInterface 0.8

benchmark/sparse_linprog.jl

-42
This file was deleted.

deps/build.jl

+33-46
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,41 @@
1-
using BinDeps
2-
31
using Libdl
42

5-
include("csip_version.jl")
6-
7-
CSIP_URL = "https://github.com/SCIP-Interfaces/CSIP/archive/v$(CSIP_VERSION).zip"
8-
CSIP_LIB = "libcsip"
9-
CSIP_UNPACKED = "CSIP-$(CSIP_VERSION)"
10-
11-
@BinDeps.setup
12-
13-
@assert haskey(ENV, "SCIPOPTDIR") "Environment variable `SCIPOPTDIR` not set!"
14-
15-
function validate_csip(name, handle)
16-
csip_version = ccall(Libdl.dlsym(handle, :CSIPgetVersion), Cint, ())
17-
csip_version == csip_required_int
3+
depsfile = joinpath(dirname(@__FILE__), "deps.jl")
4+
if isfile(depsfile)
5+
rm(depsfile)
186
end
197

20-
csipdep = library_dependency(CSIP_LIB, validate=validate_csip)
21-
22-
provides(Sources, Dict(URI(CSIP_URL) => csipdep),
23-
unpacked_dir=CSIP_UNPACKED)
24-
25-
src_dir = joinpath(BinDeps.srcdir(csipdep), CSIP_UNPACKED)
26-
scipopt_dir = ENV["SCIPOPTDIR"]
27-
28-
provides(SimpleBuild,
29-
(@build_steps begin
30-
GetSources(csipdep)
31-
@build_steps begin
32-
ChangeDirectory(joinpath(BinDeps.srcdir(csipdep), CSIP_UNPACKED))
33-
`make`
34-
`gcc -std=c99 -Wall -pedantic -I$(src_dir)/lib/include -I$(src_dir)/include -c $(src_dir)/src/csip.c -L$(src_dir)/lib -Wl,-rpath,$(scipopt_dir)/lib/ $(scipopt_dir)/lib/libscipopt.dylib -fPIC -o $(src_dir)/src/csip.o`
35-
` gcc -std=c99 -Wall -pedantic $(src_dir)/src/csip.o -L$(src_dir)/lib -Wl,-rpath,$(scipopt_dir)/lib/ $(scipopt_dir)/lib/libscipopt.dylib -fPIC -shared -dynamiclib -o $(src_dir)/lib/libcsip.dylib`
36-
`mkdir -p $(libdir(csipdep))`
37-
`install lib/libcsip.dylib $(libdir(csipdep))`
38-
end
39-
end), csipdep, os = :Darwin)
8+
function write_depsfile(path)
9+
f = open(depsfile, "w")
10+
println(f, "const libscip = \"$path\"")
11+
close(f)
12+
end
4013

14+
libname = "libscip.so"
15+
paths_to_try = []
4116

42-
provides(SimpleBuild,
43-
(@build_steps begin
44-
GetSources(csipdep)
45-
@build_steps begin
46-
ChangeDirectory(joinpath(BinDeps.srcdir(csipdep), CSIP_UNPACKED))
47-
`make`
48-
`mkdir -p $(libdir(csipdep))`
49-
`install lib/libcsip.so $(libdir(csipdep))`
50-
end
51-
end), csipdep, os = :Unix)
17+
# prefer environment variable
18+
if haskey(ENV, "SCIPOPTDIR")
19+
if Sys.islinux()
20+
push!(paths_to_try, joinpath(ENV["SCIPOPTDIR"], "lib", libname))
21+
end
22+
end
5223

24+
# but also try library path
25+
push!(paths_to_try, libname)
26+
27+
found = false
28+
for l in paths_to_try
29+
d = Libdl.dlopen_e(l)
30+
if d != C_NULL
31+
global found = true
32+
write_depsfile(l)
33+
break
34+
end
35+
end
5336

54-
@BinDeps.install Dict(:libcsip => :libcsip)
37+
if !found && !haskey(ENV, "SCIP_JL_SKIP_LIB_CHECK")
38+
error("Unable to locate SCIP installation. " *
39+
"Note that this must be downloaded separately from scip.zib.de. " *
40+
"Please set the environment variable SCIPOPTDIR to SCIP's installation path.")
41+
end

deps/csip_version.jl

-9
This file was deleted.

gen/generate_wrapper.jl

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Clang
2+
3+
HEADER_BASE = "/usr/include" # using system-wide installation of SCIP
4+
all_headers = readdir(joinpath(HEADER_BASE, "scip"))
5+
scip_headers = vcat(
6+
filter(h -> startswith(h, "type_"), all_headers),
7+
filter(h -> startswith(h, "pub_"), all_headers),
8+
filter(h -> startswith(h, "scip_"), all_headers),
9+
"scipdefplugins.h",
10+
filter(h -> startswith(h, "cons_"), all_headers),
11+
)
12+
lpi_headers = ["type_lpi.h"]
13+
nlpi_headers = ["type_expr.h", "type_nlpi.h"]
14+
15+
headers = vcat(
16+
[joinpath(HEADER_BASE, "scip", h) for h in scip_headers],
17+
[joinpath(HEADER_BASE, "lpi", h) for h in lpi_headers],
18+
[joinpath(HEADER_BASE, "nlpi", h) for h in nlpi_headers],
19+
)
20+
21+
context = Clang.init(
22+
headers=headers,
23+
common_file="commons.jl",
24+
output_dir="../src/wrapper",
25+
clang_includes=vcat(HEADER_BASE, LLVM_INCLUDE),
26+
clang_args = ["-I", HEADER_BASE],
27+
clang_diagnostics=true,
28+
header_wrapped=(header, cursorname) -> header == cursorname,
29+
header_library=header_name -> "libscip"
30+
)
31+
Clang.run(context)

0 commit comments

Comments
 (0)