-
Notifications
You must be signed in to change notification settings - Fork 38
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
RFC: Redo statuses #164
Comments
This is very well thought out! Potentially naive question regarding the constraint primal solution: what is the slack in a ranged constraint? |
I would call it the minimum distance to infeasibility, i.e., for |
I like the proposal ! |
I like the minimum distance to infeasibilty since it lines up with infinite bounds. Can we just make it signed such that
the constraint primal should be -2 |
I also like this a lot. One question: what is the distinction between |
There's a problem here at the JuMP level that this concept doesn't align with how we deal with one-sided constraints, since we always normalize them by subtracting the rhs. But that's probably something we'll have to change in JuMP. |
|
Here's a proposal for the primal constraint solution: I was hesitant to go this route because it conflicts with what JuMP does, but that's probably not a good reason. |
I think this is the least confusing definition. |
About solver status:
|
I prefer the constraint primal subsolution as slacks, because, as @blegat said,
and for ranged constraints, I am with @odow's first reaction:
But I am not a fan of ranged constraint, so I never think too much about them... I forgot to mention, very good proposal! |
There is a inconsistency between two-sided and one-sided constraints:
Here is a suggestion:
About the replacement of symbols by enums, I would like to suggest using instead
getsolution(m, id::Int, ::Type{ConPrim)) = ... instead of doing function getsolution(m, id::Int, sc::SolutionComponent)
if sc == ConPrim
...
elseif ...
end
reacttonosol(::Type{PrimDualInfeas}) = ...
function someotherfunction(...)
...
reacttonosol(whynosolution(m))
...
end instead of function someotherfunction(...)
...
reason = whynosolution(m)
if reason == PrimDualInfeas
...
elseif ...
end
...
end |
@blegat, I'm proposing for the constraint primal to return There are no range constraints in conic form, so there's no need for the con primal solution to have the same definition between LP and conic. I'd prefer not to introduce additional (redundant) solution subvectors like I'm open to considering using types instead of enums or symbols. |
@joaquimg, I changed |
I like |
Overall I think this is fantastic. My only question is what is the precise definition of the solution status I am wondering if the One case where I can imagine the |
@ccoffrin, good question. I would define One thing I was trying to achieve with this restructuring is decoupling the reason why the solver stopped from the interpretation of the solution(s) returned. I agree that a
|
It's clear that we should extend |
@mlubin ok, then I am wondering if Pulling that thread, one nice feature of the other solution status values is that they are solver independent. They are intrinsic mathematical properties of the model, which one can easily verify given the model's equations (up to some numerical tolerance). In the case of That said, if possible, I think it would be great if feasible solutions could be annotated with the mathematical properties that the each solver guarantees that they satisfy (e.g. globally optimal, locally optimal). The reason being that an average user of Math Prog solvers does not have a deep understanding of the underlying algorithms and what the guarantee. Having a domain expert encode this information is preferable. Thinking of some examples,
|
I would be open to splitting For the Mosek case, as the user I don't want to have the obligation to manually check the duality gap on all solutions returned. If the solver has the ability to label a solution as optimal, which Mosek does, then we need to have a way to make this easily accessible. Abstracting this away seems frustrating for anyone who just wants to solve a problem and check if the solver decided that the solution was optimal. The Ipopt case is interesting because in the case of infeasibility there might still be value in seeing the solution (jump-dev/JuMP.jl#938). We might need to add a |
I agree with Carleton - I think any statuses should make sense in the context of the mathematical model (of course, taking into account numerical tolerances). I think Miles' suggestion for |
Another comment on this. As soon as we generalize conic form to allow affine (or quadratic) expressions belonging to arbitrary sets, then feasibility isn't necessarily any easier to verify than optimality. If you write down a copositive constraint then you may need a fancy oracle (a.k.a. a solver) to verify feasibility. It's not clear what this means for how we should design statuses, but I wouldn't assume that feasibility is as easy to check as asking the solver for a solution. |
On nonconvex problems, solvers such as Ipopt aren't even guaranteed to find a local minimizer. All one can say is that it found a stationary point. In my view, that would be a more meaningful status and could also resolve some misunderstandings. |
Good point, @dpo. If we can find a name for "a feasible point which the solver converged to" that's not specific to NLP then I'd go with that. |
Ok, maybe the solver status should be used to deduce if the solver converged (or almost converged). |
Off the top of my head I can't think of any cases that would be outside the scope of these status. So I think this is a good solution. Because each of these will be conditioned on some tolerance values, should the solution vector also include a standardized set of tolerance values? Or maybe the solvers should have standardized,
Good point, what about addressing this in the current scheme by setting the solver status to
Agreed, if we have a clear semantics of what the optimal status means, then the check can and should be performed for the users.
That's an interesting point. When I said "easy to verify" I was thinking there is a known polynomial time check (not necessarily linear time). This is in contrast to discrete or non-convex problems where it is not obvious that such a check exists (i.e. P vs NP question). |
I removed
If someone volunteers to define standard tolerances across solvers, I'll consider it, but that won't be me. |
I renamed |
What's the difference between |
Very interesting, I wish more solvers had this! Agreed that it make sense to put this in |
Why not keeping it ? It is well defined, solver independent and adding it might motivate other solvers to implement it. |
It is specific to conic, right? Is there a non-conic generalization?
I imagine there is a reasonable notion for non-conic. Like being on hyperplane that intersects the boundary of a convex set.
|
@chriscoey, it may be specific to convex optimization, but not to conic. The first papers dealing with these issues treated the general convex case: "Projections of Convex Programs with Unattained Infima" by Robert Abrams (1975) and "Regularizing the abstract convex program" by Jon Borwein and Henry Wolkowicz (1981). |
I've just done a major update to the proposal following brainstorming with @chriscoey and @joehuchette. The main points are:
I'd like to conclude this discussion on Monday at the meetup so that we can proceed with implementation during the rest of the week. |
I like the fact that it is now clear whether what is returned is a feasible point or feasible ray (I would prefer
|
@blegat, the current thinking is that it's up to the solver to make a contract with the user about what properties its results will have under the If we can come up with a simple way of encoding optimality information without misleading users about global optimality as @ccoffrin has pointed out, then I'd be open to considering it. |
I would understand if this kind of thing is model-dependent but solver dependent is weird. The package built in top of MPB should be able to interpret the solution without knowing what the solver is. |
Like the revision! Great idea to use a boolean function for future maintenance. In terms of solution statuses, what is the semantics of With the addition of |
To interpret the solution, we probably already have everything we need with |
That's essentially hypothetical though, because all existing conic and MIP solvers with MPB interfaces guarantee global optimality. It doesn't seem critical that we address this issue, but if there's a reasonable proposal I'll consider it.
These correspond to notions that are directly reported by the solver. Mosek, for example, distinguishes between feasible and nearly feasible results. I don't know of any solver that would call a result nearly infeasible, that's just feasible.
Yes, I don't see a need to distinguish these termination statuses. You can query the gap afterwards. Solvers have a number of different termination criteria, so I don't see why
Haven't written this down yet, but I was thinking one named getter per component of the result, e.g., |
The constraint concept needs a bit more thought since LPQP solvers have multiple types of constraints (so this would affect getters), but let's leave that separate from the status discussion. |
Worth thinking about: we could have solvers return "attributes" per result, where the primal and duals could be treated identically at the API level as constraint-wise and variable-wise attributes. This allows trivial extensions for solvers to return other pieces of information like membership in an IIS (jump-dev/JuMP.jl#1035). @dourouc05 This is more of an API question that's orthogonal to how we categorize statuses. |
For IISes, results that make sense are an infeasible set that is irreducible (best case), an infeasible set without any irreducibility property (e.g., the user stopped the computation, put a flag), or no infeasible set at all (probably not yet computed). I can think of nothing else that would be interesting here. |
This proposal has been incorporated into MathOptInterface |
Here is my attempt at a revision of the status system in MathProgBase (#156). Right now I'm just trying to get the concepts right and then we can worry about the implementation.
Termination status: why did it stop?
where
XXX
is one of:OK
Success
: The algorithm ran successfully and has a result. This includes cases where the algorithm converges to an infeasible point (NLP) or converges to a solution of a homogeneous self-dual problem and has a certificate of primal/dual infeasibility.AlmostSuccess
: The algorithm almost ran successfully (e.g., to relaxed convergence tolerances) and has a result.InfeasibleNoResult
: The algorithm stopped because it decided the problem is infeasible but does not have a result to return.UnboundedNoResult
: The algorithm stopped because it decided the problem is unbounded but does not have a result to return. This does not include Gurobi's UNBOUNDED because that really means that it found a ray of the primal and doesn't imply feasibility of the primal.InfeasibleOrUnbounded
: The algorithm stopped because it decided that the problem is infeasible or unbounded; no result is available. This happens during MIP presolve.Limits
IterationLimit
TimeLimit
NodeLimit
SolutionLimit
MemoryLimit
ObjectiveLimit
: Gurobi USER_OBJ_LIMIT and CUTOFF, Knitro KTR_RC_UNBOUNDEDNormLimit
: includes diverging iterates IpoptOtherLimit
Problematic
SlowProgress
: The algorithm stopped because it was unable to continue making progress towards the solution.AlmostSuccess
should be used if there is additional information that relaxed convergence tolerances are satisfied.NumericalError
: Unexpected numerical error, like division by zeroInvalidModel
: The solver has determined that it cannot solve this model because it violates some assumption, e.g., PSD hessian.InvalidOption
Interrupted
OtherError
These will probably be defined as an enum or a type. The reason to not return a single value and let users check equality is that it's much easier to rename statuses or deprecate methods this way.
What is a result tuple?
We say a result tuple is a tuple (x,y,α,β) where
vardual
in conic)Each vector contains one component per variable or constraint. For conic, for this discussion we say each row of the
A
matrix is a constraint, regardless of the dimensions of the cones.The constraint primal vector is defined as:
lb <= a'x <= ub
-> primal con value is defined asa'x
lb <= a'x + x'Qx <= ub
-> primal con value is defined asa'x + x'Qx
lb <= f(x) <= ub
-> primal con value is definedf(x)
b-Ax \in Cone
-> primal con value is defined asb - Ax
(row-wise)How do we retrieve a result tuple?
The following methods will be used by JuMP (for example) to decide whether to return a result to the user.
Since a number of solvers support returning multiple results, we'll define the API to enable querying multiple results. If available, result number 1 should be the most important result. Arguments specifying the result number are always last, and have a default value of 1.
result_count(m)
returns the number of results available to inspectprimal_available(m, ::Int)
anddual_available(m, ::Int)
returns true or falseIt may be the case that
result_count(m)
returns 1 anddual_available(m)
returns false because the solver might decide not to return duals.How do we interpret a result tuple?
The "result status" tells us how to interpret a result returned by the solver.
where XXX is one of:
FeasiblePoint
NearlyFeasiblePoint
InfeasiblePoint
FeasibleDirection
NearlyFeasibleDirection
ReductionCertificate
NearlyReductionCertificate
Unknown
Other
These will probably be defined as an enum or a type. The reason to not return a single value and let users check equality is that it's much easier to rename statuses or deprecate methods this way.
getobjval(m, :Int)
can be used to query the objective value of a result by indexDiscussion
This resolves:
stat !=: Optimal
nlp problems jump-dev/JuMP.jl#938CPXMIP_TIME_LIM_FEAS
vsCPXMIP_TIME_LIM_INFEAS
because we will be able to return a result to the user if one is available regardless of the reason why the solver stopped. It will also greatly simplify the implementation of
solve()
in JuMP (jump-dev/JuMP.jl#1033).It resolves the undocumented
:InfeasibleOrUnbounded
status by making it official.:Suboptimal
and:Stall
now correspond tois_termination_status(m, AlmostSuccess)
.This new framework replaces
getsolution
,getreducedcosts
,getconstrsolution
,getconstrduals
,getinfeasibilityray
,getunboundedray
,getdual
,getvardual
, andstatus
.RFC procedure
This is a high priority for me, so I am planning on closing the RFC June 12 (first day of the meetup) unless there's a good reason to delay. Please consider and comment on this proposal before then if it interests you.
@chriscoey @blegat @ulfworsoe @erling-d-andersen @joehuchette @JackDunnNZ @yeesian @madeleineudell @odow @joaquimg @ccoffrin @tkelman @leethargo @fserra @chkwon @bstellato @dpo
The text was updated successfully, but these errors were encountered: