咸咸的海风吹起来初江一般的情愫,唤醒了新治本能的勇气。
考虑在 concrete domain 中的 while 的语义:
S[whilecdos]R=C[¬c](lfpF)whereF(X)=R∪S[s](C[c]X)
其实就是在求状态集合上的算子F 的最小不动点(lfp=least fixed point)。然后根据 tarski 不动点定理,对于递增链:
R⊆F(R)⊆F2(R)⊆...
有lfpF 就是 F 的不动点,即F(lfpF)=lfpF。一般求lfpF 就是不断迭代 F,迭代次数就是循环执行的次数。
然后我们想在 abstract domain 中,不用迭代那么多步,就给出lfpF 的一个 sound abstraction。这怎么办呢?我们其实可以定义一个新的二元算子类型▽,它要求:
- x⊑#x▽y,y⊑#x▽y。
- 对于任意一个序列{xn},∃N,yN=yN+1。其中yn=x0▽x1▽...▽xn。
这就是 widening operator 的定义。
然后在 abstract domain 中,会对 while 的 abstract 语义进行定义:
S#[whilecdos]R#=C#[¬c](limT#)whereT#(X#)=X#▽F#(X#);F#(X#)=defR#∪#S#[s2](C#[c]X#)
注意到几个问题,首先是lfpF 对应成了limF#。其次原本求X↦F(X) 的最小不动点,现在对应成了X#↦X#▽F#(X#) 迭代的极限。我们其实可以说明,limT#就是lfpF 的一个 sound abstraction,而且它一定存在(由 widening operator 的定义要求)。考虑如下序列:
X1#=R#X2#=X1#▽F#(X1#)X3#=X2#▽F#(X2#)X4#=X3#▽F#(X3#).....
发现根据 widening operator 的定义,有X1#⊑#X2#⊑...,即这是个递增链。再根据定义,它一定存在个极限:
Xlim#=Xlim#▽F#(Xlim#)
所以再根据定义,有F#(Xlim#)⊑#Xlim#。再根据 Tarskian fixpoint approximation:
(Tarskian fixpoint approximation) 给定完全格(C,≤,∨,∧,⊥,⊤) 上的一个单调函数f:C→C,和它在偏序集(A,⊑) 上的一个 sound abstraction (不一定单调)g:A→A,那么就会有对于所有满足g(a)⊑a 的a,它都是lfpf 的一个 sound abstraction。即lfpf≤γ(a)。
因为F#是F 的一个 sound abstraction(每一个符号都是 sound 的),所以有Xlim#就是lfpF 的一个 sound abstraction。
在实际选择中,我们可以任意选择满足要求的 widening operator,以 interval domain 举例,甚至可以[a,b]▽[c,d]=[−∞,+∞]。这样只需要迭代一次就找到了Xlim#=[−∞,+∞],它显然是lfpF 的 sound abstraction(它是任何P(I) 中元素的 sound abstraction)。但是显然这没什么意义,所以我们一般选择:
[a,b]▽[c,d]=[{a−∞ifa≤cotherwise,{b+∞ifb≤dotherwise]
这样只需要O(∣V∣) 次迭代我们就能找到Xlim#。
但是这是不够的。因为即使我们精心选择了 widening operator,可以得到lfpF 的一个 sound abstraction,但它往往不够 precise。其实我们可以有一个提纯的过程(refine),即保持是 sound abstraction 的情况下,找到尽量小的那个。于是我们可以定义 narrowing operator:△,要求它:
- X#⊓#Y#⊑#X#△Y#⊑#X#。
- 对于任意一个序列{Xn#},∃N,YN#=YN+1#。其中Yn#=X0#△...△Xn#。
它有什么作用呢?我们考虑一个迭代:X#↦X#△F#(X#)。
-
首先,它是保持 sound abstraction 的。假如X#是lfpF 的一个 sound abstraction,那么有lfpF⊆γ(X#)。根据 F 的单调性,有F(lfpF)⊆F(γ(X#))。再根据F#是 F 的一个 sound abstraction,就有:
lfpF=F(lfpF)⊆F(γ(X#))⊆γ(F#(X#))
于是F#(X#) 就是lfpF 的一个 sound abstraction。然后我们可以证明:若X#,F#(X#) 都是lfpF 的 sound abstraction,那么X#△F#(X#) 也一定是lfpF 的一个 sound abstraction。因为:
∵lfpF⊆γ(X#),lfpF⊆γ(F#(X#))∴lfpF⊆γ(X#)∩γ(F#(X#))⊆γ(X#⊓#F#(X#))⊆γ(X#△F#(X#))
-
其次,它是单调减的,因为有X#△F#(X#)⊑#X#。
因此,我们可以不断迭代,直到不再变化。这样迭代的过程就是 refine 的过程(譬如不断缩小 interval),而且最后得到的 abstraction 一定仍然是 sound 的。
我们譬如可以选择:
[a,b]△[c,d]=[{caifa=−∞otherwise,{dbifb=+∞otherwise]
就满足了上述要求。
所以总之,迭代 widening operator 是为了尽快找到lfpF 的一个 sound abstraction;而找到后可以接着迭代 narrowing operator 对我们找到的 sound abstraction 进行提纯,使得最后得到的 abstraction 尽量 precise。