Skip to content
The Lumenary

Formal mathematics laboratory

Lumenary.ChainingActions

One thing after another

Formal library

  • andThendefDefinitionNo axioms
    andThenLean 4Formally verified
    /-- `andThen f g` is the chain "do `f`, then do `g` to the result". Later you will meet it
    written `g ∘ f`, read "`g` after `f`". -/
    def andThen {α : Type} (f g : α → α) : α → α := fun x => g (f x)
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • addFivedefDefinitionNo axioms
    addFiveLean 4Formally verified
    /-- The action "add 5". -/
    def addFive (n : Nat) : Nat := n + 5
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • doubledefDefinitionNo axioms
    doubleLean 4Formally verified
    /-- The action "double". -/
    def double (n : Nat) : Nat := 2 * n
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • start_at_threetheoremProved here from basic factsNo axioms
    start_at_threeLean 4Proved here from basic factsFormally verified
    /-- Starting at 3: "add 5, then double" goes 3 → 8 → 16, but "double, then add 5" goes
    3 → 6 → 11. -/
    theorem start_at_three : andThen addFive double 3 = 16 ∧ andThen double addFive 3 = 11 := by
      decide
    Axioms used: No axiomsformal/Lumenary/ChainingActions.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
    /-- For **every** starting number `n`, "add 5, then double" gives exactly 5 more than "double,
    then add 5": doubling `n + 5` doubles the 5 as well, giving `2 × n + 10` instead of
    `2 × n + 5`. -/
    theorem add_then_double (n : Nat) :
        andThen addFive double n = andThen double addFive n + 5 := by
      unfold andThen addFive double
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • never_agreetheoremProved here from basic factspropext, Quot.sound
    never_agreeLean 4Proved here from basic factsFormally verified
    /-- So the two orders **never** give the same result, whatever number you start with. -/
    theorem never_agree (n : Nat) : andThen addFive double n ≠ andThen double addFive n := by
      rw [add_then_double]
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • adding_commutestheoremProved here from basic factspropext, Quot.sound
    adding_commutesLean 4Proved here from basic factsFormally verified
    /-- But some actions can be done in either order: "add `a`, then add `b`" is the same action as
    "add `b`, then add `a`", for every starting number. -/
    theorem adding_commutes (a b : Nat) :
        andThen (· + a) (· + b) = andThen (· + b) (· + a) := by
      funext n
      show n + a + b = n + b + a
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • multiplying_commutestheoremApplies a library theorempropext, Quot.sound
    multiplying_commutesLean 4Applies a library theoremFormally verified
    /-- Likewise "multiply by `a`, then by `b`" is the same as "multiply by `b`, then by `a`". This
    applies core Lean's `Nat.mul_right_comm`. -/
    theorem multiplying_commutes (a b : Nat) :
        andThen (· * a) (· * b) = andThen (· * b) (· * a) := by
      funext n
      exact Nat.mul_right_comm n a b
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • UndoesdefDefinitionNo axioms
    UndoesLean 4Formally verified
    /-- `Undoes u f` says that the action `u` undoes the action `f`: doing `f` and then `u` puts
    every thing back exactly as it was. -/
    def Undoes {α : Type} (u f : α → α) : Prop := ∀ x, u (f x) = x
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • socks_and_shoestheoremProved here from basic factsNo axioms
    socks_and_shoesLean 4Proved here from basic factsFormally verified
    /-- **The socks-and-shoes rule.** If `uf` undoes `f` and `ug` undoes `g`, then the chain
    "`f`, then `g`" is undone by "`ug`, then `uf`" — undo the **last** action first. After `f` and
    `g`, undoing `g` takes us back to just after `f`; then undoing `f` takes us back to the
    start. -/
    theorem socks_and_shoes {α : Type} {f g uf ug : α → α}
        (hf : Undoes uf f) (hg : Undoes ug g) : Undoes (andThen ug uf) (andThen f g) := by
      intro x
      unfold andThen
      rw [hg (f x), hf x]
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • halvedefDefinitionNo axioms
    halveLean 4Formally verified
    /-- The action "halve" on whole numbers (Lean rounds an odd number down). -/
    def halve (n : Nat) : Nat := n / 2
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • subFivedefDefinitionNo axioms
    subFiveLean 4Formally verified
    /-- The action "subtract 5" on whole numbers (Lean stops at 0). -/
    def subFive (n : Nat) : Nat := n - 5
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • halve_undoes_doubletheoremProved here from basic factspropext, Quot.sound
    halve_undoes_doubleLean 4Proved here from basic factsFormally verified
    /-- Halving undoes doubling. -/
    theorem halve_undoes_double : Undoes halve double := by
      intro n
      unfold halve double
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • subFive_undoes_addFivetheoremProved here from basic factspropext, Quot.sound
    subFive_undoes_addFiveLean 4Proved here from basic factsFormally verified
    /-- Subtracting 5 undoes adding 5. -/
    theorem subFive_undoes_addFive : Undoes subFive addFive := by
      intro n
      unfold subFive addFive
      omega
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • undo_addFive_then_doubletheoremProved here from basic factspropext, Quot.sound
    undo_addFive_then_doubleLean 4Proved here from basic factsFormally verified
    /-- "Add 5, then double" is undone by "halve, then subtract 5" — the undoing actions in reverse
    order. This is the socks-and-shoes rule applied to the two facts above. -/
    theorem undo_addFive_then_double : Undoes (andThen halve subFive) (andThen addFive double) :=
      socks_and_shoes subFive_undoes_addFive halve_undoes_double
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • wrong_order_failstheoremProved here from basic factsNo axioms
    wrong_order_failsLean 4Proved here from basic factsFormally verified
    /-- Undoing in the original order does **not** work: "subtract 5, then halve" does not undo
    "add 5, then double". From 3 the chain reaches 16, and 16 − 5 = 11 is odd, so halving cannot
    give back 3. -/
    theorem wrong_order_fails : ¬ Undoes (andThen subFive halve) (andThen addFive double) := by
      intro h
      have h3 := h 3
      revert h3
      decide
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • DirstructureDefinitionNo axioms
    DirLean 4Formally verified
    /-- The four directions an arrow on a card can point. -/
    inductive Dir where
      | up | right | down | left
      deriving DecidableEq, Repr
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • quarterTurndefDefinitionNo axioms
    quarterTurnLean 4Formally verified
    /-- A quarter turn clockwise (the way clock hands go). -/
    def quarterTurn : Dir → Dir
      | .up => .right
      | .right => .down
      | .down => .left
      | .left => .up
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • four_quarter_turnstheoremProved here from basic factsNo axioms
    four_quarter_turnsLean 4Proved here from basic factsFormally verified
    /-- Four quarter turns, one after another, have the same effect as doing nothing: a full
    turn. There are only four directions to check. -/
    theorem four_quarter_turns (d : Dir) :
        quarterTurn (quarterTurn (quarterTurn (quarterTurn d))) = d := by
      cases d <;> rfl
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • three_more_turns_undotheoremProved here from basic factsNo axioms
    three_more_turns_undoLean 4Proved here from basic factsFormally verified
    /-- So a quarter turn is undone by **three more** quarter turns. -/
    theorem three_more_turns_undo :
        Undoes (andThen quarterTurn (andThen quarterTurn quarterTurn)) quarterTurn := by
      intro d
      cases d <;> rfl
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • turnPointdefDefinitionNo axioms
    turnPointLean 4Formally verified
    /-- A quarter turn clockwise about the corner `(0, 0)`, acting on a point `(x, y)` of the grid
    (with `y` going up): it sends `(x, y)` to `(y, −x)`, so "up" `(0, 1)` goes to "right"
    `(1, 0)`. -/
    def turnPoint (p : Int × Int) : Int × Int := (p.2, -p.1)
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • flipPointdefDefinitionNo axioms
    flipPointLean 4Formally verified
    /-- Flipping a tile over, left to right: the mirror image in the up–down line through
    `(0, 0)`. -/
    def flipPoint (p : Int × Int) : Int × Int := (-p.1, p.2)
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • lShapedefDefinitionNo axioms
    lShapeLean 4Formally verified
    /-- An L-shaped tile, as the grid points it covers: a bar from `(0, 0)` up to `(0, 2)` and a
    foot out to `(1, 0)`. -/
    def lShape : List (Int × Int) := [(0, 2), (0, 1), (0, 0), (1, 0)]
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • turn_flip_differtheoremProved here from basic factspropext, Classical.choice, Quot.sound
    turn_flip_differLean 4Proved here from basic factsFormally verified
    /-- **Turning and flipping do not commute.** "Turn, then flip" moves the L so that it covers
    the point `(−1, 0)`; "flip, then turn" leaves that point empty. So the two chains put the
    tile in different positions. -/
    theorem turn_flip_differ :
        ((-1, 0) : Int × Int) ∈ lShape.map (andThen turnPoint flipPoint) ∧
        ((-1, 0) : Int × Int) ∉ lShape.map (andThen flipPoint turnPoint) := by
      decide
    Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • four_turns_pointstheoremProved here from basic factspropext
    four_turns_pointsLean 4Proved here from basic factsFormally verified
    /-- Four quarter turns move every point of the grid back to where it started:
    `(x, y) → (y, −x) → (−x, −y) → (−y, x) → (x, y)`. -/
    theorem four_turns_points (p : Int × Int) :
        turnPoint (turnPoint (turnPoint (turnPoint p))) = p := by
      obtain ⟨x, y⟩ := p
      simp [turnPoint]
    Axioms used: propextformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • StepstructureDefinitionNo axioms
    StepLean 4Formally verified
    /-- A step that can be undone: an action `act`, an action `back`, and a guarantee that `back`
    undoes `act`. -/
    structure Step (α : Type) where
      act : α → α
      back : α → α
      back_act : ∀ x, back (act x) = x
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • runStepsdefDefinitionNo axioms
    runStepsLean 4Formally verified
    /-- Follow a chain of steps, first to last. -/
    def runSteps {α : Type} : List (Step α) → α → α
      | [], x => x
      | s :: ss, x => runSteps ss (s.act x)
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • undoStepsdefDefinitionNo axioms
    undoStepsLean 4Formally verified
    /-- Undo a chain of steps: undo all the *later* steps first, and the first step last. -/
    def undoSteps {α : Type} : List (Step α) → α → α
      | [], x => x
      | s :: ss, x => s.back (undoSteps ss x)
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • undo_runtheoremProved here from basic factsNo axioms
    undo_runLean 4Proved here from basic factsFormally verified
    /-- **Undoing in reverse order works for chains of any length.** Proved by working through the
    chain: undoing the rest of the chain takes us back to just after the first step, and undoing
    the first step takes us back to the start. -/
    theorem undo_run {α : Type} (ss : List (Step α)) (x : α) : undoSteps ss (runSteps ss x) = x := by
      induction ss generalizing x with
      | nil => rfl
      | cons s ss ih =>
        simp only [runSteps, undoSteps]
        rw [ih, s.back_act]
    Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • addFiveStepdefDefinitionpropext, Quot.sound
    addFiveStepLean 4Formally verified
    /-- "Add 5", with its undo "subtract 5". -/
    def addFiveStep : Step Nat := ⟨addFive, subFive, subFive_undoes_addFive⟩
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • doubleStepdefDefinitionpropext, Quot.sound
    doubleStepLean 4Formally verified
    /-- "Double", with its undo "halve". -/
    def doubleStep : Step Nat := ⟨double, halve, halve_undoes_double⟩
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
  • there_and_backtheoremProved here from basic factspropext, Quot.sound
    there_and_backLean 4Proved here from basic factsFormally verified
    /-- There and back again: the chain add 5, double, add 5 takes 3 to 21, and undoing it in
    reverse order (subtract 5, halve, subtract 5) brings 21 back to 3. -/
    theorem there_and_back :
        runSteps [addFiveStep, doubleStep, addFiveStep] 3 = 21 ∧
        undoSteps [addFiveStep, doubleStep, addFiveStep] 21 = 3 := by
      decide
    Axioms used: propext, Quot.soundformal/Lumenary/ChainingActions.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.

start_at_threesorry × 1Try it in the Lean web editor
/-- Starting at 3, check where the two chains end.
Hint: Lean can follow the chains itself — try `decide`. -/
theorem start_at_three : andThen addFive double 3 = 16 ∧ andThen double addFive 3 = 11 := by
  sorry
Show the compiled solution
start_at_threeLean 4Proved here from basic factsFormally verified
/-- Starting at 3: "add 5, then double" goes 3 → 8 → 16, but "double, then add 5" goes
3 → 6 → 11. -/
theorem start_at_three : andThen addFive double 3 = 16 ∧ andThen double addFive 3 = 11 := by
  decide
Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
four_quarter_turnssorry × 1Try it in the Lean web editor
/-- Show that four quarter turns do nothing.
Hint: there are only four directions. `cases d <;> rfl` checks each one. -/
theorem four_quarter_turns (d : Dir) :
    quarterTurn (quarterTurn (quarterTurn (quarterTurn d))) = d := by
  sorry
Show the compiled solution
four_quarter_turnsLean 4Proved here from basic factsFormally verified
/-- Four quarter turns, one after another, have the same effect as doing nothing: a full
turn. There are only four directions to check. -/
theorem four_quarter_turns (d : Dir) :
    quarterTurn (quarterTurn (quarterTurn (quarterTurn d))) = d := by
  cases d <;> rfl
Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor
socks_and_shoessorry × 1Try it in the Lean web editor
/-- Prove the socks-and-shoes rule.
Hint: after `intro x` and `unfold andThen`, the goal is `uf (ug (g (f x))) = x`. Rewrite with
`hg (f x)` (taking off the shoes) and then with `hf x` (taking off the socks). -/
theorem socks_and_shoes {α : Type} {f g uf ug : α → α}
    (hf : Undoes uf f) (hg : Undoes ug g) : Undoes (andThen ug uf) (andThen f g) := by
  sorry
Show the compiled solution
socks_and_shoesLean 4Proved here from basic factsFormally verified
/-- **The socks-and-shoes rule.** If `uf` undoes `f` and `ug` undoes `g`, then the chain
"`f`, then `g`" is undone by "`ug`, then `uf`" — undo the **last** action first. After `f` and
`g`, undoing `g` takes us back to just after `f`; then undoing `f` takes us back to the
start. -/
theorem socks_and_shoes {α : Type} {f g uf ug : α → α}
    (hf : Undoes uf f) (hg : Undoes ug g) : Undoes (andThen ug uf) (andThen f g) := by
  intro x
  unfold andThen
  rw [hg (f x), hf x]
Axioms used: No axiomsformal/Lumenary/ChainingActions.leanTry it in the Lean web editor