Coq中的排序列表

时间:2018-03-12 02:37:04

标签: sorting coq

我按如下方式定义排序列表:

Require Import Coq.Lists.List.
Import ListNotations.

Inductive SortedList : list nat -> Prop :=
| sort0 : SortedList []
| sort1 : forall a, SortedList [a]
| sort2 : forall z1 z2 l, z1 <= z2 -> SortedList (z2 :: l) -> SortedList (z1 :: z2 :: l).

我认为以下定理是正确的。

Theorem SortedList_sep:
  forall l1 l2,
  SortedList (l1 ++ l2) -> SortedList l1 /\ SortedList l2.

但我不能证明这个定理。谁能给我一些想法?

3 个答案:

答案 0 :(得分:2)

这是一种方法。我试图让它简单易行。

Require Import List.
Import ListNotations.


Inductive SortedList : list nat -> Prop :=
| sort0 : SortedList []
| sort1 : forall a, SortedList [a]
| sort2 : forall z1 z2, forall l, z1 <= z2 -> SortedList (z2 :: l) -> SortedList (z1 :: z2 :: l).


Theorem SortedList_sep1:
  forall l1 l2,
  SortedList (l1 ++ l2) -> SortedList l1.
Proof.
  induction l1;
    firstorder.
  - now constructor.
  - destruct l1.
    now  constructor.
    rewrite <- ?app_comm_cons in *.
    inversion H.
    constructor.
    + now trivial.
    + apply IHl1 with l2.
      rewrite <- ?app_comm_cons in *.
      now trivial.
Qed.

Theorem SortedList_sep2:
  forall l1 l2,
    SortedList (l1 ++ l2) -> SortedList l2.
Proof.
  induction l1;
    firstorder.
  rewrite <- app_comm_cons in *.
  inversion H.
  - apply IHl1.
    rewrite <- H2.
    now constructor.
  - apply IHl1.
    rewrite H1 in H3.
    now apply H3.
Qed.

Theorem SortedList_sep:
  forall l1 l2,
  SortedList (l1 ++ l2) -> SortedList l1 /\ SortedList l2.
Proof.
  firstorder.
  now apply SortedList_sep1 with l2.
  now apply SortedList_sep2 with l1.
Qed.

这是一个高尔夫的代码&#39;版本,更短,但更少&#34; grokkable&#34;。

Theorem SortedList_sep:
  forall l1 l2,
  SortedList (l1 ++ l2) -> SortedList l1 /\ SortedList l2.
Proof.
  induction l1; firstorder; try destruct l1; inversion H;
    rewrite <- ?app_comm_cons in *; try constructor; firstorder.
Qed.

答案 1 :(得分:2)

进行证明的一种方法是在l1上使用归纳,因为操作++是通过对其第一个参数的递归来定义的。另一种选择是在上下文中对类型SortedList (l1 ++ l2)的术语进行归纳,这将需要更多的上下文&amp;目标管理(例如概括等)以及您似乎还需要在l1上进行多次破坏。

@ larsr的回答显示了解决问题的方法。这是一个&#34;组合&#34;我们用结合证明原始定理的方法:

Theorem SortedList_sep l1 l2 :
  SortedList (l1 ++ l2) -> SortedList l1 /\ SortedList l2.
Proof.
  induction l1 as [|h1 l1 IH]; simpl; intros H.
  - split; [constructor | assumption].
  - inversion H; subst.
    + apply eq_sym, app_eq_nil in H2 as [->->].
      split; constructor.
    + destruct l1 as [|h2 l1]; simpl in * |-.
      * subst l2; split; [constructor | assumption].
      * inversion H1; subst. apply IH in H3 as [? ?].
        split; [now constructor | assumption].
Qed.

现在我们可以轻松定义SortedList_sep1之类的特殊情况:

Theorem SortedList_sep1 l1 l2 :
  SortedList (l1 ++ l2) -> SortedList l1.
Proof. apply SortedList_sep. Qed.

Theorem SortedList_sep2 l1 l2 :
  SortedList (l1 ++ l2) -> SortedList l2.
Proof. apply SortedList_sep. Qed.

答案 2 :(得分:1)

我还建议使用数学组件库的解决方案:

Theorem SortedList_sep l1 l2 :
  sorted leq (l1 ++ l2) ->
  sorted leq l1 /\ sorted leq l2.
Proof.
rewrite -(path_min_sorted (x:=0)) // cat_path => /andP[h1 h2].
by have/allP h := order_path_min leq_trans h2; rewrite !path_min_sorted in h1 h2.
Qed.

我想证明样式可以改进,但这对读者来说是一种练习。

编辑:Anton Trunov提出了这个更好的证据,即&#34;权利&#34;之一:

Proof.
by move/(subseq_sorted leq_trans)=> h; rewrite !h ?suffix_subseq ?prefix_subseq.
Qed.

请注意,与其他解决方案相反,上述证据均未直接使用归纳法,但它们基于更一般的引理。这是非常优选的,因为它反映了真实的&#34;真实的&#34;数学家会做的。具体而言,&#34;权利&#34;证明状态:&#34;有序序列的子序列被排序&#34;,在这种情况下,IMO是正确的直觉。