0
# File I/O and Data Formats
1
2
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.
3
4
## Capabilities
5
6
### Problem File Export
7
8
Functions for writing PuLP problems to standard optimization file formats that can be read by various solvers and optimization software.
9
10
```python { .api }
11
def writeLP(prob, filename):
12
"""
13
Write optimization problem to LP (Linear Program) format file.
14
15
Parameters:
16
- prob (LpProblem): Problem to export
17
- filename (str): Output file path with .lp extension
18
19
Note: LP format is human-readable and widely supported by solvers.
20
Automatically handles line length constraints for CPLEX compatibility.
21
22
Examples:
23
writeLP(prob, "mymodel.lp")
24
writeLP(prob, "/path/to/problem.lp")
25
"""
26
27
def writeMPS(prob, filename):
28
"""
29
Write optimization problem to MPS (Mathematical Programming System) format file.
30
31
Parameters:
32
- prob (LpProblem): Problem to export
33
- filename (str): Output file path with .mps extension
34
35
Note: MPS format is the industry standard for optimization problems.
36
Provides precise numerical representation and broad solver compatibility.
37
38
Examples:
39
writeMPS(prob, "mymodel.mps")
40
writeMPS(prob, "/path/to/problem.mps")
41
"""
42
```
43
44
Usage examples:
45
46
```python
47
# Create and solve a problem
48
prob = LpProblem("Export_Example", LpMinimize)
49
x = LpVariable("x", 0, 10)
50
y = LpVariable("y", 0, 5)
51
prob += 2*x + 3*y
52
prob += x + y <= 8
53
prob += 2*x - y >= 1
54
55
# Export to different formats
56
writeLP(prob, "example.lp") # Human-readable LP format
57
writeMPS(prob, "example.mps") # Standard MPS format
58
59
# Export with paths
60
import os
61
output_dir = "optimization_models"
62
os.makedirs(output_dir, exist_ok=True)
63
64
writeLP(prob, os.path.join(output_dir, f"{prob.name}.lp"))
65
writeMPS(prob, os.path.join(output_dir, f"{prob.name}.mps"))
66
67
# Export for different solvers
68
writeLP(prob, "for_glpk.lp") # GLPK can read LP format
69
writeMPS(prob, "for_cplex.mps") # CPLEX prefers MPS format
70
writeMPS(prob, "for_gurobi.mps") # Gurobi supports both, MPS more precise
71
```
72
73
### Problem File Import
74
75
Functions for reading optimization problems from standard file formats into PuLP problem objects.
76
77
```python { .api }
78
def readMPS(path, sense, dropConsNames=False):
79
"""
80
Read optimization problem from MPS format file.
81
82
Parameters:
83
- path (str): Path to MPS file to read
84
- sense: Optimization sense (LpMinimize or LpMaximize)
85
- dropConsNames (bool): Whether to ignore constraint names from file
86
87
Returns:
88
LpProblem: Problem object created from MPS file data
89
90
Note: Enables importing problems created by other optimization software
91
or previously exported PuLP problems.
92
93
Examples:
94
prob = readMPS("external_model.mps", LpMinimize)
95
prob = readMPS("backup.mps", LpMaximize, dropConsNames=True)
96
"""
97
```
98
99
Usage examples:
100
101
```python
102
# Import problems from external sources
103
external_prob = readMPS("industry_model.mps", LpMinimize)
104
print(f"Imported problem: {external_prob.name}")
105
print(f"Variables: {len(external_prob.variables())}")
106
print(f"Constraints: {len(external_prob.constraints)}")
107
108
# Solve imported problem
109
status = external_prob.solve()
110
if status == LpStatusOptimal:
111
print("External model solved successfully")
112
for var in external_prob.variables():
113
if value(var) is not None:
114
print(f"{var.name} = {value(var)}")
115
116
# Import and modify problems
117
base_prob = readMPS("base_model.mps", LpMinimize)
118
119
# Add additional constraints to imported problem
120
additional_vars = [var for var in base_prob.variables() if 'production' in var.name]
121
if additional_vars:
122
base_prob += lpSum(additional_vars) >= 100 # Minimum production constraint
123
124
# Re-export modified problem
125
writeMPS(base_prob, "modified_model.mps")
126
```
127
128
### MPS Data Structure Classes
129
130
Classes for representing and manipulating MPS format components, providing detailed control over problem structure and data.
131
132
```python { .api }
133
class MPS:
134
"""
135
Complete MPS format representation containing all problem components.
136
Provides structured access to problem data for advanced manipulation.
137
"""
138
def __init__(self): ...
139
140
@property
141
def variables(self): ... # Access to variable definitions
142
@property
143
def constraints(self): ... # Access to constraint definitions
144
@property
145
def objective(self): ... # Access to objective function
146
@property
147
def parameters(self): ... # Access to problem parameters
148
149
class MPSParameters:
150
"""
151
Problem parameters section of MPS format.
152
Contains solver settings and problem configuration data.
153
"""
154
def __init__(self): ...
155
156
class MPSObjective:
157
"""
158
Objective function data in MPS format.
159
Represents the cost/profit coefficients and optimization sense.
160
"""
161
def __init__(self): ...
162
163
@property
164
def coefficients(self): ... # Variable coefficients in objective
165
@property
166
def sense(self): ... # Minimization or maximization
167
@property
168
def name(self): ... # Objective function name
169
170
class MPSVariable:
171
"""
172
Variable data in MPS format.
173
Contains variable definitions, bounds, and type information.
174
"""
175
def __init__(self): ...
176
177
@property
178
def name(self): ... # Variable name
179
@property
180
def bounds(self): ... # Lower and upper bounds
181
@property
182
def variable_type(self): ... # Continuous, integer, or binary
183
184
class MPSConstraint:
185
"""
186
Constraint data in MPS format.
187
Represents constraint coefficients, bounds, and relationship types.
188
"""
189
def __init__(self): ...
190
191
@property
192
def name(self): ... # Constraint name
193
@property
194
def coefficients(self): ... # Variable coefficients
195
@property
196
def sense(self): ... # <=, =, or >= relationship
197
@property
198
def rhs(self): ... # Right-hand side value
199
200
class MPSCoefficient:
201
"""
202
Individual coefficient data in MPS format.
203
Represents variable-constraint coefficient pairs.
204
"""
205
def __init__(self): ...
206
207
@property
208
def variable(self): ... # Associated variable
209
@property
210
def constraint(self): ... # Associated constraint
211
@property
212
def value(self): ... # Coefficient value
213
```
214
215
Usage examples:
216
217
```python
218
# Advanced MPS file manipulation
219
def analyze_mps_structure(mps_file_path):
220
"""Analyze the structure of an MPS file."""
221
prob = readMPS(mps_file_path, LpMinimize)
222
223
print(f"Problem Analysis: {prob.name}")
224
print(f"Variables: {len(prob.variables())}")
225
print(f"Constraints: {len(prob.constraints)}")
226
227
# Analyze variable types
228
var_types = {}
229
for var in prob.variables():
230
var_type = var.cat
231
var_types[var_type] = var_types.get(var_type, 0) + 1
232
233
print("Variable types:")
234
for vtype, count in var_types.items():
235
print(f" {vtype}: {count}")
236
237
# Analyze constraint senses
238
constraint_senses = {}
239
for constraint in prob.constraints.values():
240
sense = constraint.sense
241
sense_str = LpConstraintSenses.get(sense, str(sense))
242
constraint_senses[sense_str] = constraint_senses.get(sense_str, 0) + 1
243
244
print("Constraint types:")
245
for sense, count in constraint_senses.items():
246
print(f" {sense}: {count}")
247
248
# Create MPS data programmatically
249
def create_structured_mps_problem():
250
"""Create a problem with detailed MPS structure."""
251
prob = LpProblem("Structured_MPS_Example", LpMinimize)
252
253
# Create variables with detailed naming
254
production_vars = LpVariable.dicts("production",
255
["plant1", "plant2", "plant3"],
256
0, 1000, LpContinuous)
257
258
binary_decisions = LpVariable.dicts("use_plant",
259
["plant1", "plant2", "plant3"],
260
cat=LpBinary)
261
262
# Structured constraints with meaningful names
263
prob += (lpSum(production_vars), "total_production_limit", 2500)
264
265
for plant in production_vars:
266
# Production can only occur if plant is used
267
prob += (production_vars[plant] <= 1000 * binary_decisions[plant],
268
f"production_logic_{plant}")
269
270
# Objective with cost structure
271
plant_costs = {"plant1": 10, "plant2": 12, "plant3": 8}
272
fixed_costs = {"plant1": 1000, "plant2": 1200, "plant3": 800}
273
274
total_cost = (lpSum([plant_costs[p] * production_vars[p] for p in production_vars]) +
275
lpSum([fixed_costs[p] * binary_decisions[p] for p in binary_decisions]))
276
277
prob += total_cost
278
279
return prob
280
281
# Export with detailed structure
282
structured_prob = create_structured_mps_problem()
283
writeMPS(structured_prob, "structured_example.mps")
284
writeLP(structured_prob, "structured_example.lp")
285
```
286
287
### Sparse Matrix Support
288
289
Support for sparse matrix operations essential for large-scale optimization problems with sparse constraint matrices.
290
291
```python { .api }
292
class Matrix:
293
"""
294
Generic sparse matrix class using dictionary-based storage.
295
Efficient representation for optimization problems with sparse coefficient matrices.
296
"""
297
def __init__(self): ...
298
299
def __getitem__(self, key): ... # Access matrix elements
300
def __setitem__(self, key, value): ... # Set matrix elements
301
def keys(self): ... # Get all defined indices
302
def values(self): ... # Get all defined values
303
def items(self): ... # Get (index, value) pairs
304
```
305
306
Usage examples:
307
308
```python
309
# Sparse constraint matrix for large problems
310
def create_sparse_transportation_problem(supply_points, demand_points, connections):
311
"""
312
Create transportation problem with sparse connection matrix.
313
Only creates variables for valid supply-demand connections.
314
"""
315
prob = LpProblem("Sparse_Transportation", LpMinimize)
316
317
# Sparse matrix to track which connections exist
318
connection_matrix = Matrix()
319
transport_vars = {}
320
321
for supply, demand, cost in connections:
322
# Only create variables for valid connections
323
var_name = f"transport_{supply}_{demand}"
324
transport_vars[(supply, demand)] = LpVariable(var_name, 0)
325
connection_matrix[supply, demand] = cost
326
327
# Supply constraints (only for connected supply points)
328
supply_constraints = {}
329
for supply in supply_points:
330
connected_demands = [d for s, d in transport_vars.keys() if s == supply]
331
if connected_demands:
332
supply_constraints[supply] = lpSum([
333
transport_vars[(supply, demand)] for demand in connected_demands
334
])
335
prob += supply_constraints[supply] <= supply_points[supply]
336
337
# Demand constraints (only for connected demand points)
338
demand_constraints = {}
339
for demand in demand_points:
340
connected_supplies = [s for s, d in transport_vars.keys() if d == demand]
341
if connected_supplies:
342
demand_constraints[demand] = lpSum([
343
transport_vars[(supply, demand)] for supply in connected_supplies
344
])
345
prob += demand_constraints[demand] >= demand_points[demand]
346
347
# Sparse objective function
348
transport_cost = lpSum([
349
connection_matrix[supply, demand] * transport_vars[(supply, demand)]
350
for supply, demand in transport_vars.keys()
351
])
352
prob += transport_cost
353
354
return prob, transport_vars, connection_matrix
355
356
# Example usage with sparse data
357
supply_capacities = {"S1": 100, "S2": 150, "S3": 120}
358
demand_requirements = {"D1": 80, "D2": 90, "D3": 70, "D4": 85}
359
360
# Only some supply-demand pairs are connected (sparse network)
361
valid_connections = [
362
("S1", "D1", 10), ("S1", "D3", 15),
363
("S2", "D1", 12), ("S2", "D2", 8), ("S2", "D4", 20),
364
("S3", "D2", 14), ("S3", "D3", 11), ("S3", "D4", 16)
365
]
366
367
sparse_prob, variables, costs = create_sparse_transportation_problem(
368
supply_capacities, demand_requirements, valid_connections
369
)
370
371
# Export sparse problem
372
writeMPS(sparse_prob, "sparse_transportation.mps")
373
print(f"Created sparse problem with {len(variables)} variables")
374
print(f"Density: {len(variables)}/{len(supply_capacities)*len(demand_requirements)} = {len(variables)/(len(supply_capacities)*len(demand_requirements)):.2%}")
375
```
376
377
### File Format Utilities
378
379
Additional utilities for handling different file formats and ensuring compatibility across solvers.
380
381
```python
382
# Batch export to multiple formats
383
def export_problem_suite(problem, base_name):
384
"""Export problem to all supported formats."""
385
formats = {
386
'.lp': writeLP,
387
'.mps': writeMPS
388
}
389
390
exported_files = []
391
for extension, write_func in formats.items():
392
filename = f"{base_name}{extension}"
393
try:
394
write_func(problem, filename)
395
exported_files.append(filename)
396
print(f"Exported: {filename}")
397
except Exception as e:
398
print(f"Failed to export {filename}: {e}")
399
400
return exported_files
401
402
# Problem format conversion
403
def convert_problem_format(input_file, output_file, target_sense=LpMinimize):
404
"""Convert between problem file formats."""
405
# Determine input format from extension
406
if input_file.lower().endswith('.mps'):
407
prob = readMPS(input_file, target_sense)
408
else:
409
raise ValueError(f"Unsupported input format: {input_file}")
410
411
# Determine output format and write
412
if output_file.lower().endswith('.lp'):
413
writeLP(prob, output_file)
414
elif output_file.lower().endswith('.mps'):
415
writeMPS(prob, output_file)
416
else:
417
raise ValueError(f"Unsupported output format: {output_file}")
418
419
print(f"Converted {input_file} to {output_file}")
420
421
# Example usage
422
prob = LpProblem("Multi_Export_Example", LpMinimize)
423
x = LpVariable("x", 0, 10)
424
prob += 2*x
425
prob += x >= 5
426
427
# Export to all formats
428
exported = export_problem_suite(prob, "multi_format_example")
429
430
# Convert existing MPS to LP
431
# convert_problem_format("existing_model.mps", "converted_model.lp")
432
```