coin-or / pulp

A python Linear Programming API
http://coin-or.github.io/pulp/
Other
2.09k stars 383 forks source link

Convenient support for conjunctions and disjunctions #760

Open lverweijen opened 3 months ago

lverweijen commented 3 months ago

Occasionally, real life constraints may get the form of:

if is_married then age >= 18

These can be expressed in pulp by writing something like this:

BIG_CONSTANT = 99999
age = LpVar('age', 'Integer')
is_married = LpVar('is_married', 'Boolean')

constraint = age + (1 - is_married) * BIG_CONSTANT >= 18

but it isn't very readable.

Describe the new feature

I was thinking of adding conjunction and disjunction helpers lpOr and lpAnd that automatically convert constraints. These operators should become nestable.

Then we can write something like this:

constraint = lpOr([is_married < 1, age >= 18])

Even more convenient would be to extend & and | operators of LpConstraint, so this can be written as:

constraint = (is_married < 1) | (age >= 18)

However, there is a conflict, because LpConstraint is inheriting from OrderedDict which already implements |. Maybe consider not inheriting from MutableMapping or accept an exception to this protocol.

More consequences of this:

Additional info

Please answer these questions before submitting your feature request.

Does this feature exist in another product or project? Please provide a link.

Not sure, but Gurobi seems to support some mathematical operators as general constraints: https://www.gurobi.com/documentation/current/refman/general_constraints.html

lverweijen commented 2 months ago

In https://github.com/lverweijen/FellegiHolt/blob/main/fellegiholt/rewrite_linear.py I managed to convert a few rules to linear ones like 'and', 'or', 'not', 'implication'. I took a different approach from above and started directly convert ast.Nodes. There might be better ways of doing this, but it works for me. I would still be interested in having something like this.