Skip to content

How do I convert an LpSum to an LPConstraint?

An answer to this question on Stack Overflow.

Question

In Pulp I have constraints of the form,

lpSum([decision_vars[an_id][item] for item in a_vector]) == count_req[an_id], f'constraint_{user_id}'

and I want to convert this to use LpConstraint as a stepping stone to making this constraint elastic. i.e. LpConstraint(...).makeElasticSubProblem(...)

LpConstraint(
    e=pl.lpSum([decision_vars[an_id][item] for item in a_vector]), 
    sense=LpConstraintEQ,
    rhs=count_req[an_id],
    name=f'constraint_{an_id}'
)

Are these equivalent?

Is there some cleaner example or documentation for converting an lpSum to an LpConstraint?

Answer

It's maybe not the answer you're looking for, but I recommend against using PuLP. cvxpy is easier to learn and use (free variables instead of variables bound to models) and allows you to easily extend your models to nonlinear convex systems, which gives you much more bang for your buck in terms of effort put into learning versus capability obtained.

For instance, in cvxpy, your problem might be cast as:

from collections import defaultdict
from cvxpy import cp
decision_vars = {}
for an_id in ids:
  for item in a_vector:
    decision_vars[an_id][item] = cp.Variable(pos=True)
constraints = []
for an_id in ids:
  my_sum = sum(x for x in decision_vars[an_id].values())
  constraints.append(count_req[an_id]*lower_proportion <= my_sum)
  constraints.append(my_sum <= count_req[an_id]*upper_proportion)
problem = cp.Problem(cp.Minimize(OBJECTIVE_HERE), constraints)
optimal_value = problem.solve()
for an_id in ids:
  for item in a_vector:
    print(f"{an_id} {item} {decision_vars[an_id][item].value}")

Note that the use of free variables means that we can use standard Python constructs like dictionaries, sums, and comparison operators to build our problem. Sure, you have to construct the elastic constraint manually, but that's not challenging.