PuLP is a linear and mixed integer programming modeler that provides an intuitive Python interface for creating, manipulating, and solving mathematical optimization problems.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Functions and classes for reading and writing optimization problems in standard formats (MPS, LP) and handling structured problem data. These capabilities enable interoperability with various optimization solvers and external systems.
Functions for writing PuLP problems to standard optimization file formats that can be read by various solvers and optimization software.
def writeLP(prob, filename):
"""
Write optimization problem to LP (Linear Program) format file.
Parameters:
- prob (LpProblem): Problem to export
- filename (str): Output file path with .lp extension
Note: LP format is human-readable and widely supported by solvers.
Automatically handles line length constraints for CPLEX compatibility.
Examples:
writeLP(prob, "mymodel.lp")
writeLP(prob, "/path/to/problem.lp")
"""
def writeMPS(prob, filename):
"""
Write optimization problem to MPS (Mathematical Programming System) format file.
Parameters:
- prob (LpProblem): Problem to export
- filename (str): Output file path with .mps extension
Note: MPS format is the industry standard for optimization problems.
Provides precise numerical representation and broad solver compatibility.
Examples:
writeMPS(prob, "mymodel.mps")
writeMPS(prob, "/path/to/problem.mps")
"""Usage examples:
# Create and solve a problem
prob = LpProblem("Export_Example", LpMinimize)
x = LpVariable("x", 0, 10)
y = LpVariable("y", 0, 5)
prob += 2*x + 3*y
prob += x + y <= 8
prob += 2*x - y >= 1
# Export to different formats
writeLP(prob, "example.lp") # Human-readable LP format
writeMPS(prob, "example.mps") # Standard MPS format
# Export with paths
import os
output_dir = "optimization_models"
os.makedirs(output_dir, exist_ok=True)
writeLP(prob, os.path.join(output_dir, f"{prob.name}.lp"))
writeMPS(prob, os.path.join(output_dir, f"{prob.name}.mps"))
# Export for different solvers
writeLP(prob, "for_glpk.lp") # GLPK can read LP format
writeMPS(prob, "for_cplex.mps") # CPLEX prefers MPS format
writeMPS(prob, "for_gurobi.mps") # Gurobi supports both, MPS more preciseFunctions for reading optimization problems from standard file formats into PuLP problem objects.
def readMPS(path, sense, dropConsNames=False):
"""
Read optimization problem from MPS format file.
Parameters:
- path (str): Path to MPS file to read
- sense: Optimization sense (LpMinimize or LpMaximize)
- dropConsNames (bool): Whether to ignore constraint names from file
Returns:
LpProblem: Problem object created from MPS file data
Note: Enables importing problems created by other optimization software
or previously exported PuLP problems.
Examples:
prob = readMPS("external_model.mps", LpMinimize)
prob = readMPS("backup.mps", LpMaximize, dropConsNames=True)
"""Usage examples:
# Import problems from external sources
external_prob = readMPS("industry_model.mps", LpMinimize)
print(f"Imported problem: {external_prob.name}")
print(f"Variables: {len(external_prob.variables())}")
print(f"Constraints: {len(external_prob.constraints)}")
# Solve imported problem
status = external_prob.solve()
if status == LpStatusOptimal:
print("External model solved successfully")
for var in external_prob.variables():
if value(var) is not None:
print(f"{var.name} = {value(var)}")
# Import and modify problems
base_prob = readMPS("base_model.mps", LpMinimize)
# Add additional constraints to imported problem
additional_vars = [var for var in base_prob.variables() if 'production' in var.name]
if additional_vars:
base_prob += lpSum(additional_vars) >= 100 # Minimum production constraint
# Re-export modified problem
writeMPS(base_prob, "modified_model.mps")Classes for representing and manipulating MPS format components, providing detailed control over problem structure and data.
class MPS:
"""
Complete MPS format representation containing all problem components.
Provides structured access to problem data for advanced manipulation.
"""
def __init__(self): ...
@property
def variables(self): ... # Access to variable definitions
@property
def constraints(self): ... # Access to constraint definitions
@property
def objective(self): ... # Access to objective function
@property
def parameters(self): ... # Access to problem parameters
class MPSParameters:
"""
Problem parameters section of MPS format.
Contains solver settings and problem configuration data.
"""
def __init__(self): ...
class MPSObjective:
"""
Objective function data in MPS format.
Represents the cost/profit coefficients and optimization sense.
"""
def __init__(self): ...
@property
def coefficients(self): ... # Variable coefficients in objective
@property
def sense(self): ... # Minimization or maximization
@property
def name(self): ... # Objective function name
class MPSVariable:
"""
Variable data in MPS format.
Contains variable definitions, bounds, and type information.
"""
def __init__(self): ...
@property
def name(self): ... # Variable name
@property
def bounds(self): ... # Lower and upper bounds
@property
def variable_type(self): ... # Continuous, integer, or binary
class MPSConstraint:
"""
Constraint data in MPS format.
Represents constraint coefficients, bounds, and relationship types.
"""
def __init__(self): ...
@property
def name(self): ... # Constraint name
@property
def coefficients(self): ... # Variable coefficients
@property
def sense(self): ... # <=, =, or >= relationship
@property
def rhs(self): ... # Right-hand side value
class MPSCoefficient:
"""
Individual coefficient data in MPS format.
Represents variable-constraint coefficient pairs.
"""
def __init__(self): ...
@property
def variable(self): ... # Associated variable
@property
def constraint(self): ... # Associated constraint
@property
def value(self): ... # Coefficient valueUsage examples:
# Advanced MPS file manipulation
def analyze_mps_structure(mps_file_path):
"""Analyze the structure of an MPS file."""
prob = readMPS(mps_file_path, LpMinimize)
print(f"Problem Analysis: {prob.name}")
print(f"Variables: {len(prob.variables())}")
print(f"Constraints: {len(prob.constraints)}")
# Analyze variable types
var_types = {}
for var in prob.variables():
var_type = var.cat
var_types[var_type] = var_types.get(var_type, 0) + 1
print("Variable types:")
for vtype, count in var_types.items():
print(f" {vtype}: {count}")
# Analyze constraint senses
constraint_senses = {}
for constraint in prob.constraints.values():
sense = constraint.sense
sense_str = LpConstraintSenses.get(sense, str(sense))
constraint_senses[sense_str] = constraint_senses.get(sense_str, 0) + 1
print("Constraint types:")
for sense, count in constraint_senses.items():
print(f" {sense}: {count}")
# Create MPS data programmatically
def create_structured_mps_problem():
"""Create a problem with detailed MPS structure."""
prob = LpProblem("Structured_MPS_Example", LpMinimize)
# Create variables with detailed naming
production_vars = LpVariable.dicts("production",
["plant1", "plant2", "plant3"],
0, 1000, LpContinuous)
binary_decisions = LpVariable.dicts("use_plant",
["plant1", "plant2", "plant3"],
cat=LpBinary)
# Structured constraints with meaningful names
prob += (lpSum(production_vars), "total_production_limit", 2500)
for plant in production_vars:
# Production can only occur if plant is used
prob += (production_vars[plant] <= 1000 * binary_decisions[plant],
f"production_logic_{plant}")
# Objective with cost structure
plant_costs = {"plant1": 10, "plant2": 12, "plant3": 8}
fixed_costs = {"plant1": 1000, "plant2": 1200, "plant3": 800}
total_cost = (lpSum([plant_costs[p] * production_vars[p] for p in production_vars]) +
lpSum([fixed_costs[p] * binary_decisions[p] for p in binary_decisions]))
prob += total_cost
return prob
# Export with detailed structure
structured_prob = create_structured_mps_problem()
writeMPS(structured_prob, "structured_example.mps")
writeLP(structured_prob, "structured_example.lp")Support for sparse matrix operations essential for large-scale optimization problems with sparse constraint matrices.
class Matrix:
"""
Generic sparse matrix class using dictionary-based storage.
Efficient representation for optimization problems with sparse coefficient matrices.
"""
def __init__(self): ...
def __getitem__(self, key): ... # Access matrix elements
def __setitem__(self, key, value): ... # Set matrix elements
def keys(self): ... # Get all defined indices
def values(self): ... # Get all defined values
def items(self): ... # Get (index, value) pairsUsage examples:
# Sparse constraint matrix for large problems
def create_sparse_transportation_problem(supply_points, demand_points, connections):
"""
Create transportation problem with sparse connection matrix.
Only creates variables for valid supply-demand connections.
"""
prob = LpProblem("Sparse_Transportation", LpMinimize)
# Sparse matrix to track which connections exist
connection_matrix = Matrix()
transport_vars = {}
for supply, demand, cost in connections:
# Only create variables for valid connections
var_name = f"transport_{supply}_{demand}"
transport_vars[(supply, demand)] = LpVariable(var_name, 0)
connection_matrix[supply, demand] = cost
# Supply constraints (only for connected supply points)
supply_constraints = {}
for supply in supply_points:
connected_demands = [d for s, d in transport_vars.keys() if s == supply]
if connected_demands:
supply_constraints[supply] = lpSum([
transport_vars[(supply, demand)] for demand in connected_demands
])
prob += supply_constraints[supply] <= supply_points[supply]
# Demand constraints (only for connected demand points)
demand_constraints = {}
for demand in demand_points:
connected_supplies = [s for s, d in transport_vars.keys() if d == demand]
if connected_supplies:
demand_constraints[demand] = lpSum([
transport_vars[(supply, demand)] for supply in connected_supplies
])
prob += demand_constraints[demand] >= demand_points[demand]
# Sparse objective function
transport_cost = lpSum([
connection_matrix[supply, demand] * transport_vars[(supply, demand)]
for supply, demand in transport_vars.keys()
])
prob += transport_cost
return prob, transport_vars, connection_matrix
# Example usage with sparse data
supply_capacities = {"S1": 100, "S2": 150, "S3": 120}
demand_requirements = {"D1": 80, "D2": 90, "D3": 70, "D4": 85}
# Only some supply-demand pairs are connected (sparse network)
valid_connections = [
("S1", "D1", 10), ("S1", "D3", 15),
("S2", "D1", 12), ("S2", "D2", 8), ("S2", "D4", 20),
("S3", "D2", 14), ("S3", "D3", 11), ("S3", "D4", 16)
]
sparse_prob, variables, costs = create_sparse_transportation_problem(
supply_capacities, demand_requirements, valid_connections
)
# Export sparse problem
writeMPS(sparse_prob, "sparse_transportation.mps")
print(f"Created sparse problem with {len(variables)} variables")
print(f"Density: {len(variables)}/{len(supply_capacities)*len(demand_requirements)} = {len(variables)/(len(supply_capacities)*len(demand_requirements)):.2%}")Additional utilities for handling different file formats and ensuring compatibility across solvers.
# Batch export to multiple formats
def export_problem_suite(problem, base_name):
"""Export problem to all supported formats."""
formats = {
'.lp': writeLP,
'.mps': writeMPS
}
exported_files = []
for extension, write_func in formats.items():
filename = f"{base_name}{extension}"
try:
write_func(problem, filename)
exported_files.append(filename)
print(f"Exported: {filename}")
except Exception as e:
print(f"Failed to export {filename}: {e}")
return exported_files
# Problem format conversion
def convert_problem_format(input_file, output_file, target_sense=LpMinimize):
"""Convert between problem file formats."""
# Determine input format from extension
if input_file.lower().endswith('.mps'):
prob = readMPS(input_file, target_sense)
else:
raise ValueError(f"Unsupported input format: {input_file}")
# Determine output format and write
if output_file.lower().endswith('.lp'):
writeLP(prob, output_file)
elif output_file.lower().endswith('.mps'):
writeMPS(prob, output_file)
else:
raise ValueError(f"Unsupported output format: {output_file}")
print(f"Converted {input_file} to {output_file}")
# Example usage
prob = LpProblem("Multi_Export_Example", LpMinimize)
x = LpVariable("x", 0, 10)
prob += 2*x
prob += x >= 5
# Export to all formats
exported = export_problem_suite(prob, "multi_format_example")
# Convert existing MPS to LP
# convert_problem_format("existing_model.mps", "converted_model.lp")Install with Tessl CLI
npx tessl i tessl/pypi-pulp