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?
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())