Skip to content

Commit 174d617

Browse files
authored
[breaking] Fix a<=b to return a-b in Nonpositives instead of b-a in Nonnegatives (#593)
1 parent 7eb1726 commit 174d617

File tree

11 files changed

+18
-27
lines changed

11 files changed

+18
-27
lines changed

docs/src/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ changes.
2222
elementwise values. This does not affect the result of `relative_entropy`.
2323
* The function `constant` should be used instead of the type `Constant`
2424
(which now refers to exclusively real constants).
25+
* The constraint `a <= b` now produces `a - b in Nonpositives()` instead of
26+
`b - a in Nonnegatives()`. The primal solutions are equivalent, but **the
27+
dual variable associated with such constraints is now reversed in sign**.
28+
(Following the convention in MathOptInterface, the dual of `a <= b` is
29+
always negative, regardless of optimization sense.) (#593)
2530
* The syntaxes `dot(*)`, `dot(/)` and `dot(^)` have been removed in favor of
2631
explicit broadcasting (`x .* y`, `x ./ y`, and `x .^ y`). These were (mild)
2732
type piracy. In addition, `vecdot(x,y)` has been removed. Call

src/MOI_wrapper.jl

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,19 +310,13 @@ function MOI.get(
310310
return MOI.get(model.context.model, attr, ci)
311311
end
312312

313-
# See `constraints/constraints.jl`
314-
# `LessThan` constraints are reformulated as `rhs - lhs` unlike MOI while
315-
# `GreaterThan` constraints are reformulated as `lhs - rhs` like in MOI
316-
_flip_dual(x, ::Type{S}) where {S<:MOI.LessThan} = -x
317-
_flip_dual(x, ::Type{S}) where {S<:MOI.AbstractScalarSet} = x
318-
319313
function MOI.get(
320314
model::Optimizer,
321315
attr::Union{MOI.ConstraintDual,MOI.ConstraintPrimal},
322316
ci::MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,S},
323317
) where {S<:MOI.AbstractScalarSet}
324318
ret = MOI.get(model.context.model, attr, model.constraint_map[ci.value])
325-
return _flip_dual(ret[], S)
319+
return ret[]
326320
end
327321

328322
function MOI.get(model::Optimizer, I::Type{<:MOI.Index}, name::String)

src/atoms/exp_cone/LogSumExpAtom.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function new_conic_form!(context::Context, e::LogSumExpAtom)
3232
# log(sum(exp(x))) <= t <=> sum(exp(x)) <= exp(t) <=> sum(exp(x - t)) <= 1
3333
t = Variable()
3434
z = sum(exp(e.children[1] - t * ones(size(e.children[1]))))
35-
add_constraint!(context, z <= 1)
35+
add_constraint!(context, 1 >= z)
3636
return conic_form!(context, t)
3737
end
3838

src/atoms/lp_cone/DotSortAtom.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function new_conic_form!(context::Context{T}, x::DotSortAtom) where {T}
5050
y = vec(y)
5151
end
5252
μ, ν, e = Variable(size(y)), Variable(size(y)), ones(T, size(y))
53-
add_constraint!(context, y * x.w' <= e * ν' + μ * e')
53+
add_constraint!(context, e * ν' + μ * e' >= y * x.w')
5454
return conic_form!(context, sum(μ) + sum(ν))
5555
end
5656

src/atoms/lp_cone/MinAtom.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function new_conic_form!(context::Context, x::MinAtom)
4747
t = Variable(x.size)
4848
t_obj = conic_form!(context, t)
4949
for child in x.children
50-
add_constraint!(context, t <= child)
50+
add_constraint!(context, child >= t)
5151
end
5252
return t_obj
5353
end

src/atoms/lp_cone/MinimumAtom.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ evaluate(x::MinimumAtom) = minimum(evaluate(x.children[1]))
2424

2525
function new_conic_form!(context::Context, x::MinimumAtom)
2626
t = Variable()
27-
add_constraint!(context, t <= x.children[1])
27+
add_constraint!(context, x.children[1] >= t)
2828
return conic_form!(context, t)
2929
end
3030

src/atoms/lp_cone/SumLargestAtom.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function new_conic_form!(context::Context, x::SumLargestAtom)
4040
# sum k largest given by the solution to
4141
# minimize sum(t) + k*q
4242
# subject to c <= t + q, t >= 0
43-
add_constraint!(context, c <= t + q)
43+
add_constraint!(context, t + q >= c)
4444
add_constraint!(context, t >= 0)
4545
return conic_form!(context, sum(t) + x.k * q)
4646
end

src/constraints/LessThanConstraint.jl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,16 @@ function vexity(c::LessThanConstraint)
4040
end
4141

4242
function _add_constraint!(context::Context{T}, lt::LessThanConstraint) where {T}
43-
f = conic_form!(context, lt.rhs - lt.lhs)
43+
f = conic_form!(context, lt.lhs - lt.rhs)
4444
if f isa AbstractVector
4545
# a trivial constraint without variables like `5 <= 0`
46-
if !all(f .>= -CONSTANT_CONSTRAINT_TOL[])
46+
if !all(f .<= CONSTANT_CONSTRAINT_TOL[])
4747
@warn "Constant constraint is violated"
4848
context.detected_infeasible_during_formulation[] = true
4949
end
5050
return
5151
end
52-
set = MOI.Nonnegatives(MOI.output_dimension(f))
52+
set = MOI.Nonpositives(MOI.output_dimension(f))
5353
context.constr_to_moi_inds[lt] = MOI_add_constraint(context.model, f, set)
5454
return
5555
end
@@ -61,10 +61,6 @@ Base.:<=(lhs::AbstractExpr, rhs::Value) = <=(lhs, constant(rhs))
6161
Base.:<=(lhs::Value, rhs::AbstractExpr) = <=(constant(lhs), rhs)
6262

6363
function populate_dual!(model::MOI.ModelLike, c::LessThanConstraint, indices)
64-
# FIXME(odow): this dual is the 'wrong' sign, because Convex implements
65-
# rhs - lhs in Nonnegatives for a LessThanConstraint, instead of
66-
# lhs - rhs in Nonpositives.
67-
# Should we fix this?
6864
ret = MOI.get(model, MOI.ConstraintDual(), indices)
6965
c.dual = output(reshape(ret, c.size))
7066
return

src/problem_depot/problems/affine.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ end
762762

763763
handle_problem!(p)
764764
if test
765-
@test p.constraints[1].dual 1 atol = atol rtol = rtol
765+
@test p.constraints[1].dual -1 atol = atol rtol = rtol
766766
end
767767

768768
x = Variable()

src/problem_depot/problems/lp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
if test
1616
@test p.optval 1 atol = atol rtol = rtol
1717
@test evaluate(abs(x)) 1 atol = atol rtol = rtol
18-
@test p.constraints[1].dual 1 atol = atol rtol = rtol
18+
@test p.constraints[1].dual -1 atol = atol rtol = rtol
1919
end
2020

2121
x = Variable(2, 2)

0 commit comments

Comments
 (0)