gpt4 book ai didi

coq - 如何处理 Coq 中 Program Fixpoint 生成的非常大的术语?

转载 作者:行者123 更新时间:2023-12-04 20:31:41 26 4
gpt4 key购买 nike

我试图在 Coq 中定义并证明正确的一个函数,它可以有效地区分两个排序列表。因为它并不总是在结构上较小的项上递归(第一个或第二个列表较小),Fixpoint不会接受它,所以我尝试使用 Program Fixpoint反而。

尝试使用策略 simpl 证明函数的属性时或 program_simpl , Coq 花费几分钟计算,然后产生一个巨大的术语,数百行。我想知道我是否在使用 Program Fixpoint错误的方式,或者在推理时是否应该使用其他策略而不是简化?

我还想知道在这样的参数中包含正确性所需的属性是否是一个好习惯,或者最好有一个单独的包装函数,它将正确性属性作为参数,并使这个函数只需要两个列表进行比较?

请注意,我确实尝试定义了一个更简单的 make_diff 版本。 ,它只以 l1 和 l2 作为参数并固定了类型 A和关系 R ,但这仍然产生了一个巨大的术语,当 program_simplsimpl战术被应用。

*编辑:我的包含是(尽管这里可能不需要它们):

Require Import Coq.Sorting.Sorted.
Require Import Coq.Lists.List.
Require Import Coq.Relations.Relation_Definitions.
Require Import Recdef.
Require Import Coq.Program.Wf.
Require Import Coq.Program.Tactics.

编码:
Definition is_decidable (A : Type) (R : relation A) := forall x y, {R x y} + {~(R x y)}.
Definition eq_decidable (A : Type) := forall (x y : A), { x = y } + { ~ (x = y) }.

Inductive diff (X: Type) : Type :=
| add : X -> diff X
| remove : X -> diff X
| update : X -> X -> diff X.

Program Fixpoint make_diff (A : Type)
(R : relation A)
(dec : is_decidable A R)
(eq_dec : eq_decidable A)
(trans : transitive A R)
(lt_neq : (forall x y, R x y -> x <> y))
(l1 l2 : list A)
{measure (length l1 + length l2) } : list (diff A) :=
match l1, l2 with
| nil, nil => nil
| nil, (new_h::new_t) => (add A new_h) :: (make_diff A R dec eq_dec trans lt_neq nil new_t)
| (old_h::old_t), nil => (remove A old_h) :: (make_diff A R dec eq_dec trans lt_neq old_t nil)
| (old_h::old_t) as old_l, (new_h::new_t) as new_l =>
if dec old_h new_h
then (remove A old_h) :: make_diff A R dec eq_dec trans lt_neq old_t new_l
else if eq_dec old_h new_h
then (update A old_h new_h) :: make_diff A R dec eq_dec trans lt_neq old_t new_t
else (add A new_h) :: make_diff A R dec eq_dec trans lt_neq old_l new_t
end.
Next Obligation.
Proof.
simpl.
generalize dependent (length new_t).
generalize dependent (length old_t).
auto with arith.
Defined.
Next Obligation.
Proof.
simpl.
generalize dependent (length new_t).
generalize dependent (length old_t).
auto with arith.
Defined.

最佳答案

在这种特殊情况下,我们可以去掉 Program Fixpoint并使用简单的 Fixpoint .因为在每次递归调用时我们都会调用 make_diff在第一个列表的尾部或第二个列表的尾部,我们可以嵌套两个定点函数,如下所示。 (我在这里使用了 Section 机制以避免传递太多相同的参数)

Require Import Coq.Lists.List.
Import ListNotations.
Require Import Coq.Relations.Relations.

Section Make_diff.

Variable A : Type.
Variable R : relation A.
Variable dec : is_decidable A R.
Variable eq_dec : eq_decidable A.
Variable trans : transitive A R.
Variable lt_neq : forall x y, R x y -> x <> y.

Fixpoint make_diff (l1 l2 : list A) : list (diff A) :=
let fix make_diff2 l2 :=
match l1, l2 with
| nil, nil => nil
| nil, new_h::new_t => (add A new_h) :: make_diff2 new_t
| old_h::old_t, nil => (remove A old_h) :: make_diff old_t nil
| old_h::old_t, new_h::new_t =>
if dec old_h new_h
then (remove A old_h) :: make_diff old_t l2
else if eq_dec old_h new_h
then (update A old_h new_h) :: make_diff old_t new_t
else (add A new_h) :: make_diff2 new_t
end
in make_diff2 l2.

End Make_diff.

观察 Section机制不会在生成的签名中包含未使用的参数。这是一个幼稚的测试:
(* make the first 2 arguments implicit *)    
Arguments make_diff [A R] _ _ _ _.

Require Import Coq.Arith.Arith.

Compute make_diff lt_dec Nat.eq_dec [1;2;3] [4;5;6].
(* = [remove nat 1; remove nat 2; remove nat 3; add nat 4; add nat 5; add nat 6]
: list (diff nat) *)

关于coq - 如何处理 Coq 中 Program Fixpoint 生成的非常大的术语?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44612214/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com