伊莎贝尔:证明2个名单之间的差异

时间:2014-10-31 23:27:42

标签: isabelle theorem-proving

我是定理证明和伊莎贝尔的新手。我试图在Isabelle中证明一个关于列表的简单(?)定理。

这是理论:

theory Scratch
imports
  Main
  Option
  String
begin

fun list_difference :: "string list => string list => nat"
where
  "list_difference [] [] = 0"
| "list_difference [] x = length x"
| "list_difference x [] = length x"
| "list_difference (x#d1) (y#d2) = (if (x=y) then  list_difference d1 d2 else (1 + list_difference d1 d2))"

fun modify :: "string list ⇒ nat ⇒ string list"
where
"modify list n = list[n:=''somethingnew'']"

这些是支持性的引理

lemma diff_zero [simp]:
shows "list_difference somelist somelist = 0"
apply(induct_tac somelist, auto)
done

lemma sub1 [simp]:
shows "modify [] 0 = []"
apply(auto)
done

lemma diff_zero_basecase [simp]:
shows "list_difference somelist (modify somelist 0) <= 1"
apply(induct_tac somelist, auto)
done

这是我试图证明的原始定理

(*Description : modify will change only one or zero elements.. so diff should be <= 1*) <br>
lemma modification_lemma [simp]:
shows "list_difference somelist (modify somelist index) ≤ 1"
apply(induct_tac somelist, auto)
apply(cases index, auto)
oops

我如何着手证明这个定理?

我的另一个问题是如何在试图证明定理时从这些情况出发?我尝试过遵循Isabelle教程,但我无法得到关于此的一般建议。

1 个答案:

答案 0 :(得分:0)

我给你一个证明,并解释我用来获得结果的一些基本技巧,但却以一种相当无意义的方式。其他人可能希望提供一个解释,让您更好地理解主题:涉及natlist的归纳。

我缩短了一些标识符,我将整个理论放在下面。公式中基本上有两个需要证明的自由变量lsidx

所以,为了证明目标,在尝试的时候,我做了很多我接下来要展示的内容,或者是一些变体,cases可能induct

(*MINDLESS_TECHNIQUE_1*)
apply(induct ls, auto)
apply(induct idx, auto)

在某个时刻,auto需要花费很长时间,这意味着由于您拥有simp规则,这可能会导致循环不良。

我删除了simp规则并仅在需要的地方插入它们,这样就摆脱了auto循环。

这是第一个进步点,它让我进入MINDLESS_TECHNIQUE_2,将证明目标分解为lemma,与MINDLESS_TECHNIQUE_1一起使用,以及Sledgehammer。

此时,对于modification_lemma,在使用上述apply后,我有3个证明目标,我使用Sledgehammer来证明其中的两个。然后我打破了第3个证明目标,如下所示,这可以通过by(induct ls, auto)轻松证明。

更新:使用亚历山大的提示与上面的爆发引理达到相同的证明目标,我在下面的源代码中添加了一个证明,我打开了两个绑定变量。它仍然是一个丑陋的解决方案,所以也许有一种比结束变量更好的方法。

像我一样使用autosimp_all,我无法盲目地使用by(induct ls, auto)获得最终结果的原因是因为变量idxls受到所有元!!的约束。如果没有自动工具可以进行校对工作(我猜),它们需要打开,这会使事情变得非常混乱。

theory c2
imports Main Option String
begin

fun list_diff :: "string list => string list => nat" where
  "list_diff [] [] = 0"
 |"list_diff [] x = length x"
 |"list_diff x [] = length x"
 |"list_diff (x#d1) (y#d2) = 
   (if (x=y) then list_diff d1 d2 else (1 + list_diff d1 d2))"

fun modify :: "string list => nat => string list" where
  "modify ls n = ls[n := ''abc'']"

lemma diff_zero:
  "list_diff ls ls = 0"
by(induct_tac ls, auto)

lemma sub1:
  "modify [] 0 = []"
by(auto)

lemma diff_zero_basecase:
  "list_diff ls (modify ls 0) <= 1"
by(induct_tac ls, auto simp add: diff_zero)

(*****************************************************************************)
lemma the_mindless_result_of_eliminating_simp_rules_and_breaking_out_goals:
  "(!!a ls. list_diff ls (ls[idx := ''abc'']) <= Suc 0 ==>
     list_diff (a # ls) 
     (case idx of 0 => ''abc'' # ls | Suc j => a # ls[j := ''abc'']) <= Suc 0) 
   ==> list_diff ls (ls[Suc idx := ''abc'']) <= Suc 0 ==>
         list_diff ls (ls[idx := ''abc'']) <= Suc 0"
by(induct ls, auto)

lemma modification_lemma:
  "list_diff ls (modify ls idx) <= 1"
apply(induct ls, auto)
apply(induct idx, auto)
apply(metis diff_zero le0)
apply(metis diff_zero) (*The goal I broke out to the above lemma.*)
by (metis the_mindless_result_of_eliminating_simp_rules_and_breaking_out_goals)

(*****************************************************************************)
(*Update: After the third 'apply', I can't mindlessly do 'by(induct ls, auto)', 
  because variables 'ls' and 'idx' are bound by '!!. If I use 'auto' like I 
  did, and I don't want to break out the proof goal, I need to unwrap the 
  variables 'idx' and 'ls, as shown below.*)

lemma unwrapping_variables:
  "list_diff ls (modify ls idx) <= 1"
apply(induct ls, simp_all)
apply(induct idx, simp_all)
apply(simp_all add: diff_zero)
proof-
  fix idx
show "!!ls. ((!!a ls. list_diff ls (ls[idx := ''abc'']) <= Suc 0 ==>
     list_diff (a # ls) 
     (case idx of 0 => ''abc'' # ls | Suc j => a # ls[j := ''abc'']) <= Suc 0) 
   ==> list_diff ls (ls[Suc idx := ''abc'']) <= Suc 0 ==>
         list_diff ls (ls[idx := ''abc'']) <= Suc 0)"
  proof-
    fix ls
  show "(!!a ls. list_diff ls (ls[idx := ''abc'']) <= Suc 0 ==>
     list_diff (a # ls) 
     (case idx of 0 => ''abc'' # ls | Suc j => a # ls[j := ''abc'']) <= Suc 0) 
   ==> list_diff ls (ls[Suc idx := ''abc'']) <= Suc 0 ==>
         list_diff ls (ls[idx := ''abc'']) <= Suc 0"
    by(induct ls, auto)
  qed
qed

thm unwrapping_variables

end