You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Pyomo的扩展运输问题建模问询:阶梯函数型单位入库成本

Alright, let's walk through building this extended transportation problem with Pyomo's abstract model—especially tackling that tricky step-function inbound cost. I've broken this down into actionable steps that align with your requirements:

1. Lay out the core problem components

First, let's clarify the key pieces we need to model:

  • Decision Variables: The quantity of goods transported between each pair of warehouses (let's call this x[i,j] for shipments from warehouse i to j).
  • Cost Types:
    • Line haul cost: Per-unit cost for moving goods directly between warehouses.
    • Outbound cost: Per-unit cost for shipping goods out of a warehouse (regardless of destination).
    • Inbound cost: Per-unit cost that changes based on the total quantity received at a warehouse (the step-function cost from your CSV).
  • Objective: Minimize the sum of all three cost types.
2. Build the abstract model step-by-step

Abstract models in Pyomo are great here because they let you separate the problem structure from your specific data (like warehouse lists or cost values).

2.1 Define sets and parameters

First, we'll define the sets (groups of items) and parameters (fixed values) for our model:

from pyomo.environ import *
import pandas as pd

# Initialize the abstract model
model = AbstractModel()

# --- Sets ---
# List of all warehouses
model.Warehouses = Set()
# Valid transportation routes (pairs of warehouses i -> j)
model.Routes = Set(within=model.Warehouses * model.Warehouses)

# --- Fixed cost parameters ---
# Per-unit line haul cost for each route
model.linehaul_cost = Param(model.Routes, within=NonNegativeReals)
# Per-unit outbound cost for each warehouse
model.outbound_cost = Param(model.Warehouses, within=NonNegativeReals)

# --- Step-function inbound cost parameters (loaded from CSV) ---
# Load your CSV file (columns: Quantity_Low, Quantity_High, Unit_Cost)
inbound_df = pd.read_csv('inbound_cost_steps.csv')
# Create a list of step indices
inbound_steps = list(range(len(inbound_df)))
# Define quantity breakpoints (add infinity as the upper bound for the last step)
inbound_qty_breakpoints = list(inbound_df['Quantity_Low']) + [float('inf')]
# Map each step to its unit cost
inbound_unit_costs = dict(zip(inbound_steps, inbound_df['Unit_Cost']))

# Add these to the model as parameters
model.Inbound_Steps = Set(initialize=inbound_steps)
model.inbound_qty_breakpoints = Param(initialize=inbound_qty_breakpoints)
model.inbound_unit_costs = Param(model.Inbound_Steps, initialize=inbound_unit_costs)

2.2 Define decision variables

Next, we'll define our main decision variable (transportation quantities) plus helper variables to handle the step inbound cost:

# Main variable: quantity transported from i to j
model.x = Var(model.Routes, within=NonNegativeReals)

# Helper variable: total inbound quantity for each warehouse j
model.inbound_total = Var(model.Warehouses, within=NonNegativeReals)
# Constraint to calculate inbound total as sum of all shipments to j
def calc_inbound_total(model, j):
    return model.inbound_total[j] == sum(model.x[i,j] for i in model.Warehouses if (i,j) in model.Routes)
model.Inbound_Total_Constraint = Constraint(model.Warehouses, rule=calc_inbound_total)

# Helper variable: total inbound cost for each warehouse j
model.inbound_cost_total = Var(model.Warehouses, within=NonNegativeReals)

2.3 Implement the step-function inbound cost

This is the most critical part. Pyomo's Piecewise component makes it easy to model step-function costs without manually writing a bunch of binary variables. We'll use it to link the total inbound quantity to the total inbound cost:

def inbound_cost_rule(model, j):
    return Piecewise(
        model.inbound_cost_total[j],  # Dependent variable (total cost)
        model.inbound_total[j],       # Independent variable (total quantity)
        pw_pts=model.inbound_qty_breakpoints,  # Quantity breakpoints from CSV
        f_rule=model.inbound_unit_costs,       # Unit cost for each step
        pw_constr_type='EQ',          # Enforce equality between cost and step function
        pw_repn='CC'                  # Continuous convex representation (ideal for step costs)
    )
model.Inbound_Cost_Piecewise = Constraint(model.Warehouses, rule=inbound_cost_rule)

2.4 Define the objective function

Now we'll write the objective to minimize total cost, which is the sum of line haul, outbound, and inbound costs:

def total_cost_rule(model):
    # Calculate total line haul cost
    linehaul_total = sum(model.linehaul_cost[i,j] * model.x[i,j] for (i,j) in model.Routes)
    # Calculate total outbound cost (sum of all shipments out of each warehouse * per-unit cost)
    outbound_total = sum(
        model.outbound_cost[j] * sum(model.x[j,k] for k in model.Warehouses if (j,k) in model.Routes)
        for j in model.Warehouses
    )
    # Calculate total inbound cost (sum of helper variable values)
    inbound_total = sum(model.inbound_cost_total[j] for j in model.Warehouses)
    
    return linehaul_total + outbound_total + inbound_total

# Set the objective to minimize total cost
model.Total_Cost = Objective(rule=total_cost_rule, sense=minimize)

2.5 Add flow constraints (optional but common)

Depending on your specific problem, you might need flow balance constraints. For example, if this is a transshipment problem (no inventory stored at warehouses), add:

def flow_balance_rule(model, j):
    # Total inbound = total outbound for each warehouse
    return sum(model.x[i,j] for i in model.Warehouses if (i,j) in model.Routes) == sum(model.x[j,k] for k in model.Warehouses if (j,k) in model.Routes)
model.Flow_Balance = Constraint(model.Warehouses, rule=flow_balance_rule)

If you have supply/demand constraints (e.g., some warehouses have fixed supply, others fixed demand), adjust this accordingly.

3. Load data and solve the model

Abstract models require a data source (like a .dat file or Python dictionary) to create a concrete instance. Here's an example .dat file (transport_data.dat):

set Warehouses := W1 W2 W3;
set Routes := (W1,W2) (W1,W3) (W2,W1) (W2,W3) (W3,W1) (W3,W2);

param linehaul_cost :=
(W1,W2) 2.5
(W1,W3) 3.0
(W2,W1) 2.5
(W2,W3) 1.8
(W3,W1) 3.0
(W3,W2) 1.8;

param outbound_cost :=
W1 1.2
W2 1.0
W3 1.5;

Then load the data and solve:

# Create a concrete instance from the abstract model and data file
instance = model.create_instance('transport_data.dat')

# Choose a solver (GLPK is open-source; use Gurobi/CPLEX for larger models)
solver = SolverFactory('glpk')
result = solver.solve(instance)

# Print results
print(f"Total Minimum Cost: ${instance.Total_Cost():.2f}")
print("\nTransportation Quantities:")
for (i,j) in instance.Routes:
    print(f"From {i} to {j}: {instance.x[i,j]():.2f} units")
print("\nInbound Details per Warehouse:")
for j in instance.Warehouses:
    print(f"{j}: Inbound = {instance.inbound_total[j]():.2f} units | Inbound Cost = ${instance.inbound_cost_total[j]():.2f}")
4. Key tips and adjustments
  • Per-warehouse step costs: If each warehouse has its own step-function inbound cost, modify the inbound_unit_costs parameter to be indexed by both Warehouses and Inbound_Steps, then load CSV data per warehouse.
  • Step interval handling: Ensure your CSV's quantity intervals align with the pw_pts setup. For example, if your first step is 0-100 units, set the first breakpoint to 0, next to 100, etc.
  • Solver choice: For large-scale models, commercial solvers like Gurobi or CPLEX will perform much better than open-source options like GLPK.

内容的提问来源于stack exchange,提问作者Kreator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:40:05