IC3算法简析
IC3算法是一种形式化验证方法。 在《Efficient Implementation of Property Directed Reachability》一文中,又将此方法命名为PDR。IC3在模型检测竞赛(HWMCC)中取得突出成绩后引起广泛重视。
参考文章:A. Griggio and M. Roveri, "Comparing Different Variants of the ic3 Algorithm for Hardware Model Checking," in IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems, vol. 35, no. 6, pp. 1026-1039, June 2016, doi: 10.1109/TCAD.2015.2481869.
1 基础(preliminaries)
1.1 布尔变量(variables)
诸如x1,x2,...,xn这样取值为真(1)或假(0)的变量
1.2 文字(literals)
一个literal是一个布尔变量或者布尔变量的非,即x1、¬x2均为文字(literal)
1.3 cube和clause
一个cube是若干literal的合取,形如x1∧x2∧x6∧¬x3
一个clause是若干literal的析取,形如x1∨x3∨¬x5
根据德摩根率:对一个cube取非即可得到一个literal,即¬(x1∧x3∧¬x4)≡¬x1∨¬x3∨x4
1.4 合取范式(conjunction normal form, CNF)
形如clause∧clause∧⋯∧clause的逻辑表达式,
cube即为合取范式(CNF),
逻辑公式(formula,简称“公式”)一般用合取范式(CNF)来表示。
1.5 迁移系统(Transition System)
一个迁移系统由三部分组成,分别是变量集合、初始状态(公式)和迁移关系(公式)。
1.5.1 变量集合
包括两部分:
- 状态变量集合X:{x1,x2,…,xn}(state variables)
- 初始输入变量集合Y:{y1,…,ym}(primary input variables)
1.5.2 系统状态
可以用一个包含所有 状态变量的cube来表示一个“系统状态”,这样的cube也叫miniterm;
可以用一个包含部分 状态变量的cube来表示若干“系统状态”的集合;
所有状态变量的一种赋值为系统的一个状态;
而当一个cube成真时,可以得到一种(或若干种)所有状态变量的赋值
1.5.3 初始状态(公式)
用公式I(X)表示初始状态集合
初始状态为 “使I(X)成真时,所有状态变量的赋值的可能情况”
1.5.4 迁移关系(公式)
用公式T(Y,X,X′)表示迁移关系。
X中每个状态变量对应一个后继变量,即xi⟹x′i, xi∈X;
用对应的后继变量替换X中的每个状态变量,可得到 X' ;
Y相当于中间变量,不参与系统状态组成 ;
迁移关系形如
一步迁移可以表示为:
其中,s(X)为一个cube,用来表示系统状态;
该蕴含式可以理解为在系统M中,给定输入变量集合Y的赋值,经过一步迁移可以从状态集合si−1到达状态集合si
1.6 不变式验证问题(invariant checking problem)
公式P(X)表示安全状态集合(a set of good states);
若系统S中的所有可达状态都在安全状态集合里,则称系统S满足公式P(X), 记为S⊨P(X);
称P(X)是系统S的一个不变式(invariant);
如果P(X)不是不变式,则存在一个有限长度的状态序列(counterexample run)为s0,s1,…,sk,满足s0⊨I(X), sk⊭
1.7 归纳不变式(inductive invariant)
归纳不变式F(X)满足两个条件:
- I(X)\models F(X)
- F(X)\land T(Y, X, X') \models F(X')
若F(X)为归纳不变式,则根据定义,F(X)亦为不变式
1.8 归纳强化(inductive strengthening)
通常待验证性质P(X)可能是不变式,但通常不会是归纳不变式。
这时需要找到性质P(X)的一个归纳强化——公式R(X);
使得P(X)归纳强化后的公式P(X)\land R(X)是一个归纳不变式;
则可推出P(X)是一个不变式。
1.9 相对归纳(inductive relative)
公式F(X)相对归纳于(is inductive relative to)公式G(X, X'),则有
- I(X) \models F(X),每个初始状态都满足F
- G(X,X')\land F(X)\land T(Y, X, X')\models F(X'),在给定前提G(X,X')成立的情况下,F(X)是归纳成立的。
2 IC3算法思想
验证性质P(X)是系统S = (I(X), T(Y,X,X'))一个安全性质(不变式)
IC3算法尝试构造一个归纳不变式F(X)
使得F(X)是性质P(X)归纳强化后的公式,则有
- I(X) \models F(X)
- F(X)\land T(Y, X, X')\models F(X')
- F(X)\models P(X)
可得出性质P(X)是系统S的一个安全性质。
2.1 构造归纳不变式
IC3算法中主要维护一个公式序列F_0(X), F_1(X),\dots,F_k(X)(归纳不变式若存在,则从这序列中产生)
该序列中每一项(F_i(X))是一个frame
算法运行过程中,该序列须满足的条件是:
- F_0 =I,即F_0(X) = I(X)的简写,以下均简写
- F_i是一个clause集合,即为一个合取范式(CNF)
- F_{i+1}\subseteq F_i,表示F_{i+1}中包含的clauses是F_i的子集,亦即F_i\models F_{i+1}
- F_i(X)\land T(Y, X, X')\models F_{i+1}(X'),即从F_i可经一步迁移到F_{i+1}
- F_i\models P,\ 0\leq i<k
2.1.1 得出目标归纳不变式
若程序运行中找出了一个序列F_0,\dots, F_i,F_{i+1},\dots,F_k,该序列满足以上条件。
再检查该序列,若有F_i=F_{i+1},\ 0\leq i<k,则找到目标归纳不变式F_i .
为甚么?
- 根据上述条件4和F_i=F_{i+1},可得到F_i\land T \models F_i' ;
- 根据条件1和条件3,可得到I\models F_i;
- 根据条件5,可得到F_i\models P ;
有以上三点,根据归纳不变式定义,则F_i是目标归纳不变式,且P是不变式。
2.2 算法实现
bool IC3(I, T, P):
if is_sat(I & !P): return False
F[0] = I # first element of trace is init-formula
k = 1, F[k] = T # add a new frame to the trace
while True:
# blocking phase
while is_sat(F[k] & !P):
c = get_state(F[k] & !P) # c => F[k] & !P, c is a cube
if not rec_block(c, k):
return False # counterexample found
# propagation phase
k = k + 1, F[k] = T
for i = 1 to k-1:
for each clause c in F[i]:
if not is_sat(F[i] & c & T & !c'):
add c to F[i+1]
if F[i] == F[i+1]: return True # property proved
IC3要生成一个公式序列F_0,\dots, F_k,并确保该公式序列满足2.1
节列出的条件(以下“条件”特指2.1
节所列条件,用条件i代表第几项条件)。
1. init
首先构造初始序列F[0] = I, F[k] =T, k=1(F[k]=T相当于不包含任何clause),并检查了F_0\models P是否成立(若成立,即is\_sat(I\ \&\ !P)不能够满足;反之,IC3验证失败),若F_0\models P成立,则初始序列满足所有条件。 随后进入主while循环
2. blocking phase
当构造了一个满足所有条件的序列之后(例如上述构造的初始序列),接下来尝试拓展该序列(增加一个frame)。但在那之前,我们还需要验证公式F[k]\models P是否成立,若它成立,我们才能在F[k]之后再添加F[k+1],这确保了在添加F[k+1]之后新序列还能够满足条件5;若它不成立,我们需要调整F[1],\dots,F[k]使它成立。
若F[k]\models P不成立,等价于F[k]\land\neg P可满足(is\_sat(F[k]\ \&\ !P)),等价于F[k]表示的状态集合和\neg P表示的坏态集合有交集,用c(一个cube )表示该交集(c = get\_state(F[k]\ \&\ !P))。函数rec\_block(c,\ k)的目的是将该交集c从F[1], \dots, F[k]这些公式对应的状态集合中删除(blocking)——即递归调整F[0],\dots, F[k]的过程。
(c, k)(亦即(s, i))被称为一个证明义务(proof obligation),其中c是一个CTI(counterexample to induction),用cube表示。
# simplified recursive blocking
bool rec_block(s, i):
if i == 0: return False # reach initial states
while is_sat(F[i-1] & !s & T & s'):
c = get_predecessor(i-1, s')
if not rec_block(c, i-1): return False
!g = generalize(!s, i)
add !g to F[1],...,F[i]
return True
若i==0
,即初始状态集合(F[0]=I)和坏态集合存在交集。根据序列条件,F[0]是固定不变的,无法从F[0]中删除更多状态,故IC3验证失败并返回。否则进入while循环,执行递归删除
从每个frame中删除状态集合s(cube表示),只需向每个frame中添加一个clause(\neg s)就可以做到;
那么是不是只要添加\neg s就行呢?
答案是不一定的。
从每个frame中删除s(往其中添加\neg s)后,还需要考虑序列条件4是否依然能够保持(每个frame都需添加clause,除条件4以外的其余条件均可以保持)。
首先,考虑往F[i]和F[i-1]中添加\neg s后如下条件4是否仍然成立:
因为在没添加\neg s时,条件4已经成立,即F[i-1] \land T \models F[i]',所以上述条件4也可以写成:
- 添加\neg s后若上述条件4不成立,即is\_sat(F[i-1]\ \&\ !s\ \&\ T\ \&\ s')可满足 。这说明在(F[i-1] \land \neg s)所表示的状态集合中,还有一部分状态c无法一步迁移到(F[i]'\land \neg s'),c由语句c = get\_predecessor(i-1, s')计算得出。这部分状态集合c则需要在F[1],...,F[i-1]公式所对应的状态集合中被删除(blocking),因此递归删除rec\_block(c,\ i-1)。
- 添加\neg s后若上述条件4成立,可以根据条件3证明,对于F[i]之前的每一个frame均有上述条件4成立,则可以将\neg s添加至F[1],\dots,F[i]中的所有frame(
generalize()
函数可以将\neg s中的若干文字(literal)去除掉之后得到\neg g,满足\neg s\models \neg g, 保证将所有frame添加\neg g后,序列还能满足条件4)。
经过上述处理,F[k]\models P已经成立。
3. propagation phase
跳出blocking phase的while循环,开始扩展frame
。
增加一个frame
:k = k + 1, F[k] = T。
此时,公式序列可以满足全部序列条件,按理说,可以继续进行blocking phase。
但是进一步考虑下列情况:
设c是CNF公式F[i-1]的一个clause, T为迁移关系T(Y, X, X'),
假设F[i-1]\land T \models c',
(由于c是F[i-1]的一个clause,所以代码中的F[i-1]\land c\land T\land \neg c'等价于F[i-1]\land T\land \neg c')
再根据条件4,我们有F[i-1]\land T \models F[i]'
因此可以得到F[i-1]\land T \models F[i]'\land c'
因此将clause c添加至F[i],序列条件依然满足,并且能够进一步加强F[i],得到更精确的目标归纳不变式。
故在propagation phase中,我们要把F[i-1]中满足条件F[i-1]\land T \models c'的子句c传播到F[i]中去。
在propagation phase中,处理完一个frame F[i]之后,同时检查这两个相邻的frame是否相等(F[i]\equiv F[i+1])。若相等,则找到一个不动点(fixedpoint),F[i],即目标的归纳不变式。若不存在不动点,则继续进行主while循环,执行blocking phase和propagation phase。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 全程使用 AI 从 0 到 1 写了个小工具
· 快收藏!一个技巧从此不再搞混缓存穿透和缓存击穿
· AI 插件第二弹,更强更好用
· Blazor Hybrid适配到HarmonyOS系统