Coq中无限表示的有限子集计算

Coq中无限表示的有限子集计算,coq,Coq,我有一个函数Z->Z->whatever,我把它看作是从(Z,Z)到whatever的映射,让我们把它键入FF which是可从nix或inj\u which构造的简单和 我使用一些数据初始化此映射,方式如下: 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的ZArith中

我有一个函数
Z->Z->whatever
,我把它看作是从
(Z,Z)
whatever
的映射,让我们把它键入
FF

which
是可从
nix
inj\u which
构造的简单和

我使用一些数据初始化此映射,方式如下:

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的
ZArith
中的
Z
上的布尔可判定等式

现在我想在这两个
FF
s上实现相等,我不介意调用
functional\u extensionality
。我现在想做的是让Coq计算确定两个
FF
s的等式

例如,假设我们做了以下几点:

定义为空:FF:=fun x y=>nix。

现在,我们添加一些任意值以使
foo
foo'
,它们在函数扩展性下是等价的:

定义foo:=i0 0(i0(-42)(i56 1空))。

definitionfoo':=i0(-42)(i561(i0空))。

自动让Coq确定
foo=foo'
的好方法是什么<代码>Ltac级别的东西?实际终止计算?我是否需要将域限制为有限域


域限制有点复杂。我以
f:FF->FF
的方式操作贴图,其中
f
可以扩展定义计算的
Z x Z
子集。因此,想想看,它不能是
f:FF->FF
,而是更像
f:FF->FF_1
,其中
FF_1
Z x Z
的一个子集,由一个小常数扩展。同样地,当应用
f
n次时,最终得到
FF_n
,这相当于
FF
加上
n*常量
对域的域限制。因此函数
f
缓慢地(通过一个常数因子)扩展域FF的定义。

正如我在评论中所说的,需要更多的细节来阐述一个令人满意的答案。关于如何使用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标准库中的地图已经为您提供了这样的计算等式功能。

正如我在评论中所说的,需要更多的细节来阐述一个令人满意的答案。关于如何使用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标准库中的映射已经为您提供了这样的计算等式功能。

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

我们从检查两个整数是否相等的策略开始(使用
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=0
x 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
,直到没有其他东西可以检查并通过
自反性得出结论(实际上所有有矛盾的分支都被自动排除了!)

我们可以看到,它释放你的引理没有任何问题:

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

对于所有的导入和定义。

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

我们从检查两个整数是否相等的策略开始(使用
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=0