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

optimization
#1

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?

#2

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 callMOI.empty!` at the start of the function.
You can find a related discussion here : https://github.com/JuliaOpt/MathOptInterface.jl/pull/387

1 Like
#3

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

#4

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

#5

I got the point! I appreciate your kind response!

#6

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())
#7

@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