0

I tried to define the reciprocal of a nonzero rational number, imitating the answers in my another question. I tried to delay the proof, but it seems that I misunderstood.

The following is my code:

1) Integers: define z (= a - b) as a pair (a, b) which is in a setoid with the equiv rel (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) Positive integers: {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) Nonzero integers: {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) Rational numbers: ( 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.

I think this definitions are somewhat complex, but it was my best try... Now, how can I prove the consistency of the morphism Q_recip?

(View full code)

Kanu Kim
  • 193
  • 9

1 Answers1

1

I think you forgot to add the definition of Q_nonzero in your development, so I cannot run your code. However, I believe that the issue is that you have used Qed instead of Defined in some of your definitions. This question discusses the issue in more detail. (In any case, as Emilio points out, it is usually better to avoid definitions in proof mode, as they tend to be harder to reason about, as you've probably noticed.)

A note on style: your development mimics common definitions of number systems from first principles in set theory, where we often use equivalence classes to define the integers, the rational numbers, etc. Though elegant, this approach is often inconvenient to use in Coq. The main issue is that, because of the lack of proper quotient types, you are forced to use setoids everywhere, which prevents you from using Coq's much more convenient equality operator =. It is simpler to write these definitions as plain datatypes. For instance, you can define the integers as

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

where Posz represents the canonical injection from natural numbers into integers, and Negz maps the natural number n to the integer - n - 1. This is the approach followed in the mathematical components library. Of course, the standard library also has its own definition of the integers (here), so you do not need to replicate it. Defining the rationals is more complicated, but it can still be done: in mathematical components, they are defined as pairs of coprime integers (num, den) such that den > 0 and num.

Arthur Azevedo De Amorim
  • 23,012
  • 3
  • 33
  • 39
  • Thanks for your answer. First, Q_nonzero is defined as `Definition Q_nonzero: Set := {q : rational | Q_numerator q Z0}.` And now I have a trouble as follows: "Cannot coerce Q_recip to an evaluable reference.", when I unfold Q_recip. What does this error mean? Finally for the style... (since I am studying Coq with the aim: constructing the real numbers from the bottom, I do not want to import mathcomp.) I also feel such difficulties from using the setoid definition of integers, but I just wanted to do in 'elegant' ways (which was a wrong choice :( ) Thanks for your advice. – Kanu Kim Jul 24 '18 at 22:22
  • @KanuKim This error probably means that you ended the proof of `Q_recip` with `Qed` instead of `Defined`. – Arthur Azevedo De Amorim Jul 24 '18 at 22:24
  • Does that error occur if I use `Admitted` instead of `Defined`? – Kanu Kim Jul 24 '18 at 22:39
  • I replaced all `Admitted` with appropriate proofs. Now unfold Q_recip works, but still super complex (almost 4000 lines....) after `simpl`. [image](https://imgur.com/a/Mnfbx3o) – Kanu Kim Jul 24 '18 at 23:00
  • One more question: we considered a method which avoids the setoid definition of integers with making an axiom which states the equality, `Axiom Z_eq: forall (x y: integer), fst x + snd y = snd x + fst y <-> x = y.` (Also an integer is defined as a pair of two `nat`s). To be honest I do not prefer to bring such an axiom; is there any reason to avoid such a method? – Kanu Kim Jul 24 '18 at 23:04
  • 1
    @KanuKim This axiom is unsound because it conflicts with the notion of equality on pairs (that is, if you assume this axiom, you obtain a contradiction). For instance, the axiom implies that the pairs `(0, 0)` and `(1, 1)` are equal, but they aren't. Once again, I think that the definition with two constructors is the cleanest one for defining the integers in Coq. – Arthur Azevedo De Amorim Jul 24 '18 at 23:18