我按如下方式定义排序列表:
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.
但我不能证明这个定理。谁能给我一些想法?
答案 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是正确的直觉。