教coq检查终止
与其他许多参数不同,Coq接受一个可选的显式参数,该参数可用于指示不动点定义的递减结构 根据Gallina规范第1.3.4节教coq检查终止,coq,termination,totality,Coq,Termination,Totality,与其他许多参数不同,Coq接受一个可选的显式参数,该参数可用于指示不动点定义的递减结构 根据Gallina规范第1.3.4节 Fixpoint ident params {struct ident0 } : type0 := term0 定义语法。但从中,我们知道它必须是一个标识符,而不是一个通用的度量 然而,一般来说,存在递归函数,终止不是很明显,或者实际上是,但终止检查器很难找到递减结构。例如,以下程序交错两个列表 Fixpoint interleave (A : Set) (l1 l2
Fixpoint ident params {struct ident0 } : type0 := term0
定义语法。但从中,我们知道它必须是一个标识符,而不是一个通用的度量
然而,一般来说,存在递归函数,终止不是很明显,或者实际上是,但终止检查器很难找到递减结构。例如,以下程序交错两个列表
Fixpoint interleave (A : Set) (l1 l2 : list A) : list A :=
match l1 with
| [] => []
| h :: t => h :: interleave l2 t
end
这个函数显然终止了,而Coq就是无法理解它。原因是无论是l1
还是l2
都不是每个周期都在减少。但是,如果我们考虑一个度量,定义为“代码>长度L1+长度L2< /代码>?然后这个度量明显减少了每次递归
因此,我的问题是,在复杂的情况下,如果代码不容易以可终止检查的方式组织,您如何教育coq并说服它接受不动点定义?您可以使用一种称为
度量值的方法,而不是用结构参数来终止。为此,我认为您必须使用程序固定点
机制,该机制有点复杂,会使您的证明看起来更难看(因为它会根据您提供的证明生成结构递归,因此您实际使用的函数与您编写的函数不完全相同)
详情如下:
它看起来也像是一种叫做方程的东西,可以处理度量?
查阅
您有多个选项,所有选项最终都归结为结构递归
序言
结构递归
有时,您可以以结构递归的方式重新制定算法:
Fixpoint interleave1 {A} (l1 l2 : list A) {struct l1} : list A :=
match l1, l2 with
| [], _ => l2
| _, [] => l1
| h1 :: t1, h2 :: t2 => h1 :: h2 :: interleave1 t1 t2
end.
顺便说一句,在某些情况下,您可以对嵌套的fix
es使用技巧——请参见(仅对Fixpoint
不起作用)
程序定点
您可以使用程序固定点
机制,让您自然编写程序,然后证明它总是终止
From Coq Require Import Program Arith.
Program Fixpoint interleave2 {A} (l1 l2 : list A)
{measure (length l1 + length l2)} : list A :=
match l1 with
| [] => l2
| h :: t => h :: interleave2 l2 t
end.
Next Obligation. simpl; rewrite Nat.add_comm; trivial with arith. Qed.
功能
另一个选项是使用函数
命令,与程序定点
相比,该命令可能会受到一定限制。你可以了解更多关于他们的差异
插件
这是一个外部插件,它解决了在Coq中定义函数的许多问题,包括依赖类型和终止
From Equations Require Import Equations.
Equations interleave4 {A} (l1 l2 : list A) : list A :=
interleave4 l1 l2 by rec (length l1 + length l2) lt :=
interleave4 nil l2 := l2;
interleave4 (cons h t) l2 := cons h (interleave4 l2 t).
Next Obligation. rewrite Nat.add_comm; trivial with arith. Qed.
如果你申请,上面的代码是有效的
Fix
/Fix\F\u 2
组合器
如果您遵循“关于mergeSort
功能”中的链接,可以了解更多有关此(手动)方法的信息。顺便说一句,如果应用我前面提到的嵌套Fix
技巧,则可以在不使用Fix
的情况下定义mergeSort
函数。这是一个使用Fix\u F_2
组合器的解决方案,因为我们有两个参数,而不是像mergeSort
那样的参数:
Definition ordering {A} (l1 l2 : list A * list A) : Prop :=
length (fst l1) + length (snd l1) < length (fst l2) + length (snd l2).
Lemma ordering_wf' {A} : forall (m : nat) (p : list A * list A),
length (fst p) + length (snd p) <= m -> Acc (@ordering A) p.
Proof.
unfold ordering; induction m; intros p H; constructor; intros p'.
- apply Nat.le_0_r, Nat.eq_add_0 in H as [-> ->].
intros contra%Nat.nlt_0_r; contradiction.
- intros H'; eapply IHm, Nat.lt_succ_r, Nat.lt_le_trans; eauto.
Defined.
Lemma ordering_wf {A} : well_founded (@ordering A).
Proof. now red; intro ; eapply ordering_wf'. Defined.
(* it's in the stdlib but unfortunately opaque -- this blocks evaluation *)
Lemma destruct_list {A} (l : list A) :
{ x:A & {tl:list A | l = x::tl} } + { l = [] }.
Proof.
induction l as [|h tl]; [right | left]; trivial.
exists h, tl; reflexivity.
Defined.
Definition interleave5 {A} (xs ys : list A) : list A.
refine (Fix_F_2 (fun _ _ => list A)
(fun (l1 l2 : list A)
(interleave : (forall l1' l2', ordering (l1', l2') (l1, l2) -> list A)) =>
match destruct_list l1 with
| inright _ => l2
| inleft pf => let '(existT _ h (exist _ tl eq)) := pf in
h :: interleave l2 tl _
end) (ordering_wf (xs,ys))).
Proof. unfold ordering; rewrite eq, Nat.add_comm; auto.
Defined.
练习:如果您注释掉destruct\u list
lemma,最后一次检查会发生什么情况?您是否在询问可以用来说服Coq您的函数终止的工具?还是别的什么?比如如何使用Fixpoint
或fix
原语来实现这一点?@AntonTrunov我想问的是,如果可能的话,我是否可以证明函数终止,如何将它教给coq。为了这个例子,如何让COQ接受这个交织定义,而不改变算法的基本思想?你会考虑使用<代码>程序不动点> />代码>函数> <代码> >代码>修复> <代码>组合器/<代码>方程< /代码>插件作为解决方案吗?使用这些工具会在函数中添加一个额外的参数,其目的是让Coq相信函数正在终止。@AntonTrunov我不知道这些。我来看看。感谢上帝,这是一篇如此精练的教育性文章。
From Equations Require Import Equations.
Equations interleave4 {A} (l1 l2 : list A) : list A :=
interleave4 l1 l2 by rec (length l1 + length l2) lt :=
interleave4 nil l2 := l2;
interleave4 (cons h t) l2 := cons h (interleave4 l2 t).
Next Obligation. rewrite Nat.add_comm; trivial with arith. Qed.
Definition ordering {A} (l1 l2 : list A * list A) : Prop :=
length (fst l1) + length (snd l1) < length (fst l2) + length (snd l2).
Lemma ordering_wf' {A} : forall (m : nat) (p : list A * list A),
length (fst p) + length (snd p) <= m -> Acc (@ordering A) p.
Proof.
unfold ordering; induction m; intros p H; constructor; intros p'.
- apply Nat.le_0_r, Nat.eq_add_0 in H as [-> ->].
intros contra%Nat.nlt_0_r; contradiction.
- intros H'; eapply IHm, Nat.lt_succ_r, Nat.lt_le_trans; eauto.
Defined.
Lemma ordering_wf {A} : well_founded (@ordering A).
Proof. now red; intro ; eapply ordering_wf'. Defined.
(* it's in the stdlib but unfortunately opaque -- this blocks evaluation *)
Lemma destruct_list {A} (l : list A) :
{ x:A & {tl:list A | l = x::tl} } + { l = [] }.
Proof.
induction l as [|h tl]; [right | left]; trivial.
exists h, tl; reflexivity.
Defined.
Definition interleave5 {A} (xs ys : list A) : list A.
refine (Fix_F_2 (fun _ _ => list A)
(fun (l1 l2 : list A)
(interleave : (forall l1' l2', ordering (l1', l2') (l1, l2) -> list A)) =>
match destruct_list l1 with
| inright _ => l2
| inleft pf => let '(existT _ h (exist _ tl eq)) := pf in
h :: interleave l2 tl _
end) (ordering_wf (xs,ys))).
Proof. unfold ordering; rewrite eq, Nat.add_comm; auto.
Defined.
Check eq_refl : interleave1 [1;2;3] [4;5;6] = [1;4;2;5;3;6].
Check eq_refl : interleave2 [1;2;3] [4;5;6] = [1;4;2;5;3;6].
Check eq_refl : interleave3 ([1;2;3], [4;5;6]) = [1;4;2;5;3;6].
Fail Check eq_refl : interleave4 [1;2;3] [4;5;6] = [1;4;2;5;3;6]. (* Equations plugin *)
Check eq_refl : interleave5 [1;2;3] [4;5;6] = [1;4;2;5;3;6].