scipopt / SCIP.jl

Julia interface to SCIP solver
MIT License
95 stars 24 forks source link

Persistence Of SCIPData Object #290

Closed gtjusila closed 4 months ago

gtjusila commented 4 months ago

This fix an issue with garbage collection when only the inner object of the optimizer is used as exemplified by the following example

import SCIP

function make_optimizer()
    optimizer = SCIP.Optimizer()
    return optimizer.inner
end

function run_test1()
    scip_data = make_optimizer()
    GC.gc(true)
    @assert(scip_data.scip[] != C_NULL)
end

function run_test2()
    scip_data = SCIP.Optimizer()
    inner = scip_data.inner
    scip_data = 0
    GC.gc(true)
    @assert(inner.scip[] != C_NULL)
end

GC.enable_logging(true)

# Both test should fail before fix
run_test1()
run_test2()

The fix is to change the finalizer call to listen to garbage collection events for the SCIPdata object of the MOI Optimizer object instead of listen to garbage collection events for the whole MOI Optimizer object

matbesancon commented 4 months ago

when only the inner object of the optimizer is used

fundamentally this was one reason the issue is normally not one, we always assume the optimizer is the main structure used, SCIPData is never a stand-alone structure

gtjusila commented 4 months ago

The problem is once you are interacting with SCIP.jl all the SCIP calls are expecting you to pass a SCIPData object rather than an optimizer object. Two possible solutions here

  1. Implement a convert class that convert optimizer class to SCIPdata on the fly and ask users to only use optimizer to call scip functions
  2. Change the testcase to accommodate the usage of SCIPData as a standalone outside the SCIPData structure. The new commit implements the latter. The only requirements remaining now is that SCIPData structure still should not be created as a standalone