import LoVe.LoVelib
import AutograderLib

FPV Homework 3: Forward Proofs

In this homework, you'll practice writing forward proofs.

Homework must be done in accordance with the course policies on collaboration and academic integrity.

Replace the placeholders (e.g., := sorry) with your solutions. When you are finished, submit only this file to the appropriate Gradescope assignment. Remember that the autograder does not determine your final grade.

namespace LoVe

Question 1 (5 points): Logic Puzzles

Consider the following tactical proof:

theorem about_Impl :
  ∀a b : Prop, ¬ a ∨ b → a → b :=
  by
    intros a b hor ha
    apply Or.elim hor
    { intro hna
      apply False.elim
      apply hna
      exact ha }
    { intro hb
      exact hb }

1.1 (1 point).

Prove the same theorem again, this time by providing a proof term.

Hint: There's an easy way and a hard way. Anything goes.

@[autogradedProof 1] theorem about_Impl_term :
  ∀a b : Prop, ¬ a ∨ b → a → b :=
  sorry

1.2 (2 points).

Prove the same theorem again, this time by providing a structured proof, with fix, assume, and show.

@[autogradedProof 2] theorem about_Impl_struct :
  ∀a b : Prop, ¬ a ∨ b → a → b :=
  sorry

1.3 (2 points).

The following lemma will be helpful for part 4. Prove it! For an extra challenge, prove it without using classical logic -- no Classical.em or Classical.byContradiction.

@[autogradedProof 2]
lemma not_iff_not_self (P : Prop) : ¬ (P ↔ ¬ P) :=
 sorry


example (Q : Prop) : ¬ (Q ↔ ¬ Q) :=
  not_iff_not_self Q

1.4 (1 point).

In a certain faraway village, there is only one barber for the whole town. He shaves all those who do not shave themselves. Does the barber shave himself?

Provide a structured proof showing that this premise implies False.

section
  variable (Person : Type)
  variable (shaves : Person → Person → Prop)
  variable (barber : Person)
  variable (h : ∀ x, shaves barber x ↔ ¬ shaves x x)

  -- Show the following:
  @[autogradedProof 1] theorem false_of_barber : False :=
   sorry
end

Question 2 (3 points): Connectives and Quantifiers

Supply a structured proof of the commutativity of under a quantifier, using no other theorems than the introduction and elimination rules for , , and .

@[autogradedProof 3] theorem Or_comm_under_All {α : Type} (p q : α → Prop) :
  (∀x, p x ∨ q x) ↔ (∀x, q x ∨ p x) :=
  sorry


namespace Quasicontractibility

Question 3 (6 points): Characterizing Types from Functions

In this problem, we'll see how the mere existence of a certain function on a type can give us a great deal of information about the nature of that type. (By extension, this will tell us that such functions cannot exist on many types with which we're familiar.)

In this problem, we will call a type "quasicontractible" (a coined term corrupted from homotopy type theory) if all of its elements are equal to each other.

def Quasicontractible (α : Type) := ∀ (a b : α), a = b

3.1 (1 point).

Quasicontractible types are quite rare. Below, list two examples of quasicontractible types (you can name types from lecture or give inductive definitions). Ensure your examples have different numbers of elements (i.e., values of that type). (E.g., Bool and Option Unit have the same number of elements -- two -- despite being different types.)

It turns out that any contractible type will be "essentially the same" as one of the two types you list here -- these are, in effect, the only two "different" quasicontractible types! (For those who know the jargon, by "essentially the same," we mean "isomorphic," and by "different," we mean "distinct up to isomorphism.")

Write your answer to part 1 here.

The next item will make use of the associativity and injectivity properties of certain binary operations (i.e., binary functions).

An associative operation satisfies (a ⋆ b) ⋆ c = a ⋆ (b ⋆ c) for any a, b, and c in its domain -- intuitively, "it doesn't matter where the parentheses go." (Familiar examples of associative operations include natural-number addition and multiplication.) Written in prefix notation for a function f, this is equivalently f (f a b) c = f a (f b c).

An injective operation takes at most one input (in this case, a curried "pair") to any given output: if f a b = c, then a and b are the only input pair that maps to c under f. We express this formally by stating that if any two input pairs give the same output, then the input pairs must themselves be equal. (Convince yourself that this captures the same one-to-one property stated in the first sentence!)

We define these properties below as Associative and Injective₂. (Note that versions of these definitions are also in Mathlib, but we redefine them here for convenience and to avoid some of Mathlib's quirks.)

def Associative {α : Type} (f : α → α → α) :=
  ∀ a b c : α,
  f (f a b) c = f a (f b c)

def Injective₂ {α β γ : Type} (f : α → β → γ) :=
  ∀ (a : α) (b : β) (a' : α) (b' : β),
  f a b = f a' b' → a = a' ∧ b = b'

3.2 (2 points).

It turns out that we can always define an associative, injective function on any quasicontractible type. Write a forward proof of this fact below.

@[autogradedProof 2]
theorem exists_assoc_inj_of_quasicontractible {α : Type} :
  Quasicontractible α → ∃ f : α → α → α, Associative f ∧ Injective₂ f :=
sorry

In fact, it turns out that functions that are both injective and associative only exist on quasicontractible types! That is, if there exists an associative, injective function on some type, then that type must be quasicontractible.

3.3 (2 points).

Prove this fact below.

Note: you may (and, in fact, should) write this proof in tactic mode. However, substantial forward reasoning will be required to complete the proof.

We want to remind you of a useful tactic, unfold, which will expand a definition to its body. For instance, suppose you have the following goal state:

α : Type
f : α → α → α
hassoc : Associative f
⊢ Quasicontractible α

The tactic unfold Quasicontractible will expand the goal to ⊢ ∀ (a b : α), a = b. The tactic unfold Associative at hassoc will expand the hypothesis hassoc to hassoc : ∀ a b c : α, f (f a b) c = f a (f b c).

@[autogradedProof 2]
theorem quasicontractible_of_exists_assoc_inj {α : Type} :
  (∃ f : α → α → α, Associative f ∧ Injective₂ f) → Quasicontractible α :=
sorry

3.4 (1 point). Using quasicontractible_of_exists_assoc_inj, prove that

there exists no associative, injective binary operation on the natural numbers. You may write this as a tactic proof, though, once again, some forward reasoning will be required.

Hint: try to get an obviously false statement in your context, then use the contradiction tactic to discharge your goal. Your proof should be short!

@[autogradedProof 1]
theorem no_inj_assoc_on_nats :
  ¬∃ f : Nat → Nat → Nat, Associative f ∧ Injective₂ f :=
sorry

end Quasicontractibility

end LoVe