-
Notifications
You must be signed in to change notification settings - Fork 10
Allow setting scalar affine constraint functions via the modification API #37
Conversation
Codecov Report
@@ Coverage Diff @@
## master #37 +/- ##
==========================================
+ Coverage 76.27% 77.34% +1.06%
==========================================
Files 13 13
Lines 1252 1311 +59
==========================================
+ Hits 955 1014 +59
Misses 297 297
Continue to review full report at Codecov.
|
The modification tests need to be added to LQOI. See GLPK for an example LinQuadOptInterface.jl/test/runtests.jl Line 10 in d448b17
so it isn't well tested. This needs to improve. I usually test by running GLPK and Gurobi on the changes. @joaquimg is probably the person who understands the current state of the tests the best. |
Got it, thanks. I'll run glpk and gurobi with the modification tests on and open PRs to turn them on for those packages. |
By the way, jump-dev/Gurobi.jl#125 restricts LQOI to version [0.1, 0.2), but LQOI master is version 0.2+. Is that restriction necessary? |
PRs opened: jump-dev/GLPK.jl#56 jump-dev/Gurobi.jl#134 |
The problem with testing solutions is that one need to gather all the intermediary solutions (objective, variable primal and dual and constraint primal and dual) from some solver like Gurobi. |
Hm, i just realized this isn't quite right, as I'm not handling a possible modification of the constant in the affine function. It doesn't seem to be possible to use a |
You are planning to modify the sparsity pattern of the constraint?
I would just replace the set. |
I suspect that we will often not change the sparsity pattern, but in general I want the code to produce the right result regardless. But you're right that actually getting the existing constraint function looks like it will be very expensive. We may just have to re-write our interface to use |
Regarding testing modifications: I've been using the following in OSQP: Example usage: |
src/constraints/scalaraffine.jl
Outdated
for term in replacement.terms | ||
var = term.variable_index | ||
chg = MOI.ScalarCoefficientChange{Float64}(var, term.coefficient) | ||
MOI.modify!(m, CI, chg) |
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 also doesn't seem to support duplicate coefficients.
src/constraints/scalaraffine.jl
Outdated
chg = MOI.ScalarCoefficientChange{Float64}(var, term.coefficient) | ||
MOI.modify!(m, CI, chg) | ||
end | ||
change_rhs_coefficient!(m, m[CI], -replacement.constant) |
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.
Does this handle the constant encoded in the set properly (e.g. MOI.EqualTo(1.0)
)?
Some thoughts:
|
939876c
to
99ce57f
Compare
03271c3
to
9389980
Compare
What's the status of this? Is it necessary for the next release of LQOI? Or can it wait? |
Sorry, I haven't had time to vet this properly, and I think its handling of scalar affine functions is incorrect. It's on my todo list but not quite at the top. If you're OK with leaving this open, I'll let you know when it's ready for review. |
But to answer your question, no, this should not be necessary for the next release. It's just adding a new feature. |
@odow will this change also be rendered moot by your switch to using bridges here? I'm just trying to decide whether to keep this as a local modification for my own work or to actually put in the time to finish it correctly. |
I would keep it as a local change for now. Other than you, no one is clamoring for this change, so it doesn't make sense to spend a lot of time on it. |
9389980
to
06c8289
Compare
Hey @odow this is actually becoming a bit more pressing for my work. I believe I've fixed the bug with RHS coefficients that was previously in this branch, and the lack of this feature is currently blocking tkoolen/Parametron.jl#75 The scalar part of this PR is tested by jump-dev/GLPK.jl#56 and the vector part is tested by tkoolen/Parametron.jl#75 Would you be willing to consider merging this, even if it will eventually be replaced by the bridges? |
bc4d5c0
to
2af6a7c
Compare
This time for sure... I think this is ready for review (although we should merge #53 first, since this PR depends on that one). There are now enough tests that I'm reasonably confident it's doing the right thing. Unfortunately, this code is going to be very inefficient, particularly for GLPK. The problem is that every call to GLPK's implementation of |
I've merged #53. Will take a look at this |
src/constraints/scalaraffine.jl
Outdated
@@ -196,18 +196,65 @@ function MOI.modify!(model::LinQuadOptimizer, index::LCI{S}, change::MOI.ScalarC | |||
change_matrix_coefficient!(model, row, column, change.new_coefficient) | |||
end | |||
|
|||
function _replace_with_matching_sparsity!(model::LinQuadOptimizer, previous::Linear, replacement::Linear, row) |
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 know the rest of the code doesn't, but can we add docstrings for these new functions to remind ourselves of why they are needed and what they do?
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
rows = fill(row, length(replacement.terms)) | ||
cols = [model.variable_mapping[t.variable_index] for t in replacement.terms] | ||
coefs = MOIU.coefficient.(replacement.terms) | ||
change_matrix_coefficients!(model, 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.
Do these account for duplicate coefficients? (Edit: looks from below that the inputs are canonicalized. All the more reason for docstrings.)
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 made a note of that assumption in the various docstrings
src/constraints/scalaraffine.jl
Outdated
end | ||
change_rhs_coefficient!(model, row, get_rhs(model, row) - (replacement.constant - previous.constant)) | ||
model.constraint_constant[model[CI]] = replacement.constant | ||
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.
Nit: return
or return 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.
fixed
@@ -76,6 +76,62 @@ function MOI.modify!(model::LinQuadOptimizer, index::VLCI{<: VecLinSets}, | |||
end | |||
end | |||
|
|||
_constant(f::Linear) = f.constant | |||
_constant(f::VecLin) = f.constants |
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.
Are there MOIU functions for this?
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.
There are, but they're likewise _
-prefixed so I didn't want to use them externally. MOIU
does have constant()
but it unnecessarily allocates a vector for scalar functions.
Codecov Report
@@ Coverage Diff @@
## master #37 +/- ##
==========================================
+ Coverage 76.27% 77.11% +0.83%
==========================================
Files 13 13
Lines 1252 1315 +63
==========================================
+ Hits 955 1014 +59
- Misses 297 301 +4
Continue to review full report at Codecov.
|
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.
Thanks @rdeits
@@ -183,7 +183,7 @@ function MOI.get(model::LinQuadOptimizer, ::MOI.ConstraintFunction, index::LCI{< | |||
model.variable_references[columns], | |||
coefficients | |||
) | |||
Linear(terms, -model.constraint_constant[row]) | |||
Linear(terms, model.constraint_constant[row]) |
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 was not touched by tests?
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.
Nope. But I actually already made that fix (and added a test) in https://github.com/JuliaOpt/LinQuadOptInterface.jl/pull/53/files#diff-c1cce28d94a3c050507f8711d20ca7b2R186
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.
nice job
Looks good to go. I just added one question about the sign change. |
Ready to go? |
Yeah, I think this should be ready. Can we merge 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.
Actually, indices
should be changed to Compat.axes
in a couple of places for 1.0 compatibility.
src/constraints/vectoraffine.jl
Outdated
in canonical form. | ||
""" | ||
function _matching_sparsity_pattern(f1::T, f2::T) where {T <: Union{Linear, VecLin}} | ||
indices(f1.terms) == indices(f2.terms) || return false |
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.
indices
-> Compat.axes
.
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/solver_interface.jl
Outdated
some solver interfaces may offer more efficient implementations. | ||
""" | ||
function change_matrix_coefficients!(m, rows, cols, coefs) | ||
@boundscheck((indices(rows) == indices(cols) == indices(coefs)) || throw(DimensionMismatch())) |
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.
indices
-> Compat.axes
.
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
Merging this. We can rebase #60 on top of this and address any other compat issues. |
Fixes #32
Fixes jump-dev/GLPK.jl#58
I'm not sure how to test this. There's a
solve_func_scalaraffine_lessthan
modification unit test in MOI.Test, but it doesn't seem to be run during the LQOI tests. I'd appreciate some help turning that on (and any other tests that are available).