Is this the correct way to find all the binding constraints in JuMP?
I figure it is only binding of it has a nonzero shadow-price.
However shadow_price only works for <, > and == constraints so I am not sure i am going about this the right way.
Is there a better way that would also find when a Conic constraint was binding?
function binding_constraints(model, threshold=1e-8)
binding_cons = ConstraintRef[]
for (F, S) in list_of_constraint_types(model)
# only these relations are supported by shadow_price
S <: Union{MOI.EqualTo, MOI.LessThan, MOI.GreaterThan} || continue
for con in all_constraints(model, F, S)
if abs(shadow_price(con)) > threshold || continue
push!(binding_cons, con)
end
end
end
return binding_cons
end
Use dual instead of shadow_price. shadow_price is just for convenience for linear programs. (JuMP uses a different convention, so a lot of classes will teach “shadow price” instead of conic duality.)
Not sure yet.
Really I want to tweak my model until one particular constraint is binding.
Which probably means finding other ones that are binding and relaxing them.
So
function binding_constraints(model, threshold=1e-8)
binding_cons = ConstraintRef[]
for (F, S) in list_of_constraint_types(model)
for con in all_constraints(model, F, S)
if abs(dual(con)) > threshold || continue
push!(binding_cons, con)
end
end
end
return binding_cons
end
Careful with that abs(dual(con)): if you have conic constraints, dual(con) will be a Vector, and abs will error. I would suggest you use norm instead.
A more mathematical note (for completeness; probably not news to you): one the one hand, if the dual is non-zero, then the constraint will be tight (assuming your solution satisfies complementary slackness). Nothing new here.
On the other hand, however, there may exist a constraint a^{T}x \geq b such that, at the optimum, a^{T}x^{*} = b, but the corresponding dual is zero. This is not restricted to linear constraints, and it may happen when you have redundant constraints and/or multiple optimal solutions.