LP Example: Production Optimization
This tutorial illustrates how to model and solve a real-world linear programming (LP) problem using the OptArrow optimization engine. The example is based on a classic production optimization problem where multiple products must be manufactured using limited resources to maximize profit while respecting resource, demand, and capacity constraints.
Problem Overview
A factory has a limited stock of raw materials:
200 units of Raw Material A
120 units of Raw Material B
150 units of Raw Material C
The factory produces two types of products: Product X and Product Y.
Resource Usage |
Product X |
Product Y |
|---|---|---|
Material A (units) |
20 |
10 |
Material B (units) |
10 |
20 |
Material C (units) |
10 |
30 |
Profit per unit |
5 |
12 |
Mathematical Formulation
The LP problem can be formulated as follows:
Objective: Maximize profit
where $x$ is the number of Product X produced and $y$ is the number of Product Y produced. Subject to:
General LP Formulation
The LP problem should be structured as:
Objective: Maximize $c^T x$ where $c$ is the profit vector and $x$ is the production vector.
Subject to:
where $A$ is the resource usage matrix, $b$ is the resource availability vector, and $lb$, $ub$ are the lower and upper bounds on the production quantities.
Solving with OptArrow
The following code illustrates how this linear program can be defined and solved using OptArrow in Python:
A is the matrix in Coordinate(COO) format, which is a sparse matrix format suitable for large matrices. The row, col, and val lists represent the non-zero entries of the matrix.
ipc_dict = {
"model": {
"A": {
"row": [0, 0, 1, 1, 2, 2],
"col": [0, 1, 0, 1, 0, 1],
"val": [20, 10, 10, 20, 10, 30]
},
"b": [200, 120, 150],
"c": [5, 12],
"lb": [0, 0],
"csense": ["L", "L", "L"], # 'L' for less than or equal to constraints
"osense": "max"
},
"model_name": "product_mix_lp",
"engine": "julia", # Using Julia as the optimization engine, also supports Python
"solver": {
"solver_name": "HiGHS", # Using HiGHS solver for LP problems, also supports other solvers
"solver_type": "LP", # Specify the solver type as LP
"solver_params": {} # Additional solver parameters can be added here
}
}
Using Arrow IPC Stream Bytes Format
import pyarrow as pa
import requests
# Convert the dictionary to an Arrow table for IPC serialization
pa_arrays = [pa.array([v]) for v in ipc_dict.values()]
table = pa.Table.from_arrays(pa_arrays, names=list(ipc_dict.keys()))
# Serialize the table to IPC stream bytes
sink = pa.BufferOutputStream()
with pa.ipc.new_stream(sink, table.schema) as writer:
writer.write(table)
ipc_bytes = sink.getvalue().to_pybytes()
# Send the IPC stream bytes to the server
headers = {"Content-Type": "application/vnd.apache.arrow.stream"}
response = requests.post("http://localhost:8000/compute", data=ipc_bytes, headers=headers)
# Check if the response is successful
if response.status_code != 200:
print(f"Error: {response.status_code} - {response.text}")
# response is ipc stream
reader = pa.ipc.open_stream(response.content)
result_table = reader.read_all()
result_dict = {name: result_table.column(name).to_pylist() for name in result_table.column_names}
print(result_dict)
Using JSON
headers = {"Content-Type": "application/json"}
response = requests.post("http://localhost:8000/computeJSON", json=ipc_dict, headers=headers)
print(response.json())