-
Notifications
You must be signed in to change notification settings - Fork 25
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
WIP : MOI wrapper (based on LQOI) #27
Conversation
test/MOIWrapper.jl
Outdated
solver = ClpOptimizer(LogLevel = 0) | ||
MOIT.contlineartest(solver, linconfig, ["linear10","linear12","linear8a","linear8b","linear8c"]) | ||
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 also add
https://github.com/JuliaOpt/Gurobi.jl/blob/a01f2310ddd83c259fbcf4b7c2512ba1ced4193d/test/MOIWrapper.jl#L65-L85
and
https://github.com/JuliaOpt/Gurobi.jl/blob/odow/moi/test/MOIWrapper.jl#L6-L22
(You may need to exclude some of the tests for quadratic etc.)
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.
Added. Thanks for the review !
src/MOIWrapper.jl
Outdated
""" | ||
function LQOI.get_linear_objective!(instance::ClpOptimizer, x::Vector{Float64}) | ||
obj = get_obj_coefficients(instance.inner) | ||
for i in 1:length(obj) |
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.
copy!(x, obj)
src/MOIWrapper.jl
Outdated
function LQOI.get_linear_constraint(instance::ClpOptimizer, row::Int)::Tuple{Vector{Int}, Vector{Float64}} | ||
A = get_constraint_matrix(instance.inner) | ||
A_row = A[row,:] | ||
return (Array{Int}(A_row.nzind) .- 1, A_row.nzval) |
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.
With latest LQOI, we return 1-indexed columns
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.
Good stuff. We should strip out all the commented out functions that relate to MIPs at some point before merging
src/MOIWrapper.jl
Outdated
solution = primal_column_solution(instance.inner) | ||
for i in 1:length(solution) | ||
x[i] = solution[i] | ||
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.
For all of these, there is copy!(x, solution)
src/MOIWrapper.jl
Outdated
for i in 1:n | ||
numberInColumn = 0 | ||
rows = Vector{Int32}() | ||
elements = Vector{Float64}() |
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 Int[]
and Float64[]
are the preferred style over the above.
test/MOIWrapper.jl
Outdated
|
||
MOIT.basic_constraint_tests(solver, config, exclude = [ | ||
(MOI.SingleVariable, MOI.Integer), | ||
(MOI.SingleVariable, MOI.ZeroOne) |
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.
Hmm you shouldn't have to exclude these. This should only test constraints that you support. (See my comment in supported constraints.)
src/MOIWrapper.jl
Outdated
(LQOI.SinVar, LQOI.GE), | ||
(LQOI.SinVar, LQOI.IV), | ||
(LQOI.SinVar, MOI.ZeroOne), | ||
(LQOI.SinVar, MOI.Integer), |
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.
Clp doesn't support binary and integer constraints
test/MOIWrapper.jl
Outdated
]) | ||
|
||
MOIT.unittest(solver, config, [ | ||
"solve_affine_interval", |
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 is this excluded?
REQUIRE
Outdated
@@ -1,3 +1,4 @@ | |||
julia 0.6 | |||
Cbc | |||
MathProgBase 0.5 0.8 | |||
LinQuadOptInterface |
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 should have a strict bound of LinQuadOptInterface 0.1 0.2
src/MOIWrapper.jl
Outdated
""" | ||
function LQOI.get_variable_lowerbound(instance::ClpOptimizer, col::Int)::Float64 | ||
lower = replaceInf(get_col_lower(instance.inner)) | ||
return lower[col]; |
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.
Two comments. Since you only query one element, you don't need to call replaceInf
on the whole lowerbound vector. But also, if get_col_lower
returns 10+20
, why should we change that to Inf
? The real bound in Clp is 10+20
.
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.
About the second comment. I am honestly about the reason behind that. I just tried to be consistent with the mathprog wrapper. If we fix it we should do it for both at the same time to avoid inconsistencies, especially for those who would like to move from the mathprog wrapper to MOI wrapper. So I suggest we open a separate issue for this.
src/MOIWrapper.jl
Outdated
""" | ||
function LQOI.get_variable_upperbound(instance::ClpOptimizer, col::Int)::Float64 | ||
upper = replaceInf(get_col_upper(instance.inner)) | ||
return upper[col]; |
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.
Ditto here. Also trailing ;
is unneeded.
src/MOIWrapper.jl
Outdated
return get_num_rows(instance.inner) | ||
end | ||
|
||
function addrow(row, lower, upper, instance, rows, cols, coefs) |
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.
The ordering on these arguments is inconsistent with the rest of the calls. They could be typed for readability?
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.
It is also pretty confusing that you pass in the A matrix but only add one row. At the very least it should be documented
src/MOIWrapper.jl
Outdated
The `sense` is given by `backend_type(m, set)`. | ||
Ranged constraints (`set=MOI.Interval`) should be added via `add_ranged_constraint!` instead. | ||
See also: `LinQuadOptInterface.CSRMatrix`. | ||
""" |
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 and throughout: you don't need this docstring since it is already in LQOI
src/MOIWrapper.jl
Outdated
error("sense must be Cchar(x) where x is in ['L','G',E']") | ||
end | ||
|
||
addrow(row, lower, upper, instance, rows, cols, coefs) |
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 got confused here, see comment with addrow
above
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 ve added a comment on the function and types for arguments
src/MOIWrapper.jl
Outdated
upper[row] = coef | ||
chg_row_upper(instance.inner, upper) | ||
else | ||
error("Either row_lower or row_upper must be of abs less than 1e20") |
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.
So when adding a constraint it allows bigger coefficients, but it truncates them to 1e20, but when modifying it doesn't? Confusing.
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.
Disallowing for both is needed here. I used it to know the active side of the range
src/MOIWrapper.jl
Outdated
function LQOI.set_linear_objective!(instance::ClpOptimizer, cols::Vector{Int}, coefs::Vector{Float64})::Void | ||
obj_in = zeros(Float64, get_num_cols(instance.inner)) | ||
for i in 1:length(cols) | ||
obj_in[cols[i]] = coefs[i] |
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 it is sufficient to go obj_in[cols] .= coefs
instead of the loop
src/MOIWrapper.jl
Outdated
numberInColumn = 0 | ||
rows = Int32[] | ||
elements = Float64[] | ||
add_column(instance.inner, numberInColumn, rows, elements, -Inf, +Inf, 0.0) |
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.
So Inf
bounds are okay here? Not 1e20
?
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.
The C code will test and truncate it anyway.
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 can probably just be add_column(instance.inner, 0, Int32[], Float64[], -Inf, Inf, 0.0)
The failing test is due to an error inside CLP I think: after deleting a column, getVectorStrats returns a wrong vector. I have reproduced this issue using C interface only and reported 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.
The failing test is due to an error inside CLP I think: after deleting a column, getVectorStrats returns a wrong vector. I have reproduced this issue using C interface only and reported it.
That's great, but in my experience there's a 95% chance this bug report will be ignored. The Clp author is more responsive on the mailing list. Disable this test so we can pass on travis and leave a comment explaining the situation.
src/ClpCInterface.jl
Outdated
#This function exists in cpp but not c interface | ||
function add_row(model::ClpModel, number_in_row::Integer, columns::Vector{Int32}, elements::Vector{Float64}, | ||
row_lower::Float64, row_upper::Float64) | ||
_row_starts = Vector{Int32}(2) |
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.
Naming: variables in the scope of a function shouldn't start with underscores. _row_upper
could be row_upper_vector
. Same comment below.
src/MOIWrapper.jl
Outdated
using LinQuadOptInterface | ||
using Clp.ClpCInterface | ||
|
||
function replaceInf(x) |
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.
naming: no camel case, use replace_inf
.
src/MOIWrapper.jl
Outdated
end | ||
|
||
function ClpOptimizer(;kwargs...) | ||
# env = Env() |
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 leave code commented without an explanation why. If the code doesn't do anything, remove it.
src/MOIWrapper.jl
Outdated
end | ||
|
||
""" | ||
Helper function for adding a row. it adds the row in the components |
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.
Start docstrings with the function signature.
src/MOIWrapper.jl
Outdated
Helper function for adding a row. it adds the row in the components | ||
that build the LQOI sparse matrix, and it adds the row in the solver. | ||
""" | ||
function addrow(row::Int, lower::Float64, upper::Float64, instance::ClpOptimizer, |
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.
Naming: add_row
.
src/MOIWrapper.jl
Outdated
cols = A.columns | ||
coefs = A.coefficients | ||
|
||
nbrows = length(rhs) |
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.
Naming: num_rows
.
src/MOIWrapper.jl
Outdated
end | ||
|
||
""" | ||
get_linear_constraint(m, row::Int)::Tuple{Vector{Int}, Vector{Float64}} |
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.
Formatting: indent the signature with 4 spaces so it displays like code.
src/MOIWrapper.jl
Outdated
get_linear_constraint(m, row::Int)::Tuple{Vector{Int}, Vector{Float64}} | ||
|
||
Get the linear component of the constraint in the 1-indexed row `row` in | ||
the model `m`. Returns a tuple of `(cols, vals)`. |
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.
Which model m
? There's no m
below.
src/MOIWrapper.jl
Outdated
return MOI.InfeasibleNoResult | ||
elseif s == 2 | ||
return MOI.UnboundedNoResult | ||
# if s in [0, 1, 2] |
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.
Remove or explain why it's commented.
There is an error on Linux but not on Mac. Can someone with Linux check the origin of this error? |
Yes, linear11 is failing on my Linux computer. You can probably add it in the exclude list. The problem seems to come from Clp and not from the wrapper. |
Thanks @blegat ! We had the same issue with Cbc (since it uses the C++ Clp ), so we disabled the linear11 test there as well. |
@IssamT is this ready to merge? |
@mlubin, Yes. I've just run the tests with the latest master on MOI / LQOI. (But with julia 0.6) |
LQOI 0.2 is released, could you update the PR? It's not good for the ecosystem to start being split by LQOI version. |
Sorry @mlubin , but I think I am missing something here.
Which updates of LQOI are you talking about? |
LQOI 0.3 could easily contain a change that would break this package. There should be an upper bound on LQOI to prevent users from seeing a broken package, like we do with MOI and MPB dependencies. |
The bounds on LQOI look good now. Clp was previously passing tests on 0.7 (https://travis-ci.org/JuliaOpt/Clp.jl/builds/364908514), so the failure looks like a regression. Could you take a quick look at why it's failing? |
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 isn't ready to merge yet. Mainly because LQOI has been moving forward and not all changes are reflected here (e.g., regarding interval constraints). And there are a few bugs. Let me know if you have time to fix otherwise I'll go through and tidy up.
test/MOIWrapper.jl
Outdated
config = MOIT.TestConfig() | ||
solver = ClpOptimizer(LogLevel = 0) | ||
# TODO uncomment after adding MOIT.TestConfig.multiple_bounds | ||
# MOIT.basic_constraint_tests(solver, config) |
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
end | ||
# TODO uncomment after adding MOIT.TestConfig.multiple_bounds | ||
# @testset "orderedindicestest" begin | ||
# MOIT.orderedindicestest(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.
src/ClpCInterface.jl
Outdated
row_starts_vector[2] = number_in_row | ||
row_upper_vector = [row_upper] | ||
row_lower_vector = [row_lower] | ||
add_rows(model, 1, row_lower_vector, row_upper_vector, row_starts_vector, columns, elements) |
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.
Isn't it just as simple to go
add_rows(model, 1, [row_lower], [row_upper], [0, number_in_row], columns, elements)
src/ClpCInterface.jl
Outdated
_column_starts[2] = number_in_column | ||
_column_upper = [column_upper] | ||
_column_lower = [column_lower] | ||
_objective = [objective] |
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.
Ditto here, or at least no underscore variable names
src/MOIWrapper.jl
Outdated
lowerbounds[cols[i]] = values[i] | ||
else | ||
error("sense is " * string(senses[i]) * ", but only " * Cchar('U') * | ||
" and " * Cchar('L') * " senses are supported") |
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.
Is this preferred over string interpolation?
"sense is $(senses[i]), but only 'U' and 'L' senses are supported."
src/MOIWrapper.jl
Outdated
error("Either row_lower or row_upper must be of abs less than 1e20") | ||
end | ||
|
||
sense = sense[i] |
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.
Bug? Is this tested? I shouldn't imagine that this passed...
src/MOIWrapper.jl
Outdated
""" | ||
function LQOI.set_linear_objective!(instance::ClpOptimizer, cols::Vector{Int}, coefs::Vector{Float64})::Void | ||
obj_in = zeros(Float64, get_num_cols(instance.inner)) | ||
obj_in[cols] .= coefs |
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.
Doesn't account for duplicates. See jump-dev/MathOptInterface.jl#432
src/MOIWrapper.jl
Outdated
numberInColumn = 0 | ||
rows = Int32[] | ||
elements = Float64[] | ||
add_column(instance.inner, numberInColumn, rows, elements, -Inf, +Inf, 0.0) |
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 can probably just be add_column(instance.inner, 0, Int32[], Float64[], -Inf, Inf, 0.0)
src/MOIWrapper.jl
Outdated
return lb | ||
elseif ub < Inf | ||
return ub | ||
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.
What about interval constraints? You need to implement get_range
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.
And also modify_ranged_constraints!
test/MOIWrapper.jl
Outdated
# linear1 test is disabled due to the following bug. | ||
# https://projects.coin-or.org/Clp/ticket/84 | ||
MOIT.contlineartest(solver, linconfig, ["linear1", "linear10","linear11", | ||
"linear12","linear8a","linear8b","linear8c"]) |
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 are these tests excluded?
@mlubin, looking quickly at the error on 0.7, apparently it is due to LQOI failing under 0.7, which is due to Nullables.jl failing under 0.7. Supporting LQOI on both 0.6, 0.7 requires Nullables. |
Do you know why we need nullables in LQOI? |
However, as far as I can tell, I am not sure if that justifies a dependency ... |
Tidy up
Okay, Nullables was removed from LQOI. Now we just need to wait for MOI to be tagged, then LQOI, then we can merge this with a new bound for LQOI. We should also refactor |
Codecov Report
@@ Coverage Diff @@
## master #27 +/- ##
=========================================
Coverage ? 48.13%
=========================================
Files ? 3
Lines ? 644
Branches ? 0
=========================================
Hits ? 310
Misses ? 334
Partials ? 0
Continue to review full report at Codecov.
|
You just need to add 0.7 on travis and make sure it passes |
test/MOIWrapper.jl
Outdated
@testset "Unit Tests" begin | ||
config = MOIT.TestConfig() | ||
solver = Clp.Optimizer(LogLevel = 0) | ||
# MOIT.basic_constraint_tests(solver, config) |
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 can be enabled
Is there still something required for this PR? |
There a lot of deprecation warnings, but they can be addressed in another PR. |
No description provided.