Logical conditions

I’m working on an optimization problem in JuMP where I need to ensure that certain constraints are enforced based on a binary variable. Here are the variables and constraints I have defined in my model:

Variable Definitions:

@variable(model, 0 <= x[1:n] <= 1)
@variable(model, 0 <= w[1:n, 1:T] <= 1)
@variable(model, 0 <= v[1:T] <= 1)
@variable(model, 0 <= wn[i=1:T, j=1:T] <= 1)
@variable(model, beta[1:T], Bin)


@constraint(model, sum_w[i=1:n], x[i] >= sum(w[i, j] for j in 1:T))
@constraint(model, sum_wn[i=1:T], v[i] >= sum(wn[i, j] for j in i:T))
@constraint(model, [t=1:T], v[t] <= beta[t])
@constraint(model, [i=1:n, t=1:T], w[i, t] <= 1 - beta[t])
@constraint(model, [i=1:T, t=1:T], wn[i, t] <= 1 - beta[t])

Desired Logic:

The binary variable \beta is used to enforce the following conditions:

When \beta[t] = 1:

  • Variable v[t] can take a positive value.

  • Variables w[i,t] and wn[i,t] must be zero.

When \beta[t] = 0:

  • Variable v[t] must be zero.

  • Variable wn[i,t] and w[i,t] can take positive values.

This is enforced by the last three constraints defined above.

To enforce that wn must hit its maximum possible values before w can take a positive value when \beta[t] = 0, I have defined the following constraint:

@constraint(model, [i=1:T, t=1:T], sum(wn[i, j] for j in i:T) - v[t] >= -beta[t])


Despite the above constraints, the results suggest that the variables wn are not necessarily taking their maximum possible value or even positive values before the variable w takes a positive value.


What could be going wrong with my current approach?

Try to use an SOS-1 approach here.

Disclaimer: sorry , I am on my phone :sweat_smile:.

Let x be the binary decision variable and p another one. To enforce that p can take arbitrary values if and only if b is equal to one use

(1-x)*p = 0

Or it’s relaxed counterpart

(1-x)*p <= eps

Which helps the solver to navigate the zero crossing. To hit the maximum use

(1-x)*(p-maxval) = 0

Or its relaxed counterpart.

I’ve tried using indicator constraint (to replace the last constraint) to enforce the conditions as well, but that gives same results. There is something incorrect in the way I’m trying to enforce the logical conditions.

Hi @papar,

You need to introduce a new binary variable:

n, T = 2, 3
model = Model()
@variables(model, begin
    0 <= x[1:n] <= 1
    0 <= w[1:n, 1:T] <= 1
    0 <= v[1:T] <= 1
    0 <= wn[1:T, 1:T] <= 1
    beta[1:T], Bin
    # new
    z_wn[1:T, 1:T], Bin
@constraints(model, begin
    [i in 1:n], x[i] >= sum(w[i, :])
    [i in 1:T], v[i] >= sum(wn[i, i:T])
    [t in 1:T], v[t] <= beta[t]
    [i in 1:n, t in 1:T], w[i, t] <= 1 - beta[t]
    [i in 1:T, t in 1:T], wn[i, t] <= 1 - beta[t]
    # new
    # z_wn can be 1 only if w_n is at it's maximum
    [i in 1:T, t in 1:T], z_wn[i, t] <= w_n[i, t]
    # w can be positive only if z_wn is 1
    [i in 1:n, t in 1:T], w[i, t] <= z_wn[i, t]

But w and wn are not the same size, so I don’t really know what constraint you intend?

We will have a problem with the following constraint:

# z_wn can be 1 only if w_n is at its maximum
[i in 1:T, t in 1:T], z_wn[i, t] <= w_n[i, t]

This is due to the constraint:

@constraint(model, sum_wn[i=1:T], v[i] >= sum(wn[i, j] for j in i:T))

Variables wn are restricted by variables v, and in most cases, both of these variables will take values less than 1. If we define the constraint as suggested, it will try to enforce wn variables to hit 1, which usually will not happen.

The maximum possible values of variables wn at t are given by:

wn_{i,t} = v_i - \sum_{j=i}^{t-1} wn_{i,j}

We will need to enforce this as constraint. This is why I was trying to defining a constraint to enforce sum(wn[i, j] for j in i:T) - v[t] >= 0

You are right that w and wn are the same size, but that doesn’t matter as the index t is the same across both, at which decisions are made based on the logical conditions.

Could you please provide further clarification or an alternative approach to correctly enforce the constraint that z_wn can be 1 only if wn is at its maximum as defined below? wn_{i,t} = v_i - \sum_{j=i}^{t-1} wn_{i,j}

I interpreted 'at the maximum" to be the upper bound.

You’ll need to change the constraint to something like

    [i in 1:T, t in 1:T], wn[i, t] <= v[i] - sum(wn[i, 1:t-1])
    # z_wn can be 1 only if w_n is at it's maximum
    [i in 1:T, t in 1:T], z_wn[i, t] <= 1 - (v[i] - sum(wn[i, 1:t-1]) - w_n[i, t])

but I didn’t check the details very carefully. I don’t know that I understand your variables very well.

You’re really just looking for a constraint like:
z_wn[i, t] <= 1 - (limit - wn[i, t])
So that if wn is less than limit, then the right-hand side is 1 - positive_value which forces z_wn to 0.

If limit is not in [0, 1] then you’ll need some additional scaling factor in there to get it to work.