pulp: Pulp classes
|
An LP Problem |
|
Thin wrapper over the Rust Variable. |
|
Thin wrapper around Rust AffineExpr. |
|
LP constraint backed by Rust for a row already stored in the model. |
The LpProblem Class
- class pulp.LpProblem(name: str = 'NoName', sense: int = 1)
Bases:
objectAn LP Problem
Creates an LP Problem
This function creates a new LP Problem with the specified associated parameters
- Parameters:
name – name of the problem used in the output .lp file
sense – of the LP problem objective. Either
LpMinimize(default) orLpMaximize.
- Returns:
An LP Problem
An important attribute of the problem is:
- objective
The objective of the problem, an
LpAffineExpression
Creating variables (see How to create variables):
- add_variable(name: str, lowBound: int | float | Decimal | None = None, upBound: int | float | Decimal | None = None, cat: Literal['Continuous', 'Integer', 'Binary'] = 'Continuous') LpVariable
Create a variable in this problem and return it.
- Parameters:
name – the variable’s name
lowBound – lower bound (
None: no bound); must be finiteupBound – upper bound (
None: no bound); must be finitecat –
"Continuous","Integer"or"Binary"(stored as an integer variable with bounds 0 and 1)
- add_variable_dicts(name: str, indices: tuple[Iterable[Any], ...] | Iterable[Any] | None = None, lowBound: int | float | Decimal | None = None, upBound: int | float | Decimal | None = None, cat: Literal['Continuous', 'Integer', 'Binary'] = 'Continuous', indexStart: list[Any] | None = None) dict[Any, Any]
Create one variable per index value and return them in a dictionary.
- Parameters:
name – prefix of the variable names. One
_%sper index is appended unlessnamealready contains%splaceholders.indices – an iterable of index values, or a tuple of iterables for several indices. Several indices give nested dictionaries, one level per index.
lowBound – lower bound of every variable (
None: no bound)upBound – upper bound of every variable (
None: no bound)cat –
"Continuous","Integer"or"Binary"indexStart – index values already used in the name (used for the nested levels)
- Returns:
{index: variable}, or{i: {j: variable}}for two indices, and so on
>>> buy = prob.add_variable_dicts("buy", ["A", "B"], lowBound=0) >>> buy["A"].name 'buy_A' >>> flow = prob.add_variable_dicts("flow", (["A", "B"], [1, 2]), cat="Integer") >>> flow["A"][2].name 'flow_A_2'
- add_variable_dict(name: str, indices: tuple[Iterable[Any], ...] | Iterable[Any] | None, lowBound: int | float | Decimal | None = None, upBound: int | float | Decimal | None = None, cat: Literal['Continuous', 'Integer', 'Binary'] = 'Continuous') dict[Any, LpVariable]
Create one variable per combination of the indices and return them in one flat dictionary keyed by tuples (by value for a single index). Takes the same arguments as
add_variable_dicts().>>> assign = prob.add_variable_dict("assign", (["A", "B"], [1, 2])) >>> assign["A", 1].name 'assign_A_1'
- add_variable_matrix(name: str, indices: tuple[Iterable[Any], ...] | Iterable[Any] | None = None, lowBound: int | float | Decimal | None = None, upBound: int | float | Decimal | None = None, cat: Literal['Continuous', 'Integer', 'Binary'] = 'Continuous', indexStart: list[Any] | None = None) list[Any]
Create one variable per index value and return them in a list, or nested lists for several indices, indexed by position. Takes the same arguments as
add_variable_dicts().>>> grid = prob.add_variable_matrix("grid", (["A", "B"], [1, 2])) >>> grid[0][1].name 'grid_A_2'
Constraints (see How to edit constraints):
- addConstraint(constraint: LpAffineExpression, name: str | None = None) LpConstraint
Adds
constraint(an expression with a sense) and returns it as stored in the problem. Edit the returnedLpConstraintto change the problem; editingconstraintafterwards does not.
- constraints() list[LpConstraint]
The problem’s constraints (
LpConstraint), in the order they were added. Editing them edits the problem.
- get_constraint_by_name(name: str) LpConstraint | None
The constraint called
name, orNoneif there is none.
Column-wise modelling (see How to model column-wise):
- add_column(name: str, lowBound: int | float | Decimal | None = None, upBound: int | float | Decimal | None = None, cat: Literal['Continuous', 'Integer', 'Binary'] = 'Continuous', obj: float = 0.0, coefficients: Mapping[LpConstraint, float] | None = None) LpVariable
Add a variable column-wise: with objective coefficient
objand itscoefficientsin constraints already in the problem (column generation). Returns the new LpVariable.- Parameters:
coefficients –
{constraint: coefficient}for constraints of this problem (LpConstraint, e.g. as returned byaddConstraint()); zeros are skipped- Raises:
ValueError – on an infinite or NaN coefficient; the problem is left unchanged
>>> c = prob.addConstraint(x >= 1, "c") >>> y = prob.add_column("y", 0, 1, obj=2, coefficients={c: 1})
- remove_variables(variables: Iterable[LpVariable]) None
Drop
variablesfrom every constraint, the objective and every SOS group. The variables themselves stay valid but unused, so the solvers and the LP/MPS writers leave them out.
Some of the more important methods:
- solve(solver: LpSolver | None = None, **kwargs: Any) LpSolveStats
Solve the given Lp problem.
- Parameters:
solver – Optional: the specific solver to be used, defaults to the problem’s solver, then to the default solver.
- Returns:
an
LpSolveStatsdescribing the solve
- Side Effects:
The variables and constraints of the problem get the values of the solution the solver handed back
- roundSolution(epsInt: float = 1e-05, eps: float = 1e-07) None
Rounds the lp variables
- Inputs:
none
- Side Effects:
The lp variables are rounded
- setObjective(obj: LpAffineExpression | LpVariable | int | float) None
Sets the objective function.
- Parameters:
obj – the objective function (LpAffineExpression, LpVariable, or numeric)
- Side Effects:
The objective function is set
- writeLP(filename: str, writeSOS: int | bool = 1, mip: bool = True, max_length: int = 100) list[LpVariable]
Write the given Lp problem to a .lp file.
This function writes the specifications (objective function, constraints, variables) of the defined Lp problem to a file.
- Parameters:
filename (str) – the name of the file to be created.
- Returns:
variables
- Side Effects:
The file is created
- writeMPS(filename: str, mpsSense: int = 0, rename: bool = False, mip: bool = True, with_objsense: bool = False) tuple[list[str], list[str], str, list[str]]
Writes an mps file from the problem information.
- Parameters:
filename – name of the file to write
mpsSense – 0 (use problem sense), 1 minimize, -1 maximize
rename – if True, normalized names (X0000000, C0000000) are used in the file
mip – include integer/binary markers
with_objsense – write OBJSENSE section
- Returns:
(variable_names, constraint_names, objective_name, pulp_names_in_column_order)
- toJson(filename: str, *args: Any, **kwargs: Any) None
Creates a json file from the LpProblem information
- Parameters:
filename (str) – filename to write json
args – additional arguments for json function
kwargs – additional keyword arguments for json function
- Returns:
None
- classmethod fromJson(filename: str) tuple[dict[str, LpVariable], LpProblem]
Creates a new LpProblem from a json file with information
- variables() list[LpVariable]
Problem variables from the Rust model, in id order (same order as
constraints()).
Variables and Expressions
- class pulp.LpVariable(_var: Variable)
Thin wrapper over the Rust Variable. Created only via LpProblem.add_variable() or add_variable_dicts/dict/matrix.
- classmethod fromDataclass(problem: LpProblem, mps: mpslp.MPSVariable)
Initializes a variable from a dataclass by adding it to the given problem.
- Parameters:
problem – the problem to add the variable to
mps – a
mpslp.MPSVariablewith the variable information
- Returns:
- classmethod fromDict(problem: LpProblem, data: dict[str, Any])
Initializes a variable from a dict by adding it to the given problem.
- Parameters:
problem – the problem to add the variable to
data – a dict with the variable information
- Returns:
- toDataclass() MPSVariable
Exports a variable into a dataclass with its relevant information
- Returns:
a
mpslp.MPSVariablewith the variable information- Return type:
:mpslp.MPSVariable
Example (variables are created from a problem):
>>> prob = LpProblem("example", LpMinimize)
>>> x = prob.add_variable('x', lowBound=0, cat='Continuous')
>>> y = prob.add_variable('y', upBound=5, cat='Integer')
gives \(x \in [0,\infty)\), \(y \in (-\infty, 5]\), an integer.
- class pulp.LpAffineExpression(_expr: AffineExpr)
Bases:
objectThin wrapper around Rust AffineExpr. A linear combination of LpVariables + constant. Optionally carries a constraint sense (for pending constraints created by <=, >=, ==).
- Use factory class methods to create instances:
LpAffineExpression.empty()
LpAffineExpression.from_variable(v)
LpAffineExpression.from_constant(c)
LpAffineExpression.from_dict({v: coeff, …})
LpAffineExpression.from_list([(v, coeff), …])
In brief, \(\textsf{LpAffineExpression([(x[i],a[i]) for i in I])} = \sum_{i \in I} a_i x_i\) where (note the order):
x[i]is anLpVariablea[i]is a numerical coefficient.
- pulp.lpSum(vector: Iterable[LpAffineExpression | LpVariable | int | float] | Iterable[tuple[LpVariable, float]] | int | float | LpVariable) LpAffineExpression
Calculate the sum of a list of linear expressions
- Parameters:
vector – A list of linear expressions
Constraints
- class pulp.LpConstraint(_constr: Constraint)
Bases:
objectLP constraint backed by Rust for a row already stored in the model.
Instances appear in
LpProblem.constraints()as a list in model order; they are not pending expressions and must not be combined with+/-on affine expressions. Usecopy()to obtain a pendingLpAffineExpression.Editing an instance edits the row in the problem:
c[x] = 2,del c[x],c.changeRHS(3),c.sense = ...orc += y.A constraint of a problem, as returned by
LpProblem.addConstraint(),LpProblem.constraints()andLpProblem.get_constraint_by_name(). Editing it edits the problem:>>> c = prob.addConstraint(x + y <= 5, "c") >>> c[x] = 2 # 2*x + y <= 5 >>> c.changeRHS(8) # 2*x + y <= 8 >>> c += 3 # 2*x + y <= 5
Editing the expression that was added does not; see How to edit constraints.
- __delitem__(key: LpVariable) None
del c[x]: removexfrom this constraint.
- __iadd__(other: Any) LpConstraint
c += expr: addexprto the left-hand side.
- __isub__(other: Any) LpConstraint
c -= expr: subtractexprfrom the left-hand side.
- __setitem__(key: LpVariable, value: float) None
c[x] = value: same asset_coefficient().
- addInPlace(other: Any, sign: Literal[1, -1] = 1) LpConstraint
Add
other(variable, expression, number…) to this row’s left-hand side.
- copy() LpAffineExpression
Return a pending LpAffineExpression copy with sense set.
- set_coefficient(var: LpVariable, coefficient: float) None
Set
var’s coefficient in this constraint (0 removes the term), e.g. to add a new column to existing rows.
Combinations and Permutations
- pulp.combination(iterable, r)
Return successive r-length combinations of elements in the iterable.
combinations(range(4), 3) –> (0,1,2), (0,1,3), (0,2,3), (1,2,3)
- pulp.allcombinations(orgset: list[Any], k: int) Iterator[tuple[Any, ...]]
returns all combinations of orgset with up to k items
- Parameters:
orgset – the list to be iterated
k – the maxcardinality of the subsets
- Returns:
an iterator of the subsets
example:
>>> c = allcombinations([1,2,3,4],2) >>> for s in c: ... print(s) (1,) (2,) (3,) (4,) (1, 2) (1, 3) (1, 4) (2, 3) (2, 4) (3, 4)
- pulp.permutation(iterable, r=None)
Return successive r-length permutations of elements in the iterable.
permutations(range(3), 2) –> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)
- pulp.allpermutations(orgset: list[Any], k: int) Iterator[tuple[Any, ...]]
returns all permutations of orgset with up to k items
- Parameters:
orgset – the list to be iterated
k – the maxcardinality of the subsets
- Returns:
an iterator of the subsets
example:
>>> c = allpermutations([1,2,3,4],2) >>> for s in c: ... print(s) (1,) (2,) (3,) (4,) (1, 2) (1, 3) (1, 4) (2, 1) (2, 3) (2, 4) (3, 1) (3, 2) (3, 4) (4, 1) (4, 2) (4, 3)