证明可逆列表是Coq中的回文

时间:2014-06-23 10:10:08

标签: palindrome coq theorem-proving

这是我对回文的归纳定义:

Inductive pal { X : Type } : list X -> Prop :=
  | pal0 : pal []
  | pal1 : forall ( x : X ), pal [x]
  | pal2 : forall ( x : X ) ( l : list X ), pal l -> pal ( x :: l ++ [x] ).

我想要证明的定理来自 Software Foundations

Theorem rev_eq_pal : forall ( X : Type ) ( l : list X ),
  l = rev l -> pal l.

我的证据非正式概述如下:

  

假设l0l0 = rev l0的任意列表。然后必须保持以下三种情况之一。 l0有:

     

(a)零元素,在这种情况下,根据定义它是回文。

     

(b)一个元素,在这种情况下,根据定义它也是一个回文。

     

(c)两个或更多元素,在这种情况下l0 = x :: l1 ++ [x]用于某个元素x,有些列表l1用于l1 = rev l1

     

现在,从l1 = rev l1开始,以下三种案例中的一种必须持有......

     

递归案例分析将针对任何有限列表l0终止,因为分析列表的长度在每次迭代时减少2。如果它终止于任何列表ln,它的所有外部列表都是l0也是回文,因为通过在回文的两端附加两个相同元素构建的列表也是回文。

我认为推理是合理的,但我不确定如何将其形式化。它可以变成Coq的证明吗?关于战术如何运作的一些解释将特别有用。

2 个答案:

答案 0 :(得分:10)

这是一个很好的例子,其中"直接"归纳法根本不能很好地工作,因为你不能直接在尾部进行递归调用,而是在尾部的部分。在这种情况下,我通常建议用列表的长度来陈述你的引理,而不是列表本身。然后你可以专门化它。那将是这样的:

Lemma rev_eq_pal_length: forall (X: Type) (n: nat) (l: list X), length l <= n -> l = rev l -> pal l.
Proof.
(* by induction on [n], not [l] *)
Qed.

Theorem rev_eq_pal: forall (X: Type) (l: list X), l = rev l -> pal l.
Proof.
(* apply the previous lemma with n = length l *)
Qed.

如有必要,我可以更详细地帮助您,只需发表评论。

祝你好运!

编辑:只是为了帮助你,我需要以下的引理来做出这个证据,你也可能需要它们。

Lemma tool : forall (X:Type) (l l': list X) (a b: X),                                                                                                         
            a :: l = l' ++ b :: nil -> (a = b /\ l = nil) \/ exists k, l = k ++ b :: nil.

Lemma tool2 : forall (X:Type) (l1 l2 : list X) (a b: X),                                                                                                         
     l1 ++ a :: nil = l2 ++ b :: nil -> a = b /\ l1 = l2.

答案 1 :(得分:2)

您还可以从有充分理由的归纳法中获得归纳原理。

Notation " [ ] " := nil : list_scope.
Notation " [ x1 ; .. ; x2 ] " := (cons x1 .. (cons x2 nil) ..) : list_scope.
Open Scope list_scope.

Conjecture C1 : forall t1 f1 p1, (forall x1, (forall x2, f1 x2 < f1 x1 -> p1 x2) -> p1 x1) -> forall x1 : t1, p1 x1.
Conjecture C2 : forall t1 p1, p1 [] -> (forall x1 l1, p1 ([x1] ++ l1)) -> forall l1 : list t1, p1 l1.
Conjecture C3 : forall t1 p1, p1 [] -> (forall x1 l1, p1 (l1 ++ [x1])) -> forall l1 : list t1, p1 l1.
Conjecture C4 : forall t1 (x1 x2 : t1) l1, length l1 < length ([x1] ++ l1 ++ [x2]).

Theorem T1 : forall t1 p1,
  p1 [] ->
  (forall x1, p1 [x1]) ->
  (forall x1 x2 l1, p1 l1 -> p1 ([x1] ++ l1 ++ [x2])) ->
  forall l1 : list t1, p1 l1.
Proof.
intros t1 p1 h1 h2 h3.
induction l1 as [l1 h4] using (C1 (list t1) (@length t1)).
induction l1 as [| x1 l1] using C2.
eapply h1.
induction l1 as [| x2 l1] using C3.
simpl.
eapply h2.
eapply h3.
eapply h4.
eapply C4.
Qed.

你可以通过首先将假设应用于结论,然后在C1上使用结构归纳,然后使用关于f1 x1的一些事实来证明猜想<

要证明没有归纳假设的C3,您首先在is_empty l1上使用案例分析,然后使用事实is_empty l1 = true -> l1 = []is_empty l1 = false -> l1 = delete_last l1 ++ [get_last l1]({{1}将需要一个默认值。)