Some solvers, as Gurobi, have a value (GRB_UNDEFINED in Gurobi) that means the variable has not a MIP start set. This is useful not only to specify a partial warm start (which can also be obtained just by not setting a MIP start for some variable), but because this allows to clean an older MIP start (what seems to be impossible right now without throwing the whole model away). One reason to do that cleaning is to be able to set a new partial MIP start. If a MIP start is partial this means that it does not describe a valid solution, and the solver may need to define a value for other variables (that have no MIP start set) to find a valid/feasible solution from it. If the variables it needs to change have already an older MIP start set, then it has not this freedom. The way it is now, calls to set_start_value will accumulate, "dirtying" the state from the model in a way that can only be "cleaned"/reset by a full empty! (basically you need to recreate the whole model just to be able to set a new MIP start). There is no concept of starting a new MIP start.
The solution I propose is just not requiring the value passed to JuMP.set_start_value to be of a Number. As it can be seen here, the method just calls MOI.set, and in Gurobi.jl, for example, MOI.set is defined to take a Union{Float64, Nothing}. Let the error be raised at the wrapper level if something not supported is passed.
set_start_value should very clearly follow what's defined in MOI. On a quick glance, I didn't find any MOI tests that set nothing for VariablePrimalStart, and the docs for VariablePrimalStart don't mention nothing as a valid value, so it looks like there's work to do at the MOI level before making changes to JuMP.
basically you need to recreate the whole model just to be able to set a new MIP start
Point understood, but this is a bit of an exaggeration. There are workarounds like calling MOI.set directly.
I guess I'm responsible for the nothing, but I don't remember the specific conversation. I seem to recall that if a variable didn't have a start value set, we returned nothing, so it seems the logical thing to do is pass nothing to unset the start value.
Point understood, but this is a bit of an exaggeration. There are workarounds like calling MOI.set directly.
Yes, I expressed myself wrongly, there is no way to do this using pure JuMP, but calling MOI.set is theoretically a solver-agnostic workaround, if every solver that supports such feature decides to represent undefined values with nothing.
and the docs for VariablePrimalStart don't mention nothing as a valid value
To be entirely fair, the documentation for VariablePrimalStart is very short and its does not explicitly restrict/specify the allowed values (if GRB_UNDEFINED is a Float64 it could probably be passed by MOI.set). What would be the work at MOI level? Just add to the documentation that nothing is the canonical representation of undefined values (or maybe missing would be a better conceptual match?) and some tests for it. Or it need some kind of supports verification?
What would be the work at MOI level?
To apply to Socratic method: If you were reading the MOI documentation, what would be sufficient to give you confidence that nothing is a valid value to set for VariablePrimalStart?
We do already use nothing very often in MOI for unset values (e.g., start_value returns nothing if no value has been set yet). We had a discussion a while back and concluded that nothing is better than missing because missing propagates silently, i.e., 2.0 * start_value(x) would trigger an error if the start value is nothing but not if it's missing.
Task for the sprint:
nothing to be passed as an argument, and document that this unsets the start value.Related items:
VariablePrimalStart tests to MOI https://github.com/jump-dev/MathOptInterface.jl/issues/794, https://github.com/jump-dev/MathOptInterface.jl/issues/853I think I can spare some hours to take care of that. In the worst case I will work just a little each sprint. How I get assigned to it?
I know the first sprint is next weekend, but I had some spare time today as my gaming partners took the day off for other activities.
I started trying to build the current MathOptInterface docs, and they give the error in the end of this comment. Seems like that in the documentation tests MathOptInterface was abbreviated as MOI but the code that output the types obviously is blind to such abbreviations. Should I fix this first? Or this is expected behavior and the documentation is always generated disabling those tests? (Or at least preventing they stop the documentation generation in an error.)
โ Error: doctest failure in src/apireference.md:643-649
โ
โ ```jldoctest bridged_variable_function
โ MOI.Bridges.bridged_variable_function(bridged_model, bridged_variable)
โ
โ # output
โ
โ MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(1))], 1.0)
โ ```
โ
โ Subexpression:
โ
โ MOI.Bridges.bridged_variable_function(bridged_model, bridged_variable)
โ
โ Evaluated output:
โ
โ MathOptInterface.ScalarAffineFunction{Float64}(MathOptInterface.ScalarAffineTerm{Float64}[MathOptInterface.ScalarAffineTerm{Float64}(1.0, MathOptInterface.VariableIndex(1))], 1.0)
โ
โ Expected output:
โ
โ MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(1))], 1.0)
โ
โ diff = MOI.ScalarAffineFunction{Float64}(MOI.ScalarAffineTerm{Float64}[ScalarAffineTerm{Float64}(1.0, VariableIndex(1))], MathOptInterface.ScalarAffineFunction{Float64}(MathOptInterface.ScalarAffineTerm{Float64}[MathOptInterface.ScalarAffineTerm{Float64}(1.0, MathOptInterface.VariableIndex(1))], 1.0)
โ @ Documenter.DocTests ~/.julia/packages/Documenter/PLD7m/src/DocTests.jl:369
See https://github.com/jump-dev/MathOptInterface.jl/issues/990. For now, we just build the docs on Julia 1.0.
Thanks, I was about to comment that I had similar problems with JuMP.jl. I will build the documentation of both using Julia 1.0.
I was able to build the JuMP docs with a new .julia/ and using julia-1.0.5, however MathOptInterface fails differently now. I am not sure exactly what are the error but the message ERROR: LoadError:makedocsencountered errors. Terminating build appears after [ Info: Populate: populating indices. (it is not an error in the doctests anymore), there are some Warning: undefined binding [...] and Warning: no doc found for reference but nothing that seems to be fatal.
I will probably not work more on this today, so you do not need to hurry to answer.
@henriquebecker91 see https://github.com/jump-dev/JuMP.jl/pull/2266
I apologize for disappearing for the last three weeks. They were more hectic than I expected. I intend to work in this yet, but I cannot guarantee I will finish it until the end of the next weekend (I can only work sparsely on this during the weekdays, maybe now things will be simple and I will finish quickly, in the worst case I will reserve some time to finish it in the next weekend). I hope I am not delaying the 1.0 release roadmap, I apologize again if this is the case. I got the documentation generation to work with your last comment on #2266.
I apologize
@henriquebecker91, everyone who works on JuMP are volunteers. You don't have to meet deadlines or apologize for not doing free work! The 1.0 release will be ready when it is finished. We don't have a deadline we are trying to meet.
Most helpful comment
I guess I'm responsible for the
nothing, but I don't remember the specific conversation. I seem to recall that if a variable didn't have a start value set, we returnednothing, so it seems the logical thing to do is passnothingto unset the start value.