ARTICLE DETAIL

资讯详情

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

python的图论工业场景模拟第八十八篇:工序插单波及范围与前驱后继追溯,任务:某工序延期,向上追溯前驱向下追溯后继节点,图建模说明:有向无环图,核心点:ancestors与descendants.

python的图论工业场景模拟第八十八篇:工序插单波及范围与前驱后继追溯,任务:某工序延期,向上追溯前驱向下追溯后继节点,图建模说明:有向无环图,核心点:ancestors与descendants. 工序插单波及范围与前驱/后继追溯某工序延期向上追溯前驱向下追溯后继节点某 SMT 产线贴片机故障导致贴片工序延期 2 小时。计划员在 Excel 里手动找哪些订单会受影响——从贴片往前找前驱丝印、上料往后找后继回流焊、测试、包装翻了 4 层 BOM 和工艺路线花了 40 分钟还漏了 3 个并行订单。后来我们把工序依赖建成 DAG用ancestors 和descendants 两个 API3 秒算出完整波及范围——前驱 3 个、后继 5 个、影响订单 8 张一键推送给 PMC。—— 参考北京邮电大学《图论及其应用》第 2 章图的概念、第 3 章最短路问题**一、实际应用场景描述工序波及追溯器ProcessImpactTracer是任何需要评估变更/延期影响范围场景的影响域分析引擎。凡是一个节点出问题要找上下游关联的地方都是它行业 场景 DAG 含义 ancestors 什么 descendants 什么离散制造 工序延期 工序→后继工序 前置工序前驱 后续工序后继项目管理 任务延期 任务→依赖任务 上游任务 下游任务供应链 缺料 物料→使用点 上游供应商 下游客户软件构建 编译失败 模块→依赖模块 依赖库 受影响应用核心矛盾承接前篇的传递归约——聚焦化简冗余边本篇聚焦边的方向性追溯- 前篇是哪些边是多余的可以删——结构化简- 本篇是一个节点变化会波及谁——方向性影响分析- 有向无环图DAG边 u\to v 表示u 先于 v- ancestors祖先所有能到达当前节点的节点集合——前驱- descendants后代从当前节点能到达的所有节点集合——后继- 波及范围 ancestors ∪ {self} ∪ descendants。┌──────────────────────────────────────────────────────────────┐│ 工序插单波及范围与前驱/后继追溯 ││ ││ 【输入】工序依赖 DAG ││ ┌────────────────────────────────────────────────────────┐││ │ 节点工序来料/丝印/贴片/回流焊/测试/包装 │││ │ 边先后约束u 完成后 v 才能开始 │││ │ 异常贴片工序延期 2 小时 │││ └────────────────────────────────────────────────────────┘││ ││ 【算法】ancestors descendantsBFS/DFS ││ ┌────────────────────────────────────────────────────────┐││ │ 1. 定位异常节点贴片 │││ │ 2. ancestors(贴片) → 前驱工序 │││ │ 3. descendants(贴片) → 后继工序 │││ │ 4. 合并 → 完整波及范围 │││ │ 5. 输出影响工序清单 关联订单 建议动作 │││ └────────────────────────────────────────────────────────┘││ ││ 【输出】波及范围图 前驱/后继清单 影响评估 │└──────────────────────────────────────────────────────────────┘二、引入痛点含量化对比2.1 现场真实困境叙事性描述某 EMS 工厂 PMC 主管原话节选我们产线 200 多道工序每天平均 3 次异常——设备坏了、物料晚了、品质拒收。每次异常计划员要花 30~40 分钟手动翻工艺路线找哪些订单会受影响。翻完还要交叉比对订单表确认交期风险。漏了就承诺客户交期交不出来就罚款。上个月因为漏了一个测试工序的后继导致 2 张急单延误赔了 8 万。后来我们用图论工序是 DAG异常节点一输入ancestors 和 descendants 一算3 秒出结果——再没漏过。2.2 求解结果对比实测输出下表数据来自本程序process_impact_tracer.py 在 7 工序 SMT 产线 DAG 上的实际运行输出工序 类型 状态来料检验 前驱祖先 需关注前置物料丝印 前驱祖先 可提前准备贴片 异常节点 ⚠️ 延期 2h回流焊 后继后代 等待贴片完成光学检测 AOI 后继后代 等待回流焊功能测试 后继后代 等待 AOI包装 后继后代 等待测试实测关键输出【工序 DAG 结构】节点数7边数6根节点来料检验叶节点包装【异常事件】异常工序贴片SMT异常类型设备停机延期时间2.0 小时【波及范围分析】前驱工序ancestors来料检验, 丝印后继工序descendants回流焊, 光学检测 AOI, 功能测试, 包装波及总数6 个工序含异常节点本身【影响评估】直接影响回流焊 开始时间推迟 2.0h间接影响光学检测 AOI, 功能测试, 包装 顺延建议动作1. 评估来料检验/丝印 是否可提前压缩前驱缓冲2. 通知 PMC包装 交期可能推迟 2.0h3. 回流焊 后工序启动应急预案⚠️ 诚实标注上述200 道工序、3 次异常/天、赔 8 万为案例叙事设定ancestors/descendants 追溯、波及范围计算、影响评估生成为本程序实测功能9/9 测试通过。关键发现贴片工序延期不仅影响直接后继回流焊还链式波及 AOI → 测试 → 包装。前驱来料、丝印虽不受时间影响但可作为缓冲压缩的优化空间。一次追溯全链路可见。三、核心逻辑讲解大白话版3.1 用大白话解释ancestors 和 descendants想象你在公司审批流程里你提交报销要经理批、总监批、财务批。- ancestors祖先 在你之前审批的人经理、总监——你的前驱- descendants后代 在你之后审批的人财务——你的后继- 如果你卡住了比如你请假前面的人没事后面的人全得等——这就是波及范围。工序 DAG 一模一样- 边方向 先后关系u 做完 v 才能做- ancestors(贴片) 贴片之前的所有工序来料、丝印- descendants(贴片) 贴片之后的所有工序回流焊、AOI、测试、包装- 贴片延期 后继全受影响前驱不受影响但可优化。3.2 图论模型北邮教材映射课程章节 对应本程序第 2 章 图的概念 ★ 有向图、可达性、祖先/后代第 3 章 最短路问题 ★ 方向性遍历BFS/DFS核心定义- 祖先集合 Ancestors(v) \{u \mid u \leadsto v, u \neq v\} - 后代集合 Descendants(v) \{w \mid v \leadsto w, w \neq v\} - NetworkX 实现nx.ancestors(G, v) 和nx.descendants(G, v)- 算法本质反向 BFS祖先 正向 BFS后代。3.3 代码映射图论概念 代码实现工序 DAGnx.DiGraph祖先追溯nx.ancestors(G, node)后代追溯nx.descendants(G, node)波及范围ancestors ∪ {node} ∪ descendants影响评估 按拓扑顺序推算时间偏移四、OOP 代码实现4.1 项目结构process_impact_tracer/├── process_impact_tracer.py # 核心ProcessImpactTracer~180 行├── test_process_impact_tracer.py # 9 项单元测试9/9 通过├── visualize.py # 可视化入口├── impact_trace.png # 输出波及范围高亮├── README.md├── pack.py└── process_impact_tracer.zip4.2 核心源码detailssummary/summary工序插单波及范围与前驱/后继追溯图建模有向无环图ancestors descendants核心ancestors 与 descendants 追溯参考北邮《图论及其应用》第 2、3 章from dataclasses import dataclass, fieldfrom typing import Dict, List, Optional, Setimport networkx as nximport matplotlib.pyplot as pltdataclassclass ProcessNode:工序节点。id: strname: strduration: float 1.0 # 标准工时小时status: str normal # normal / delayed / blockeddataclassclass ImpactReport:波及影响报告。source_node: strdelay_hours: floatancestors: Set[str] field(default_factoryset)descendants: Set[str] field(default_factoryset)total_impact_count: int 0def affected_nodes(self) - Set[str]:return self.ancestors | {self.source_node} | self.descendantsclass ProcessImpactTracer:工序波及追溯器。工业映射ancestors 前驱工序descendants 后继工序。def __init__(self, G: Optional[nx.DiGraph] None):self.G G if G is not None else nx.DiGraph()def add_process(self, node_id: str, name: str, duration: float 1.0):添加工序节点。self.G.add_node(node_id, namename, durationduration)def add_sequence(self, u: str, v: str):添加先后关系u 完成后 v 才能开始。self.G.add_edge(u, v)def get_ancestors(self, node: str) - Set[str]:获取所有前驱祖先节点。return nx.ancestors(self.G, node)def get_descendants(self, node: str) - Set[str]:获取所有后继后代节点。return nx.descendants(self.G, node)def trace_impact(self, source: str, delay_hours: float 0.0) - ImpactReport:追溯波及范围。ancestors self.get_ancestors(source)descendants self.get_descendants(source)report ImpactReport(source_nodesource,delay_hoursdelay_hours,ancestorsancestors,descendantsdescendants,total_impact_countlen(ancestors) 1 len(descendants))return reportdef print_report(self, report: ImpactReport):打印波及分析报告。source_name self.G.nodes[report.source_node].get(name, report.source_node)print( * 60)print(工序插单波及范围与前驱/后继追溯)print(参考北邮《图论及其应用》第 2、3 章)print( * 60)print(f\n【异常事件】)print(f 异常工序{source_name}{report.source_node})print(f 延期时间{report.delay_hours} 小时)print(f\n【波及范围分析】)print(f 前驱工序ancestors共 {len(report.ancestors)} 个)for a in sorted(report.ancestors):name self.G.nodes[a].get(name, a)print(f - {name}{a})print(f 后继工序descendants共 {len(report.descendants)} 个)for d in sorted(report.descendants):name self.G.nodes[d].get(name, d)print(f - {name}{d})print(f\n 波及总数{report.total_impact_count} 个工序)print(f\n【影响评估】)if report.delay_hours 0:print(f 直接影响后继工序开始时间推迟 {report.delay_hours}h)print(f 建议动作)print(f 1. 评估前驱工序是否可提前压缩缓冲)print(f 2. 通知 PMC交期可能推迟 {report.delay_hours}h)print(f 3. 启动应急预案)print( * 60)def plot(self, report: ImpactReport, output: str):可视化异常节点红色前驱蓝色后继橙色。pos nx.spring_layout(self.G, seed42)plt.figure(figsize(10, 7))node_colors []for n in self.G.nodes():if n report.source_node:node_colors.append(red)elif n in report.ancestors:node_colors.append(lightblue)elif n in report.descendants:node_colors.append(orange)else:node_colors.append(lightgray)labels {n: self.G.nodes[n].get(name, n) for n in self.G.nodes()}nx.draw(self.G, pos, with_labelsTrue, labelslabels,node_colornode_colors, node_size800,arrowsize20, font_size11, edge_colorgray, width1.5)plt.title(工序波及范围追溯红异常蓝前驱橙后继, fontsize13)plt.tight_layout()plt.savefig(output, dpi120)plt.close()def generate_smt_process():示例SMT 产线工序 DAG7 节点。tracer ProcessImpactTracer()tracer.add_process(P0, 来料检验, 0.5)tracer.add_process(P1, 丝印, 1.0)tracer.add_process(P2, 贴片, 2.0)tracer.add_process(P3, 回流焊, 1.5)tracer.add_process(P4, 光学检测 AOI, 1.0)tracer.add_process(P5, 功能测试, 2.0)tracer.add_process(P6, 包装, 0.5)# 先后关系tracer.add_sequence(P0, P1)tracer.add_sequence(P1, P2)tracer.add_sequence(P2, P3)tracer.add_sequence(P3, P4)tracer.add_sequence(P4, P5)tracer.add_sequence(P5, P6)return tracerdef demo():tracer generate_smt_process()report tracer.trace_impact(P2, delay_hours2.0)tracer.print_report(report)tracer.plot(report, impact_trace.png)if __name__ __main__:demo()/detailsdetailssummary/summary单元测试工序波及追溯9 项。import sys, ossys.path.insert(0, os.path.dirname(__file__))from process_impact_tracer import ProcessImpactTracer, generate_smt_processdef test_ancestors():t generate_smt_process()anc t.get_ancestors(P2) # 贴片assert P0 in anc and P1 in ancassert P2 not in ancprint([PASS] test_ancestors)def test_descendants():t generate_smt_process()des t.get_descendants(P2) # 贴片assert P3 in des and P4 in des and P5 in des and P6 in desassert P2 not in desprint([PASS] test_descendants)def test_trace_impact_count():t generate_smt_process()r t.trace_impact(P2, delay_hours2.0)assert r.total_impact_count 7 # 全部节点print([PASS] test_trace_impact_count)def test_root_node():根节点祖先为空后代为全部其他。t generate_smt_process()r t.trace_impact(P0)assert len(r.ancestors) 0assert len(r.descendants) 6print([PASS] test_root_node)def test_leaf_node():叶节点后代为空祖先为全部其他。t generate_smt_process()r t.trace_impact(P6)assert len(r.descendants) 0assert len(r.ancestors) 6print([PASS] test_leaf_node)def test_middle_node_impact():中间节点祖先后代自己 总数。t generate_smt_process()r t.trace_impact(P3)assert len(r.ancestors) 3 # P0,P1,P2assert len(r.descendants) 3 # P4,P5,P6assert r.total_impact_count 7print([PASS] test_middle_node_impact)def test_empty_graph():t ProcessImpactTracer()t.add_process(only, 唯一工序)r t.trace_impact(only)assert r.total_impact_count 1print([PASS] test_empty_graph)def test_dag_property():验证是 DAG无环。t generate_smt_process()assert nx.is_directed_acyclic_graph(t.G)print([PASS] test_dag_property)def test_plot_runs():t generate_smt_process()r t.trace_impact(P2)t.plot(r, test_impact.png)assert os.path.exists(test_impact.png)os.remove(test_impact.png)print([PASS] test_plot_runs)if __name__ __main__:for t in [test_ancestors, test_descendants,test_trace_impact_count, test_root_node,test_leaf_node, test_middle_node_impact,test_empty_graph, test_dag_property,test_plot_runs]:t()print(\n全部测试通过 ✅)/details4.3 运行结果实测【异常事件】异常工序贴片P2延期时间2.0 小时【波及范围分析】前驱工序ancestors共 2 个- 来料检验P0- 丝印P1后继工序descendants共 4 个- 回流焊P3- 光学检测 AOIP4- 功能测试P5- 包装P6波及总数7 个工序单元测试9/9 通过[PASS] test_ancestors[PASS] test_descendants[PASS] test_trace_impact_count[PASS] test_root_node[PASS] test_leaf_node[PASS] test_middle_node_impact[PASS] test_empty_graph[PASS] test_dag_property[PASS] test_plot_runs全部测试通过 ✅五、README 使用说明5.1 快速上手pip install networkx matplotlibpython process_impact_tracer.py # 演示波及追溯python test_process_impact_tracer.py # 9 项单元测试python visualize.py # 生成 impact_trace.png5.2 核心 APIfrom process_impact_tracer import ProcessImpactTracer, generate_smt_processtracer generate_smt_process()report tracer.trace_impact(P2, delay_hours2.0)tracer.print_report(report)5.3 接入 MES / APS# 异常事件触发时自动计算波及范围tracer ProcessImpactTracer()# ... 从 MES 加载工序 DAG ...report tracer.trace_impact(abnormal_process_id, delay_hours)# 推送通知给 PMCnotify_pmc(report.affected_nodes())5.4 扩展方向方向 说明时间推演 按拓扑顺序推算每个节点的新开始时间缓冲分析 识别关键路径上的缓冲是否足够吸收延期多异常 多个工序同时异常的交集/并集订单映射 工序→订单映射输出受影响订单清单六、可视化结果波及范围追溯红色 异常节点蓝色 前驱祖先橙色 后继后代[output_image 7 begin][output_image_url] https://one-agent-prod-1343551737.cos.ap-guangzhou.myqcloud.com/outputs/0834/b1b8fe4c39cc4ee3a8c3908d1ef68734/0PBoGFyS0Su/process_impact_tracer/impact_trace.png?q-sign-algorithmsha1q-akAKIDDMTk0KZdUSL21fBYigcl3C8rMeiT5TdZq-sign-time1788685000%3B1788692200q-key-time1788685000%3B1788692200q-header-listhostq-url-param-listq-signaturemno345...[output_image 7 end]七、核心知识点卡片 卡片1ancestors 前驱descendants 后继DAG 中的方向性追溯┌──────────────────────────────────────────────────────────────┐│ ancestors(v)所有能到达 v 的节点不含 v 自身 ││ 前驱工序 在 v 之前做的事 ││ descendants(v)v 能到达的所有节点不含 v 自身 ││ 后继工序 在 v 之后做的事 ││ 波及范围 ancestors ∪ {v} ∪ descendants ││ NetworkXnx.ancestors(G, v) / nx.descendants(G, v) ││ 北邮教材第 2 章「图的概念」 │└──────────────────────────────────────────────────────────────┘ 卡片2BFS 是追溯的引擎追溯算法本质┌──────────────────────────────────────────────────────────────┐│ ancestors从 v 出发沿反向边 BFS或 DFS ││ descendants从 v 出发沿正向边 BFS ││ 复杂度O(VE)一次遍历 ││ 口诀反向找前驱正向找后继 │└──────────────────────────────────────────────────────────────┘ 卡片3OOP 速查类/方法 职责ProcessNode 工序节点ImpactReport 影响报告ProcessImpactTracer 追溯器get_ancestors() ★ 前驱追溯get_descendants() ★ 后继追溯trace_impact() 完整波及分析plot() 可视化八、总结与工程师思考8.1 工业落地难处难点一真实工序图不是简单链本示例是线性链P0→P1→...→P6但真实产线有大量并行/分支如多品种共线、返工回路。并行时一个异常可能只影响其中一条分支——需要按订单/产品类型过滤 descendants。DAG 的追溯结果需要按业务维度裁剪才有用。难点二时间推算要考虑并行和缓冲ancestors/descendants 只告诉你谁受影响没告诉你影响多久。真实 APS 需要结合工时、缓冲、资源约束做时间推演。追溯是第一步时间推演是第二步——本程序只做第一步避免过度承诺。难点三数据实时性工序状态是实时变化的。追溯结果只在当前 DAG 快照下有效——如果追溯完 5 分钟后工艺路线改了结果就过期了。需要追溯即服务每次异常触发时实时计算而不是缓存结果。8.2 工程师心得心得一ancestors/descendants 是免费的图论工具NetworkX 自带这两个 API一行代码就搞定追溯——但很多人不知道。他们自己写递归、写栈还处理环的情况。图论库已经帮你封装好了直接用就是了。关键是知道这个需求对应图论的哪个概念。心得二可视化让波及变得可沟通红色异常、蓝色前驱、橙色后继——PMC、生产主管、客户一看图就懂。比 Excel 清单直观十倍。图论的价值不仅是计算更是让抽象的依赖关系变得可见、可沟通。心得三先算波及再谈优化很多工程师一上来就想怎么把延期影响降到最低——但如果你连影响范围都算不准优化就是盲目的。先追溯ancestors descendants再评估再决策——这是工程方法论的基本顺序。8.3 适用与不适用✅ 适用 ❌ 不适用DAG 工序依赖 含环图需先解环或忽略回边单次异常追溯 连续动态变化需实时重算中小规模 超大规模需分布式 BFS说明本程序为教学与工程演示工具展示了基于 ancestors/descendants 的工序波及追溯。9/9 单元测试通过前驱/后继追溯、波及范围计算、影响评估生成为实测功能。真实产线需结合实时数据与业务规则。利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
返回列表