Skip to content

Commit 53c4f6e

Browse files
authored
Merge pull request #301 from gtjusila/eventhandlerupdate
Added Coverage For EventHandlerCallback
2 parents 5b81774 + fe3fb10 commit 53c4f6e

File tree

2 files changed

+80
-13
lines changed

2 files changed

+80
-13
lines changed

src/event_handler.jl

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ function eventexec(event::T) where {T<:AbstractEventhdlr}
1919
error("eventexec not implemented for type $(T)")
2020
end
2121

22+
"""
23+
Default eventinit function.
24+
"""
25+
function eventinit(event::AbstractEventhdlr) end
26+
27+
"""
28+
Default eventexit function.
29+
"""
30+
function eventexit(event::AbstractEventhdlr) end
2231
"""
2332
This is the function that will be converted to a C function. It signature
2433
matches the one given in the SCIP documentation for SCIP_DECL_EVENTEXEC.
@@ -30,17 +39,46 @@ function _eventexec(
3039
eventhdlr::Ptr{SCIP_Eventhdlr},
3140
event::Ptr{SCIP_Event},
3241
eventdata::Ptr{SCIP_EventData},
33-
)
42+
)::SCIP_RETCODE
3443
# Get Julia object out of eventhandler data
3544
data::Ptr{SCIP_EventData} = SCIPeventhdlrGetData(eventhdlr)
3645
event = unsafe_pointer_to_objref(data)
3746

3847
#call user method
3948
eventexec(event)
49+
return SCIP_OKAY
50+
end
4051

52+
"""
53+
Internal function that will be converted to a C function and passed to SCIP as a callback.
54+
Its signature matches the one given in the SCIP documentation for `SCIP_DECL_EVENTINIT`.
55+
"""
56+
function _eventinit(
57+
scip::Ptr{SCIP_},
58+
eventhdlr::Ptr{SCIP_Eventhdlr},
59+
)::SCIP_RETCODE
60+
# Get Julia object out of eventhandler data
61+
data::Ptr{SCIP_EventData} = SCIPeventhdlrGetData(eventhdlr)
62+
event = unsafe_pointer_to_objref(data)
63+
64+
#call user method
65+
eventinit(event)
4166
return SCIP_OKAY
4267
end
4368

69+
"""
70+
Internal function that will be converted to a C function passed to SCIP.
71+
Its signature matches the one given in the SCIP documentation for `SCIP_DECL_EVENTEXIT`.
72+
"""
73+
function _eventexit(
74+
scip::Ptr{SCIP_},
75+
eventhdlr::Ptr{SCIP_Eventhdlr},
76+
)::SCIP_RETCODE
77+
data::Ptr{SCIP_EventData} = SCIPeventhdlrGetData(eventhdlr)
78+
event = unsafe_pointer_to_objref(data)
79+
eventexit(event)
80+
return SCIP_OKAY
81+
end
4482
"""
4583
include_event_handler(scipd::SCIP.SCIPData, event_handler::EVENTHDLR; name="", desc="")
4684
@@ -59,6 +97,10 @@ function include_event_handler(
5997
name="",
6098
desc="",
6199
) where {EVENTHDLR<:AbstractEventhdlr}
100+
_eventinit =
101+
@cfunction(_eventinit, SCIP_RETCODE, (Ptr{SCIP_}, Ptr{SCIP_Eventhdlr}))
102+
_eventexit =
103+
@cfunction(_eventexit, SCIP_RETCODE, (Ptr{SCIP_}, Ptr{SCIP_Eventhdlr}))
62104
_eventexec = @cfunction(
63105
_eventexec,
64106
SCIP_RETCODE,
@@ -80,7 +122,8 @@ function include_event_handler(
80122
_eventexec,
81123
eventhdlr,
82124
)
83-
125+
@SCIP_CALL SCIPsetEventhdlrInit(scipd.scip[], eventhdlrptr[], _eventinit)
126+
@SCIP_CALL SCIPsetEventhdlrExit(scipd.scip[], eventhdlrptr[], _eventexit)
84127
@assert eventhdlrptr[] != C_NULL
85128
#Persist in scip store against GC
86129
scipd.eventhdlrs[event_handler] = eventhdlrptr[]
@@ -91,6 +134,7 @@ end
91134
92135
Catch an event in SCIP. This function is a wrapper around the SCIPcatchEvent function.
93136
Warning! This function should only be called after the SCIP has been transformed.
137+
Use this instead of calling SCIPcatchEvent directly.
94138
"""
95139
function catch_event(
96140
scipd::SCIP.SCIPData,
@@ -102,3 +146,21 @@ function catch_event(
102146
eventhdlrptr = scipd.eventhdlrs[eventhdlr]
103147
@SCIP_CALL SCIPcatchEvent(scipd, eventtype, eventhdlrptr, C_NULL, C_NULL)
104148
end
149+
150+
"""
151+
drop_event(scipd::SCIP.SCIPData, eventtype::SCIP_EVENTTYPE, eventhdlr::EVENTHDLR)
152+
153+
Drop an event in SCIP. This function is a wrapper around the SCIPdropEvent function.
154+
Warning! This function should only be called after the SCIP has been transformed.
155+
Use this instead of calling SCIPdropEvent directly.
156+
"""
157+
function drop_event(
158+
scipd::SCIP.SCIPData,
159+
eventtype::SCIP_EVENTTYPE,
160+
eventhdlr::EVENTHDLR,
161+
) where {EVENTHDLR<:AbstractEventhdlr}
162+
@assert SCIPgetStage(scipd) != SCIP_STAGE_INIT
163+
@assert SCIPgetStage(scipd) != SCIP_STAGE_PROBLEM
164+
eventhdlrptr = scipd.eventhdlrs[eventhdlr]
165+
@SCIP_CALL SCIPdropEvent(scipd, eventtype, eventhdlrptr, C_NULL, -1)
166+
end

test/eventhdlr.jl

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# It is assumed that test/sepa_support.jl is already included
33
using SCIP
44
import MathOptInterface as MOI
5-
5+
using Test
66
module FirstLPEventTest
77
# A simple event handler that stores the objective value of the first LP solve at the root node
88
using SCIP
@@ -21,9 +21,21 @@ function SCIP.eventexec(event::FirstLPEvent)
2121
event.firstlpobj = SCIP.SCIPgetLPObjval(scip)
2222
end
2323
end
24+
25+
function SCIP.eventinit(event::FirstLPEvent)
26+
SCIP.catch_event(event.scip, SCIP.SCIP_EVENTTYPE_FIRSTLPSOLVED, event)
27+
return
28+
end
29+
30+
function SCIP.eventexit(event::FirstLPEvent)
31+
SCIP.drop_event(event.scip, SCIP.SCIP_EVENTTYPE_FIRSTLPSOLVED, event)
32+
return
33+
end
34+
2435
end
2536

2637
@testset "Listen to first LP solve" begin
38+
using .FirstLPEventTest
2739
# create an empty problem
2840
optimizer = SCIP.Optimizer()
2941
inner = optimizer.inner
@@ -60,27 +72,24 @@ end
6072
SCIP.include_event_handler(
6173
inner,
6274
eventhdlr;
63-
name="firstlp",
6475
desc="Store the objective value of the first LP solve at the root node",
6576
)
6677

6778
# transform the problem into SCIP
6879
SCIP.@SCIP_CALL SCIP.SCIPtransformProb(inner)
6980

70-
# catch the event. Again this can only be done after the problem is transformed
71-
SCIP.catch_event(inner, SCIP.SCIP_EVENTTYPE_FIRSTLPSOLVED, eventhdlr)
72-
7381
# solve the problem
7482
SCIP.@SCIP_CALL SCIP.SCIPsolve(inner.scip[])
7583

7684
# test if the event handler worked
77-
@test eventhdlr.firstlpobj != 10
85+
@test eventhdlr.firstlpobj != 10.0
7886

7987
# free the problem
8088
finalize(inner)
8189
end
8290

8391
@testset "Nameless Event handler" begin
92+
using .FirstLPEventTest
8493
# create an empty problem
8594
optimizer = SCIP.Optimizer()
8695
inner = optimizer.inner
@@ -117,21 +126,17 @@ end
117126
SCIP.include_event_handler(
118127
inner,
119128
eventhdlr;
120-
name="firstlp",
121129
desc="Store the objective value of the first LP solve at the root node",
122130
)
123131

124132
# transform the problem into SCIP
125133
SCIP.@SCIP_CALL SCIP.SCIPtransformProb(inner)
126134

127-
# catch the event. Again this can only be done after the problem is transformed
128-
SCIP.catch_event(inner, SCIP.SCIP_EVENTTYPE_FIRSTLPSOLVED, eventhdlr)
129-
130135
# solve the problem
131136
SCIP.@SCIP_CALL SCIP.SCIPsolve(inner.scip[])
132137

133138
# test if the event handler worked
134-
@test eventhdlr.firstlpobj != 10
139+
@test eventhdlr.firstlpobj != 10.0
135140

136141
# free the problem
137142
finalize(inner)

0 commit comments

Comments
 (0)