suppose that a module foo.jl
depends on external packages which take several seconds to load, e.g.
julia> tic(); using JuMP, GLPKMathProgInterface; toc()
elapsed time: 4.929913064 seconds
in my case, foo.jl
only eventually uses JuMP, thus it seems more convenient to load it only when needed.
the strategy that i’ve used successfully with PyPlot
is to evaluate the using
command at run-time. however, it fails here. the problem appears with the @variable
macro.
for example:
module foo
function my_fun(...)
...
if isdefined(:JuMP)
eval(Expr(:using, :JuMP))
model = JuMP.Model(solver=GLPKSolverLP())
JuMP.@variable(model, x[1:p.dim]) # << triggers: LoadError: UndefVarError: JuMP not defined
...
else
error("...")
end
end
end #module foo
is there a way to “avoid expanding the macro”? or, is there another workaround for optionally loading a package? Thanks
EDIT. here’s a MWE:
module foo
using JuMP
using GLPKMathProgInterface
function my_fun(C::Float64)::Float64
m = Model(solver = GLPKSolverLP())
@variable(m, 0 <= x <= 2)
@variable(m, 0 <= y <= 30)
@objective(m, Max, 5x + 3*y)
@constraint(m, 1x + 5y <= C)
print(m)
status = solve(m)
println("Objective value: ", getobjectivevalue(m))
println("x = ", getvalue(x))
println("y = ", getvalue(y))
return getobjectivevalue(m)
end
export my_fun
end # module foo.jl
and:
julia> tic(); include("foo.jl"); using foo; toc()
elapsed time: 6.753355159 seconds
6.753355159
julia> my_fun(3.0)
Max 5 x + 3 y
Subject to
x + 5 y ≤ 3
0 ≤ x ≤ 2
0 ≤ y ≤ 30
Objective value: 10.6
x = 2.0
y = 0.2
10.6
now let’s try the package Requires.jl :
module bar
using Requires
function my_fun(C::Float64)::Float64
!isdefined(:JuMP) ? eval(:(using JuMP)) : nothing
!isdefined(:GLPKMathProgInterface) ? eval(:(using GLPKMathProgInterface)) : nothing
@require JuMP begin
@require GLPKMathProgInterface begin
m = Model(solver = GLPKSolverLP())
end
@variable(m, 0 <= x <= 2)
@variable(m, 0 <= y <= 30)
@objective(m, Max, 5x + 3*y)
@constraint(m, 1x + 5y <= C)
print(m)
status = solve(m)
println("Objective value: ", getobjectivevalue(m))
println("x = ", getvalue(x))
println("y = ", getvalue(y))
return getobjectivevalue(m)
end
end
export my_fun
end # module bar.jl
then
julia> tic(); include("bar.jl"); using bar; toc()
elapsed time: 0.087633098 seconds
0.087633098
julia> my_fun(3.0)
WARNING: Error requiring JuMP from bar:
UndefVarError: C not defined
Stacktrace:
[1] err(::bar.##7#15, ::Module, ::String) at /Users/forets/.julia/v0.6/Requires/src/require.jl:42
[2] withpath(::bar.##6#14, ::String) at /Users/forets/.julia/v0.6/Requires/src/require.jl:32
[3] listenmod(::bar.##5#13, ::Symbol) at /Users/forets/.julia/v0.6/Requires/src/require.jl:13
[4] macro expansion at /Users/forets/.julia/v0.6/Requires/src/require.jl:52 [inlined]
[5] my_fun(::Float64) at /Users/forets/Projects/Compositional/CompositionalHA.jl/test/Sets/bar.jl:7
[6] eval(::Module, ::Any) at ./boot.jl:235
[7] eval_user_input(::Any, ::Base.REPL.REPLBackend) at ./REPL.jl:66
[8] macro expansion at ./REPL.jl:97 [inlined]
[9] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
ERROR: MethodError: Cannot `convert` an object of type Void to an object of type Float64
This may have arisen from a call to the constructor Float64(...),
since type constructors fall back to convert methods.
Stacktrace:
[1] macro expansion at /Users/forets/.julia/v0.6/Requires/src/require.jl:52 [inlined]
[2] my_fun(::Float64) at /Users/forets/Projects/Compositional/CompositionalHA.jl/test/Sets/bar.jl:4774:
why’s that? (without passing the C as argument, it works).