ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

python的运筹学工业场景模拟第二十八篇:零部件分配,多车间共用稀缺模具,整数规划分配模具,最大化整体产出。

python的运筹学工业场景模拟第二十八篇:零部件分配,多车间共用稀缺模具,整数规划分配模具,最大化整体产出。 多车间模具分配优化用 Python PuLP 破解稀缺资源困局某压铸厂有3个压铸车间共用8套大型模具其中2套是进口高寿命模单套采购周期6个月、单价80万。某月接到5个客户的订单涉及12种零件。模具产能是整条产线的瓶颈——一套模具一天最多压铸800次而3个车间加起来有15台压铸机等着用模具。生产主管的分配逻辑是先到先得谁催得急给谁结果2套进口模被车间A占了做低毛利零件车间B和C因为拿不到模具被迫停产待料当月整体产出比理论产能少了31%。后来用整数规划跑了一版模具-零件-车间分配模型把稀缺模具优先分配给高边际贡献的零件、同时兼顾各车间负载均衡当月总产出提升了27%多赚了约86万。—— 参考北京理工大学《运筹学》第6章整数规划、第7章运输与分配问题一、实际应用场景描述在压铸、冲压、注塑、锻造、粉末冶金等依赖模具成型的离散制造行业企业普遍面临一个硬约束模具是稀缺资源——好模具数量少、寿命有限、采购周期长而多个车间/多台设备都要抢这些模具。怎么把有限的模具分配给不同的车间和零件让整体产出最大、或者整体利润最高这不是简单的谁需要就给谁——因为不同零件用模具的产出效率不同、边际利润不同、模具损耗速度也不同。把进口高寿命模拿去做低毛利的大路货就是暴殄天物。┌──────────────────────────────────────────────────────────────┐│ 多车间模具分配 · 稀缺资源最大化产出系统 ││ ││ 【零件需求12种压铸零件月需求】 ││ ┌────┬──────────┬────────┬────────┬───────────────────────┐││ │ ID │ 零件 │ 月需求 │ 边际利润│ 适配模具 │││ ├────┼──────────┼────────┼────────┼───────────────────────┤││ │ P1 │ 壳体A │ 15000件│ 8.5元 │ M1(进口), M3(国产) │││ │ P2 │ 端盖B │ 22000件│ 4.2元 │ M2(进口), M4(国产) ││ │ P3 │ 支架C │ 8000件 │ 12.0元 │ M1(进口) ← 高利润! │││ │ P4 │ 法兰D │ 18000件│ 3.8元 │ M3(国产), M5(国产) │││ │ ...│ ... │ ... │ ... │ ... │││ └────┴──────────┴────────┴────────┴───────────────────────┘││ ││ 【模具资源8套多车间共用】 ││ ┌────┬──────────┬────────┬────────┬───────────────────────┐││ │ ID │ 模具 │ 类型 │ 日产能 │ 剩余寿命 │ 适配零件 │││ ├────┼──────────┼────────┼────────┼────────┼──────────────┤││ │ M1 │ 进口模-1 │ 高寿命│ 800次/天│ 45000次│ P1, P3, P7 │││ │ M2 │ 进口模-2 │ 高寿命│ 800次/天│ 38000次│ P2, P5, P9 │││ │ M3 │ 国产模-1 │ 中寿命│ 600次/天│ 12000次│ P1, P4, P6 │││ │ M4 │ 国产模-2 │ 中寿命│ 600次/天│ 15000次│ P2, P8 │││ │ ...│ ... │ ... │ ... │ ... │ ... │││ └────┴──────────┴────────┴────────┴────────┴──────────────┘││ ││ 【车间3个压铸车间】 ││ • WS1: 5台压铸机月可用工时 7200 h ││ • WS2: 5台压铸机月可用工时 7200 h ││ • WS3: 5台压铸机月可用工时 7200 h ││ ││ 【核心矛盾】 ││ • 进口模产能有限2套×800次/天×26天≈41600次/月 ││ • 但高利润零件P3(8000件)P7(6000件)只需要M1模 ││ • 如果M1被P1低利润大批量占满 → P3做不了 → 损失利润 ││ • 目标: 分配模具给各车间的各零件最大化总产出价值 ││ ││ 【本方案求解架构】 ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐││ │ 零件/模具/ │──►│ 分配MIP模型 │──►│ PuLP求解分配方案│││ │ 车间/利润 │ │ 0-1变量产能 │ │ 模具→零件→车间 │││ └──────────────┘ └──────────────┘ └──────────────────┘│└──────────────────────────────────────────────────────────────┘二、引入痛点含量化对比2.1 现场真实困境某压铸厂生产计划主管原话我们厂3个压铸车间、15台压铸机但核心模具只有8套——其中2套进口模是宝贝单价80万采购周期半年。平时分配模具全靠我一张嘴车间A这周用M1做壳体车间B你用M3做法兰。问题出在我没有量化标准。上个月车间A的主任来找我说壳体订单急M1给我们用两周。我想着壳体量大、交期紧就答应了。结果M1连续跑了10天全在做壳体低毛利4.2元/件而车间C的高利润支架零件边际利润12元/件因为拿不到M1只做了计划量的40%。月底一盘算壳体多做了3000件多赚1.26万但支架少做了5000件少赚6万——捡了芝麻丢了西瓜。后来我用PuLP建了个模型把零件-模具-车间的三维分配问题写成整数规划目标函数是最大化总边际贡献约束是模具产能上限、车间机时上限、零件需求上限。跑出来M1应该优先给支架高利润壳体用国产M3做虽然效率低一点但利润影响小。按这个方案执行一个月总利润比之前高了27%。2.2 经验分配 vs 运筹学最优分配量化对比指标 经验分配先到先得谁催给谁 LP最优分配本方案 改善效果月总产出价值 186 万元 236 万元 27.0%高利润零件(P3)完成率 42% 100% 58pp进口模利用率 98%但做低利润品 96%做高利润品 质量更高车间待料停产 3次/月 0次 消除模具寿命消耗 进口模消耗快做大批量的 均衡消耗 延长整体寿命月均增收 - 约 50 万元 净增年化收益 - 约 600 万元 按12个月计关键发现稀缺模具分配的本质是机会成本决策——把模具给A零件做就放弃了用它做B零件的可能。经验分配靠感觉判断而整数规划把所有零件的利润、模具产能、车间机时放在一个目标函数里统筹自动选出放弃低利润的、保高利润的最优组合。2.3 核心矛盾模具分配的核心矛盾是稀缺模具产能与多车间多零件竞争之间的冲突。贪心策略谁急给谁/谁量大给谁忽略了不同零件的利润密度差异。整数规划把模具→零件→车间的三维分配变成一个带产能约束的最大化利润运输问题——让数学帮你决定每一套模具的每一分钟产能应该用来生产什么。三、核心逻辑讲解大白话版3.1 用大白话解释模具分配想象你在经营一家只有2台烤箱的面包店同时要烤5种面包场景- 你只有2个好烤箱进口模还有1个老烤箱国产模。- 法棍要用蒸汽烤箱只有烤箱A能烤可颂用普通烤箱也行但效果差一点。- 法棍利润高8元/个吐司利润低3元/个。- 烤箱A一天最多烤200个面包。贪心做法今天吐司订单多100个全塞烤箱A烤——法棍没烤箱烤只能少做。聪明做法整数规划- 算一笔账烤箱A的200个位置给法棍能赚1600元给吐司只能赚300元。- 显然烤箱A应该优先给法棍吐司放老烤箱哪怕烤得慢一点、差一点。- 这就是机会成本思维烤箱A的每一分钟都应该用来做单位时间利润最高的事。工业现场版- 烤箱 模具- 面包种类 零件- 蒸汽烤箱 进口高精模- 法棍 高利润精密零件- 吐司 低利润大路货- 聪明做法 整数规划分配模型大白话总结- 决策变量模具 m 分配给车间 w 做零件 p 的数量或时间比例- 目标总利润件数 × 边际利润最大- 约束模具产能有限、车间机时有限、需求不能超- 核心洞察模具的每一分钟都是稀缺的——应该用在刀刃上3.2 运筹学模型北理工《运筹学》标准建模模具分配模型带产能约束的最大化运输问题 · MIP集合定义- p \in P 零件集合- m \in M 模具集合- w \in W 车间集合- A \subseteq P \times M \times W 可行的(零件,模具,车间)组合决策变量- x_{pmw} \ge 0 模具 m 在车间 w 生产零件 p 的数量- y_{pmw} \in \{0,1\} 是否启用该分配组合可选控制切换次数参数- r_{pm} 模具 m 生产零件 p 的产出率件/小时- profit_p 零件 p 的单位边际利润元/件- Cap_m 模具 m 的可用总工时小时/月- Cap_w 车间 w 的可用总机时小时/月- Demand_p 零件 p 的最大需求件/月目标函数最大化总边际贡献\max \sum_{(p,m,w) \in A} profit_p \cdot x_{pmw}约束条件1. 需求上限\sum_{m,w} x_{pmw} \le Demand_p \quad \forall p \in P2. 模具产能约束\sum_{p,w} \frac{x_{pmw}}{r_{pm}} \le Cap_m \quad \forall m \in M3. 车间机时约束\sum_{p,m} \frac{x_{pmw}}{r_{pm}} \le Cap_w \quad \forall w \in W4. 非负约束 x_{pmw} \ge 0参考北理工《运筹学》- 第7章运输与分配问题§7.1 运输问题本问题是运输问题的三维扩展- 第6章整数规划§6.2 0-1型整数规划如加入切换约束3.3 如何映射到代码中数学模型/概念 Python 代码零件集合 PPart 数据类列表模具集合 MMold 数据类列表车间集合 WWorkshop 数据类列表可行组合 AAllocationProblem.allowed 属性三元组列表产出率 r_{pm}Mold.production_rates[part_id]决策变量 x_{pmw}pulp.LpVariable(falloc_{p}_{m}_{w}, 0, demand)目标函数prob pulp.lpSum(profit * x)模具产能prob pulp.lpSum(hours) capacity四、OOP 代码实现精简可运行4.1 项目结构mold_allocation/├── mold_allocation.py # 核心代码单文件~280行├── README.md # 使用说明└── requirements.txt # 依赖库4.2 完整源代码可直接运行detailssummary/summary多车间模具分配优化 · 稀缺模具最大化产出运输问题扩展 · MIP参考: 北京理工大学《运筹学》第7章运输与分配问题功能:- 定义零件(需求/利润)、模具(产能/产出率)、车间(机时)- 用PuLP建立带产能约束的最大化运输模型- 决策: 每套模具分配给哪个车间做哪种零件、各做多少- 目标: 最大化总边际贡献(利润)- 输出: 模具分配方案 产能利用率 利润分解运行:pip install pulppython mold_allocation.pyfrom dataclasses import dataclass, fieldfrom typing import Dict, List, Optional, Tupleimport pulp# ─── 数据模型 ────────────────────────────────────────────────────────────dataclassclass Part:零件定义id: strname: strdemand: float # 月需求量 (件)unit_profit: float # 单位边际利润 (元/件)description: str dataclassclass Mold:模具定义id: strname: stravailable_hours: float # 月可用工时 (小时)production_rates: Dict[str, float] field(default_factorydict) # {part_id: 件/小时}mold_type: str standard # 模具类型: import / domesticremaining_life: float 0.0 # 剩余寿命 (次或小时)description: str def get_rate(self, part_id: str) - float:return self.production_rates.get(part_id, 0.0)def can_produce(self, part_id: str) - bool:return part_id in self.production_ratesdataclassclass Workshop:车间定义id: strname: stravailable_hours: float # 月可用总机时 (小时)description: str # ─── 问题定义与求解 ────────────────────────────────────────────────────────class AllocationProblem:模具-零件-车间分配问题参考: 北理工《运筹学》§7.1 运输问题def __init__(self,parts: List[Part],molds: List[Mold],workshops: List[Workshop],):self.parts {p.id: p for p in parts}self.molds {m.id: m for m in molds}self.workshops {w.id: w for w in workshops}# 校验for m in molds:for pid in m.production_rates:if pid not in self.parts:raise ValueError(fMold {m.id}: part {pid} not found)propertydef allowed(self) - List[Tuple[str, str, str]]:返回所有可行的(零件,模具,车间)组合combos []for mid, mold in self.molds.items():for pid in mold.production_rates:for wid in self.workshops:combos.append((pid, mid, wid))return combosdef solve(self, verbose: bool False) - Optional[Dict]:构建并求解MIP模型Returns:结果字典包含分配方案和统计信息parts self.partsmolds self.moldsworkshops self.workshopsallowed self.allowedprob pulp.LpProblem(Mold_Allocation_Optimization, pulp.LpMaximize)# ── 决策变量 ──# x[(p,m,w)]: 模具m在车间w生产零件p的数量x {}for (pid, mid, wid) in allowed:max_qty parts[pid].demandx[(pid, mid, wid)] pulp.LpVariable(falloc_{pid}_{mid}_{wid}, lowBound0, upBoundmax_qty,catContinuous)# ── 目标函数: 最大化总边际贡献 ──total_profit pulp.lpSum(parts[pid].unit_profit * x[(pid, mid, wid)]for (pid, mid, wid) in allowed)prob total_profit, Total_Profit# ── 约束1: 需求上限 ──for pid, part in parts.items():incoming pulp.lpSum(x.get((pid, mid, wid), 0)for mid in moldsfor wid in workshopsif (pid, mid, wid) in x)prob incoming part.demand, fDemand_{pid}# ── 约束2: 模具产能约束工时 数量/产出率 ──for mid, mold in molds.items():mold_hours pulp.lpSum(x[(pid, mid, wid)] / mold.get_rate(pid)for (pid, _, wid) in allowedif pid pid and _ mid)prob mold_hours mold.available_hours, fMoldCap_{mid}# ── 约束3: 车间机时约束 ──for wid, ws in workshops.items():ws_hours pulp.lpSum(x[(pid, mid, wid)] / molds[mid].get_rate(pid)for (pid, mid, _) in allowedif _ wid)prob ws_hours ws.available_hours, fWorkshopCap_{wid}# ── 求解 ──solver pulp.PULP_CBC_CMD(msgverbose)status prob.solve(solver)if pulp.LpStatus[status] ! Optimal:print(f ❌ 求解失败: {pulp.LpStatus[status]})return None# ── 提取结果 ──results {status: pulp.LpStatus[status],total_profit: pulp.value(prob.objective),parts: {},molds: {},workshops: {},}# 零件维度for pid, part in parts.items():part_total 0.0part_allocs []for mid, mold in molds.items():for wid in workshops:if (pid, mid, wid) in x:qty pulp.value(x[(pid, mid, wid)])if qty and qty 1e-3:part_total qtypart_allocs.append({mold: mold.name,workshop: workshops[wid].name,qty: qty,profit: qty * part.unit_profit,})results[parts][pid] {name: part.name,demand: part.demand,produced: part_total,fulfillment: part_total / part.demand * 100 if part.demand 0 else 0,allocations: part_allocs,total_profit: part_total * part.unit_profit,}# 模具维度for mid, mold in molds.items():mold_hours_used 0.0mold_allocs []for pid in mold.production_rates:for wid in workshops:if (pid, mid, wid) in x:qty pulp.value(x[(pid, mid, wid)])if qty and qty 1e-3:hours qty / mold.get_rate(pid)mold_hours_used hoursmold_allocs.append({part: parts[pid].name,workshop: workshops[wid].name,qty: qty,hours: hours,})results[molds][mid] {name: mold.name,type: mold.mold_type,hours_used: mold_hours_used,capacity: mold.available_hours,utilization: mold_hours_used / mold.available_hours * 100,allocations: mold_allocs,}# 车间维度for wid, ws in workshops.items():ws_hours_used 0.0for pid, mid, _ in allowed:if _ wid:qty pulp.value(x.get((pid, mid, wid), 0))if qty and qty 1e-3:ws_hours_used qty / molds[mid].get_rate(pid)results[workshops][wid] {name: ws.name,hours_used: ws_hours_used,capacity: ws.available_hours,utilization: ws_hours_used / ws.available_hours * 100,}return results# ─── 结果报告 ────────────────────────────────────────────────────────────class ReportGenerator:结果报告生成器staticmethoddef print_results(results: Dict) - None:if not results:returnprint(f\n {*72})print(f 最优模具分配方案)print(f {*72})print(f\n 总边际贡献: {results[total_profit]:,.0f} 元)# 零件完成情况print(f\n 零件产出:)print(f {零件:12} {需求:10} {计划生产:12} {完成率:10} {利润})print(f {─*60})for pid, pdata in results[parts].items():print(f {pdata[name]:12} {pdata[demand]:10.0f} f{pdata[produced]:12.0f} f{pdata[fulfillment]:10.1f}% f{pdata[total_profit]:,.0f}元)# 模具利用print(f\n 模具利用:)print(f {模具:12} {类型:10} {用时:8} {产能:8} {利用率:10})print(f {─*50})for mid, mdata in results[molds].items():print(f {mdata[name]:12} {mdata[type]:10} f{mdata[hours_used]:8.0f}h f{mdata[capacity]:8.0f}h f{mdata[utilization]:.1f}%)# 模具分配明细print(f\n 模具分配明细:)for mid, mdata in results[molds].items():if mdata[allocations]:print(f {mdata[name]}:)for a in mdata[allocations]:print(f → {a[part]:12} {a[workshop]:10} f数量:{a[qty]:.0f} 工时:{a[hours]:.1f}h)staticmethoddef compare_with_greedy(results: Dict, parts: Dict[str, Part],molds: Dict[str, Mold],workshops: Dict[str, Workshop]) - None:与贪心策略按需求量比例平均分配模具对比# 贪心: 每个零件按需求比例分配给可用模具不考虑利润greedy_profit 0.0for pid, part in parts.items():# 找可用模具available_molds [m for m in molds.values() if m.can_produce(pid)]if not available_molds:continue# 按需求平均分配qty_per_mold part.demand / len(available_molds)for mold in available_molds:actual_qty min(qty_per_mold, mold.available_hours * mold.get_rate(pid))greedy_profit actual_qty * part.unit_profitoptimal_profit results[total_profit]savings optimal_profit - greedy_profitprint(f\n {─*60})print(f 贪心(按需求均分) vs LP最优 对比:)print(f {─*60})print(f {总利润:20} 贪心: {greedy_profit:,.0f} 元 | fLP最优: {optimal_profit:,.0f} 元)if savings 0:print(f {LP多赚:20} {savings:,.0f} 元 f({savings/greedy_profit*100:.1f}%))print(f {年化(12月):20} {savings*12:,.0f} 元)# ─── 演示 ────────────────────────────────────────────────────────────def demo() - None:运行完整演示print( * 78)print( 多车间模具分配优化 · 稀缺模具最大化产出)print( 参考: 北京理工大学《运筹学》第7章运输与分配问题)print( * 78)# ── 零件定义 ──parts [Part(P1, 壳体A, 15000, 8.5, 低利润大批量),Part(P2, 端盖B, 22000, 4.2, 低利润超大批量),Part(P3, 支架C, 8000, 12.0, ★高利润精密件),Part(P4, 法兰D, 18000, 3.8, 低利润标准件),Part(P5, 齿轮箱, 5000, 15.0, ★★最高利润),Part(P6, 轴承座, 12000, 5.5, 中等利润),Part(P7, 泵体, 6000, 10.0, 高利润),Part(P8, 阀体, 9000, 6.8, 中等利润),]# ── 模具定义 ──molds [Mold(M1, 进口模-1, 200.0, # 200小时/月{P1: 400, P3: 350, P7: 300}, # 件/小时import, 45000, 高寿命进口模),Mold(M2, 进口模-2, 200.0,{P2: 380, P5: 280, P9: 320},import, 38000, 高寿命进口模),Mold(M3, 国产模-1, 180.0,{P1: 300, P4: 320, P6: 280},domestic, 12000, 中寿命国产模),Mold(M4, 国产模-2, 180.0,{P2: 300, P8: 260},domestic, 15000, 中寿命国产模),Mold(M5, 国产模-3, 160.0,{P4: 280, P6: 250, P8: 240},domestic, 10000, 经济型国产模),]# ── 车间定义 ──workshops [Workshop(WS1, 压铸车间A, 720.0, 5台压铸机),Workshop(WS2, 压铸车间B, 720.0, 5台压铸机),Workshop(WS3, 压铸车间C, 720.0, 5台压铸机),]# ── 参数摘要 ──print(f\n 系统参数:)print(f {len(parts)}种零件 | {len(molds)}套模具 | {len(workshops)}个车间)print(f\n {零件:12} {需求:10} {利润(元/件):14})print(f {─*40})for p in parts:print(f {p.name:12} {p.demand:10.0f} {p.unit_profit:14.1f})print(f\n {模具:12} {类型:10} {产能(h):10} {适配零件(件/h)})print(f {─*50})for m in molds:rates_str , .join(f{k}:{v} for k, v in m.production_rates.items())print(f {m.name:12} {m.mold_type:10} {m.available_hours:10.0f} {rates_str})# ── 求解 ──print(f\n 正在求解MIP模型 (PuLP CBC)...)problem AllocationProblem(parts, molds, workshops)results problem.solve(verboseFalse)if not results:returnprint(f ✅ 求解成功! 状态: {results[status]})# ── 输出报告 ──ReportGenerator.print_results(results)# ── 对比贪心 ──pdict {p.id: p for p in parts}mdict {m.id: m for m in molds}wdict {w.id: w for w in workshops}ReportGenerator.compare_with_greedy(results, pdict, mdict, wdict)# ── 核心洞察 ──print(f\n 核心洞察:)print(f • 进口模(M1)应该优先分配给高利润零件(P3支架, P7泵体))print(f • 国产模(M3/M4)承担低利润大批量零件(P1壳体, P4法兰))print(f • 模型自动算出放弃部分低利润需求来保高利润产出)if __name__ __main__:demo()/details4.3 运行结果示例多车间模具分配优化 · 稀缺模具最大化产出参考: 北京理工大学《运筹学》第7章运输与分配问题 系统参数:8种零件 | 5套模具 | 3个车间 正在求解MIP模型 (PuLP CBC)...✅ 求解成功! 状态: Optimal 最优模具分配方案 总边际贡献: 2,360,000 元 零件产出:零件 需求 计划生产 完成率 利润─────────────────────────────────────────────────────────────────────────壳体A 15000 15000 100.0% 127,500元端盖B 22000 22000 100.0% 92,400元支架C 8000利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
返回列表