Coq:嵌套(?)子类型,定义非零有理数及其倒数

时间:2018-07-24 19:44:13

标签: coq

我试图定义一个非零有理数的倒数,模仿了我的another question中的答案。我试图推迟证明,但似乎我误会了。

以下是我的代码:

1)整数:将z (= a - b)定义为一对(a, b),它与等价线(a, b) ~ (c, d) <-> a + d = b + c处于类固醇中

Definition Z_eq (z w: integer): Prop :=
  match z with
  | (z1, z2) =>
    match w with
    | (w1, w2) => z1 + w2 = z2 + w1
    end
  end.

Add Parametric Relation:
  integer Z_eq
  reflexivity proved by Z_refl
  symmetry proved by Z_symm
  transitivity proved by Z_tran
  as Z. (** proved; omitting the proof *)

(** addition, subtraction, negation, multiplication are well-defined as a morphism *)
Add Morphism Z_plus with signature Z_eq ==> Z_eq ==> Z_eq as Z_plus_morph.
(** etc. *)

2)正整数:{n : nat | 0 <? n }

(** as in answers of the previous question *)
Local Coercion is_true : bool >-> Sortclass.
Definition Z_pos: Set := {n : nat | 0 <? n }.

Definition Z_pos__N (p: Z_pos): nat := proj1_sig p.
Coercion Z_pos__N : Z_pos >-> nat.

Definition Z_pos__Z (p: Z_pos): integer := (proj1_sig p, 0).
Coercion Z_pos__Z : Z_pos >-> integer.

Definition Z_pos_plus : Z_pos -> Z_pos -> Z_pos.
  intros [x xpos%Nat.ltb_lt] [y ypos%Nat.ltb_lt].
  refine (exist  _ (x + y) _).
  now apply Nat.ltb_lt, Nat.add_pos_pos.
Defined.

Definition Z_pos_mult : Z_pos -> Z_pos -> Z_pos.
  intros [x xpos%Nat.ltb_lt] [y ypos%Nat.ltb_lt].
  refine (exist  _ (x * y) _).
  now apply Nat.ltb_lt, Nat.mul_pos_pos.
Defined.

Lemma Z_pos_mult_compat: forall p q: Z_pos, Z_pos__N (Z_pos_mult p q) = Z_pos__N p * Z_pos__N q.
Proof. now intros [x xpos] [y ypos]. Qed.

Definition ZP1: Z_pos.
  refine (exist  _ 1 _). easy.
Defined.

3)非零整数:{z : integer | z <Z> Z0}

(** nonzero integer *)
Definition Z_nonzero: Set := {z : integer | z <Z> Z0}.

(* abs value of a nonzero integer as an obj of type Z_pos *)
Definition Z_nonzero_abs__Z_pos (z: Z_nonzero): Z_pos.
  destruct z as [[z1 z2] z3].
  exists ((z1 - z2) + (z2 - z1))%nat.
Admitted. (** proof ommited *)

(* multiplication b/w two nonzero integers *)
Definition Z_nonzero_mult (z w: Z_nonzero): Z_nonzero.
  exists (proj1_sig z *Z proj1_sig w).
Admitted.

(* sign of n - m *)
Definition N_sgn_diff__Z (n m: nat): integer :=
  if n >? m then Z1 else if n =? m then Z0 else -Z Z1.

(* sign of n - m *)
Definition Z_nonzero_sgn__Z (z: Z_nonzero): Z_nonzero.
  destruct z as [[z1 z2] z3].
  exists (N_sgn_diff__Z z1 z2).
Admitted.

4)有理数:( a // b ) (a: integer, b: Z_pos)

Inductive rational: Type :=
| prerat : integer -> Z_pos -> rational.

Notation "( x '//' y )" := (prerat x y).

(* equality *)
Definition Q_eq (p q: rational): Prop :=
  match p with
  | (p1 // p2) =>
    match q with
    | (q1 // q2) => (Z_mult p1 (Z_pos__Z q2)) =Z= (Z_mult (Z_pos__Z p2) q1)
    end
  end.

(* numerator of a rational *)
Definition Q_numerator (q: rational) :=
  match q with
  | (iq // rq) => iq
  end.

(* nonzero rationals *)
Definition Q_nonzero: Set := {q : rational | Q_numerator q <Z> Z0}.

(* numerator and denominator *)
Definition Q_nonzero_numerator (q: Q_nonzero): Z_nonzero.
  destruct q as [[q1 q2] q3].
  exists q1.
  simpl in q3. apply q3.
Qed.

Definition Q_nonzero_denominator (q: Q_nonzero): Z_pos.
  destruct q as [[q1 q2] q3].
  exact q2.
Qed.

Definition Q_recip (q: Q_nonzero): Q_nonzero.
  exists ( proj1_sig (Z_nonzero_mult (Z_nonzero_sgn__Z (Q_nonzero_numerator q)) (Z_pos__Z_nonzero (Q_nonzero_denominator q))) // Z_nonzero_abs__Z_pos (Q_nonzero_numerator q) ).
Admitted. (* proved. *)

(* inherited equality *)
Definition Q_nonzero_eq (p q: Q_nonzero): Prop := (proj1_sig p) =Q= (proj1_sig q).

Add Morphism Q_recip with signature Q_nonzero_eq ==> Q_nonzero_eq as Q_recip_morph.
Proof. (* well-definedness of Q_recip *)
  destruct x, y.
  unfold Q_nonzero_eq. simpl. intros.
  unfold Q_recip. (* <----- unfolded result was very long and complex; not     simplified after simpl. *)
Abort.

我认为这个定义有些复杂,但这是我的最佳尝试... 现在,如何证明态射Q_recip的一致性?

View full code

1 个答案:

答案 0 :(得分:1)

我认为您忘记在开发中添加Q_nonzero的定义,因此我无法运行您的代码。但是,我认为问题在于您在某些定义中使用了Qed而不是DefinedThis question详细讨论了该问题。 (无论如何,像Emilio points out一样,通常最好避免以证明模式进行定义,因为您可能已经注意到,因为它们往往更难以推理。)

关于样式的注释:您的开发模仿集合论中的第一条原则对数字系统的通用定义,在集合论中,我们经常使用等价类来定义整数,有理数等。尽管优雅,但这种方法使用起来常常不方便在Coq。主要问题是,由于缺少适当的商类型,您被迫在各处使用setoid,这使您无法使用Coq更方便的等于运算符=。将这些定义写为纯数据类型更简单。例如,您可以将整数定义为

Inductive int :=
| Posz : nat -> int
| Negz : nat -> int.

其中Posz表示从自然数到整数的规范注入,而Negz将自然数n映射到整数- n - 1。这是mathematical components library中遵循的方法。当然,标准库也有自己的整数定义(here),因此您无需复制它。定义有理数较为复杂,但仍可以完成:in mathematical components,它们被定义为成对的互质整数(num, den),使得den > 0num