CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pulp

PuLP is a linear and mixed integer programming modeler that provides an intuitive Python interface for creating, manipulating, and solving mathematical optimization problems.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

constants-enums.mddocs/

Constants and Enums

Essential constants for variable categories, problem senses, constraint types, and status codes used throughout PuLP's modeling system. These constants provide standardized values for optimization problem specification and solution interpretation.

Capabilities

Package Metadata

Version information and precision constants for the PuLP package.

VERSION: str = "3.2.2"  # PuLP package version
EPS: float = 1e-7       # Default numerical precision tolerance

Variable Categories

Constants defining the types of decision variables supported in optimization problems.

LpContinuous: str = "Continuous"  # Continuous variables (real numbers)
LpInteger: str = "Integer"        # Integer variables (whole numbers)
LpBinary: str = "Binary"          # Binary variables (0 or 1)

LpCategories: dict = {
    LpContinuous: "Continuous",
    LpInteger: "Integer", 
    LpBinary: "Binary"
}  # Mapping of category constants to string representations

Usage examples:

# Create variables with different categories
x_cont = LpVariable("x", cat=LpContinuous)    # Can take any real value
y_int = LpVariable("y", cat=LpInteger)        # Must be whole number
z_bin = LpVariable("z", cat=LpBinary)         # Must be 0 or 1

# Check variable category
if x_cont.cat == LpContinuous:
    print("x is a continuous variable")

# Use in bulk creation
binary_vars = LpVariable.dicts("decision", range(10), cat=LpBinary)

Optimization Senses

Constants specifying whether the optimization problem seeks to minimize or maximize the objective function.

LpMinimize: int = 1   # Minimize the objective function
LpMaximize: int = -1  # Maximize the objective function

LpSenses: dict = {
    LpMinimize: "Minimize",
    LpMaximize: "Maximize"
}  # Mapping of sense constants to string representations

LpSensesMPS: dict = {
    LpMaximize: "MAX",
    LpMinimize: "MIN" 
}  # MPS format sense representations

Usage examples:

# Create problems with different senses
min_prob = LpProblem("Cost_Minimization", LpMinimize)
max_prob = LpProblem("Profit_Maximization", LpMaximize)

# Check problem sense
if min_prob.sense == LpMinimize:
    print("This is a minimization problem")

# Convert sense to string
print(f"Problem sense: {LpSenses[min_prob.sense]}")

Problem Status Constants

Status codes returned after solving optimization problems, indicating the solution state.

LpStatusNotSolved: int = 0   # Problem has not been solved yet
LpStatusOptimal: int = 1     # Optimal solution found
LpStatusInfeasible: int = -1 # Problem has no feasible solution
LpStatusUnbounded: int = -2  # Problem is unbounded (infinite optimum)
LpStatusUndefined: int = -3  # Solution status is undefined/unknown

LpStatus: dict = {
    LpStatusNotSolved: "Not Solved",
    LpStatusOptimal: "Optimal",
    LpStatusInfeasible: "Infeasible", 
    LpStatusUnbounded: "Unbounded",
    LpStatusUndefined: "Undefined"
}  # Mapping of status codes to descriptive strings

Usage examples:

# Solve problem and check status
status = prob.solve()

if status == LpStatusOptimal:
    print("Optimal solution found!")
    print(f"Objective value: {value(prob.objective)}")
elif status == LpStatusInfeasible:
    print("Problem is infeasible - no solution exists")
elif status == LpStatusUnbounded:
    print("Problem is unbounded - infinite optimum")
else:
    print(f"Solution status: {LpStatus[status]}")

# Robust status checking
def interpret_solution(status):
    return LpStatus.get(status, f"Unknown status: {status}")

print(interpret_solution(status))

Solution Status Constants

Detailed solution status codes providing more granular information about the solution quality and type.

LpSolutionNoSolutionFound: int = 0    # No solution found by solver
LpSolutionOptimal: int = 1            # Optimal solution found
LpSolutionIntegerFeasible: int = 2    # Integer feasible solution (may not be optimal)
LpSolutionInfeasible: int = -1        # No feasible solution exists
LpSolutionUnbounded: int = -2         # Unbounded solution

LpSolution: dict = {
    LpSolutionNoSolutionFound: "No Solution Found",
    LpSolutionOptimal: "Optimal",
    LpSolutionIntegerFeasible: "Integer Feasible",
    LpSolutionInfeasible: "Infeasible",
    LpSolutionUnbounded: "Unbounded"
}  # Solution status to string mappings

LpStatusToSolution: dict = {
    LpStatusNotSolved: LpSolutionNoSolutionFound,
    LpStatusOptimal: LpSolutionOptimal,
    LpStatusInfeasible: LpSolutionInfeasible,
    LpStatusUnbounded: LpSolutionUnbounded,
    LpStatusUndefined: LpSolutionNoSolutionFound
}  # Mapping from problem status to solution status

Usage examples:

# Get detailed solution information
status = prob.solve()
solution_status = LpStatusToSolution[status]

print(f"Problem status: {LpStatus[status]}")
print(f"Solution status: {LpSolution[solution_status]}")

# Handle different solution qualities
if solution_status == LpSolutionOptimal:
    print("Found proven optimal solution")
elif solution_status == LpSolutionIntegerFeasible:
    print("Found feasible integer solution (may not be optimal)")

Constraint Senses

Constants defining the mathematical relationship types for constraints (less than or equal, equal, greater than or equal).

LpConstraintLE: int = -1  # Less than or equal constraint (<=)
LpConstraintEQ: int = 0   # Equality constraint (=)
LpConstraintGE: int = 1   # Greater than or equal constraint (>=)

LpConstraintSenses: dict = {
    LpConstraintLE: "<=",
    LpConstraintEQ: "=", 
    LpConstraintGE: ">="
}  # Constraint sense to symbol mapping

LpConstraintTypeToMps: dict = {
    LpConstraintLE: "L",
    LpConstraintEQ: "E",
    LpConstraintGE: "G"
}  # MPS format constraint type codes

Usage examples:

# Create constraints with explicit senses
constraint1 = LpConstraint(x + y, LpConstraintLE, "capacity", 100)  # x + y <= 100
constraint2 = LpConstraint(2*x, LpConstraintEQ, "balance", 50)      # 2*x = 50
constraint3 = LpConstraint(y, LpConstraintGE, "minimum", 10)        # y >= 10

# Add to problem
prob += constraint1
prob += constraint2  
prob += constraint3

# Check constraint sense
print(f"Constraint sense: {LpConstraintSenses[constraint1.sense]}")

# Programmatic constraint generation
def create_constraint(expr, sense_type, rhs):
    if sense_type == "<=":
        sense = LpConstraintLE
    elif sense_type == "=":
        sense = LpConstraintEQ
    elif sense_type == ">=":
        sense = LpConstraintGE
    else:
        raise ValueError(f"Unknown constraint sense: {sense_type}")
    
    return LpConstraint(expr, sense, rhs=rhs)

# Use constraint senses in loops
capacity_constraints = []
for i in range(n_facilities):
    constraint = LpConstraint(
        lpSum(production[i]), 
        LpConstraintLE, 
        f"capacity_{i}", 
        facility_capacity[i]
    )
    capacity_constraints.append(constraint)
    prob += constraint

File Format Constants

Constants for file formatting and solver compatibility, particularly for MPS and LP file formats.

LpCplexLPLineSize: int = 78  # Maximum line length for CPLEX LP format files

Usage example:

# Used internally when writing LP format files
# Ensures compatibility with CPLEX and other solvers that expect specific line lengths
prob.writeLP("problem.lp")  # Automatically handles line length constraints

Status and Error Checking Utilities

Utility functions and patterns for robust status checking and error handling.

# Common status checking patterns
def check_solution_status(problem):
    """Check and report problem solution status."""
    status = problem.status
    
    if status == LpStatusOptimal:
        return True, "Optimal solution found"
    elif status == LpStatusInfeasible:
        return False, "Problem is infeasible"
    elif status == LpStatusUnbounded: 
        return False, "Problem is unbounded"
    elif status == LpStatusNotSolved:
        return False, "Problem not solved yet"
    else:
        return False, f"Unknown status: {LpStatus.get(status, status)}"

# Robust solution extraction
def safe_get_values(variables):
    """Safely extract variable values with status checking."""
    results = {}
    for var in variables:
        val = value(var)
        if val is not None:
            results[var.name] = val
        else:
            results[var.name] = "Not solved"
    return results

# Status-based decision making
def handle_solution(prob):
    status = prob.solve()
    
    if status in [LpStatusOptimal, LpSolutionIntegerFeasible]:
        # Process successful solution
        return extract_solution(prob)
    elif status == LpStatusInfeasible:
        # Analyze infeasibility
        return analyze_infeasibility(prob)
    elif status == LpStatusUnbounded:
        # Handle unbounded case
        return add_bounds_and_retry(prob)
    else:
        # Handle other cases
        return handle_solve_failure(prob, status)

Exception Types

class PulpError(Exception):
    """
    Base exception class for PuLP-specific errors.
    Raised for general PuLP modeling and solving errors.
    """

class PulpSolverError(Exception):
    """
    Exception class for solver-specific errors.
    Raised when solver execution fails or returns unexpected results.
    """

Usage examples:

try:
    status = prob.solve(CPLEX_CMD())
except PulpSolverError as e:
    print(f"Solver error: {e}")
    # Try alternative solver
    status = prob.solve(PULP_CBC_CMD())
except PulpError as e:
    print(f"PuLP error: {e}")
    # Handle general PuLP errors

Install with Tessl CLI

npx tessl i tessl/pypi-pulp

docs

constants-enums.md

core-modeling.md

file-io.md

index.md

mathematical-operations.md

solver-interfaces.md

utility-functions.md

tile.json