2

I have following definitions: (definition of positive integers as a subtype of nat)

Definition Z_pos_filter (p: nat) : bool :=
  if (beq_nat p 0) then false else true.
Definition Z_pos: Set := {n : nat | is_true (Z_pos_filter n) }.

Definition Z_pos__N (p: Z_pos): nat := proj1_sig p.

Definition Z_pos_mult (p q: Z_pos): Z_pos.
destruct (Z_pos_filter (Z_pos__N p * Z_pos__N q)) eqn:prf.
- exact ((exist _ (Z_pos__N p * Z_pos__N q) prf)).
- assert (forall n: nat, S n <> 0) by (intros; omega).
  assert (forall a b: nat, a <> 0 /\ b <> 0 -> a * b <> 0).
  { intros. destruct a, b. omega. omega. omega. simpl. apply H. }
  assert (forall r: Z_pos, Z_pos__N r <> 0) by apply Z_pos_nonzero_N.
  assert (Z_pos__N p * Z_pos__N q <> 0) by (apply H0; split; apply H1).
  unfold Z_pos_filter in prf.
  rewrite <- beq_nat_false_iff in H2.
  rewrite H2 in prf. inversion prf.
Defined.

But I stuck on showing that the Z_pos_mult is compatible with the multiplication b/w natural numbers:

Lemma compat: forall p q: Z_pos, Z_pos__N (Z_pos_mult p q) = Z_pos__N p * Z_pos__N q.

How can I solve this?

Kanu Kim
  • 193
  • 9

3 Answers3

1

Your definition of Z_pos_mult is too complicated. It relies on dependent pattern matching right from the start. I advise to use this kind of dependent pattern matching only for proofs, not for definitions.

Here is an alternative definition. Not that it fixes the returned value before doing any proof.

Definition Z_pos_mult (p q : Z_pos) : Z_pos.
exists (Z_pos__N p * Z_pos__N q).
destruct p as [p ph]; destruct q as [q qh].
unfold Z_pos_filter in ph, qh |- *; simpl.
destruct (p =? 0) eqn: ph'; try discriminate.
destruct (q =? 0) eqn: qh'; try discriminate.
rewrite beq_nat_false_iff in ph'.
rewrite beq_nat_false_iff in qh'.
destruct (p * q =? 0) eqn:pqh'; auto.
rewrite beq_nat_true_iff in pqh'.
destruct p; destruct q; try solve[discriminate | case ph'; auto | case qh'; auto].
Defined.

With this definition, the proof you request is easy to write.

Lemma compat: forall p q: Z_pos, Z_pos__N (Z_pos_mult p q) = Z_pos__N p * Z_pos__N q.
Proof.
intros [p ph] [q qh]; unfold Z_pos_mult; simpl; auto.
Qed.

In principle, the proof for your code is also possible, but this is exceedingly difficult.

Yves
  • 3,808
  • 12
  • 12
  • To be honest, I know nothing about such a subset notation or the pattern matching and I just imitated what I saw from another post, so I cannot understand what makes the difference. Could you explain what is the significance difference of my definition of Z_pos_mult and yours? And... is there any good reference to learn these stuff? I've followed [logical foundation](https://softwarefoundations.cis.upenn.edu/current/lf-current/index.html) but I think it was not sufficient enough. I want to see some examples and exercises. Thanks. – Kanu Kim Jul 23 '18 at 17:35
  • I understand that at the beginning you mostly copy what other people do. Still in your case, there should not be a need to test whether Z_pos_filter is satisfied or not, so you should just return the value. It is also what the other answers suggest. If you first return the value and then do the proof that it is positive, then there is no difficulty. I will try to clarify the difficult corner in a later answer where the two styles are compared. – Yves Jul 24 '18 at 01:14
  • I tried to give the value first and prove its existence in [definition of reciprocals of nonzero rationals](https://stackoverflow.com/questions/51506431/coq-nested-subtype-defining-nonzero-rational-numbers-and-their-reciprocals) but it failed to simplify. Could you tell me what's the problem? – Kanu Kim Jul 24 '18 at 19:47
1

IMHO answering this question in the original form is advocating a questionable style. I think that multiplication for such numbers should be just the multiplication of the base type; and the proof should just follow from injectivity of the projection, as is done in mathcomp.

In general, you are going to have quite a lot of problems if non-fully opaque proofs appear in your terms after reduction.

ejgallego
  • 6,709
  • 1
  • 14
  • 29
  • What do you mean by 'questionable style' and 'follow from injectivity of the projection'? Does the latter mean the method in Trunov's answer? – Kanu Kim Jul 23 '18 at 18:40
0

Here is how I would do it in vanilla Coq. I'm assuming we can still tweak the definitions.

From Coq Require Import Arith.
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.

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 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.

Let me add that dealing with this kind of thing is much more pleasant in SSReflect/Mathcomp.

Anton Trunov
  • 15,074
  • 2
  • 23
  • 43
  • Could you explain what 'Local Coercion' and 'Sortclass' mean? I've seen [here](https://coq.inria.fr/refman/addendum/implicit-coercions.html) but I cannot figure out what it means clearly. – Kanu Kim Jul 23 '18 at 17:27
  • That declaration means that wherever Coq expects a proposition (which has *sort* `Prop`, hence `Sortclass`), but you provide a boolean, the system will insert `is_true` coercion to make the expression typecheck. `is_true b` is `b = true` by definition. So what you really have is `0 n = true` (you can see it for yourself using `Set Printing Coercions.` command) – Anton Trunov Jul 23 '18 at 17:43