CPLEX.jl
CPLEX.jl copied to clipboard
Installing CPLEX.jl without cplex, as a placeholder / "empty wrapper"
I'm helping to develop a package (https://github.com/genXProject/genX) that can use CPLEX (through JuMP), and can also use other solvers. Not all users will have access to commercial solvers (and neither does our test server).
The Gurobi.jl package optionally looks for an environment variable GUROBI_JL_SKIP_LIB_CHECK
which allows it to be installed (but not used of course) on systems without Gurobi.
Would it be possible to have a similar interface for CPLEX.jl? Otherwise, is there a recommended workaround? We're admittedly somewhat new to julia package management.
There's no work-around, but I guess there's precedence with Gurobi so we could add CPLEX_JL_SKIP_LIB_CHECK
.
I'm usually pretty skeptical of packages which try to install CPLEX/Gurobi if the user doesn't have a license.
The correct work-around is to setup your project so that the user can pass in the solver they want to use, and to use an open-source solver like HiGHS as the default.
Related:
- https://github.com/jump-dev/HiGHS.jl/issues/122
- https://github.com/jump-dev/HiGHS.jl/issues/118
I don't think configuring solvers like this is a good idea: https://github.com/GenXProject/GenX/blob/main/src/configure_solver/configure_cplex.jl
It means that your project installs a whole bunch of solvers that aren't actually used: https://github.com/GenXProject/GenX/blob/66cc78a4133a947af8a001d6fb923aeb193e83cc/Project.toml#L9-L10
Just provide one good default (HiGHS), and document how you can use something else.
cc @sambuddhac
I feel that this feature is though very interesting to enable features that are not common with other solvers. In a repo, I am working on a more efficient procedure that exploits benders decomposition.
Currently, I am trying to use as a workaround a try-catch approach to enable CPLEX only when it is installed in the environment, without adding it as a dependency in the toml.
Davide, does your approach work? Would you be able to share the code?
Davide, does your approach work? Would you be able to share the code?
I'll release the complete package soon. However, the principle is as follows:
- Import CPLEX package in a try-catch-end block:
try
using CPLEX
catch e
@warn "Impossible to import CPLEX package, features may be limited"
end
- Where the CPLEX features are needed, place those features in another catch-try. In my case, I had a function like:
function add_feature(::Any, options)
@warn "Feature not implemented yet or not available"
end
try
function add_feature(::CPLEX.Optimizer, options)
# do stuff
end
catch e
@warn "Feature by CPLEX not available"
end
I tested this in an environment where CPLEX was installed, yet the and it actually works; however a warning by Julia is usually prompted to notify that the package does not have CPLEX as a dependency. That is annoying but it works
Thanks @cfe316 , @cfe316 , and @odow .... looking forward to the release and meanwhile, trying this approach out for GenX
The code exactly is the follows;
try
"""
Add notations for CPLEX backend
"""
function add_notations!(model, ::Type{CPLEX.Optimizer})
variable_classification = get_annotations(model)
num_variables = sum(length(it) for it in values(variable_classification))
if num_variables != JuMP.num_variables(model)
@warn "Annotation for $num_variables out of the total $(JuMP.num_variables(model)) variables"
end
indices, annotations = CPLEX.CPXINT[], CPLEX.CPXLONG[]
for (key, value) in variable_classification
indices_value = map(x->CPLEX.CPXINT(x.index.value-1), value)
append!(indices, indices_value)
append!(annotations, fill(CPLEX.CPXLONG(CPLEX.CPX_BENDERS_MASTERVALUE + key), length(indices_value)))
end
cplex = JuMP.backend(model)
index_p = Ref{CPLEX.CPXINT}()
CPLEX.CPXnewlongannotation(
cplex.env,
cplex.lp,
CPLEX.CPX_BENDERS_ANNOTATION,
CPLEX.CPX_BENDERS_MASTERVALUE,
)
CPLEX.CPXgetlongannotationindex(
cplex.env,
cplex.lp,
CPLEX.CPX_BENDERS_ANNOTATION,
index_p,
)
CPLEX.CPXsetlongannotations(
cplex.env,
cplex.lp,
index_p[],
CPLEX.CPX_ANNOTATIONOBJ_COL,
length(indices),
indices,
annotations,
)
return
end
catch e
@warn "Notation by CPLEX are not enabled"
end
You just need to adapt the get_annotations(model)
function to use the code
Julia 1.9 has an upcoming "weakdeps" feature that should support functionality like this. It'll allow you to write code that gets loaded only if two packages are installed.
Closing because we won't be enabling CPLEX.jl to be installed without a working version of CPLEX.