使用Coq中无限表示的有限子集进行计算

时间:2017-12-28 23:00:21

标签: coq

我有一个函数Z -> Z -> whatever我将其视为(Z, Z)whatever的一种地图,我们将其键入FF

whatevernixinj_whatever的简单总和。

这张地图我用一些数据初始化,方式为:

Definition i (x y : Z) (f : FF) : FF :=
  fun x' y' =>
    if andb (x =? x') (y =? y')
    then inj_whatever
    else f x y.

=?表示来自Coq Z的{​​{1}}上的布尔可判定等式。

现在我想在两个ZArith上保持平等,我不介意调用FF。我现在要做的是让Coq在计算上决定两个functional_extensionality s的相等性。

例如,假设我们按照以下方式做了一些事情:

FF

现在我们添加一些任意值来制作Definition empty : FF := fun x y => nix.foo,这些值在功能扩展性下是等价的:

foo'
Definition foo := i 0 0 (i 0 (-42) (i 56 1 empty)).

自动让Coq确定Definition foo' := i 0 (-42) (i 56 1 (i 0 0 empty)).的好方法是什么。 foo = foo'级别的东西?实际终止计算?我是否需要对有限域限制?

域名限制有点复杂。我以Ltac的方式操纵地图,其中f : FF -> FF可以扩展定义计算的f子集。因此,考虑到它,它不能是Z x Z,而是更像f : FF -> FF,其中f : FF -> FF_1FF_1的一个子集,由一个小常量扩展。因此,当一个人应用Z x Z n次时,最终会使用f,这相当于域FF_nFF的域限制。因此函数n * constant缓慢(通过常数因子)扩展域FF定义。

2 个答案:

答案 0 :(得分:2)

正如我在评论中所说,需要更多具体细节才能得出令人满意的答案。请参阅下面的示例---用于逐步说明---如何使用mathcomp在限制函数范围内使用相等:

From mathcomp Require Import all_ssreflect all_algebra.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

(* We need this in order for the computation to work. *)
Section AllU.
Variable n : nat.

(* Bounded and unbounded fun *)
Definition FFb := {ffun 'I_n -> nat}.

Implicit Type (f : FFb).

Lemma FFP1 f1 f2 : reflect (f1 = f2) [forall x : 'I_n, f1 x == f2 x].
Proof. exact/(equivP eqfunP)/ffunP. Qed.

Lemma FFP2 f1 f2 : 
  [forall x : 'I_n, f1 x == f2 x] = all [fun x => f1 x == f2 x] (enum 'I_n).
Proof.
by apply/eqfunP/allP=> [eqf x he|eqf x]; apply/eqP/eqf; rewrite ?enumT.
Qed.

Definition f_inj (f : nat -> nat) : FFb := [ffun x => f (val x)].

Lemma FFP3 (f1 f2 : nat -> nat) :
  all [fun x => f1 x == f2 x] (iota 0 n) -> f_inj f1 = f_inj f2.
Proof.
move/allP=> /= hb; apply/FFP1; rewrite FFP2; apply/allP=> x hx /=.
by rewrite !ffunE; apply/hb; rewrite mem_iota ?ltn_ord.
Qed.

(* Exercise, derive bounded eq from f_inj f1 = f_inj f2 *)

End AllU.

最后的引理确实应该允许你将函数的相等性减少到计算的,完全可运行的Gallina函数。

上述更简单的版本,可能对您更有用:

Lemma FFP n (f1 f2 : nat -> nat) :
  [forall x : 'I_n, f1 x == f2 x] = all [pred x | f1 x == f2 x] (iota 0 n).
Proof.
apply/eqfunP/allP=> eqf x; last by apply/eqP/eqf; rewrite mem_iota /=.
by rewrite mem_iota; case/andP=> ? hx; have /= -> := eqf (Ordinal hx).
Qed.

但这取决于你指定范围限制的条件(缺席)。

编辑之后,我想我应该在地图相等的更一般主题上添加一个注释,实际上你可以定义一个更具体的地图类型而不是A -> B,然后建立一个决策程序。

大多数典型的地图类型[包括stdlib中的那些]都可以工作,只要它们支持"绑定检索"的操作,这样你就可以减少相等的检查有限多个绑定值

事实上,Coq标准库中的地图已经为您提供了这样的计算相等功能。

答案 1 :(得分:2)

好的,这是一个相当残酷的解决方案,它不会试图避免多次执行相同的案例区分,但它是完全自动化的。

我们从一种策略开始,检查两个整数是否相等(使用Z.eqb)并将结果转换为omega可以处理的命题。

Ltac inspect_eq y x :=
  let p := fresh "p" in
  let q := fresh "q" in
  let H := fresh "H" in
  assert (p := proj1 (Z.eqb_eq x y));
  assert (q := proj1 (Z.eqb_neq x y));
  destruct (Z.eqb x y) eqn: H;
  [apply (fun p => p eq_refl) in p; clear q|
   apply (fun p => p eq_refl) in q; clear p].

然后我们可以编写一个函数来触发它可以找到的i的第一次出现。这可能会在上下文中引入相互矛盾的假设,例如:如果上一个匹配项已显示x = 0但我们现在调用inspect x 0,则第二个分支将在上下文中同时包含x = 0x <> 0。它将被omega自动解除。

Ltac fire_i x y := match goal with
  | [ |- context[i ?x' ?y' _ _] ] =>
    unfold i at 1; inspect_eq x x'; inspect_eq y y'; (omega || simpl)
end.

然后我们可以将所有内容组合在一起:调用两次函数扩展,重复fire_i,直到没有其他内容可以检查并以reflexivity结束(实际上所有带有矛盾的分支都已被自动解除!)。 / p>

Ltac eqFF :=
  let x := fresh "x" in
  let y := fresh "y" in
  intros;
  apply functional_extensionality; intro x;
  apply functional_extensionality; intro y;
  repeat fire_i x y; reflexivity.

我们可以看到它毫无问题地解除你的引理:

Lemma foo_eq : foo = foo'.
Proof.
unfold foo, foo'; eqFF.
Qed.

Here is a self-contained gist包含所有导入和定义。