Using expression must be at top level

In order to make my package Solver parametric, I am trying to read the user prompt to determine which solver he wants to use alongside with JuMP

mutable struct SolverOptimizer
    solver::DataType
    id::Int
end

function readsolveropt()
    solver = readline()
    println("Select your solver [Gurobi | SCIP]")

    if occursin("gurobi", lowercase(solver))
        using Gurobi
        return SolverOptimizer(Gurobi.Optimizer, 1)
    else
        using SCIP
        return SolverOptimizer(SCIP.Optimizer, 2)
    end
end

However, I get the error ERROR: syntax: "using" expression not at top level, both when used in a module and when used in the REPL. Does that mean I can’t encapsulate my if statement in a function and must put it in top level where my main module is defined?

Also, is it appropriate to create a post on Julia Discourse for this kind of “small” questions? Is there a more appropriate place, e.g., would you recommend that I create a Slack account or something more “chatty” “SMS” than a formal post?

1 Like

Yes. using can’t be used inside a function.

Yes.

There is surely a better approach. Instead of taking a string like "gurobi" from the user, you could simply take the MOI.AbstractOptimizer (e.g., Gurobi.Optimizer).

Furthermore, if you really want to explicitly depend on specific solvers, you should prefer weak dependencies (via package extensions) over the usual, strong, dependencies.

1 Like

Dear @nsajko, thank you so much for your reply! I was not aware of weak dependencies! This is suitable in my case :blush:

I still hesitate between coding via MathOptInterface or via JuMP and specific solvers.

Concorde.jl doesn’t rely on JuMP but I also read in MathOptInterface doc that creating your own solver is a lot of more work!

I need more experienced Julia developers points of view on this choice!

1 Like

Personally I almost never used JuMP.jl, only MOI, but I think my advice above should apply independently of whether you use JuMP or MOI.

You don’t need to create your own solver, though.

2 Likes

Instead of getting the user to pass a string, get them to pass the Gurobi.Optimizer object directly.

The user should call something like:

using SCIP
RSP.rspoptimize(pars, id_instance; optimizer = SCIP.Optimizer)
3 Likes

@odow @nsajko, thank you very much for your clear inputs :smiley:

2 Likes

No worries :smile:

A key design principle of JuMP is that it should be agnostic to the solver. The user could even use a solver that you have never seen or heard of and it should still work.

4 Likes

I remember one of my PhD supervisor telling me at some point during my thesis:

“I can’t use CPLEX with your code, only Gurobi”

And I was thinking: “that is normal, I have not coded with the idea that you will!”
And now I realize how in advance my supervisor was haha :smiley:

2 Likes

Is your solution documented somewhere in JuMP manual? If not, I believe it has its place there

See Design patterns for larger models · JuMP

1 Like