使用 Isabelle 证明(命令式)算法的正确性和终止

Proving correctness and termination of an (imperative) algorithm using Isabelle

我是一名本科生,正在尝试证明欧几里德gcd命令式版本和欧几里德扩展gcd算法的正确性和终止性。我用IMP语言实现了第一个,Hoare逻辑证明了正确性和终止:

lemma "⊢{λs. s ''a'' = n ∧ s ''b'' = m ∧ n > 0 ∧ m > 0 ∧ (gcd (s ''a'') (s ''b'') = gcd (n) (m))}
        WHILE (Or (Less (V ''b'') (V ''a'')) (Less (V ''a'') (V ''b'')))
        DO (IF (Less (V ''b'') (V ''a'')) THEN
               (''a'' ::= Sub (V ''a'') (V ''b''))
            ELSE
               (''b'' ::= Sub (V ''b'') (V ''a'')))
        {λs. s ''a'' = gcd (s ''A'') (s ''B'')}"
  apply (rule While'[where P = "λs. s ''a'' = n ∧ s ''b'' = m ∧ 0 < n ∧ 0 < m ∧ gcd (s ''a'') (s ''b'') = gcd n m"])
  apply auto
    apply (rule Assign')
    apply auto
    prefer 2
    apply (rule Assign')
  apply auto

剩余的子目标是:

proof (prove)
goal (3 subgoals):
 1. ⋀s. 0 < s ''a'' ⟹ m = s ''b'' ⟹ n = s ''a'' ⟹ s ''a'' < s ''b'' ⟹ False
 2. ⋀s. 0 < s ''b'' ⟹ m = s ''b'' ⟹ n = s ''a'' ⟹ s ''b'' < s ''a'' ⟹ False
 3. ⋀s. n = s ''a'' ⟹ m = s ''a'' ⟹ 0 < s ''a'' ⟹ s ''b'' = s ''a'' ⟹ s ''a'' = gcd (s ''A'') (s ''B'')

我现在不知道如何完成证明。这里的 gcd 函数是 GCD 库中的默认 gcd。我还尝试了 Arith2 库中的这个定义:

definition cd :: "[nat, nat, nat] ⇒ bool"
  where "cd x m n ⟷ x dvd m ∧ x dvd n"

definition gcd :: "[nat, nat] ⇒ nat"
  where "gcd m n = (SOME x. x>0 ∧ cd x m n & (∀y.(cd y m n) ⟶ y dvd x))"

我写的是否正确,我应该如何继续?我应该改用这些定义还是应该自己编写 gcd 函数的递归版本?这种做法正确吗?

首先,你在一个地方有一个类型,在那里你谈论 s ''A''s ''B'' 而不是 s ''a''s ''b''。但这当然不是你问的问题。

这里的问题是前提条件太强而无法使用 WHILE 规则。它包含条件 s ''a'' = ns ''b'' = m,这显然不能用作循环不变量,因为循环修改了变量 ab,因此在一次循环迭代后,一个的条件 s ''a'' = ns ''b'' = m 将不再成立。

你需要找出一个比你现在拥有的更弱的适当不变量。你要做的就是踢出s ''a'' = ns ''b'' = m。然后你的证明就通过了。

然后您可以使用 strengthen_pre 规则恢复您实际想要显示的语句。

所以你的证明的开头看起来像这样:

lemma "⊢{λs. s ''a'' = n ∧ s ''b'' = m ∧ n ≥ 0 ∧ m ≥ 0 ∧ (gcd (s ''a'') (s ''b'') = gcd (n) (m))}
        WHILE (Or (Less (V ''b'') (V ''a'')) (Less (V ''a'') (V ''b'')))
        DO (IF (Less (V ''b'') (V ''a'')) THEN
               (''a'' ::= Sub (V ''a'') (V ''b''))
            ELSE
               (''b'' ::= Sub (V ''b'') (V ''a'')))
        {λs. s ''a'' = gcd (s ''a'') (s ''b'')}"
  apply (rule strengthen_pre) 
  defer
   apply (rule While'[where P = "λs. s ''a'' ≥ 0 ∧ s ''b'' ≥ 0 ∧ gcd (s ''a'') (s ''b'') = gcd n m"])

为了避免这种笨拙的手动使用strengthen_pre,其他版本的 IMP 允许直接在算法本身中注释 WHILE 循环的不变量,这样 VCG(验证条件生成器)可以自动为您提供所有你必须证明的事情,你不必手动应用霍尔规则。

附录: 但是请注意,您的后置条件也存在问题:

{λs. s ''a'' = gcd (s ''a'') (s ''b'')}

这不是你想展示的!这只是意味着 a 执行后的值是 ab 执行后 的值的 GCD。这也恰好是真的,因为 ab 在算法完成后总是相等的——但你真正想知道的是执行后 a 的值等于ab 执行之前的 GCD,即等于 gcd n m。因此,您必须将后置条件更改为

{λs. s ''a'' = gcd n m}