# \`max\` constraints in JuMP

**URL:** <https://discourse.julialang.org/t/max-constraints-in-jump/8983>\
**Category:** Optimization (Mathematical)\
**Tags:** jump\
**Created:** [February 11, 2018, 12:09am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983 "2018-02-11T00:09:10Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jacob-roth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jacob-roth/32/1862_2.png) [@jacob-roth](https://discourse.julialang.org/u/jacob-roth)\
**Post date:** [February 11, 2018, 12:09am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983/1 "2018-02-11T00:09:10Z")

</div>

Similar to [this](https://discourse.julialang.org/t/help-rewriting-convex-jl-problem-in-jump-jl/4321) question, how can I formulate a constraint involving `max` of the form \sum\_{i=1}^m [z\_i + t]\_+ \leq c where [x]\_+ = \max(x,0), both t,c \in \mathbb{R}, and z = My \in \mathbb{R}^m for variable y \in \mathbb{R}^n with data matrix M \in \mathbb{R}^{m \times n}. My attempt is

```julia
m, n = size(M)
@variable(model, y[1:n])
@variable(model, t)
zz = [M[i,:]'*y + t for i=1:m]
z = [max(zz[i], 0.0) for i=1:m]
@constraint(model, sum(z) <= c)

```

but I got the following error:

```julia
MethodError: no method matching isless(::Float64, ::JuMP.GenericAffExpr{Float64,JuMP.Variable})

```

I tried adding a non-negative variable `s` and doing the following

```julia
m, n = size(M)
@variable(model, y[1:n])
@variable(model, t)
@variable(model, s >= 0.0)
z = [M[i,:]'*y + t for i=1:m]
@constraint(model, z >= s)
@constraint(model, sum(z) <= c)

```

but wasn’t sure if this is the standard way of adding this type of constraint. For example, is this what `Convex.jl` does, or where could I check?

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [February 11, 2018, 12:28am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983/2 "2018-02-11T00:28:23Z")

</div>

> [@jacob-roth](#):
>
> yy = [y’\*data[i] + t for i=1:ncols]  
> @constraint(model, max(yy, 0.0))

This makes no sense to me. `yy` is a bunch of expressions, and the “constraint” is not really constraining anything. Also `data[i]` should probably be `data[:,i]`. In the question you referred to, the OP was trying to minimize the sum of terms each of which is of the form `max(expr, 0)`, so the standard way is to define `z` and constrain `z >= expr` and `z >= 0`, then minimize `z` instead, which due to the minimization behavior of the optimization algorithm, `z` will eventually land on either `expr` or `0`, and in the process `expr` will be pushed as low as possible until it gets to or below `0`, then `z` will not push it down anymore.

---

<div class="post-metadata">

**Author:** ![jacob-roth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jacob-roth/32/1862_2.png) [@jacob-roth](https://discourse.julialang.org/u/jacob-roth)\
**Post date:** [February 11, 2018, 2:09am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983/3 "2018-02-11T02:09:19Z")

</div>

Thanks, my original question was off… Edited to reflect my issue better

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [February 11, 2018, 3:06am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983/4 "2018-02-11T03:06:54Z")

</div>

> [@jacob-roth](#):
>
> @variable(model, s \>= 0.0)

`@variable(model, s[1:m] >= 0.0)`

> [@jacob-roth](#):
>
> @constraint(model, z \>= s)

`@constraint(model, [i=1:m], s[i] >= z[i])`

> [@jacob-roth](#):
>
> @constraint(model, sum(z) \<= c)

`@constraint(model, sum(s[i] for i=1:m) <= c)`

Note that under this transformation, there is no guarantee that `s[i]` will be exactly equal to `max(z[i], 0)` (may or may not be the case depending on your objective). `s[i]` can take any value greater than or equal to `max(z[i], 0)` as long as `sum(s)` is less than or equal to `c`. But satisfying the transformed constraints clearly guarantees satisfying your original constraints. That is for every feasible solution (y\_f,t\_f,s\_f) to the transformed constraints, the solution (y\_f, t\_f) is guaranteed to satisfy your original constraints. And conversely, for every feasible solution (y\_f,t\_f) to the original constraints, there exists at least 1 feasible solution (y\_f,t\_f,s\_f) to the transformed constraints by setting s\_f[i] = max(z[i], 0) for example, so you are not “missing” on any feasible solution to the original constraints by replacing them with the transformed set of constraints.

---

<div class="post-metadata">

**Author:** ![jacob-roth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jacob-roth/32/1862_2.png) [@jacob-roth](https://discourse.julialang.org/u/jacob-roth)\
**Post date:** [February 11, 2018, 4:54am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983/5 "2018-02-11T04:54:08Z")

</div>

Thanks – the feasibility argument makes sense, but why did you constrain the sum of `s[i]` and not `z`?. Is there a way to doe the `max(z[i] + t, 0)` constraint precisely? In `Convex.jl`, I was able to solve the toy problem:

```julia
using Convex
using Mosek
m = 10
n = 3
t = Variable(1)
y = Variable(n)
M = randn(m,n)
c = 100
r = randn(n)
problem = minimize(r'*y)
problem.constraints += [t >= 0]
z = max.([M[i,:]'*y + t for i=1:m], 0.0)
problem.constraints += [sum(z) <= c]
solve!(problem, MosekSolver(),verbose=true) 
y.value

```

but don’t entirely know how `Convex` is treating that `max` constraint.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [February 11, 2018, 5:39am UTC](https://discourse.julialang.org/t/max-constraints-in-jump/8983/6 "2018-02-11T05:39:30Z")

</div>

The above transformation will do precisely what you want, just ignore `s` in the final solution, it doesn’t add any semantics to your model. As for Convex.jl, I haven’t read the src but one possibility is that Convex.jl is doing the same transformation under the hood and is hiding away the `s` details from you, so you only see what you want to see. Or another possibility is that the `max` expression is processed as a non-smooth function using sub-gradients, I have no idea which one it is using.
