Skip to content
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

Merged
merged 8 commits into from
Sep 3, 2018
Merged

MOI/LQOI basic support for ILP #181

merged 8 commits into from
Sep 3, 2018

Conversation

IssamT
Copy link
Contributor

@IssamT IssamT commented Aug 5, 2018

No description provided.

Copy link
Member

@odow odow left a 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

@@ -0,0 +1,283 @@
export CplexOptimizer
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add LQOI.SinVar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

for (name,value) in kwargs
set_param!(env, string(name), value)
end
m = CplexOptimizer(nothing)
Copy link
Member

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

return m
end

LQOI.supported_constraints(s::CplexOptimizer) = SUPPORTED_CONSTRAINTS
Copy link
Member

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

LQOI.backend_type(m::CplexOptimizer, ::MOI.Nonnegatives) = Cchar('E')

# TODO - improve single type
function LQOI.change_variable_bounds!(instance::CplexOptimizer,
Copy link
Member

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

function LQOI.set_linear_objective!(instance::CplexOptimizer,
columns::Vector{Int}, coefficients::Vector{Float64})

n = num_var(instance.inner)
Copy link
Member

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

Copy link
Contributor Author

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.

end

function LQOI.get_variable_primal_solution!(instance::CplexOptimizer, result)
fill_solution(instance.inner, result)
Copy link
Member

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_?

Copy link
Contributor Author

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 !

end

function LQOI.get_objective_value(instance::CplexOptimizer)
get_objval(instance.inner)
Copy link
Member

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

@@ -156,6 +166,21 @@ function get_constr_senses(model::Model)
return senses
end

function chg_sense!(model::Model, indices::IVec, senses::CVec)
Copy link
Member

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.

Copy link
Contributor Author

@IssamT IssamT Aug 6, 2018

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: getlb

Copy link
Contributor Author

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.

@IssamT
Copy link
Contributor Author

IssamT commented Aug 14, 2018

@odow, are you fine with the current names?

Copy link
Member

@odow odow left a 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.

if stat != 0
throw(CplexError(model.env, stat))
end
end

function c_api_getrhs(model::Model, row_start::Cint, row_end::Cint)
Copy link
Member

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)

Copy link
Contributor Author

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.

@IssamT
Copy link
Contributor Author

IssamT commented Aug 15, 2018

How about renaming all files like

cpx_model.jl -> c_api_model.jl
cpx_vars.jl -> c_api_vars.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

@IssamT
Copy link
Contributor Author

IssamT commented Aug 24, 2018

@odow should we go with the above renaming?

@odow
Copy link
Member

odow commented Aug 24, 2018

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

@IssamT
Copy link
Contributor Author

IssamT commented Aug 24, 2018

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.

Copy link
Member

@odow odow left a 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 is mbegin, m, surplus_p etc.)
  • v0.7 support?
  • missing a few MOI tests.

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
Copy link
Member

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)

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
Copy link
Member

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
Copy link
Member

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)]
Copy link
Member

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
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here again.

@@ -0,0 +1,36 @@
using CPLEX, Base.Test, MathOptInterface, MathOptInterface.Test
Copy link
Member

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.

Copy link
Member

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

solver = CPLEX.Optimizer()
MOIT.intlineartest(solver, intconfig, ["int2", "int3"])
# 3 is ranged, 2 has sos
end
Copy link
Member

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
Copy link
Member

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?


function MOI.free!(m::Optimizer)
# close_CPLEX(model.inner)
end
Copy link
Member

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.

@IssamT
Copy link
Contributor Author

IssamT commented Aug 25, 2018

I think we can keep the upgrade to julia 0.7 for another PR, since the MathProgBase interface is also failing it.

Copy link
Member

@odow odow left a 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?

n = num_var(model.inner)
all_coefs = zeros(Float64, n)
for (col, coef) in zip(columns, coefficients)
all_coefs[col] = coef
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -0,0 +1,36 @@
using CPLEX, Base.Test, MathOptInterface, MathOptInterface.Test
Copy link
Member

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

solver = CPLEX.Optimizer()
# TODO add a test config to disable testing problem name.
# @testset "nametest" begin
# MOIT.nametest(solver)
Copy link
Member

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...

Copy link
Contributor Author

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.

@IssamT
Copy link
Contributor Author

IssamT commented Sep 2, 2018

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.

@joaquimg
Copy link
Member

joaquimg commented Sep 3, 2018

I agree

@odow
Copy link
Member

odow commented Sep 3, 2018

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

@odow odow merged commit 9ac7fbf into jump-dev:master Sep 3, 2018
This was referenced Sep 3, 2018
@odow odow mentioned this pull request Oct 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants