One possible way to say that n m : nat
are adjacent even numbers in Coq is to define that relation inductively, beginning with 0 and 2.
Inductive adj_ev : nat -> nat -> Prop :=
| ae_0 : adj_ev 0 2
| ae_1 : forall ( n m : nat ), adj_ev n m -> adj_ev m ( S ( S m ) )
| ae_2 : forall ( n m : nat ), adj_ev n m -> adj_ev m n.
ae_0
states that 0 and 2 are adjacent even numbers. ae_1
states that if some n m : nat
are adjacent even numbers, so are m
and m + 2
. With these two constructors we can cover all pairs of adjacent even numbers up to infinity. But wait! This works for n
and m
if and only if n < m
. So we need the last constructor ae_2
that flips any given number pair in the relation.
Now that I've defined the relation, I want to do some sanity checks on it to make sure it works. For instance, I know that 1 and 3 are not adjacent even numbers, and I also know that adj_ev 1 3
can never be obtained from the way I defined adj_ev
. So I can surely prove that ~ ( adj_ev 1 3 )
, right?
Theorem test' : ~ ( adj_ev 1 3 ).
unfold not. intros H.
inversion H. inversion H0.
After a few inversions I quickly get stuck in an infinite loop. It's like I'm asking Coq, "How can n
and m
be adjacent and even?" Coq answers "well, perhaps m
and n
are adjacent and even..." Then I ask, "How are m
and n
adjacent and even?" Coq says "well, perhaps n
and m
are adjacent and even..." ad infinitum.
The general problem is that, when you have some inductively defined symmetrical relation R
, it is easy to show that R
holds where it really does hold, but difficult to show that it doesn't where it doesn't. Perhaps there is a better tactic than inversion
for extracting a contradiction in such cases, but I'm not sure what it might be.
Any thoughts?
First I tried induction
with some extra equations, but that wasn't enough.
Goal forall n1 n2, adj_ev n1 n2 -> n1 = 1 -> n2 = 3 -> False.
Proof. induction 1. Abort.
I managed to prove your theorem by first proving that two adjacent even numbers are even.
Enable rewriting with equivalence relations.
Require Import Coq.Setoids.Setoid.
Turn off proof search when using firstorder
. Allow only simplification.
Set Firstorder Depth 0.
Create a hint database Hints
for use with auto
, autorewrite
, or autounfold
.
Create HintDb Hints.
Shorthand for commonly used tactics.
Ltac simplify := repeat (firstorder || subst || autorewrite with Hints in *).
Inductive even : nat -> Prop :=
| even_0 : even 0
| even_S : forall n1, even n1 -> even (S (S n1)).
Simple enough.
Conjecture C1 : even 0 <-> True.
Conjecture C2 : even 1 <-> False.
Conjecture C3 : forall n1, even (S (S n1)) <-> even n1.
Hint Rewrite C1 C2 C3 : Hints.
Theorem T1 : forall n1 n2, adj_ev n1 n2 -> even n1 /\ even n2.
Proof. induction 1; simplify. Qed.
Goal ~ adj_ev 1 3. Proof. intro H1. apply T1 in H1. simplify. Qed.
You could have also defined
Definition least : (nat -> Prop) -> nat -> Prop := fun p1 n1 => p1 n1 /\ (forall n2, p1 n2 -> n2 >= n1).
Definition greatest : (nat -> Prop) -> nat -> Prop := fun p1 n1 => p1 n1 /\ (forall n2, p1 n2 -> n2 <= n1).
Definition even : nat -> Prop := fun n1 => exists n2, n1 = 2 * n2.
Definition least_greater_even : nat -> nat -> Prop := fun n1 => least (fun n2 => n2 > n1 /\ even n2).
Definition greatest_less_even : nat -> nat -> Prop := fun n1 => greatest (fun n2 => n2 < n1 /\ even n2).
Definition adjacent_even : nat -> nat -> Prop := fun n1 n2 => least_greater_even n1 n2 /\ greatest_less_even n2 n1 \/ greatest_less_even n1 n2 /\ least_greater_even n2 n1.
and worked from there. And there are other ways of defining your predicate.
Inductive adj_ev : nat -> nat -> Prop :=
| adj_ev_0_2 : adj_ev 0 2
| adj_ev_2_0 : adj_ev 2 0
| adj_ev_S_S : forall n1 n2, adj_ev n1 n2 -> adj_ev (S (S n1)) (S (S n2)).
Goal ~ adj_ev 1 3. Proof. inversion 1. Qed.