Skip to content

9 Combine LP and stitching

View or edit on GitHub

This page is synchronized from trase/models/lp/9_Combine_LP_and_stitching.ipynb. Last modified on 2026-05-06 16:54 CEST by Trase Admin. Please view or edit the original file there; changes should be reflected here after a midnight build (CET time), or manually triggering it with a GitHub action (link).

Combine LP and stitching

import pandas as pd

from pulp import getSolver
from trase.tools.sps import solve_transportation_problem, stitch_dataframes


df_exports = pd.DataFrame(
    data=[
        ("PORT-1", "EXPORTER-1", 100),
        ("PORT-1", "EXPORTER-2", 200),
        ("PORT-1", "EXPORTER-3", 50),
        ("PORT-2", "EXPORTER-1", 50),
        ("PORT-3", "EXPORTER-2", 100),
    ],
    columns=["port", "exporter", "vol"],
)

df_supply = pd.DataFrame(
    data=[
        ("SILO-1", 100),
        ("SILO-2", 100),
        ("SILO-3", 100),
        ("SILO-4", 100),
        ("SILO-5", 100),
    ],
    columns=["silo", "vol"],
)

df_costs = pd.DataFrame(
    data=[
        ("SILO-1", "PORT-1", 40),
        ("SILO-1", "PORT-2", 60),
        ("SILO-1", "PORT-3", 80),
        ("SILO-2", "PORT-1", 30),
        ("SILO-2", "PORT-2", 50),
        ("SILO-2", "PORT-3", 70),
        ("SILO-3", "PORT-1", 20),
        ("SILO-3", "PORT-2", 10),
        ("SILO-3", "PORT-3", 20),
        ("SILO-4", "PORT-1", 35),
        ("SILO-4", "PORT-2", 35),
        ("SILO-4", "PORT-3", 55),
        ("SILO-5", "PORT-1", 80),
        ("SILO-5", "PORT-2", 60),
        ("SILO-5", "PORT-3", 40),
    ],
    columns=["origin", "destination", "cost"],
)
supply = df_supply.set_index("silo")["vol"]
demand = df_exports.groupby("port")["vol"].sum()
costs = df_costs.set_index(["origin", "destination"])["cost"]

solution, leftover_supply = solve_transportation_problem(
    supply=supply,
    demand=demand,
    costs=costs,
    solver=getSolver("GLPK_CMD"),
)
GLPSOL--GLPK LP/MIP Solver 5.0
Parameter(s) specified in the command line:
 --cpxlp /tmp/4671b6287ff445e79e43cee2e98507c4-pulp.lp -o /tmp/4671b6287ff445e79e43cee2e98507c4-pulp.sol
Reading problem data from '/tmp/4671b6287ff445e79e43cee2e98507c4-pulp.lp'...
8 rows, 15 columns, 30 non-zeros
14 lines were read
GLPK Simplex Optimizer 5.0
8 rows, 15 columns, 30 non-zeros
Preprocessing...
8 rows, 15 columns, 30 non-zeros
Scaling...
 A: min|aij| =  1.000e+00  max|aij| =  1.000e+00  ratio =  1.000e+00
Problem data seem to be well scaled
Constructing initial basis...
Size of triangular part is 8
      0: obj =   3.500000000e+04 inf =   4.000e+02 (1)
      5: obj =   1.950000000e+04 inf =   0.000e+00 (0)
*     8: obj =   1.600000000e+04 inf =   0.000e+00 (0)
OPTIMAL LP SOLUTION FOUND
Time used:   0.0 secs
Memory used: 0.0 Mb (39693 bytes)
Writing basic solution to '/tmp/4671b6287ff445e79e43cee2e98507c4-pulp.sol'...


/mnt/custom-file-systems/efs/fs-049d752ef37739434/shared/shared_repos/TRASE/trase/tools/sei_pcs/pandas_lp.py:275: FutureWarning: The provided callable <built-in function sum> is currently using np.sum. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string np.sum instead.
  .apply(sum)
/mnt/custom-file-systems/efs/fs-049d752ef37739434/shared/shared_repos/TRASE/trase/tools/sei_pcs/pandas_lp.py:346: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  infeasible = df.groupby("sink_group").apply(
/mnt/custom-file-systems/efs/fs-049d752ef37739434/shared/shared_repos/TRASE/trase/tools/sei_pcs/pandas_lp.py:532: FutureWarning: The provided callable <built-in function sum> is currently using np.sum. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string np.sum instead.
  df_allocation.groupby(["source"])["quantity"].apply(sum).to_frame()
df_solution = solution.reset_index()
df_solution
silo port vol
0 SILO-1 PORT-1 100.0
1 SILO-2 PORT-1 100.0
2 SILO-3 PORT-1 50.0
3 SILO-3 PORT-2 50.0
4 SILO-4 PORT-1 100.0
5 SILO-5 PORT-3 100.0
df = stitch_dataframes(df_solution, df_exports, volume_column="vol")
df[["silo", "port", "exporter", "vol"]]
silo port exporter vol
0 SILO-1 PORT-1 EXPORTER-1 28.571429
1 SILO-2 PORT-1 EXPORTER-1 28.571429
2 SILO-3 PORT-1 EXPORTER-1 14.285714
3 SILO-4 PORT-1 EXPORTER-1 28.571429
4 SILO-1 PORT-1 EXPORTER-2 57.142857
5 SILO-2 PORT-1 EXPORTER-2 57.142857
6 SILO-3 PORT-1 EXPORTER-2 28.571429
7 SILO-4 PORT-1 EXPORTER-2 57.142857
8 SILO-1 PORT-1 EXPORTER-3 14.285714
9 SILO-2 PORT-1 EXPORTER-3 14.285714
10 SILO-3 PORT-1 EXPORTER-3 7.142857
11 SILO-4 PORT-1 EXPORTER-3 14.285714
12 SILO-3 PORT-2 EXPORTER-1 50.000000
13 SILO-5 PORT-3 EXPORTER-2 100.000000