Formal Software Verification

4.3. Reasoning about Connectives and Quantifiers🔗

Lecture 1 presented the rules of the connectives as inference figures. Each figure is an ordinary Lean theorem. An introduction rule has the connective as the outermost symbol of its conclusion and says how to prove it, and an elimination rule has the connective in a hypothesis and says how a proof of it may be used. The display below lists the rules for ∧, ∨ and ↔, with metavariables in the places the rules leave open.

And.intro : ?a → ?b → ?a ∧ ?b
And.left  : ?a ∧ ?b → ?a
And.right : ?a ∧ ?b → ?b
Or.inl    : ?a → ?a ∨ ?b
Or.inr    : ?b → ?a ∨ ?b
Or.elim   : ?a ∨ ?b → (?a → ?c) → (?b → ?c) → ?c
Iff.intro : (?a → ?b) → (?b → ?a) → (?a ↔ ?b)
Iff.mp    : (?a ↔ ?b) → ?a → ?b
Iff.mpr   : (?a ↔ ?b) → ?b → ?a

The rules for the existential quantifier, truth, falsehood and the classical principles round out the display. Implication and the universal quantifier appear in none of these displays, because both are dependent function types, so their introduction is intro and their elimination is application, the juxtaposition of Lecture 2. Negation needs no rules of its own, since ¬a is defined as a → False, so intro applies to a negated conclusion, as Lecture 1 showed. True.intro is the only rule for truth, and False.elim is the only rule for falsehood. Lean's core logic is constructive, and it offers classical reasoning explicitly through Classical.em and Classical.byContradiction, which rest on added axioms. Both appeared since Lecture 1 and now apply backwards.

Exists.intro : ∀ (w : ?α), ?p w → ∃ x, ?p x
Exists.elim  : (∃ x, ?p x) → (∀ (w : ?α), ?p w → ?b) → ?b
True.intro   : True
False.elim   : False → ?c
Classical.em : ∀ (p : Prop), p ∨ ¬p
Classical.byContradiction : (¬?a → False) → ?a

A metavariable ?a stands for a term still to be determined. When apply matches the conclusion of the goal with the conclusion of a rule, unification determines some metavariables and leaves the others as new goals, and those usually disappear as the proof proceeds. The proof below applies the introduction rule of ∧ backwards and closes each subgoal with an elimination rule.

namespace Backward theorem And_swap (a b : Prop) : a b b a := a:Propb:Propa b b a a:Propb:Prophab:a bb a a:Propb:Prophab:a bba:Propb:Prophab:a ba a:Propb:Prophab:a b?left.a ba:Propb:Prophab:a bPropa:Propb:Prophab:a ba a:Propb:Prophab:a ba a:Propb:Prophab:a ba ?right.ba:Propb:Prophab:a bProp All goals completed! 🐙 end Backward

The · bullet, used since Lecture 1, focuses each subgoal, and juxtaposition instantiates a rule forwards, passing the hypothesis directly instead of waiting for it to appear as a subgoal. This is a small forward step inside a backward proof, and it avoids the metavariables that apply leaves behind.

namespace Backward theorem And_swap_braces : a b : Prop, a b b a := (a b : Prop), a b b a a:Propb:Prophab:a bb a a:Propb:Prophab:a bba:Propb:Prophab:a ba a:Propb:Prophab:a bb All goals completed! 🐙 a:Propb:Prophab:a ba All goals completed! 🐙 end Backward

Juxtaposition also instantiates a universal hypothesis, exactly as in Lecture 2.

namespace Backward opaque f : theorem f5_if (h : n : , f n = n) : f 5 = 5 := h: (n : ), f n = nf 5 = 5 All goals completed! 🐙 end Backward

The elimination rule of ∨ performs the case analysis that the tactic cases performed in Lecture 1, and modus_ponens and Not_Not_intro combine the rules seen so far.

namespace Backward theorem Or_swap (a b : Prop) : a b b a := a:Propb:Propa b b a a:Propb:Prophab:a bb a a:Propb:Prophab:a ba b aa:Propb:Prophab:a bb b a a:Propb:Prophab:a ba b a a:Propb:Prophab:a bha:ab a All goals completed! 🐙 a:Propb:Prophab:a bb b a a:Propb:Prophab:a bhb:bb a All goals completed! 🐙 theorem modus_ponens (a b : Prop) : (a b) a b := a:Propb:Prop(a b) a b a:Propb:Prophab:a bha:ab a:Propb:Prophab:a bha:aa All goals completed! 🐙 theorem Not_Not_intro (a : Prop) : a ¬¬ a := a:Propa ¬¬a a:Propha:ahna:¬aFalse a:Propha:ahna:¬aa All goals completed! 🐙 end Backward

For proving statements of propositional logic, the guide offers the following strategies.

  • Look at the conclusion. If it is an implication or a negation, intro makes progress.

  • Look at the hypotheses. A conjunction offers And.left and And.right, a disjunction offers Or.elim, and an equivalence offers Iff.mp and Iff.mpr.

  • Match the conclusion of the goal with the conclusion of an introduction rule and apply it.

  • Prefer tactics that preserve provability while they make progress, and record the choice points where a tactic commits to a side.

  • When a subgoal repeats a hypothesis, exact or assumption closes it.

  • When nothing constructive applies, consider a case analysis on Classical.em.

  • If the proof makes no progress, backtrack to the last choice point and try the other option.

4.3.1. Examples🔗

The examples below apply the rules backwards with apply, instantiate them forwards by juxtaposition, and watch the metavariables that appear along the way.

Example 1. apply And.intro splits the conjunction into two goals, and the trace shows both.

example (a b : Prop) (hab : a b) : b a := a:Propb:Prophab:a bb a a:Propb:Prophab:a bba:Propb:Prophab:a ba a b:Prophab:a bb a b:Prophab:a baa:Propb:Prophab:a bba:Propb:Prophab:a ba a:Propb:Prophab:a bb All goals completed! 🐙 a:Propb:Prophab:a ba All goals completed! 🐙
a b:Prophab:a  bb

a b:Prophab:a  ba

Example 2. Juxtaposition closes a goal in one step, passing the hypothesis to the elimination rule.

example (a b : Prop) (hab : a b) : b := a:Propb:Prophab:a bb All goals completed! 🐙

Example 3. Applying the elimination rule backwards leaves a metavariable ?a in the conclusion, and even a second goal asking for ?a itself. The final exact instantiates both at once.

example (a b : Prop) (hab : a b) : b := a:Propb:Prophab:a bb a:Propb:Prophab:a b?a ba:Propb:Prophab:a bProp a b:Prophab:a b?a b a b:Prophab:a bPropa:Propb:Prophab:a b?a ba:Propb:Prophab:a bProp All goals completed! 🐙
a b:Prophab:a  b?a  b

a b:Prophab:a  bProp

Example 4. apply Or.inl chooses the left side and leaves its proof as the goal.

example (a b : Prop) (ha : a) : a b := a:Propb:Propha:aa b a:Propb:Propha:aa All goals completed! 🐙

Example 5. apply Or.elim h produces one subgoal per disjunct, and a bullet closes each.

example (a b c : Prop) (h : a b) (hac : a c) (hbc : b c) : c := a:Propb:Propc:Proph:a bhac:a chbc:b cc a:Propb:Propc:Proph:a bhac:a chbc:b ca ca:Propb:Propc:Proph:a bhac:a chbc:b cb c a:Propb:Propc:Proph:a bhac:a chbc:b ca c a:Propb:Propc:Proph:a bhac:a chbc:b cha:ac All goals completed! 🐙 a:Propb:Propc:Proph:a bhac:a chbc:b cb c a:Propb:Propc:Proph:a bhac:a chbc:b chb:bc All goals completed! 🐙

Example 6. apply Iff.intro splits an equivalence into its two implications.

example (a : Prop) : a a a := a:Propa a a a:Propa a aa:Propa a a a:Propa a a a:Prophaa:a aa All goals completed! 🐙 a:Propa a a a:Propha:aa a All goals completed! 🐙

Example 7. Iff.mp and Iff.mpr extract the two directions of an equivalence hypothesis by juxtaposition.

example (a b : Prop) (hab : a b) (ha : a) : b := a:Propb:Prophab:a bha:ab All goals completed! 🐙 example (a b : Prop) (hab : a b) (hb : b) : a := a:Propb:Prophab:a bhb:ba All goals completed! 🐙

Example 8. apply Exists.intro supplies a witness, and the hypothesis at the witness closes what remains.

example (P : Prop) (h : P 3) : n, P n := P: Proph:P 3 n, P n P: Proph:P 3P 3 All goals completed! 🐙

Example 9. apply Exists.elim h consumes an existential hypothesis and names its witness.

example (α : Type) (P : α Prop) (Q : Prop) (hex : x, P x) (h : x, P x Q) : Q := α:TypeP:α PropQ:Prophex: x, P xh: (x : α), P x QQ α:TypeP:α PropQ:Prophex: x, P xh: (x : α), P x Q (x : α), P x Q α:TypeP:α PropQ:Prophex: x, P xh: (x : α), P x Qa:αhPa:P aQ All goals completed! 🐙

Example 10. Three one-line proofs. intro applies to a negated conclusion, True.intro is the only rule for truth, and apply False.elim closes any goal from a proof of False, since falsehood has no introduction rule.

example : ¬False := ¬False h:FalseFalse All goals completed! 🐙 example : True := True All goals completed! 🐙 example (a : Prop) (h : False) : a := a:Proph:Falsea a:Proph:FalseFalse All goals completed! 🐙