@odow Thanks, I’ve learnt how to realize 0 allocation.
Here is a simple test you can take a look at the results
import JuMP, Gurobi
using BenchmarkTools
const r = Ref{Float64}();
const m = Settings.Model();
const o = JuMP.backend(m);
const N = 1000;
const c = rand(N);
JuMP.@variable(m, x[1:N]);
myset(o, x, c) = for (x, c) = zip(x, c)
Settings.setoc(o, x, c)
end;
macroset(m, x, c) = JuMP.@objective(m, Min, c'x);
myget(o, x, r) = for x = x
Settings.value(o, x, r) > -1.0 || error()
end
jumpget(x) = for x = x
JuMP.value(x) > -1.0 || error()
end
function jumpdot(x)
v = JuMP.value.(x)
for v = v
v > -1.0 || error()
end
end
@btime myset($o, $x, $c) # 42.442 μs (0 allocations: 0 bytes)
@btime macroset($m, $x, $c); # 124.206 μs (74 allocations: 165.95 KiB)
myset(o, x, zeros(N)); JuMP.optimize!(m)
@btime myget($o, $x, $r) # 38.061 μs (0 allocations: 0 bytes)
@btime jumpget($x) # 413.360 μs (9488 allocations: 195.12 KiB)
@btime jumpdot($x) # 422.070 μs (9490 allocations: 202.98 KiB)
my module `Settings`
module Settings
import JuMP, Gurobi
const SAF = JuMP.MOI.ObjectiveFunction{JuMP.MOI.ScalarAffineFunction{Float64}}()
_gcc(o, x) = Gurobi.c_column(o, JuMP.index(x));
_gv!(r, o, x) = Gurobi.GRBgetdblattrelement(o, "X", _gcc(o, x), r);
value(o, x, r) = (_gv!(r, o, x); r.x);
setoc(o, x, c) = JuMP.MOI.modify(o, SAF, JuMP.MOI.ScalarCoefficientChange(JuMP.index(x), c))
function printinfo()
th = map(Threads.nthreads, (:default, :interactive))
println("Settings> Threads=$th")
end
# The "Crossover=0" option is observed to be too vague (e.g. terminate with a 3% rGap) for certain cases, thus abandoned
const C = Dict{String, Any}("OutputFlag" => 0, "Threads" => 1, "MIPGap" => 0, "MIPGapAbs" => 0, "Method" => 2)
Env() = Gurobi.Env(C) # generate a _new_ one as defined by `Gurobi.Env`
Model() = JuMP.direct_model(Gurobi.Optimizer(Env()))
# multi-threading
Model(tks, v) = for i=eachindex(tks) setindex!(tks, Threads.@spawn(setindex!(v, Model(), i)), i) end
function Model(tks)
v = similar(tks, JuMP.Model)
Model(tks, v)
foreach(wait, tks)
v
end
# JuMP.set_objective_sense(m, JuMP.MIN_SENSE)
end