Skip to content
The Lumenary

Formal mathematics laboratory

Lumenary.ChainingFunctions

Function machines in sequence

Formal library

  • andThendefDefinitionNo axioms
    andThenLean 4Formally verified
    /-- "Do `f`, then `g`": the function that sends `a` to `g (f a)`. It can only be formed when the
    outputs of `f` (of type `β`) are inputs that `g` accepts. -/
    def andThen {α β γ : Type} (f : α → β) (g : β → γ) : α → γ := fun a => g (f a)
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • and_then_eq_comptheoremProved here from basic factsNo axioms
    and_then_eq_compLean 4Proved here from basic factsFormally verified
    /-- Our `andThen f g` is the function Lean's library writes `g ∘ f`, read "`g` after `f`".
    They agree by definition, so `rfl` proves it. -/
    theorem and_then_eq_comp {α β γ : Type} (f : α → β) (g : β → γ) : andThen f g = g ∘ f := rfl
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • add_then_doubletheoremProved here from basic factspropext, Quot.sound
    add_then_doubleLean 4Proved here from basic factsFormally verified
    /-- "Add 3, then double" sends `x` to `2(x + 3) = 2x + 6`. -/
    theorem add_then_double (x : Int) : andThen (fun n => n + 3) (fun n => 2 * n) x = 2 * x + 6 := by
      show 2 * (x + 3) = 2 * x + 6
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • double_then_addtheoremProved here from basic factsNo axioms
    double_then_addLean 4Proved here from basic factsFormally verified
    /-- "Double, then add 3" sends `x` to `2x + 3`. -/
    theorem double_then_add (x : Int) : andThen (fun n => 2 * n) (fun n => n + 3) x = 2 * x + 3 := by
      show 2 * x + 3 = 2 * x + 3
      rfl
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • order_matterstheoremProved here from basic factspropext, Quot.sound
    order_mattersLean 4Proved here from basic factsFormally verified
    /-- **Order matters**: "add 3, then double" and "double, then add 3" are different functions.
    One input is enough to tell them apart: at `0` they give `6` and `3`. -/
    theorem order_matters :
        andThen (fun n : Int => n + 3) (fun n => 2 * n) ≠ andThen (fun n : Int => 2 * n) (fun n => n + 3) := by
      intro h
      have h0 := congrFun h 0
      rw [add_then_double, double_then_add] at h0
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • add_mul_swap_ifftheoremProved here from basic factspropext, Quot.sound
    add_mul_swap_iffLean 4Proved here from basic factsFormally verified
    /-- **When can "add `a`" and "multiply by `m`" be swapped?** "Add `a`, then multiply by `m`" gives
    `m(x + a) = mx + ma`, while "multiply by `m`, then add `a`" gives `mx + a`. They agree for every
    `x` exactly when `ma = a`, that is, when `a = 0` or `m = 1`. -/
    theorem add_mul_swap_iff (a m : Int) :
        (∀ x, andThen (fun n => n + a) (fun n => m * n) x = andThen (fun n => m * n) (fun n => n + a) x)
          ↔ a = 0 ∨ m = 1 := by
      constructor
      · intro h
        -- At `x = 0` the two chains give `m · a` and `a`.
        have h0 : m * (0 + a) = m * 0 + a := h 0
        have hma : (m - 1) * a = 0 := by
          rw [Int.sub_mul, Int.one_mul]
          rw [Int.zero_add, Int.mul_zero, Int.zero_add] at h0
          omega
        cases Int.mul_eq_zero.mp hma with
        | inl hm => exact Or.inr (by omega)
        | inr ha => exact Or.inl ha
      · intro h x
        show m * (x + a) = m * x + a
        cases h with
        | inl ha => rw [ha, Int.add_zero, Int.add_zero]
        | inr hm => rw [hm, Int.one_mul, Int.one_mul]
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • id_and_thentheoremProved here from basic factsNo axioms
    id_and_thenLean 4Proved here from basic factsFormally verified
    /-- Doing nothing first changes nothing: "identity, then `f`" is `f`. -/
    theorem id_and_then {α β : Type} (f : α → β) : andThen id f = f := rfl
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • and_then_idtheoremProved here from basic factsNo axioms
    and_then_idLean 4Proved here from basic factsFormally verified
    /-- Doing nothing afterwards changes nothing: "`f`, then identity" is `f`. -/
    theorem and_then_id {α β : Type} (f : α → β) : andThen f id = f := rfl
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • UndoesdefDefinitionNo axioms
    UndoesLean 4Formally verified
    /-- `g` **undoes** `f` if doing `f` and then `g` always gives back the input: `g (f a) = a`. -/
    def Undoes {α β : Type} (g : β → α) (f : α → β) : Prop := ∀ a, g (f a) = a
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • sub_undoes_addtheoremProved here from basic factspropext, Quot.sound
    sub_undoes_addLean 4Proved here from basic factsFormally verified
    /-- "Subtract 3" undoes "add 3" … -/
    theorem sub_undoes_add : Undoes (fun x : Int => x - 3) (fun x => x + 3) := by
      intro a
      show a + 3 - 3 = a
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • add_undoes_subtheoremProved here from basic factspropext, Quot.sound
    add_undoes_subLean 4Proved here from basic factsFormally verified
    /-- … and "add 3" undoes "subtract 3". Each undoes the other: they are **inverse** functions. -/
    theorem add_undoes_sub : Undoes (fun x : Int => x + 3) (fun x => x - 3) := by
      intro a
      show a - 3 + 3 = a
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • halve_undoes_doubletheoremProved here from basic factspropext, Classical.choice, Quot.sound
    halve_undoes_doubleLean 4Proved here from basic factsFormally verified
    /-- On the rational numbers, "halve" undoes "double" and "double" undoes "halve": `x ↦ 2x` and
    `x ↦ x / 2` are inverse functions of `ℚ`. -/
    theorem halve_undoes_double :
        Undoes (fun x : Rat => x / 2) (fun x => 2 * x) ∧ Undoes (fun x : Rat => 2 * x) (fun x => x / 2) := by
      constructor
      · intro a
        show 2 * a / 2 = a
        grind
      · intro a
        show 2 * (a / 2) = a
        grind
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • int_halve_undoes_doubletheoremApplies a library theorempropext
    int_halve_undoes_doubleLean 4Applies a library theoremFormally verified
    /-- On the integers, halving *with rounding down* (Lean's `y / 2`) still undoes doubling:
    `(2x) / 2 = x`. This applies core Lean's `Int.mul_ediv_cancel_left`. -/
    theorem int_halve_undoes_double : Undoes (fun y : Int => y / 2) (fun x => 2 * x) :=
      fun x => Int.mul_ediv_cancel_left x (by decide)
    Axioms used: propextformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • int_double_not_undoes_halvetheoremProved here from basic factsNo axioms
    int_double_not_undoes_halveLean 4Proved here from basic factsFormally verified
    /-- … but on the integers doubling does **not** undo halving: `1` is halved (rounding down) to
    `0`, and doubling `0` gives `0`, not `1`. So `x ↦ 2x` has no inverse function `ℤ → ℤ`: odd
    numbers are never outputs, so nothing can be sent back to them. -/
    theorem int_double_not_undoes_halve : ¬ Undoes (fun x : Int => 2 * x) (fun y => y / 2) := by
      intro h
      have h1 : 2 * (1 / 2 : Int) = 1 := h 1
      exact absurd h1 (by decide)
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • undo_chaintheoremProved here from basic factsNo axioms
    undo_chainLean 4Proved here from basic factsFormally verified
    /-- **Socks and shoes.** If `f'` undoes `f` and `g'` undoes `g`, then "`f`, then `g`" is undone by
    "`g'`, then `f'`": undo the **last** step **first**. The calculation:
    `f' (g' (g (f a))) = f' (f a) = a`. -/
    theorem undo_chain {α β γ : Type} {f : α → β} {g : β → γ} {f' : β → α} {g' : γ → β}
        (hf : Undoes f' f) (hg : Undoes g' g) : Undoes (andThen g' f') (andThen f g) := by
      intro a
      calc andThen g' f' (andThen f g a) = f' (g' (g (f a))) := rfl
        _ = f' (f a) := by rw [hg (f a)]
        _ = a := hf a
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • toFahrenheitdefDefinitionpropext, Classical.choice, Quot.sound
    toFahrenheitLean 4Formally verified
    /-- Celsius to Fahrenheit: multiply by `9/5`, then add `32`. -/
    def toFahrenheit : Rat → Rat := andThen (fun c => 9 / 5 * c) (fun x => x + 32)
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • toCelsiusdefDefinitionpropext, Classical.choice, Quot.sound
    toCelsiusLean 4Formally verified
    /-- Fahrenheit to Celsius: subtract `32`, then multiply by `5/9` — the undoing steps, in reverse
    order. -/
    def toCelsius : Rat → Rat := andThen (fun f => f - 32) (fun x => 5 / 9 * x)
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • thirty_degreestheoremProved here from basic factspropext, Classical.choice, Quot.sound
    thirty_degreesLean 4Proved here from basic factsFormally verified
    /-- A warm day: `30 °C` is `86 °F`, and converting back gives `30 °C` again. Lean checks the
    fraction arithmetic exactly (`decide +kernel` evaluates both sides). -/
    theorem thirty_degrees : toFahrenheit 30 = 86 ∧ toCelsius 86 = 30 := by
      decide +kernel
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • to_celsius_undoestheoremProved here from basic factspropext, Classical.choice, Quot.sound
    to_celsius_undoesLean 4Proved here from basic factsFormally verified
    /-- `toCelsius` undoes `toFahrenheit` for **every** temperature. This is the socks-and-shoes rule
    `undo_chain` applied to the two steps: `× 5/9` undoes `× 9/5`, and `− 32` undoes `+ 32`. -/
    theorem to_celsius_undoes : Undoes toCelsius toFahrenheit := by
      apply undo_chain
      · intro c
        show 5 / 9 * (9 / 5 * c) = c
        grind
      · intro x
        show x + 32 - 32 = x
        grind
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • wrong_order_failstheoremProved here from basic factspropext, Classical.choice, Quot.sound
    wrong_order_failsLean 4Proved here from basic factsFormally verified
    /-- Undoing the steps in the **wrong** order fails: "multiply by `5/9`, then subtract `32`" does
    not undo `toFahrenheit`. At `0 °C`: `toFahrenheit 0 = 32`, and `5/9 · 32 − 32 = −128/9 ≠ 0`. -/
    theorem wrong_order_fails :
        ¬ Undoes (andThen (fun x : Rat => 5 / 9 * x) (fun x => x - 32)) toFahrenheit := by
      intro h
      have h0 := h 0
      revert h0
      decide +kernel
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • injective_of_undoestheoremProved here from basic factsNo axioms
    injective_of_undoesLean 4Proved here from basic factsFormally verified
    /-- If `f` can be undone, then different inputs always give different outputs: from
    `f a = f b`, apply the undoing function `g` to both sides to get `a = g (f a) = g (f b) = b`. -/
    theorem injective_of_undoes {α β : Type} {f : α → β} {g : β → α} (h : Undoes g f) (a b : α)
        (hab : f a = f b) : a = b :=
      calc a = g (f a) := (h a).symm
        _ = g (f b) := by rw [hab]
        _ = b := h b
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • injective_of_undoes_librarytheoremApplies a library theoremNo axioms
    injective_of_undoes_libraryLean 4Applies a library theoremFormally verified
    /-- The same fact from core Lean's library, where "`g` undoes `f`" is called
    `Function.LeftInverse g f` (it is defined exactly like our `Undoes g f`) and "never sends two
    inputs to the same output" is `Function.Injective f`. This applies
    `Function.LeftInverse.injective`. -/
    theorem injective_of_undoes_library {α β : Type} {f : α → β} {g : β → α} (h : Undoes g f) :
        Function.Injective f :=
      Function.LeftInverse.injective h
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
  • square_cannot_be_undonetheoremProved here from basic factsNo axioms
    square_cannot_be_undoneLean 4Proved here from basic factsFormally verified
    /-- **Squaring on ℤ cannot be undone**: `2² = (−2)² = 4`, so an undoing function would have to
    send `4` back to both `2` and `−2`. -/
    theorem square_cannot_be_undone : ¬ ∃ g : Int → Int, Undoes g (fun x => x * x) := by
      intro ⟨g, hg⟩
      have h : (2 : Int) = -2 := injective_of_undoes hg 2 (-2) (by decide)
      exact absurd h (by decide)
    Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor

Formal exercises

Each exercise contains a sorry for you to replace. Open it in the Lean web editor, or clone the repository and run lake build.

add_undoes_subsorry × 1Try it in the Lean web editor
/-- Show that "add 3" undoes "subtract 3".
Hint: `intro a`, then `show a - 3 + 3 = a` to unfold the definitions, and finish with `omega`. -/
theorem add_undoes_sub : Undoes (fun x : Int => x + 3) (fun x => x - 3) := by
  sorry
Show the compiled solution
add_undoes_subLean 4Proved here from basic factsFormally verified
/-- … and "add 3" undoes "subtract 3". Each undoes the other: they are **inverse** functions. -/
theorem add_undoes_sub : Undoes (fun x : Int => x + 3) (fun x => x - 3) := by
  intro a
  show a - 3 + 3 = a
  omega
Axioms used: propext, Quot.soundformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor
undo_chainsorry × 1Try it in the Lean web editor
/-- Socks and shoes: "`f`, then `g`" is undone by "`g'`, then `f'`".
Hint: `intro a`. The goal unfolds to `f' (g' (g (f a))) = a`. Rewrite with `hg (f a)`, which says
`g' (g (f a)) = f a`, and finish with `hf a`. You may need `show f' (g' (g (f a))) = a` first. -/
theorem undo_chain {α β γ : Type} {f : α → β} {g : β → γ} {f' : β → α} {g' : γ → β}
    (hf : Undoes f' f) (hg : Undoes g' g) : Undoes (andThen g' f') (andThen f g) := by
  sorry
Show the compiled solution
undo_chainLean 4Proved here from basic factsFormally verified
/-- **Socks and shoes.** If `f'` undoes `f` and `g'` undoes `g`, then "`f`, then `g`" is undone by
"`g'`, then `f'`": undo the **last** step **first**. The calculation:
`f' (g' (g (f a))) = f' (f a) = a`. -/
theorem undo_chain {α β γ : Type} {f : α → β} {g : β → γ} {f' : β → α} {g' : γ → β}
    (hf : Undoes f' f) (hg : Undoes g' g) : Undoes (andThen g' f') (andThen f g) := by
  intro a
  calc andThen g' f' (andThen f g a) = f' (g' (g (f a))) := rfl
    _ = f' (f a) := by rw [hg (f a)]
    _ = a := hf a
Axioms used: No axiomsformal/Lumenary/ChainingFunctions.leanTry it in the Lean web editor