Exercise session 1

🏠 Go back to the course homepage.

Try and solve the following exercises by using the tactics shown in class:

intro, apply, destruct, split, left, right, exfalso, simpl, reflexivity,
f_equal, induction, assumption.

Lemmas currently end with the keyword Admitted which means the lemma is accepted and can be used without a proof. Replace Admitted with Qed once you have completed the proofs.

There are more exercises than what can be done in the exercise session during the lecture. Proving is like programming: You will have to practice at home. It is fine not to do all the exercises, but you should feel like you could do the exercises. We will help you with this assessment at the start of every lecture.

Please send us this file with your (partial) solutions by email before the next lecture: yannick.forster@inria.fr, theo.winterhalter@inria.fr

We will begin with the exercises you have seen already.

P: Prop

P -> P
P: Prop

P -> P
P: Prop
h: P

P
apply h.
P_imp_P is defined
P, Q: Prop

P /\ Q -> Q /\ P
P, Q: Prop

P /\ Q -> Q /\ P
P, Q: Prop
h: P /\ Q

Q /\ P
P, Q: Prop
hP: P
hQ: Q

Q /\ P
P, Q: Prop
hP: P
hQ: Q

Q
P, Q: Prop
hP: P
hQ: Q
P
P, Q: Prop
hP: P
hQ: Q

Q
apply hQ.
P, Q: Prop
hP: P
hQ: Q

P
apply hP.
and_comm is defined
P, Q: Prop

P \/ Q -> Q \/ P
P, Q: Prop

P \/ Q -> Q \/ P
P, Q: Prop
h: P \/ Q

Q \/ P
P, Q: Prop
hP: P

Q \/ P
P, Q: Prop
hQ: Q
Q \/ P
P, Q: Prop
hP: P

Q \/ P
P, Q: Prop
hP: P

P
apply hP.
P, Q: Prop
hQ: Q

Q \/ P
P, Q: Prop
hQ: Q

Q
apply hQ.
or_comm is defined

True
split.
truetrue is defined
P: Prop

False -> P
P: Prop

False -> P
P: Prop
h: False

P
destruct h.
anything_goes is defined

~ False

~ False
h: False

False
apply h.
nofalse is defined

Now some new exercises about propositional logic.

P, Q, R: Prop

(P -> Q) -> (Q -> R) -> P -> R
P, Q, R: Prop

(P -> Q) -> (Q -> R) -> P -> R
P, Q, R: Prop
hPQ: P -> Q

(Q -> R) -> P -> R
P, Q, R: Prop
hPQ: P -> Q
hQR: Q -> R

P -> R
P, Q, R: Prop
hPQ: P -> Q
hQR: Q -> R
hP: P

R
P, Q, R: Prop
hPQ: P -> Q
hQR: Q -> R
hP: P

Q
P, Q, R: Prop
hPQ: P -> Q
hQR: Q -> R
hP: P

P
apply hP.
imp_trans is defined
P: Prop

P -> ~ ~ P
P: Prop

P -> ~ ~ P
P: Prop
hP: P

~ ~ P
P: Prop
hP: P
hnP: ~ P

False
P: Prop
hP: P
hnP: ~ P

P
apply hP.
to_not_not is defined

For this one, note that if you already separated a case distinction with dashes (-) then you can use + at the next level. The following level is marked with *.

P, Q, R: Prop

(P \/ Q) /\ R -> P /\ R \/ Q /\ R
P, Q, R: Prop

(P \/ Q) /\ R -> P /\ R \/ Q /\ R
P, Q, R: Prop
h: (P \/ Q) /\ R

P /\ R \/ Q /\ R
P, Q, R: Prop
hPQ: P \/ Q
hR: R

P /\ R \/ Q /\ R
P, Q, R: Prop
hP: P
hR: R

P /\ R \/ Q /\ R
P, Q, R: Prop
hQ: Q
hR: R
P /\ R \/ Q /\ R
P, Q, R: Prop
hP: P
hR: R

P /\ R \/ Q /\ R
P, Q, R: Prop
hP: P
hR: R

P /\ R
P, Q, R: Prop
hP: P
hR: R

P
P, Q, R: Prop
hP: P
hR: R
R
P, Q, R: Prop
hP: P
hR: R

P
apply hP.
P, Q, R: Prop
hP: P
hR: R

R
apply hR.
P, Q, R: Prop
hQ: Q
hR: R

P /\ R \/ Q /\ R
P, Q, R: Prop
hQ: Q
hR: R

Q /\ R
P, Q, R: Prop
hQ: Q
hR: R

Q
P, Q, R: Prop
hQ: Q
hR: R
R
P, Q, R: Prop
hQ: Q
hR: R

Q
apply hQ.
P, Q, R: Prop
hQ: Q
hR: R

R
apply hR.
distr is defined
P: Prop

P /\ ~ P -> False
P: Prop

P /\ ~ P -> False
P: Prop
h: P /\ ~ P

False
P: Prop
hP: P
hnP: ~ P

False
P: Prop
hP: P
hnP: ~ P

P
apply hP.
contrad is defined
P, Q: Prop

P \/ ~ P -> ((P -> Q) -> P) -> P
P, Q: Prop

P \/ ~ P -> ((P -> Q) -> P) -> P
P, Q: Prop
lem: P \/ ~ P

((P -> Q) -> P) -> P
P, Q: Prop
lem: P \/ ~ P
h: (P -> Q) -> P

P
P, Q: Prop
hP: P
h: (P -> Q) -> P

P
P, Q: Prop
hnP: ~ P
h: (P -> Q) -> P
P
P, Q: Prop
hP: P
h: (P -> Q) -> P

P
apply hP.
P, Q: Prop
hnP: ~ P
h: (P -> Q) -> P

P
P, Q: Prop
hnP: ~ P
h: (P -> Q) -> P

P -> Q
P, Q: Prop
hnP: ~ P
h: (P -> Q) -> P
hP: P

Q
P, Q: Prop
hnP: ~ P
h: (P -> Q) -> P
hP: P

False
P, Q: Prop
hnP: ~ P
h: (P -> Q) -> P
hP: P

P
apply hP.
lem_pl is defined
P: Prop

P \/ ~ P -> ~ ~ P -> P
P: Prop

P \/ ~ P -> ~ ~ P -> P
P: Prop
lem: P \/ ~ P

~ ~ P -> P
P: Prop
lem: P \/ ~ P
hnnP: ~ ~ P

P
P: Prop
hP: P
hnnP: ~ ~ P

P
P: Prop
hnP: ~ P
hnnP: ~ ~ P
P
P: Prop
hP: P
hnnP: ~ ~ P

P
assumption.
P: Prop
hnP: ~ P
hnnP: ~ ~ P

P
P: Prop
hnP: ~ P
hnnP: ~ ~ P

False
P: Prop
hnP: ~ P
hnnP: ~ ~ P

~ P
apply hnP.
lem_dns is defined

To introduce several variables at once, you can use the intros tactic.

P, Q: Prop

(P -> Q) -> ~ ~ P -> ~ ~ Q
P, Q: Prop

(P -> Q) -> ~ ~ P -> ~ ~ Q
P, Q: Prop
hPQ: P -> Q
hnnP: ~ ~ P

~ ~ Q
P, Q: Prop
hPQ: P -> Q
hnnP: ~ ~ P
hnQ: ~ Q

False
P, Q: Prop
hPQ: P -> Q
hnnP: ~ ~ P
hnQ: ~ Q

~ P
P, Q: Prop
hPQ: P -> Q
hnnP: ~ ~ P
hnQ: ~ Q
hP: P

False
P, Q: Prop
hPQ: P -> Q
hnnP: ~ ~ P
hnQ: ~ Q
hP: P

Q
P, Q: Prop
hPQ: P -> Q
hnnP: ~ ~ P
hnQ: ~ Q
hP: P

P
apply hP.
dn_functorial is defined

Let us switch to Booleans again.

b1, b2, b3: bool

(b1 && (b2 || b3))%bool = (b1 && b2 || b1 && b3)%bool
b1, b2, b3: bool

(b1 && (b2 || b3))%bool = (b1 && b2 || b1 && b3)%bool
b2, b3: bool

(true && (b2 || b3))%bool = (true && b2 || true && b3)%bool
b2, b3: bool
(false && (b2 || b3))%bool = (false && b2 || false && b3)%bool
b2, b3: bool

(true && (b2 || b3))%bool = (true && b2 || true && b3)%bool
b2, b3: bool

(b2 || b3)%bool = (b2 || b3)%bool
reflexivity.
b2, b3: bool

(false && (b2 || b3))%bool = (false && b2 || false && b3)%bool
b2, b3: bool

false = false
reflexivity.
andb_orb_distr is defined
b1, b2: bool

negb (b1 && b2) = (negb b1 || negb b2)%bool
b1, b2: bool

negb (b1 && b2) = (negb b1 || negb b2)%bool
b2: bool

negb (true && b2) = (negb true || negb b2)%bool
b2: bool
negb (false && b2) = (negb false || negb b2)%bool
b2: bool

negb (true && b2) = (negb true || negb b2)%bool
b2: bool

negb b2 = negb b2
reflexivity.
b2: bool

negb (false && b2) = (negb false || negb b2)%bool
b2: bool

true = true
reflexivity.
de_morgan is defined

Let us switch to natural numbers.


12 + 3 = 15

12 + 3 = 15

15 = 15
reflexivity.
calc_12_3 is defined

Let us make a lemma out of the n + 0 = n property.

You can then apply this lemma by using apply n_plus_0 like for hypotheses!

n: nat

n + 0 = n
n: nat

n + 0 = n

0 + 0 = 0
n: nat
IHn: n + 0 = n
S n + 0 = S n

0 + 0 = 0

0 = 0
reflexivity.
n: nat
IHn: n + 0 = n

S n + 0 = S n
n: nat
IHn: n + 0 = n

S (n + 0) = S n
n: nat
IHn: n + 0 = n

n + 0 = n
assumption.
n_plus_0 is defined
n: nat

n + n = 2 * n
n: nat

n + n = 2 * n
n: nat

n + n = n + (n + 0)
n: nat

n = n + 0
n: nat

n = n
reflexivity.
double_eq is defined
n, m: nat

n + S m = S n + m
n, m: nat

n + S m = S n + m
m: nat

0 + S m = 1 + m
n, m: nat
ih: n + S m = S n + m
S n + S m = S (S n) + m
m: nat

0 + S m = 1 + m
m: nat

S m = S m
reflexivity.
n, m: nat
ih: n + S m = S n + m

S n + S m = S (S n) + m
n, m: nat
ih: n + S m = S n + m

S (n + S m) = S (S (n + m))
n, m: nat
ih: n + S m = S n + m

n + S m = S (n + m)
apply ih.
plus_S is defined
n, m: nat

n + m = m + n
n, m: nat

n + m = m + n
m: nat

0 + m = m + 0
n, m: nat
IHn: n + m = m + n
S n + m = m + S n
m: nat

0 + m = m + 0
m: nat

m = m + 0
m: nat

m = m
reflexivity.
n, m: nat
IHn: n + m = m + n

S n + m = m + S n
n, m: nat
IHn: n + m = m + n

S (n + m) = m + S n
n, m: nat
IHn: n + m = m + n

S (n + m) = S m + n
n, m: nat
IHn: n + m = m + n

S (n + m) = S (m + n)
n, m: nat
IHn: n + m = m + n

n + m = m + n
assumption.
plus_comm is defined

Show associativity of additon.

k, n, m: nat

k + n + m = k + (n + m)
k, n, m: nat

k + n + m = k + (n + m)
n, m: nat

0 + n + m = 0 + (n + m)
k, n, m: nat
IHk: k + n + m = k + (n + m)
S k + n + m = S k + (n + m)
n, m: nat

0 + n + m = 0 + (n + m)
n, m: nat

n + m = n + m
reflexivity.
k, n, m: nat
IHk: k + n + m = k + (n + m)

S k + n + m = S k + (n + m)
k, n, m: nat
IHk: k + n + m = k + (n + m)

S (k + n + m) = S (k + (n + m))
k, n, m: nat
IHk: k + n + m = k + (n + m)

k + n + m = k + (n + m)
assumption.
plus_assoc is defined

We can also show commutativity of multiplication. Try to come up with the lemmas yourself. Note that you can also use rewrite in the opposite direction by using:

rewrite <- n_plus_0

for instance. You can also use rewrite with hypotheses you have.

If you ever find yourself with x = y to prove, when you think you can prove y = x, you can also use the symmetry tactic.

Fill in the cases for the following function.

min is defined
min is recursively defined (guarded on 1st argument)

forall n m : nat, min n m = min m n

forall n m : nat, min n m = min m n
n: nat

forall m : nat, min n m = min m n

Hint: start the induction before introducing m.

  

forall m : nat, min 0 m = min m 0
n: nat
ih:= forall m: nat, min n m = min m n
forall m : nat, min (S n) m = min m (S n)

forall m : nat, min 0 m = min m 0
m: nat

min 0 m = min m 0

min 0 0 = min 0 0
m: nat
min 0 (S m) = min (S m) 0

min 0 0 = min 0 0

0 = 0
reflexivity.
m: nat

min 0 (S m) = min (S m) 0
m: nat

0 = 0
reflexivity.
n: nat
ih:= forall m: nat, min n m = min m n

forall m : nat, min (S n) m = min m (S n)
n: nat
ih:= forall m: nat, min n m = min m n
m: nat

min (S n) m = min m (S n)
n: nat
ih:= forall m: nat, min n m = min m n

min (S n) 0 = min 0 (S n)
n: nat
ih:= forall m: nat, min n m = min m n
m: nat
min (S n) (S m) = min (S m) (S n)
n: nat
ih:= forall m: nat, min n m = min m n

min (S n) 0 = min 0 (S n)
n: nat
ih:= forall m: nat, min n m = min m n

0 = 0
reflexivity.
n: nat
ih:= forall m: nat, min n m = min m n
m: nat

min (S n) (S m) = min (S m) (S n)
n: nat
ih:= forall m: nat, min n m = min m n
m: nat

min n m = min m n
apply ih.
min_comm is defined

ADVANCED EXERCISES

If you have already used Rocq before or you are done with the exercises, give the advanced exercises a try. They hopefully teach you thinks you have not seen before.

Section Advanced.

  
P is declared
Q is declared
R is declared

We introduce a new notation P <-> Q meaning P is equivalent to Q.

It is essentially a notation for P -> Q /\ Q -> P so you can use the tactics split and destruct to prove it and use it.

Here is a trivial example to understand it.

  
P, Q, R: Prop

P <-> P
P, Q, R: Prop

P <-> P
P, Q, R: Prop

P -> P
P, Q, R: Prop
P -> P
P, Q, R: Prop

P -> P
P, Q, R: Prop
H: P

P
assumption.
P, Q, R: Prop

P -> P
P, Q, R: Prop
H: P

P
assumption.
P_iff_P is defined

And here is a new tactic that is going to be useful: assert.

When you write assert (h : P) you are telling Rocq that you want to prove P and that then you are going to use this as an hypothesis named h. This is sometimes called forward reasoning.

See how it works below.

  
P, Q, R: Prop

(Q -> P) /\ (R -> P) -> Q \/ R -> ~ ~ P
P, Q, R: Prop

(Q -> P) /\ (R -> P) -> Q \/ R -> ~ ~ P
P, Q, R: Prop
h1: (Q -> P) /\ (R -> P)
h2: Q \/ R

~ ~ P
P, Q, R: Prop
h1: (Q -> P) /\ (R -> P)
h2: Q \/ R

P
P, Q, R: Prop
h1: (Q -> P) /\ (R -> P)
h2: Q \/ R
hP: P
~ ~ P
P, Q, R: Prop
h1: (Q -> P) /\ (R -> P)
h2: Q \/ R

P
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
h2: Q \/ R

P
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
hQ: Q

P
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
hR: R
P
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
hQ: Q

P
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
hQ: Q

Q
apply hQ.
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
hR: R

P
P, Q, R: Prop
hQP: Q -> P
hRP: R -> P
hR: R

R
apply hR.
P, Q, R: Prop
h1: (Q -> P) /\ (R -> P)
h2: Q \/ R
hP: P

~ ~ P
P, Q, R: Prop
h1: (Q -> P) /\ (R -> P)
h2: Q \/ R
hP: P

P
apply hP.
or_imp is defined
P, Q, R: Prop

~ (P <-> ~ P)
P, Q, R: Prop

~ (P <-> ~ P)
P, Q, R: Prop
h: P <-> ~ P

False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P

False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P

P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P
False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P

P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P

~ P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P
P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

P
apply hP.
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

P
apply hP.
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

~ P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P
hnP: ~ P
False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

~ P
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P

P
apply hP.
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P
hnP: ~ P

False
P, Q, R: Prop
h1: P -> ~ P
h2: ~ P -> P
hP: P
hnP: ~ P

P
apply hP.
Russel is defined
End Advanced.

For even more advanced stuff we are going to use quantifiers on propositions too. Its basically the same as with natural numbers.

If you have some hypothesis of the form:

h : forall x, P x

then know that you can use specialize (h y) to obtain h : P y. See the following example.


(forall P : Prop, P) -> False

(forall P : Prop, P) -> False
h:= forall P: Prop, P

False
h: False

False
assumption.
forall_False is defined

Note that it would work with apply directly in this case.


(forall P : Prop, P) -> False

(forall P : Prop, P) -> False
h:= forall P: Prop, P

False
apply h.
forall_False' is defined

Prove the converse now.


False -> forall P : Prop, P

False -> forall P : Prop, P
h: False

forall P : Prop, P
destruct h.
False_forall is defined

Rocq is, at its basis, as system that has nothing but elimination and introduction rules for disjunctions:

\begin{equation*} \frac{P}{P \vee Q} \end{equation*}
\begin{equation*} \frac{Q}{P \vee Q} \end{equation*}
\begin{equation*} \frac{P \vee Q \qquad P \Longrightarrow R \qquad Q \Longrightarrow R}{R} \end{equation*}

In particular, these rules do not allow proving

\begin{equation*} P \vee \neg P \end{equation*}

In other words, Rocq implements intuitionistic logic. This allows

  • assuming classical laws of reasoning like the law of excluded middle and doing classical math

  • not assuming the law of excluded middle, thus being able to have interesting proofs of the form A -> LEM for a statement A.

We will prove A <-> LEM for two statements now:

Law of Excluded Middle

theLEM is defined

Double Negation Shift

theDNS is defined

Peirce's law

thePL is defined

We can now prove the other direction from before.


theLEM -> theDNS

theLEM -> theDNS

You can use unfold to replace a name by its definition.

  

(forall P : Prop, P \/ ~ P) -> forall P : Prop, ~ ~ P -> P
lem:= forall P: Prop, P \/ ~ P
P: Prop
h: ~ ~ P

P
lem:= forall P: Prop, P \/ ~ P
P: Prop
h: ~ ~ P
hP: P

P
lem:= forall P: Prop, P \/ ~ P
P: Prop
h: ~ ~ P
hnP: ~ P
P
lem:= forall P: Prop, P \/ ~ P
P: Prop
h: ~ ~ P
hP: P

P
assumption.
lem:= forall P: Prop, P \/ ~ P
P: Prop
h: ~ ~ P
hnP: ~ P

P
contradiction.
lem_dns_general is defined

theLEM -> thePL

theLEM -> thePL

(forall P : Prop, P \/ ~ P) -> forall P Q : Prop, ((P -> Q) -> P) -> P
lem:= forall P: Prop, P \/ ~ P
P, Q: Prop
h: (P -> Q) -> P

P
lem:= forall P: Prop, P \/ ~ P
P, Q: Prop
h: (P -> Q) -> P
hP: P

P
lem:= forall P: Prop, P \/ ~ P
P, Q: Prop
h: (P -> Q) -> P
hnP: ~ P
P
lem:= forall P: Prop, P \/ ~ P
P, Q: Prop
h: (P -> Q) -> P
hP: P

P
assumption.
lem:= forall P: Prop, P \/ ~ P
P, Q: Prop
h: (P -> Q) -> P
hnP: ~ P

P
lem:= forall P: Prop, P \/ ~ P
P, Q: Prop
h: (P -> Q) -> P
hnP: ~ P

P -> Q
contradiction.
lem_pl_general is defined

theDNS -> theLEM

theDNS -> theLEM

(forall P : Prop, ~ ~ P -> P) -> forall P : Prop, P \/ ~ P
dns:= forall P: Prop, ~ ~ P -> P
P: Prop

P \/ ~ P
dns:= forall P: Prop, ~ ~ P -> P
P: Prop

~ ~ (P \/ ~ P)
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)

False
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)

~ P
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hnP: ~ P
False
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)

~ P
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hP: P

False
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hP: P

P \/ ~ P
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hP: P

P
assumption.
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hnP: ~ P

False
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hnP: ~ P

P \/ ~ P
dns:= forall P: Prop, ~ ~ P -> P
P: Prop
hn: ~ (P \/ ~ P)
hnP: ~ P

~ P
assumption.
dns_lem is defined

thePL -> theLEM

thePL -> theLEM

(forall P Q : Prop, ((P -> Q) -> P) -> P) -> theLEM
pl:= forall P Q: Prop, ((P -> Q) -> P) -> P

theLEM
pl:= forall P Q: Prop, ((P -> Q) -> P) -> P

theDNS
pl:= forall P Q: Prop, ((P -> Q) -> P) -> P

forall P : Prop, ~ ~ P -> P
pl:= forall P Q: Prop, ((P -> Q) -> P) -> P
P: Prop

~ ~ P -> P
P: Prop
pl:= forall Q: Prop, ((P -> Q) -> P) -> P

~ ~ P -> P
P: Prop
pl: ((P -> False) -> P) -> P

~ ~ P -> P
P: Prop
pl: ((P -> False) -> P) -> P
hnnP: ~ ~ P

P
P: Prop
pl: ((P -> False) -> P) -> P
hnnP: ~ ~ P

(P -> False) -> P
P: Prop
pl: ((P -> False) -> P) -> P
hnnP: ~ ~ P
hnP: P -> False

P
contradiction.
pl_lem is defined

Advanced advanced exercise

  • Come up with more natural statements equivalent to LEM.

  • Come up with a statement S such that LEM -> S, you cannot prove S -> LEM, but S is also not provable without any assumptions in Rocq.

  • Found one? Great! Now find a statement S' such that S -> S', you cannot prove S' -> S, but S' is also not provable without any assumptions in Rocq.

  • Can you come up with a hierarchy S_i of such statements such that S_0 is the strongest and they get subsequently weaker?

  • Can you come up with a hierarchy S_i of such statements such that S_0 is the weakest and they get subsequently stronger?

🗣️ Talk to us if you want to know more about the solution.

An example of commuting forall and \/.


forall (P : nat -> Prop) (Q : Prop), Q \/ ~ Q -> (forall x : nat, P x \/ Q) -> (forall x : nat, P x) \/ Q

forall (P : nat -> Prop) (Q : Prop), Q \/ ~ Q -> (forall x : nat, P x \/ Q) -> (forall x : nat, P x) \/ Q
P: nat -> Prop
Q: Prop
lemQ: Q \/ ~ Q
h:= forall x: nat, P x \/ Q

(forall x : nat, P x) \/ Q
P: nat -> Prop
Q: Prop
hQ: Q
h:= forall x: nat, P x \/ Q

(forall x : nat, P x) \/ Q
P: nat -> Prop
Q: Prop
hnQ: ~ Q
h:= forall x: nat, P x \/ Q
(forall x : nat, P x) \/ Q
P: nat -> Prop
Q: Prop
hQ: Q
h:= forall x: nat, P x \/ Q

(forall x : nat, P x) \/ Q
P: nat -> Prop
Q: Prop
hQ: Q
h:= forall x: nat, P x \/ Q

Q
assumption.
P: nat -> Prop
Q: Prop
hnQ: ~ Q
h:= forall x: nat, P x \/ Q

(forall x : nat, P x) \/ Q
P: nat -> Prop
Q: Prop
hnQ: ~ Q
h:= forall x: nat, P x \/ Q

forall x : nat, P x
P: nat -> Prop
Q: Prop
hnQ: ~ Q
h:= forall x: nat, P x \/ Q
x: nat

P x
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
h: P x \/ Q

P x
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
hPx: P x

P x
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
hQ: Q
P x
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
hPx: P x

P x
assumption.
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
hQ: Q

P x
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
hQ: Q

False
P: nat -> Prop
Q: Prop
hnQ: ~ Q
x: nat
hQ: Q

Q
assumption.
forall_or is defined

More classical reasoning


theLEM -> forall P Q : Prop, (~ Q -> P) -> P \/ Q

theLEM -> forall P Q : Prop, (~ Q -> P) -> P \/ Q
lem: theLEM
P, Q: Prop
h: ~ Q -> P

P \/ Q
Q: Prop
lem: Q \/ ~ Q
P: Prop
h: ~ Q -> P

P \/ Q
Q: Prop
hQ: Q
P: Prop
h: ~ Q -> P

P \/ Q
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> P
P \/ Q
Q: Prop
hQ: Q
P: Prop
h: ~ Q -> P

P \/ Q
Q: Prop
hQ: Q
P: Prop
h: ~ Q -> P

Q
assumption.
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> P

P \/ Q
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> P

P
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> P

~ Q
assumption.
classical_or_contra_r is defined

For the following do you need LEM for both directions?


theLEM -> forall P Q : Prop, (P -> Q) <-> ~ P \/ Q

theLEM -> forall P Q : Prop, (P -> Q) <-> ~ P \/ Q
lem: theLEM
P, Q: Prop

(P -> Q) <-> ~ P \/ Q
lem: theLEM
P, Q: Prop

(P -> Q) -> ~ P \/ Q
lem: theLEM
P, Q: Prop
~ P \/ Q -> P -> Q
lem: theLEM
P, Q: Prop

(P -> Q) -> ~ P \/ Q
lem: theLEM
P, Q: Prop
h: P -> Q

~ P \/ Q
P: Prop
lem: P \/ ~ P
Q: Prop
h: P -> Q

~ P \/ Q
P: Prop
H: P
Q: Prop
h: P -> Q

~ P \/ Q
P: Prop
H: ~ P
Q: Prop
h: P -> Q
~ P \/ Q
P: Prop
H: P
Q: Prop
h: P -> Q

~ P \/ Q
P: Prop
H: P
Q: Prop
h: P -> Q

Q
P: Prop
H: P
Q: Prop
h: P -> Q

P
assumption.
P: Prop
H: ~ P
Q: Prop
h: P -> Q

~ P \/ Q
P: Prop
H: ~ P
Q: Prop
h: P -> Q

~ P
assumption.
lem: theLEM
P, Q: Prop

~ P \/ Q -> P -> Q
lem: theLEM
P, Q: Prop
h: ~ P \/ Q
hP: P

Q
lem: theLEM
P, Q: Prop
hnP: ~ P
hP: P

Q
lem: theLEM
P, Q: Prop
hQ: Q
hP: P
Q
lem: theLEM
P, Q: Prop
hnP: ~ P
hP: P

Q
lem: theLEM
P, Q: Prop
hnP: ~ P
hP: P

False
lem: theLEM
P, Q: Prop
hnP: ~ P
hP: P

P
apply hP.
lem: theLEM
P, Q: Prop
hQ: Q
hP: P

Q
assumption.
classical_impl is defined

theLEM -> forall P Q : Prop, (~ Q -> ~ P) -> P -> Q

theLEM -> forall P Q : Prop, (~ Q -> ~ P) -> P -> Q
lem: theLEM
P, Q: Prop
h: ~ Q -> ~ P
hP: P

Q
Q: Prop
lem: Q \/ ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P

Q
Q: Prop
hQ: Q
P: Prop
h: ~ Q -> ~ P
hP: P

Q
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P
Q
Q: Prop
hQ: Q
P: Prop
h: ~ Q -> ~ P
hP: P

Q
assumption.
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P

Q
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P

False
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P

~ Q
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P
P

Notice we get two goals! Because h : ~ Q -> P -> False.

    
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P

~ Q
assumption.
Q: Prop
hnQ: ~ Q
P: Prop
h: ~ Q -> ~ P
hP: P

P
assumption.
contrapositive is defined

Note: if you want to use specialize on a hyothesis twice, you can use specialize (h x) as hx to create a new hypothesis instead of replacing h.


theLEM -> forall P Q : Prop, ((P -> Q) -> Q) -> (Q -> P) -> P

theLEM -> forall P Q : Prop, ((P -> Q) -> Q) -> (Q -> P) -> P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
lemP: P \/ ~ P

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hP: P

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hP: P

P
assumption.
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
lemQ: Q \/ ~ Q

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hQ: Q

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q
P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hQ: Q

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hQ: Q

Q
assumption.
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q

P
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q

False
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q

Q
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q

P -> Q
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q
hP: P

Q
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q
hP: P

False
lem: theLEM
P, Q: Prop
h: (P -> Q) -> Q
h': Q -> P
hnP: ~ P
hnQ: ~ Q
hP: P

P
apply hP.
twice is defined

More natural numbers


forall n m k : nat, k * (n + m) = k * n + k * m

forall n m k : nat, k * (n + m) = k * n + k * m
n, m, k: nat

k * (n + m) = k * n + k * m
n, m: nat

0 * (n + m) = 0 * n + 0 * m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m
S k * (n + m) = S k * n + S k * m
n, m: nat

0 * (n + m) = 0 * n + 0 * m
n, m: nat

0 = 0
reflexivity.
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

S k * (n + m) = S k * n + S k * m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + m + k * (n + m) = n + k * n + (m + k * m)
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + m + (k * n + k * m) = n + k * n + (m + k * m)
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + m + k * n + k * m = n + k * n + (m + k * m)
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + k * n + (m + k * m) = n + m + k * n + k * m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + k * n + m + k * m = n + m + k * n + k * m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + k * n + m = n + m + k * n
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + m + k * n = n + k * n + m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

k * n + (n + m) = n + k * n + m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

k * n + n + m = n + k * n + m
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

k * n + n = n + k * n
n, m, k: nat
ihk:= forall n m: nat, k * (n + m) = k * n + k * m

n + k * n = n + k * n
reflexivity.
mult_distr is defined

If you thought this kind of proof is extremely annoying, rest assured, most would agree and in practice you don't have to do them by hand. We torture you so you understand better how things work.

In practice Rocq users will use the lia tactic to solve a lot of integer arithmetic problems.

From Stdlib Require Import Lia.


forall n m k : nat, k * (n + m) = k * n + k * m

forall n m k : nat, k * (n + m) = k * n + k * m
lia.

See? Much better. 😊

mult_distr_lia is defined