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

基于采购量的成本最小化:Pyomo中添加供应商依赖型运费问题

Adding Dependent Freight Costs to Your Pyomo Model

To model the freight costs that depend on your total purchase from each supplier, we'll use binary variables and big-M constraints to capture the step-function logic. Here's how to modify your existing code:

Step 1: Add Binary Variables

We'll create binary variables for each supplier to indicate whether we're in the freight-paying region (1 if total cost ≤ threshold, 0 otherwise):

model.y_A = Var(within=Binary)  # 1 if total from A ≤100, else 0
model.y_B = Var(within=Binary)  # 1 if total from B ≤150, else 0

Step 2: Calculate Total Purchase Cost per Supplier

Define expressions to track the total cost spent at each supplier:

# Total cost from supplier A
model.total_A = Expression(expr=sum(p[n, 'A'] * model.x[n, 'A'] for n in N))
# Total cost from supplier B
model.total_B = Expression(expr=sum(p[n, 'B'] * model.x[n, 'B'] for n in N))

We use "big-M" constraints to enforce that the binary variable correctly reflects whether we're above or below the freight threshold. Choose a large M (bigger than the maximum possible total cost from either supplier) and a small epsilon to handle continuous variables:

M = 1000  # Larger than max possible total from A (790) or B (710)
epsilon = 0.001  # Small enough to avoid overlap between threshold regions

# Supplier A constraints
def constraint_A1(model):
    # If y_A=1, total_A ≤100; if y_A=0, total_A can be up to 100+M (no restriction)
    return model.total_A <= 100 + M * (1 - model.y_A)
model.constraint_A1 = Constraint(rule=constraint_A1)

def constraint_A2(model):
    # If y_A=0, total_A ≥100+epsilon (so >100); if y_A=1, this is automatically satisfied
    return model.total_A >= 100 + epsilon * (1 - model.y_A)
model.constraint_A2 = Constraint(rule=constraint_A2)

# Supplier B constraints
def constraint_B1(model):
    return model.total_B <= 150 + M * (1 - model.y_B)
model.constraint_B1 = Constraint(rule=constraint_B1)

def constraint_B2(model):
    return model.total_B >= 150 + epsilon * (1 - model.y_B)
model.constraint_B2 = Constraint(rule=constraint_B2)

Step 4: Update the Objective Function to Include Freight Costs

Modify your objective to add the freight costs based on the binary variables:

def obj_rule(model):
    purchase_cost = sum(p[n,m] * model.x[n,m] for n in N for m in M)
    freight_cost = 10 * model.y_A + 8 * model.y_B
    return purchase_cost + freight_cost
model.obj = Objective(rule=obj_rule)

Full Modified Code

Putting it all together, your code will look like this:

from pyomo.environ import ConcreteModel, Var, Objective, Constraint, SolverFactory, Binary, Expression

model = ConcreteModel(name="(MN_2)")
# products
N = ['prod1', 'prod2', 'prod3']
# suppliers
M = ['A', 'B']
# price
p = {('prod1', 'A'): 10, ('prod2', 'A'): 9, ('prod3', 'A'): 50, ('prod1', 'B'): 16, ('prod2', 'B'): 20, ('prod3', 'B'): 35}
# user quantity constraint
q_u = {('prod1', 'A'): 2, ('prod2', 'A'): 1, ('prod3', 'A'): 1, ('prod1', 'B'): 1, ('prod2', 'B'): 1, ('prod3', 'B'): 1}
# seller quantity constraint
q_s = {('prod1', 'A'): 20, ('prod2', 'A'): 10, ('prod3', 'A'): 10, ('prod1', 'B'): 10, ('prod2', 'B'): 10, ('prod3', 'B'): 10}

# Quantity of product n bought from supplier m
model.x = Var(N, M, bounds=(0,10))

# Binary variables for freight thresholds
model.y_A = Var(within=Binary)
model.y_B = Var(within=Binary)

# Total cost expressions per supplier
model.total_A = Expression(expr=sum(p[n, 'A'] * model.x[n, 'A'] for n in N))
model.total_B = Expression(expr=sum(p[n, 'B'] * model.x[n, 'B'] for n in N))

# Objective function including purchase and freight costs
def obj_rule(model):
    purchase_cost = sum(p[n,m] * model.x[n,m] for n in N for m in M)
    freight_cost = 10 * model.y_A + 8 * model.y_B
    return purchase_cost + freight_cost
model.obj = Objective(rule=obj_rule)

# User minimum quantity constraints
def user_quantity(model, n, m):
    return model.x[n,m] >= q_u[n,m]
model.user_quantity = Constraint(N, M, rule=user_quantity)

# Seller maximum quantity constraints
def seller_quantity(model, n, m):
    return model.x[n,m] <= q_s[n,m]
model.seller_quantity = Constraint(N, M, rule=seller_quantity)

# Freight threshold constraints
M = 1000
epsilon = 0.001

def constraint_A1(model):
    return model.total_A <= 100 + M * (1 - model.y_A)
model.constraint_A1 = Constraint(rule=constraint_A1)

def constraint_A2(model):
    return model.total_A >= 100 + epsilon * (1 - model.y_A)
model.constraint_A2 = Constraint(rule=constraint_A2)

def constraint_B1(model):
    return model.total_B <= 150 + M * (1 - model.y_B)
model.constraint_B1 = Constraint(rule=constraint_B1)

def constraint_B2(model):
    return model.total_B >= 150 + epsilon * (1 - model.y_B)
model.constraint_B2 = Constraint(rule=constraint_B2)

# Solve the model
solver = SolverFactory('glpk')
solver.solve(model)

# Print results
print("Purchase Quantities:")
model.x.pprint()
print("\nFreight Indicators (1 = pay freight, 0 = no freight):")
print(f"y_A: {model.y_A.value}")
print(f"y_B: {model.y_B.value}")
print("\nTotal Purchase Cost:", sum(p[n,m]*model.x[n,m].value for n in N for m in M))
print("Total Freight Cost:", 10*model.y_A.value +8*model.y_B.value)
print("Total Cost:", model.obj())

How It Works

  • The binary variables y_A and y_B act as switches: they're 1 when your total purchase from the supplier is below the threshold (so you pay freight), and 0 when you're above (no freight).
  • The big-M constraints ensure the binary variables correctly align with the total cost: if y_A is 1, your total from A can't exceed 100; if y_A is 0, your total from A must be over 100.
  • GLPK (your chosen solver) handles mixed-integer linear programming, so it can optimize both the continuous purchase quantities and binary freight switches.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:07:16