Equivalent of the logical any() in PuLP

66 Views Asked by At

Im using PuLP to solve a big MILP. As part of a more complex system of restrictions, I have an array of Boolean decision variables var_array, and an individual Boolean variable var_all_zeros.

I am trying and failing to build a restriction that var_all_zeros needs to be False if any of the var_array are True.

So I am looking for an equivalent to the python logical any(), but for PuLP.

What I want to put into a restriction is:

var_all_zeros = False if any(var_array) else True

One (mathematically) possible way to add a restriction to the problem: would be to put


problem = pulp.LpProblem("Boolean_Optimization", pulp.LpMaximize)
problem += pl.LPSum(var_array) * var_all_zeros == 0

This would mathematically enable the constraint, as var_all_zeros can only be True if sum(var_array) is zero, otherwise it has to be False.

But this is not allowed in PuLP, as decision variables cannot be multiplied with one another.

Any suggestions on how to encode this restriction?

2

There are 2 best solutions below

1
Reinderien On BEST ANSWER

You only need one (or maybe two, depending on how the variable is used) constraints - not one constraint row per entry in var_array.

import pulp

prob = pulp.LpProblem(name='Boolean_Optimization', sense=pulp.LpMaximize)

n = 4
var_array = pulp.LpVariable.matrix(
    name='var_array',
    indices=range(n),
    cat=pulp.LpBinary,
)
var_all_zeros = pulp.LpVariable(
    name='var_all_zeros',
    cat=pulp.LpBinary,
)
prob.addConstraint(
    name='all_zeros_upper',
    constraint=var_all_zeros <= 1 - 1/(n + 1)*pulp.lpSum(var_array),
)
prob.addConstraint(
    name='all_zeros_lower',
    constraint=var_all_zeros >= 0.5 - pulp.lpSum(var_array),
)

# Adjust to see different outputs
prob.objective = pulp.lpDot(var_array, (1, -1, -1, -1))

print(prob)
prob.solve()
assert prob.status == pulp.LpStatusOptimal
print('var_array =', [v.value() for v in var_array])
print('var_all_zeros =', var_all_zeros.value())
0
AirSquid On

You just need to constrain your summary variable to be less than each of the values in the array to build the "or" condition:

var_all_zeros <= 1 - var_array[i]  for each i in I