-
Notifications
You must be signed in to change notification settings - Fork 87
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
Add Parameter{T} <: AbstractScalarSet #2094
Comments
There is yet another alternative: have a variable bridge for constrained variables in What I would suggest is:
Then we would have:
|
I agree that adding a Here is my small contribution to the discussion: The POI codebase is a little complicated and has to store a lot of internal states because supporting parametric operations anywhere within the problem and supporting most Adding support for parameters directly in solvers would end up in rewriting a subset of POI on each solver. This could make each small POI wrapper very efficient for the solver in question but would also require additional hours to maintain it. Also, it would not be trivial to maintain it on every solver. In my opinion, adding the |
POI has 2 reasons to be a bit scary in terms of bookkeeping:
If solvers want to have POI functionality native in their wrapper, the code complexity will grow meaningfully, mainly if they want that to be efficient, and if they will end up requiring dual (which they will, just a matter of time between considering parameters and then requiring duals). So, as @guilhermebodin mentioned, I am also a bit worried that solvers will start doing that on their own. About the bridges, for me, is the same reasoning as the solvers. Now people want parameters. There is a not-very-complicated fix for that. But tomorrow, they will want duals (they already want them). Bridges will get more complicated and painful to maintain. I think there will be no free lunch. What is the difference between bridges and layers like POI? I'd say that some refactoring to simplify POI is the more general and more sustainable alternative and should not be a complex task, as things already work: we have benchmarks and working tests. I have no objection to adding MOI.Parameter, which might even simplify POI. My fears are: complicating the solver wrappers or adding a bridge that only does half of the work and is not better than POI. On a very side note, MOI.Parameter might be useful in DiffOpt, although it might just need all of POI infrastructure anyway. So not clear if Parameter being on POI or MOI makes much difference. |
I agree that implementing parameter support in solver wrappers is not a good idea. It would only be meaningful if the underlying solver already has support for it.
I agree, this is why I suggest the variable bridge approach instead of #2092. It is easy to add since all the complicated part is already part of the variable bridging mechanism which is common to all variable bridges. The advantage is that we don't have to implement support for |
I'd say that the complexity of POI has other issues besides maintenance. I was never able to get all the features from JuMP implemented in PowerSimulations.jl when the model used POI. Simple tasks like getting the model variable bounds or querying a parameter value after a problem modification became intractable and require many workarounds. After testing with ParameterJuMP, POI and also just using variables and letting the solver manage the equalities we had to go with the later solution which wasn't ideal because we end up hitting the limits on the number of variables in the solvers. However, it was the only way to get all the JuMP model exploration features working and also not hit the issue of the double dict of parametrized expressions. Further, when benchmarking build and solve time POI against adding variables and using The idea of having native support for parameters in the solver will allow to optimize how the solvers manage updating, specially the the RHS. We know that Gurobi is better on an element by element basis while Xpress is better on batch updates. It stands to reason that if every solver has a "best" way to do parameter update the support for that lives in the solver. |
These are bugs, and must be fixed. Are all of them issues in POI already?
Is it detailed somewhere?
I think this is expected, mainly in commercial solvers. The issues are with much larger problems, as you mentioned, and that it does not extend to multiplicative parameters.
|
Yes, I opened issues for every case I ran into. However, the crux of the issue is that POI was no better than using
Lots of detail here JuliaStochOpt/ParameterJuMP.jl#85
But the multiplicative parameter update optimizations are very solver dependent, I would argue even more than RHS. Each solver handles very differently how refactor or update the LHS matrix. Multiplicative parameter update would be an argument to add parameter support at the solver level.
Yes, this is true. That being said, it is worth exploring how much more code that is. If we take it as a simple index container like ParameterJuMP it doesn't seem to be that much of a deal IMO but I might be wrong.
|
Benchmarks in POI showed that you would need 3 or 4 update+solve after build to have an improvement. We can try improving if there is a MWE.
Ok, it is a ParameterJuMP only issue, it is not an issue in POI. I got confuse because there is a helper data structure in MOI called DoubleDict which is extensively used in POI. Hence I was (incorrectly) worried about some issues with their usage that led to some problems.
First, we have to check if this is really not doable from POI. The one issue I know is gurobi requires a call to "update" between getters and setters. This can be avoided with batch methods and with a Gurobi wrapper attribute to change this behaviour to some manual mode, which would be way simpler than moving all the work that POI does to Gurobi.jl.
ParameterJuMP does not handles multiplicative parameters, so it can be much simpler. At the same time we can refactor POI a bit to reduce code. I do not see how a wrapper level implementation of parameters would be simpler than a cleaned-up POI. You have to cache the very same information at the end. |
I agree with @joaquimg I tend to find a solver-independent implementation such as POI more readable and I don't see how specializing the code for a solver would simplify it so much. I might be wrong but we should have a clear idea why a solver-independent solution is not possible before implementing something solver specific. If there is something missing in the MOI modification API then improving the MOI API would be a win for other applications as well |
I'm fairly happy with this. I've updated Ipopt to use It was quite finicky though, so I can see how getting solvers to support parameters would be an issue. |
Perhaps relevant to this conversation are some considerable performance limitations I ran into with POI: jump-dev/ParametricOptInterface.jl#129 |
I think I'm going to close this as "done" for the MOI side of things. We now have first-class support in JuMP, plumbing all the way from JuMP to Ipopt, and bridges to |
Today I had a call with @sstroemer and @jd-lara, and we discussed the logistics of adding a
Parameter{T} <: AbstractScalarSet
to MOI.Motivation
The
Parameter{T}
set is similar to theEqualTo{T}
set, but with the special case that solvers could supportadd_constrained_variable(model, ::Parameter)
and not add the index as a decision variable to the underlying solver object.The goal is to support JuMP syntax like:
The benefits of an explicit parameter are that, compared to
EqualTo
, they can reduce the problem size and allow solvers to interpretp * x
as an affine function instead of quadratic.Backstory
We've tried quite a few ways to achieve this over the years...
EqualTo
The easiest approach is just to use fixed variables a parameters and let the solvers presolve them out. This works for additive parameters, but fails for
p * x
if the solver does not support quadratic constraints.Another downside is that it leads to more decision variables in the problem because
p
is added as a decision variable.Nonlinear
JuMP already has nonlinear parameters, which are added via
@NLparameter
. If we add aNonlinearFunction
, #2059, then we'll need some way to add parameters to MOI anyway.The current parameter implementation is very specialized inside
MOI.Nonlinear.Model
.ParameterJuMP
@joaquimg started ParameterJuMP.jl to support right-hand side parameters in JuMP.
The core premise is that it is a JuMP extension which defines a new
ParameterRef <: AbstractVariableRef
, and then stores parameterized JuMP expressions as a double expression:There are two main downsides to this approach:
AffExpr
on the stack instead of heap, means that memory overhead can be 2-3X larger than a JuMP model with theEqualTo
approach.p * x
; only additive terms are supported.ParametricOptInterface
To work-around the two problems in ParameterJuMP, the PUC-Rio/PSR folks (@guilhermebodin, @rafabench, and @tomasfmg) have been developing https://github.com/jump-dev/ParametricOptInterface.jl.
This is a MOI solver layer that adds a
ParametricOptInterface.Parameter
set, and then intercepts the model to replace parameters by their fixed constants.The main downsides are the complexity of the implementation, and how much state is needed to be stored inside the optimizer to track where and when the parameters are stored.
Recent work
@sstroemer has been hard at work exploring this, also motivated by an energy systems model.
One idea is to use the recently added
Bridges.final_touch
to rewrite quadratic constraints to affine:#2092
Another is to add support at the JuMP-level to track parameters: jump-dev/JuMP.jl#3215.
Loosely, these correspond to the approaches in ParametricOptInterface and ParameterJuMP.
Proposal
The basic part of the proposal is to add a
MOI.Parameter
set to MOI. We already know this is useful, because it is identical to what is added by ParametericOptInterface. In addition, we're going to need it for the nonlinear stuff.The more complicated question is what should happen after that.
ParameterToEqualToBridge
We should add a bridge from
Parameter
toEqualTo
. This would be a pretty trivial fallback that'll mean it should work across all solvers.FixParametricVariablesBridge
We can update #2092 to use only
Parameter
instead ofEqualTo
. This should letp * x
be re-written to affine for solvers not supporting quadratic.But for solvers supporting quadratic, and for additive parameters to be efficient, we'll need...
Solver support
Solvers will need to declare support for
MOI.Parameter
, and then parse constraints as they're added to extract parameters into the constant terms. They'll also need to maintain a mapping so that updating a parameter updates all of constraints inside the solver.Why not double down on ParametricOptInterface
This is a good question. At minimum, adding
Parameter
will also help POI.I don't have a good answer on the rest. One objection is that the POI codebase is complicated, and there is a lot of internal state to maintain. The bridge in #2092 is very simple in comparison. But perhaps the overhead of adding native parameter support to Gurobi.jl (for example) would be equally challenging.
The argument in favor of solver-specific implementations is that they could make their updates more efficient.
The text was updated successfully, but these errors were encountered: