Proving the symmetry of natural numbers - coq

I am a beginner in coq. I want to prove symmetry of a boolean equality on natural numbers. I have applied induction and destruct commands, but it does not work. Please guide me in proving the theorem.
Fixpoint beqnat(n m : nat): bool:=
match n with
|0=> match m with
|0=> true
|S m' => false
end
|S n'=> match m with
|0=>false
|S m'=> beqnat n' m'
end
end.
Theorem beq sys:
forall(n m:nat),
beqnat n m = beqnat m n.

The proof follows by induction on n followed by destruction on m:
Theorem beq_sym: forall n m : nat, beqnat n m = beqnat m n.
Proof.
induction n as [|n' IH]; destruct m; auto.
apply IH.
Qed.
To understand what is happening:
Do induction n which gives subgoals for n = 0 and n = S n'.
Do simpl on each subgoal to see how the first match/with reduces.
Now you need to do something to m to reduce the second match/with. Induction is not necessary because your beqnat is structurally recursive on n (type Print beqnat and look for {struct n} to confirm), not m. So, destruct m suffices. Again, use simpl to see why.
The induction hypothesis is needed for the recursive call to beqnat in the second subgoal.

Related

Proof of "less than or equal" transitive law in Coq

I recently started learning Coq at a university course. I have an assignment with a problem, and I got stuck. I need to demonstrate the transitivity of the <= law, which states that for all m, n and p, if m <= n and n <= p, then m <= p. I tried every basic tactic possible, and I didn't figure it out. I want to mention that I'm a beginner and any basic solution without complicated tactics would be appreciated. It should be done with induction as well. Thanks!
Inductive Nat := O : Nat | S : Nat -> Nat.
Fixpoint le_Nat (m n : Nat) : bool :=
match m with
| O => true
| S m' => match n with
| O => false
| S n' => (le_Nat m' n')
end
end.
Lemma le_Trans :
forall m n p,
le_Nat m n = true -> le_Nat n p = true -> le_Nat m p = true.
Proof.
...
Qed.
Here is a long, detailled version:
Proof.
induction m as [| m IHm]; simpl.
- reflexivity.
- destruct n; simpl.
+ intros; discriminate.
+ destruct p; simpl.
* intros; assumption.
* apply IHm.
Qed.
and a shorter one:
induction m;destruct n; destruct p; simpl; try (reflexivity || discriminate).
apply IHm.
Qed.
You may start your proof with three nested induction/case analyses.
Many sub-goals will be trivial or easy to solve.
The last sub-goal will apply the induction hypothesis.
Proof.
induction m; destruct n ; destruct p; simpl.
(* ... *)

Addition of natural numbers in Coq

Coq's standard libraries give the Peano natural numbers and addition:
Inductive nat : Set :=
| O : nat
| S : nat -> nat.
Fixpoint add n m :=
match n with
| 0 => m
| S p => S (add p m)
end.
I am curious if I change the fix_definition of addition like
Fixpoint add n m :=
match n with
| 0 => m
| S p => add p (S m)
end.
Is the new addition equivalent to the old one? I tried to prove their equivalence by proving forall n m, add (S n) m = S (add n m) but failed.
In order to proof your helper lemma, you need to be careful what to introduce. If you don't introduce m, you get a more general induction hypothesis as in:
Require Import Nat.
Print add.
Fixpoint my_add n m :=
match n with
| 0 => m
| S p => my_add p (S m)
end.
Lemma my_add_S_r: forall n m, my_add n (S m) = S (my_add n m).
Proof.
(* Note: don't introduce m here - you get a more general induction hypothesis this way *)
intros n.
induction n.
- intros; reflexivity.
- intros; cbn. rewrite IHn. reflexivity.
Qed.
Lemma my_add_equiv: forall n m, add n m = my_add n m.
intros.
induction n.
- reflexivity.
- cbn. rewrite my_add_S_r. rewrite IHn. reflexivity.
Qed.
Yes both additions are equivalent, you can prove it using the lemma plus_n_Sm : forall n m : nat, S (n + m) = n + S m from the standard library (found using Search "+" (S _).) and an adequate induction hypothesis (for instance P(n) := forall m, n + m = add n m).

Proof by case analysis in Coq

I am trying to prove a Proposition about the following function:
Program Fixpoint division (m:nat) (n:nat) {measure m} : nat :=
match lt_nat 0 n with
| false => 0
| true => match leq_nat n m with
| false => 0
| true => S (division (menos m n) n)
end
end.
menos is natural subtraction.
I am trying to prove some fact involving division. I wrote down an informal proof were I first consider a case analysis in lt_nat 0 n and then in the case when lt_nat is true a further case analysis in leq_nat n m. This is in order to reduce the definition of division.
However I can not find how to express this case analysis in Coq. I tried with destruct (leq_nat n m) but it does nothing. I am expecting Coq to generate two subgoals: one where I need to prove my proposition assuming leq_nat n m = false and one assuming leq_nat n m = true.
Furthermore, I can not unfold the definition of division in my proof! When I try unfold division I get: division_func (existT (fun _ : nat => nat) m n).
How can I perfom case analysis in leq_nat n m? Why is it that I can not unfold the definition of division as I usually do with other functions?
Thank you.
Everything is more complicated than usual because of Program Fixpoint, which does not define your function as you would expect with a classic Fixpoint, since it needs to find a structurally recursive way of defining it. What division really is, is hidden in division_func.
Therefore, to manipulate your function, you need to prove basic lemmas, including the one stating that your function can be replaced by its body.
Lemma division_eq : forall m n, division m n = match lt_nat 0 n with
| false => 0
| true => match leq_nat n m with
| false => 0
| true => S (division (menos m n) n)
end
end.
Now, the question is how to prove this result. Here is the only solution I know, which I consider really unsatisfying.
I use the tactic fix_sub_eq located in Program.Wf, or fix_sub_eq_ext in Program.Wf.WfExtensionality.
This gives something like:
Proof.
intros.
unfold division. unfold division_func at 1.
rewrite fix_sub_eq; repeat fold division_func.
- simpl. destruct (lt_nat 0 n) eqn:H.
destruct (leq_nat n m) eqn:H0. reflexivity.
reflexivity. reflexivity.
But the second goal is quite complicated. The easy and general way of solving it is to use the axioms proof_irrelevance and functional_extensionality. It should be possible to prove this particular subgoal without any axioms, but I have not found the right way to do it. Instead of manually applying the axioms, you can use the second tactic fix_sub_eq_ext which calls them directly, leaving you a single goal.
Proof.
intros.
unfold division. unfold division_func at 1.
rewrite fix_sub_eq_ext; repeat fold division_func.
simpl. destruct (lt_nat 0 n) eqn:H.
destruct (leq_nat n m) eqn:H0. reflexivity.
reflexivity. reflexivity.
Qed.
I have not found a better way to use Program Fixpoint, that's why I prefer using Function, which has other defaults, but generates directly the equation lemma.
Require Recdef.
Function division (m:nat) (n:nat) {measure (fun n => n) m} : nat :=
match lt_nat 0 n with
| false => 0
| true => match leq_nat n m with
| false => 0
| true => S (division (menos m n) n)
end
end.
Proof.
intros m n. revert m. induction n; intros.
- discriminate teq.
- destruct m. discriminate teq0.
simpl. destruct n. destruct m; apply le_n.
transitivity m. apply IHn. reflexivity. assumption. apply le_n.
Qed.
Check division_equation.
Now you have the equation lemma, you can rewrite with it and reason as usual.
About your problem with destruct, destruct does not unfold the definitions. Therefore, if you have no occurrences of the term you're destructing in your goal or any of the hypotheses, destruct will not do anything interesting, unless you save the equation it produces. You can use destruct ... eqn:H for this purpose. I did not know case_eq but it seems to do the same thing.

How to prove False from obviously contradictory assumptions

Suppose I want to prove following Theorem:
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
This one is trivial since m cannot be both successor and zero, as assumed. However I found it quite tricky to prove it, and I don't know how to make it without an auxiliary lemma:
Lemma succ_neq_zero_lemma : forall n : nat, O = S n -> False.
Proof.
intros.
inversion H.
Qed.
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
Proof.
intros.
symmetry in H.
apply (succ_neq_zero_lemma n).
transitivity m.
assumption.
assumption.
Qed.
I am pretty sure there is a better way to prove this. What is the best way to do it?
You just need to substitute for m in the first equation:
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
Proof.
intros n m H1 H2; rewrite <- H2 in H1; inversion H1.
Qed.
There's a very easy way to prove it:
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
Proof.
congruence.
Qed.
The congruence tactic is a decision procedure for ground equalities on uninterpreted symbols. It's complete for uninterpreted symbols and for constructors, so in cases like this one, it can prove that the equality 0 = m is impossible.
It might be useful to know how congruence works.
To prove that two terms constructed by different constructors are in fact different, just create a function that returns True in one case and False in the other cases, and then use it to prove True = False. I think this is explained in Coq'Art
Example not_congruent: 0 <> 1.
intros C. (* now our goal is 'False' *)
pose (fun m=>match m with 0=>True |S _=>False end) as f.
assert (Contra: f 1 = f 0) by (rewrite C; reflexivity).
now replace False with True by Contra.
Qed.

Proving commutativity of max in coq

I have a function max:
Fixpoint max (n : nat) (m : nat) : nat :=
match n, m with
| O, O => O
| O, S x => S x
| S x, O => S x
| S x, S y => S (max x y)
end.
and a proof of the commutativity of max as follows:
Theorem max_comm :
forall n m : nat, max n m = max m n.
Proof.
intros n m.
induction n as [|n'];
induction m as [|m'];
simpl; trivial.
(* Qed. *)
This leaves off at S (max n' m') = S (max m' n'), which seems correct, and given the base case has already been proven, seems like one should be able to tell coq "just use the recursion!". However, I cannot figure out how to do it. Any help?
The problem is you introduce variable m before doing induction on variable n, and that makes the induction hypothesis less general. Try this instead.
intro n; induction n as [| n' IHn'];
intro m; destruct m as [| m'];
simpl; try (rewrite IHn'); trivial.