You’re right that that can be a confusing topic. We should probably add more explanation to the JuMP docs.
A key realization is that:
- The sign convention is arbitrary. I could assume that \lambda was non-positive if I put a - sign in front of the summation
- JuMP uses the duality conventions from conic duality.
These part of the documentation may be helpful:
The way I remember JuMP.dual
is:
- the sign of
JuMP.dual(constraint)
does not depend on whether we are minimizing or maximizing - the sign of
JuMP.dual(constraint)
is non-negative for \ge and non-positive for \le
In more detail:
- the dual of a \le constraint is non-positive, because f(x) \le y is rewritten to f(x) - y \in \mathbb{R}_- (the
MOI.Nonpositives
cone), and the dual cone ofMOI.Nonpositives
isMOI.Nonpositives
- the dual of a \ge constraint is non-negative, because f(x) \ge y is rewritten to f(x) - y \in \mathbb{R}_+ (the
MOI.Nonnegatives
cone), and the dual cone ofMOI.Nonnegatives
isMOI.Nonnegatives
. - the dual of a = constraint is free, because f(x) = y is rewritten to f(x) - y \in {0} (the
MOI.Zeros
cone), and the dual of theMOI.Zeros
cone isMOI.Reals
Notably, this is the opposite to your statement that λ is required to be nonnegative
, so to convert to your assumed Lagragian, you need to add -
sign.
shadow_price
and reduced_cost
are mostly useful for people coming from a background in linear programming. There, shadow_price
is the change in the objective value as the constraint is relaxed, and the sign depends on whether we are maximizing or minimizing.