Skip to content

Commit f3b8a46

Browse files
authored
Merge pull request #109 from SCIP-Interfaces/rs/conshdlr
add support for constraint handlers
2 parents 670d761 + b575101 commit f3b8a46

File tree

14 files changed

+1105
-8
lines changed

14 files changed

+1105
-8
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# News
22

3+
## v0.9.1
4+
5+
- Add a Julia wrapper for constraint handlers. [109](https://github.com/SCIP-Interfaces/SCIP.jl/pull/109)
6+
37
## v0.9.0
48

59
- support MOI v0.9 [#126](https://github.com/SCIP-Interfaces/SCIP.jl/pull/126)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ The goal is to support [JuMP](https://github.com/JuliaOpt/JuMP.jl) (from version
2020
Currently, we support LP, MIP and QCP problems, as well as some nonlinear constraints, both through `MOI` sets
2121
(e.g., for second-order cones) as well as for expression graphs (see below).
2222

23-
We still have feature loss in the area of callbacks compared to previous versions.
23+
It is now possible to implement SCIP constraint handlers in Julia. Other plugin
24+
types are not yet supported.
2425

2526
## Getting Started
2627

src/MOI_wrapper.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ end
9191

9292
"Go back from solved stage to problem modification stage, invalidating results."
9393
function allow_modification(o::Optimizer)
94-
if SCIPgetStage(o) != SCIP_STAGE_PROBLEM
94+
if !(SCIPgetStage(o) in (SCIP_STAGE_PROBLEM, SCIP_STAGE_SOLVING))
9595
@SC SCIPfreeTransform(o)
9696
end
9797
return nothing
@@ -202,3 +202,4 @@ include(joinpath("MOI_wrapper", "indicator_constraints.jl"))
202202
include(joinpath("MOI_wrapper", "nonlinear_constraints.jl"))
203203
include(joinpath("MOI_wrapper", "objective.jl"))
204204
include(joinpath("MOI_wrapper", "results.jl"))
205+
include(joinpath("MOI_wrapper", "conshdlr.jl"))

src/MOI_wrapper/conshdlr.jl

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#
2+
# Adding constraint handlers and constraints to SCIP.Optimizer.
3+
#
4+
5+
"""
6+
include_conshdlr(
7+
o::Optimizer,
8+
ch::CH;
9+
name::String,
10+
description::String,
11+
enforce_priority::Int,
12+
check_priority::Int,
13+
eager_frequency::Int,
14+
needs_constraints::Bool
15+
)
16+
17+
Include a user defined constraint handler `ch` to SCIP optimizer instance `o`.
18+
19+
All parameters have default values that can be set as keyword arguments.
20+
In particular, note the boolean `needs_constraints`:
21+
* If set to `true`, then the callbacks are only called for the constraints that
22+
were added explicitly using `add_constraint`.
23+
* If set to `false`, the callback functions will always be called, even if no
24+
corresponding constraint was added. It probably makes sense to set
25+
`misc/allowdualreds` to `FALSE` in this case.
26+
"""
27+
function include_conshdlr(o::Optimizer, ch::CH;
28+
name="", description="", enforce_priority=-15,
29+
check_priority=-7000000, eager_frequency=100,
30+
needs_constraints=true) where CH <: AbstractConstraintHandler
31+
include_conshdlr(o.mscip, ch, name=name, description=description,
32+
enforce_priority=enforce_priority,
33+
check_priority=check_priority,
34+
eager_frequency=eager_frequency,
35+
needs_constraints=needs_constraints)
36+
end
37+
38+
"""
39+
add_constraint(
40+
o::Optimizer,
41+
ch::CH,
42+
c::C;
43+
initial=true,
44+
separate=true,
45+
enforce=true,
46+
check=true,
47+
propagate=true,
48+
_local=false,
49+
modifiable=false,
50+
dynamic=false,
51+
removable=false,
52+
stickingatnode=false
53+
)::ConsRef
54+
55+
56+
Add constraint `c` belonging to user-defined constraint handler `ch` to model.
57+
Returns constraint reference.
58+
59+
All keyword arguments are passed to the `SCIPcreateCons` call.
60+
"""
61+
function add_constraint(o::Optimizer, ch::CH, c::C;
62+
initial=true, separate=true, enforce=true, check=true,
63+
propagate=true, _local=false, modifiable=false,
64+
dynamic=false, removable=false, stickingatnode=false) where {CH <:AbstractConstraintHandler, C <: AbstractConstraint{CH}}
65+
return add_constraint(o.mscip, ch, c, initial=initial, separate=separate,
66+
enforce=enforce, check=check, propagate=propagate,
67+
_local=_local, modifiable=modifiable, dynamic=dynamic,
68+
removable=removable, stickingatnode=stickingatnode)
69+
end

src/MOI_wrapper/results.jl

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,25 @@ end
4141

4242
"Make sure that SCIP is currently in one of the allowed stages."
4343
function assert_stage(o::Optimizer, stages)
44-
if !(SCIPgetStage(o) in stages)
45-
error("SCIP is wrong stage, can not query results!")
44+
stage = SCIPgetStage(o)
45+
if !(stage in stages)
46+
error("SCIP is wrong stage ($stage, need $stages), can not query results!")
4647
end
4748
end
4849

4950
"Make sure that the problem was solved (SCIP is in SOLVED stage)."
50-
assert_solved(o::Optimizer) = assert_stage(o, [SCIP_STAGE_SOLVED])
51+
function assert_solved(o::Optimizer)
52+
# SCIP's stage is SOLVING when stopped by user limit!
53+
assert_stage(o, [SCIP_STAGE_SOLVING, SCIP_STAGE_SOLVED])
54+
55+
# Check for invalid status (when stage is SOLVING).
56+
status = SCIPgetStage(o)
57+
if status in (SCIP_STATUS_UNKNOWN,
58+
SCIP_STATUS_USERINTERRUPT,
59+
SCIP_STATUS_TERMINATE)
60+
error("SCIP's solving was interrupted, but not by a user-given limit!")
61+
end
62+
end
5163

5264
"Make sure that: TRANSFORMED ≤ stage ≤ SOLVED."
5365
assert_after_prob(o::Optimizer) = assert_stage(o, SCIP_Stage.(3:10))

src/MOI_wrapper/variable.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ MOI.get(o::Optimizer, ::MOI.NumberOfVariables) = length(o.mscip.vars)
1313
MOI.get(o::Optimizer, ::MOI.ListOfVariableIndices) = [VI(k.val) for k in keys(o.mscip.vars)]
1414
MOI.is_valid(o::Optimizer, vi::VI) = haskey(o.mscip.vars, VarRef(vi.value))
1515

16-
function MOI.get(o::Optimizer, ::MOI.VariableName, vi::VI)
17-
return GC.@preserve o SCIPvarGetName(var(o, vi))
16+
function MOI.get(o::Optimizer, ::MOI.VariableName, vi::VI)::String
17+
return GC.@preserve o unsafe_string(SCIPvarGetName(var(o, vi)))
1818
end
1919

2020
function MOI.set(o::Optimizer, ::MOI.VariableName, vi::VI, name::String)

src/SCIP.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@ include("managed_scip.jl")
1515
# constraints from nonlinear expressions
1616
include("nonlinear.jl")
1717

18+
# constraint handlers
19+
include("conshdlr.jl")
20+
1821
# implementation of MOI
1922
include("MOI_wrapper.jl")
2023

24+
# convenience functions
25+
include("convenience.jl")
26+
2127
# warn about rewrite
2228
include("compat.jl")
2329

0 commit comments

Comments
 (0)