2026/9/15 19:38:19

混成系统安全验证实战:KeYmaera X与微分动态逻辑详解

混成系统安全验证实战:KeYmaera X与微分动态逻辑详解 “模型检测”这个词在技术圈里其实有两副面孔。做AI方向的人听到它第一反应是YOLO、版面检测、红外小目标检测这种“检测模型”作用是从图像或数据里“找问题”但在形式化验证这个方向上模型检测Model Checking指的是用数学方法证明一个系统“永远不会出问题”今天要聊的KeYmaera正是这一类工具里专门啃“混成系统”硬骨头的那个。KeYmaera不是一个用来跑深度学习的工具也不是一个画状态机然后帮你枚举状态的普通验证器。它验证的对象是包含连续物理过程、又包含离散控制逻辑的系统比如自动紧急制动、无人机高度控制、舰船自主航行、恒温器调节这类“既有微分方程、又有if/else”的闭环控制系统。它的核心能力是证明这类系统在所有情况下都满足安全性质而不是只在测试用例覆盖到的场景下安全。这篇文章我会从“它到底解决什么问题”讲起然后做一次工具选型对比接着用两个完整示例带你把KeYmaera X跑起来最后把我实际用下来的坑和排查思路整理成速查表。无论你是刚接触形式化验证的学生还是在嵌入式安全领域摸爬滚打的工程师这篇文章的目标都是让你读完就能上手。1. 这个工具到底解决什么问题混成系统的“数学安检”1.1 先厘清一个高频误会模型检测不是“检测模型”如果你是因为搜“检测模型”误打误撞进来的这里先把话说明白。AI圈常说的“版面检测模型”“漏水检测训练模型”“车牌检测识别模型”本质是从样本中学习特征并推理的算法它们给出的结论是概率性的而且是针对一张图、一段波形、一帧对象做瞬时判断。而形式化验证领域的模型检测思路完全不同把系统建模成严格的状态迁移结构把需要的性质写成时序逻辑公式然后用算法遍历或推导证明性质在全部可达状态上都成立。它不依赖数据训练也不会说“99%安全”要么证明成立要么给出反例。KeYmaera在模型检测这个谱系里又往前走了一步。经典模型检测擅长分析离散状态系统而对连续动态系统通常是做抽象、离散化或有限时间仿真。KeYmaera处理的是“离散-连续耦合”的混成系统而且往往能做无限时间、全域成立的验证这一点是绝大多数数值工具做不到的。1.2 混成系统为什么难验证连续与离散的“跨域联动”先看一个直觉例子。一辆车在直道上行驶位置是x速度是v。刹车时车辆动力学满足微分方程x vv -b b是制动减速度而控制逻辑是离散的if (v^2 2*b*(S - x)) { a : -b; // 触发制动 } else { a : A; // 正常加速 }这就是一个典型的混成系统。连续部分由微分方程描述离散部分由程序分支和赋值描述两者互相影响。验证它不能只用微积分因为控制逻辑引入了状态跳转也不能只用程序验证因为连续动态会产生无穷多状态。更麻烦的是很多安全性质是无界时间的系统可能运行1毫秒也可能运行10年。数值仿真跑100万步也不能证明第100万零1步不会出事。KeYmaera的优势就在这它把混成系统程序化用微分动态逻辑表达“程序运行之后必然满足某个公式”再通过证明演算在符号层面完成验证从而覆盖无穷多初始状态和无穷长运行时间。1.3 KeYmaera的核心武器微分动态逻辑微分动态逻辑differential dynamic logic简称dC/dL读起来像“D-L”是KeYmaera的理论地基。它的公式形态比普通逻辑多两类算子[α]φ在混成程序α的所有运行结束后φ一定成立。对应“必然性”。αφ存在α的一条运行轨迹结束后φ成立。对应“可能性”。其中α是一种叫**混成程序hybrid program**的语法结构支持的原子操作包括x : θ离散赋值控制逻辑修改变量{x f(x) Q}连续演化系统按微分方程运动并且整个运动过程保持在约束Q内?F测试如果当前状态满足F就继续否则该分支失败;、∪、*顺序组合、选择分支、循环。举个简单例子[{x v, v -b v 0}] (x S)这条公式的意思是在满足演化域约束v 0的前提下系统按x v, v -b持续演化演化结束后位置x仍然不超过安全边界S。这正好对应“匀速减速过程中不会撞墙”这个安全性质。KeYmaera的证明过程本质上是对公式做结构归纳遇到连续演化就尝试找微分不变式遇到循环就找循环不变式遇到分支就两边分别证明。最终把连续动态的问题转化为代数问题由量词消解quantifier elimination完成收尾。这个过程不需要枚举状态所以能处理无穷状态空间。2. 工具选型为什么是KeYmaera而不是别的验证器2.1 先分清KeYmaera 3和KeYmaera X如果你去查资料会看到KeYmaera、KeYmaera 3、KeYmaera X三种叫法。简单区分一下KeYmaera是最早期的原型现在基本不用了。KeYmaera 3是较老的稳定版本有桌面客户端支持较多策略脚本但交互体验和扩展性都一般。KeYmaera X是当前主力版本由Scala写成底层数学引擎和证明架构重写了一遍提供Web界面可以加载.kyx模型文件也能用Tactic脚本控制证明流程。实际新项目优先选KeYmaera X。它的证明搜索策略更现代能输出更接近人类可读的证明树而且支持把证明导出成形式化校验过的证书在安全关键场景里更容易对接审计需求。2.2 和主流混成系统验证工具的对比混成系统验证工具不少我列一个对比表方便你按场景选型工具验证方式时间范围非线性支持输出适合场景HyTech多面体可达集计算无限时间弱可达/不可达线性混成系统早期教学SpaceEx支撑函数可达集计算无限时间可近似弱可达集规模较大的线性系统Flow*泰勒模型流管有界时间中等可达集估计非线性系统有界验证dReal区间约束求解有界时间强可满足/不可满足非线性约束求解delta-完备KeYmaera X演绎证明无限时间强证明证书无限时间安全性的严格证明从表里能看到一个明显的分界HyTech、SpaceEx、Flow*这类工具走的是“计算可达集”路线优点是自动化程度高缺点是一般只能处理有界时间或者需要做近似近似过头就可能漏报问题KeYmaera X走的是“逻辑证明”路线不需要枚举状态所以能处理无界时间缺点是证明过程需要人的参与尤其是找不变式的时候。2.3 数值仿真和形式证明的根本差别很多工程师第一次接触KeYmaera时会问这个用Simulink做一万次蒙特卡洛仿真不是也能验证吗答案是不能。仿真只能覆盖你跑过的那些输入和参数组合而混成系统的危险往往出现在参数边界和状态切换瞬间。更关键的是仿真结果本身是浮点数计算有数值误差它永远无法回答“在任意合法输入下所有时间点都安全”这个全称命题。KeYmaera的证明则完全不同。它处理的是符号表达式用的是逻辑推导规则最后一步的量词消解也是精确的代数运算。证明通过后结论对初始状态的整个连续区域都成立。代价也很明确你必须要能写出足够强的不变式或者至少能为证明器提供合理的引导。这不是工具缺陷而是逻辑蕴含类问题的本质成本。3. 从零上手安装、语法与第一条证明3.1 安装与启动KeYmaera X是基于JVM的所以第一步是装Java运行时。下载方面直接从KeYmaera X官网获取发行版压缩包即可通常是一个带完整依赖的zip包。安装和启动流程解压下载的压缩包到任意目录进入bin目录Windows下运行keymaeraX.batLinux/macOS下运行keymaeraX.sh等待脚本启动内嵌的Web服务器默认端口是8090浏览器打开http://localhost:8090进入KeYmaera X的图形界面。启动后你会看到几个区域左侧是模型文件列表和证明任务区中间是模型编辑器右侧是证明搜索面板和证明树视图。界面整体走极简路线没有花哨的按钮核心操作就那么几个加载模型、创建证明任务、运行证明策略、展开证明树。我建议第一次用的时候直接打开自带示例里的00-basics或CPS tutorials系列先跑通一个证明再写自己的模型。不要一上来就挑战复杂问题KeYmaera X的证明策略对模型写法非常敏感先熟悉它的“脾气”很重要。3.2 一个最小模型常值制动下的安全距离下面看一个最经典的入门模型汽车以恒定减速度刹车证明只要初始速度满足安全距离条件刹车过程中就不会越过危险边界S。创建一个.kyx文件内容如下ProgramVariables R x, v, b, S; End Problem v 0 b 0 S 0 v^2 2*b*(S - x) - [ {x v, v -b v 0} ] x S End逐行解释一下ProgramVariables声明了实数类型的变量x位置、v速度、b制动减速度、S边界位置Problem部分写待证明公式符号表示合取-表示蕴含[ ... ]是必然性算子{x v, v -b v 0}是一个连续演化程序后面是演化域约束这里表示演化的全过程速度必须非负最后的安全性质是x S也就是位置始终不超过边界。这个模型的物理含义很直观初始速度的平方不超过2*b*(S - x)也就是当前剩余距离足够把车刹停那么以恒定减速度b刹车车在停下来之前不会撞到边界。3.3 运行自动证明理解证明背后的规则在编辑器中加载这段模型后点击“Derive”或“Run Proof Search”按钮KeYmaera X会自动尝试证明。如果策略成功右侧会生成一棵证明树树的叶子都标记为closed。多数情况下你会看到证明树里包含这样几步关键操作应用连续演化规则把[{x v, v -b v 0}] (x S)拆成关于微分不变式的子目标。寻找微分不变式因为x在变v也在变直接证明x S在演化过程中恒成立并不容易需要找一个更强的辅助条件。这个例子里一个自然的微分不变式是v^2 2*b*(S - x)为什么这个式子能当不变式因为它对时间求导等于2*v*v 2*b*v 2*v*(-b) 2*b*v 0导数恒等于0说明这个量在运动过程中保持不变。只要初始满足整个刹车过程就始终满足。这个“求导为零”的性质正是微分不变式规则dI能证明的目标。处理边界与算术条件剩余子目标变成纯代数不等式KeYmaera X调用量词消解引擎完成闭合。从这个例子里你已经能感受到KeYmaera的工作模式它不是一个“炼丹”工具而是一个“解题”工具你的任务是提供安全性质、物理模型以及必要时候的辅助不变式。自动策略能处理常规套路但遇到非线性强、分支多的系统它需要你喂思路。4. 核心实操验证一个带控制策略的紧急制动模型4.1 建模两个离散分支下的连续动力学现在把上一节的单段制动扩展成完整控制循环车辆先正常行驶当检测到距离过近时触发紧急制动然后循环可以重复。用KeYmaera X可以写出这样的混成程序ProgramVariables R x, v, a, A, b, S; End Problem x 0 v 0 b 0 A 0 v^2 2*b*(S - x) - [ ({ if (v^2 b*(S - x)) { a : -b; } else { a : A; } {x v, v a v 0} })* ] x S End这段代码里({ ... })*表示控制策略可以无限次重复执行。每次迭代先根据当前状态选择一个加速度值再按连续动力学演化一小段时间演化过程中速度始终非负。需要说明的是这个完整模型的安全证明比单段制动要复杂得多自动策略一般无法一步跑通。这里我特意把模型写出来是为了展示真实混成程序的样子赋值、分支、连续演化以循环的形式嵌套在一起。你能清楚看到“离散控制决定连续动态连续动态反过来改变离散判断条件”的双向耦合。4.2 找出全局不变式验证的灵魂步骤对于带循环的程序要证明[α*]φ核心策略是找一个循环不变式I满足三个条件初始状态蕴含II经过一次循环体后仍然成立归纳步I蕴含目标性质φ。在刹车这个例子里最自然的循环不变式还是那个安全距离不等式I : (v^2 2*b*(S - x))从物理意义看它恰好描述了“剩余制动距离足够”这一安全裕量。只要每次控制循环结束时安全裕量保持最终就不会撞上边界。接下来要验证三个条件。初始条件不难因为前提里已经给了。归纳步分两个分支若v^2 b*(S - x)则执行a : -b车辆以最大减速度制动。需要证明从安全裕量满足的任意状态出发制动一段时间后仍然满足I。此时又需要用微分不变式或微分割dC对连续演化做细粒度分析。若v^2 b*(S - x)则执行a : A车辆可以加速。但要保证加速不超过安全边界因此演化域约束v 0和前提条件中的v^2 2*b*(S - x)共同限制了可加速的幅度和时长。第三步验证I - (x S)这是纯代数推导由量词消解直接处理。4.3 在KeYmaera X中实操如何引导证明策略直接点自动证明基本会失败因为策略第一步需要人工指定循环不变式。实操中的做法是在界面上对[α*]φ应用循环不变式规则KeYmaera X会弹出对话框要求输入不变式输入上面讨论的v^2 2*b*(S - x)确认后证明树会生成三个分支分别对应初始条件、归纳步、目标蕴含归纳步继续展开先处理赋值再处理连续演化连续演化分支通常在自动策略下可能再次卡住这时可以手动应用dC微分割把v^2 2*b*(S - x)作为额外约束加进去降低证明难度最后剩下的纯算术目标交给量词消解策略收尾。这里一定要有心理准备证明过程不是“一键生成”的尤其第一次接触循环不变式时你大概率要反复试几次。KeYmaera X的好处是证明树会保留你所有操作步骤失败分支可以回滚不会弄乱全局状态。我通常的习惯是先用自动策略跑观察它卡在哪一步再针对卡住的子目标手动引入辅助不变式。4.4 一个容易犯的建模错误演化域约束过强写连续演化时一个非常容易犯的错误是把演化域当成“额外保证”来用比如写成{x v, v -b x S}这样写表面上把安全性质塞进了演化域好像系统的运行范围被限制住了但实际是自欺欺人。KeYmaera会认为这个演化程序只在x S的区域内运行一旦车辆到达边界程序行为就变得不确定或直接终止于是你证实的东西不再是“永远不会撞墙”而是“在没撞墙之前它没撞墙”。这种循环论证看起来证明了安全实际上什么都没证明。正确做法是演化域只放物理必然成立的限制条件比如v 0速度不会为负因为车在撞上前不会再反向行驶、水位有上下界这类由物理规律保证的不变条件。目标性质永远放在方括号后面让它成为待证明的结论而不是前提的一部分。5. 常见问题与排查技巧实录5.1 证明卡住/超时的排查思路KeYmaera X跑不动大多数原因不是工具不行而是模型或策略有问题。我按频率排序列几个最常见的情况现象可能原因排查思路自动策略几秒钟就停止叶子未关闭缺少辅助不变式检查是否需要对连续演化施加微分割是否循环不变式太弱证明树一直变深但无法收敛循环不变式不成立或不够强从物理意义上重新设计不变式用仿真画图辅助验证量词消解阶段极慢存在高次多项式或参数耦合尝试对参数做归一化消除次要参数简化模型再验证出现unknown或tool error变量未声明或使用了不支持的操作检查.kyx语法确保所有常量在ProgramVariables或Functions中声明其中“不变式太弱”是最隐蔽的坑。你可能想了一个不变式初始条件蕴含它它也能推出目标但归纳步就是过不去。这说明当前不变式没有充分刻画系统在循环体执行过程中的关键守恒量需要补充额外的辅助不变式。5.2 关于微分不变式的心得微分不变式是整个KeYmaera使用中最考验直觉的一环。我自己的经验是先写出系统的物理守恒量再把它转化成一个不等式。比如刹车模型里守恒量是“总制动距离预算”对应代数式v^2 2*b*x 2*b*S它随时间导数为零。又比如水箱水位模型守恒量可以是“注入速度和排出速度的差值”。从物理守恒量出发找不变式成功率远高于凭空猜代数式。另一个小技巧微分不变式不一定非要“导数为零”只需导数符号满足方向条件即可。比如要证明F 0始终保持只需要在F 0的边界上让F 0这样F不会穿过零向下。KeYmaera X的dI规则会自动处理这种边界条件但你需要知道它可以这样用否则容易错过很多可行的不变式。5.3 新手最容易踩的五个坑模型写得太复杂。一上来就想验证完整的自动驾驶系统结果找不到不变式。正确的路径是先验证纯动力学子问题再逐步加入控制分支。忽略前提条件的完备性。安全性质往往只在物理可能的状态下成立前提里要写清楚变量范围如b 0、v 0、S 0否则证明会失败而且失败得很莫名其妙。混淆KeYmaera 3和KeYmaera X语法。网上的老教程很多是KeYmaera 3时代的语法直接复制到KeYmaera X会报错。认准.kyx格式的现代语法。跳过量词消解的符号问题。有时公式在实数上成立但因为有未声明类型的变量量词消解引擎会把它当复数或新常量处理。解决办法是所有变量显式声明为R实数。把仿真结果当成验证依据。仿真能帮你理解系统行为、寻找不变式线索但它不能替代证明。在KeYmaera里仿真的角色是辅助建模不是结论来源。5.4 我推荐的上手路线图如果你是从零开始不要急着做自己的系统。先按这个顺序练手跑通KeYmaera X自带的00-basics系列理解证明树界面把本文的常值制动模型复现一遍尝试修改参数观察证明树变化自己设计一个简单的水箱液位控制模型用[ ... ]公式描述“水位不超限”再尝试给模型加一个离散反馈分支体会循环不变式的作用最后再挑战完整控制策略的验证并尝试引入微分割、辅助不变式等高级技巧。这个过程走完你对KeYmaera的建模语法、证明策略和不变式思维基本就有感觉了。最后分享一点个人体会我实际用下来的最大感受是KeYmaera真正逼人成长的地方不在证明本身而在写模型的过程。为了能证明一个性质你必须把控制策略、物理假设、边界条件全部表达得极其精确任何一处模糊都会在证明器里变成错误或卡住的分支。这种建模纪律反哺到平时的系统设计里收益远比“证明通过”这个结果本身值钱。另一个让我印象深刻的点是不变式的思考方式。以前我写控制代码只关心当前时刻的行为对不对用过KeYmaera之后我会习惯性问自己这个控制回路的循环里什么量是真正守恒的什么条件必须永远保持这个“跳出单步执行、看全生命周期”的视角对做安全和可靠性相关的系统开发尤其重要。最后再给大家一个实际经验从最小模型开始。哪怕你的目标是验证一个大型系统也一定先拆出最核心的物理约束用几行代码跑通一条最简单的证明再逐步加入控制分支、扰动、参数不确定性。模型一旦复杂起来找问题和修不变式的时间是指数级增长的前期的简化能帮你省下大量调试时间。这个原则我在多次实操里反复验证过按这个节奏走KeYmaera的门槛会低很多。