-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MOI/LQOI basic support for ILP #181
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome. Mainly lots of style things. See
jump-dev/GLPK.jl#59
jump-dev/Gurobi.jl#146
src/MOIWrapper.jl
Outdated
@@ -0,0 +1,283 @@ | |||
export CplexOptimizer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor CplexOptimizer
to CPLEX.Optimizer
and remove the export.
const MOI = LQOI.MOI | ||
|
||
const SUPPORTED_OBJECTIVES = [ | ||
LQOI.Linear |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add LQOI.SinVar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/MOIWrapper.jl
Outdated
for (name,value) in kwargs | ||
set_param!(env, string(name), value) | ||
end | ||
m = CplexOptimizer(nothing) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: always name the optimizer model
src/MOIWrapper.jl
Outdated
return m | ||
end | ||
|
||
LQOI.supported_constraints(s::CplexOptimizer) = SUPPORTED_CONSTRAINTS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: don't name s
it it isn't used
src/MOIWrapper.jl
Outdated
LQOI.backend_type(m::CplexOptimizer, ::MOI.Nonnegatives) = Cchar('E') | ||
|
||
# TODO - improve single type | ||
function LQOI.change_variable_bounds!(instance::CplexOptimizer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: refactor instance
to model
src/MOIWrapper.jl
Outdated
function LQOI.set_linear_objective!(instance::CplexOptimizer, | ||
columns::Vector{Int}, coefficients::Vector{Float64}) | ||
|
||
n = num_var(instance.inner) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: no one-letter variable names
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But n
and m
are often used in linear programming. And these are local vars in functions that always fully fit in a laptop screen; so if one doesn't know what the variable is, he can just look above.
src/MOIWrapper.jl
Outdated
end | ||
|
||
function LQOI.get_variable_primal_solution!(instance::CplexOptimizer, result) | ||
fill_solution(instance.inner, result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: get_
instead of fill_
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there are already get functions with the same name, the name should be different for inplace functions. following our discussion yesterday, I will use get_
with !
src/MOIWrapper.jl
Outdated
end | ||
|
||
function LQOI.get_objective_value(instance::CplexOptimizer) | ||
get_objval(instance.inner) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: all functions that explicitly return something should use return
src/cpx_constrs.jl
Outdated
@@ -156,6 +166,21 @@ function get_constr_senses(model::Model) | |||
return senses | |||
end | |||
|
|||
function chg_sense!(model::Model, indices::IVec, senses::CVec) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: I think if we are wrapping new CPLEX functions, we should use exactly the CPLEX name. So refactor chg_sense!
to chgsense
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only added few functions, so I tried to keep the style consistent with the rest of the wrapper functions. Plus I think if we use underscores everywhere else in julia code, it's better to keep those underscores. I opened an issue to see what the others think of this jump-dev/JuMP.jl#1409
src/cpx_vars.jl
Outdated
@@ -78,6 +78,22 @@ function add_var!(model::Model, constridx::Vector, constrcoef::Vector, l::Vector | |||
return add_var!(model, ivec(constridx), fvec(constrcoef), fvec(l), fvec(u), fvec(objcoef)) | |||
end | |||
|
|||
function get_varLB(model::Model, col::Cint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style: getlb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep the name get_lb
for the function that does exactly the same as cpxgetlb
, namely getting lowerbounds for a range of columns and not for just one column.
@odow, are you fine with the current names? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I like c_api_xxx
. However, maybe we should put all of the c_api_xxx
functions in a new c_api.jl
file for now. In the long-term, I would like to remove/deprecate many of the existing CPLEX functions.
src/cpx_constrs.jl
Outdated
if stat != 0 | ||
throw(CplexError(model.env, stat)) | ||
end | ||
end | ||
|
||
function c_api_getrhs(model::Model, row_start::Cint, row_end::Cint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think users should have to pass in the rhs
vector as well.
function c_api_getrhs(model::Model, rhs::Vector{Cdouble}, row_start::Cint, row_end::Cint)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@odow, I agree with you. higher layers can benefit from that doing in place modification even if it's not the case of LQOI for this specific function. I will update it.
How about renaming all files like cpx_model.jl -> c_api_model.jl and move the helper functions that we want to keep as few as possible from those file to a single file helpers_c_api.jl |
@odow should we go with the above renaming? |
I think for now, leave the current cplex unmodified and place any new functions in a new file. We can make another pr that does a tidy |
I also renamed some of the old ones used also by Mathprogbase when they matched the C API. If you prefer doing the renaming in another PR, then I think it's better to keep the functions in the same files. otherwise we will have subsets of functions organized differently without any reason. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, lets leave the functions where they are for now. A few comments.
- It needs to be upgraded to LQOI v0.3.
- There are lot of style/naming things (e.g., in
c_api_getrows
, what ismbegin
,m
,surplus_p
etc.) - v0.7 support?
- missing a few MOI tests.
src/cpx_constrs.jl
Outdated
ncons = @cpx_ccall(getnumrows, Cint, ( | ||
Ptr{Void}, | ||
Ptr{Void} | ||
), | ||
model.env.ptr, model.lp) | ||
return ncons | ||
end | ||
num_constr = c_api_getnumrows # Needed by MathProgBase Interface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially missed this, it might be better to go num_constr(model::Model) = c_api_getnumrows(model)
src/cpx_constrs.jl
Outdated
if stat != 0 | ||
throw(CplexError(model.env, stat)) | ||
end | ||
end | ||
|
||
function c_api_getrhs(model::Model, rhs::Vector{Cdouble}, row_start::Cint, row_end::Cint) | ||
ncons = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used?
src/cpx_solve.jl
Outdated
@@ -79,28 +80,53 @@ function get_objval(model::Model) | |||
end | |||
return objval[1] | |||
end | |||
get_objval = c_api_getobjval |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_objval(model::Model) = c_api_getobjval(model)
src/cpx_solve.jl
Outdated
nvars = num_var(model) | ||
x = Vector{Cdouble}(nvars) | ||
function c_api_solninfo(model::Model) | ||
solnmethod_p = [Cint(-1)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make these solnmethod_p = Ref{Cint}()
, and then return solnmethod_p[]
. This avoids allocating a vector.
src/cpx_solve.jl
Outdated
return @cpx_ccall(getstat, Cint, (Ptr{Void}, Ptr{Void}), | ||
model.env.ptr, model.lp) | ||
end | ||
get_status_code = c_api_getstat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_status_code(model::Model) = c_api_getstat(model)
src/cpx_vars.jl
Outdated
nvar = @cpx_ccall(getnumcols, Cint, ( | ||
Ptr{Void}, | ||
Ptr{Void} | ||
), | ||
model.env.ptr, model.lp) | ||
return(nvar) | ||
end | ||
num_var = c_api_getnumcols |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here again.
test/MOIWrapper.jl
Outdated
@@ -0,0 +1,36 @@ | |||
using CPLEX, Base.Test, MathOptInterface, MathOptInterface.Test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should test this on v0.7 as well. It will need Compat.Test
instead of Base.Test
, or we can leave that for another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also don't need the using MathOptInterface.Test
test/MOIWrapper.jl
Outdated
solver = CPLEX.Optimizer() | ||
MOIT.intlineartest(solver, intconfig, ["int2", "int3"]) | ||
# 3 is ranged, 2 has sos | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go see the Gurobi and GLPK tests, there are a few missing here.
src/cpx_model.jl
Outdated
else | ||
error("CPLEX: problem object or environment does not exist") | ||
return :Min | ||
else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we drop the check for sense_int == -1
and the else
error?
src/MOIWrapper.jl
Outdated
|
||
function MOI.free!(m::Optimizer) | ||
# close_CPLEX(model.inner) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not needed.
I think we can keep the upgrade to julia 0.7 for another PR, since the MathProgBase interface is also failing it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the tests pass?
src/MOIWrapper.jl
Outdated
n = num_var(model.inner) | ||
all_coefs = zeros(Float64, n) | ||
for (col, coef) in zip(columns, coefficients) | ||
all_coefs[col] = coef |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the tests pass? This doesn't account for duplicate coefficients. Should be all_coefs[col] += coef
MOIT.TestConfig() | ||
) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add the modellike tests
https://github.com/JuliaOpt/Gurobi.jl/blob/9bf2a76e27c82198ab4b2ce387944d666e5618eb/test/MOIWrapper.jl#L80-L97
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
test/MOIWrapper.jl
Outdated
"solve_affine_interval", # not implemented | ||
"solve_qp_edge_cases", # not implemented | ||
"solve_qcp_edge_cases", # not implemented | ||
"solve_objbound_edge_cases", # TODO fix the non zero constant case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test/MOIWrapper.jl
Outdated
@@ -0,0 +1,36 @@ | |||
using CPLEX, Base.Test, MathOptInterface, MathOptInterface.Test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also don't need the using MathOptInterface.Test
test/MOIWrapper.jl
Outdated
solver = CPLEX.Optimizer() | ||
# TODO add a test config to disable testing problem name. | ||
# @testset "nametest" begin | ||
# MOIT.nametest(solver) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the nametest fail? Since CLPEX uses LQOI it should pass...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. My bad.
I think it s better to do the update for MOI 0.6 in a separate PR, to keep a version for comparaison. Any minor issues left can be discussed in the MOI 0.6 update PR. |
I agree |
Okay, I have tagged a release of CPLEX prior to merging this: JuliaLang/METADATA.jl#17661 I'll squash and merge this, then you can make another PR updating to MOI v0.6 and Julia v0.7. Then we can tag as v0.4.0 |
No description provided.