Best practice to solve optimization problem repeatedly in a function with MathOptInterface

I want to create the function to solve multiple optimization problems with MathOptInterface, such as

using MathOptInterface
const MOI = MathOptInterface

function opt(optimizer::MOI.AbstractOptimizer)
    ...
    for i in 1:n 
        ...
        x = MOI.add_variables(optimizer, ...)
        MOI.set(optimizer, ...) # scalar affine objective function
        MOI.add_constraints(optimizer, ...) # scalar affine constraint
        MOI.optimize!(optimizer)
        ...
    end
    ...
end

I think I have to initialize Optimizer instance in every for loops, but there is no method to do it.

Currently, my code is

using MathOptInterface
const MOI = MathOptInterface
using GLPK

function opt(mathod::Symbol)
    ...
    for i in 1:n 
        ...
        optimizer = GLPK.Optimizer(method=method) # Only use GLPK optimizer
        x = MOI.add_variables(optimizer, ...)
        MOI.set(optimizer, ...) # scalar affine objective function
        MOI.add_constraints(optimizer, ...) # scalar affine constraint
        MOI.optimize!(optimizer)
        ...
    end
    ...
end

However, I don’t want to do hard coding, want to allow the various kinds of solver, such as Clp.Optimizer and CDDLib.Optimizer.

What is the best practice to do this?

The current recommendation is to ask the user to provide a JuMP.OptimizerFactory with with_optimizer.
Then you get a new instance with factory().
You could also take an AbstractOptimizer at argument and call MOI.empty!` at the start of the function.
You can find a related discussion here : https://github.com/JuliaOpt/MathOptInterface.jl/pull/387

1 Like

Thank you!
But why do you recommend JuMP.OptimizerFactory rather than MOI.empty! ? Is there any difference in speed or something?

No difference in speed but MOI.empty! don’t work if you want to use several instances of the same solver simultaneously.

I got the point! I appreciate your kind response!

You don’t have to use JuMP.OptimizerFactory. You could just go

using MathOptInterface
const MOI = MathOptInterface
using GLPK

function opt(factory::Function)
    ...
    for i in 1:n 
        ...
        optimizer = factory()
        x = MOI.add_variables(optimizer, ...)
        MOI.set(optimizer, ...) # scalar affine objective function
        MOI.add_constraints(optimizer, ...) # scalar affine constraint
        MOI.optimize!(optimizer)
        ...
    end
    ...
end

# Then you can call it with
opt(() -> GLPK.Optimizer())

@odow that would work but if it is part of a package, I would recommend using with_optimizer to provide a more consistent interface with the rest of the ecosystem