import Foam.Engine import Foam.Marks namespace Foam def pull : Compass → Compass → Compass | .n, .n => .e | .n, .e => .e | .n, .s => .e | .n, .w => .n | .e, .n => .e | .e, .e => .s | .e, .s => .s | .e, .w => .s | .s, .n => .w | .s, .e => .s | .s, .s => .w | .s, .w => .w | .w, .n => .n | .w, .e => .n | .w, .s => .w | .w, .w => .n def zipPull : List Compass → List Compass → List Compass | c :: cs, d :: ds => pull c d :: zipPull cs ds | [], _ => [] | _ :: _, [] => [] def rotateLeft : List Compass → List Compass | [] => [] | c :: cs => cs ++ [c] def round (v : List Compass) : List Compass := zipPull v (rotateLeft v) theorem pull_turns (c d : Compass) : pull c.step d.step = (pull c d).step := by cases c <;> cases d <;> rfl theorem the_quarter_turn_moves : ∀ c : Compass, c.step ≠ c | .n, h => nomatch h | .e, h => nomatch h | .s, h => nomatch h | .w, h => nomatch h theorem the_half_turn_parts : ∀ c : Compass, c ≠ c.step.step | .n, h => nomatch h | .e, h => nomatch h | .s, h => nomatch h | .w, h => nomatch h theorem map_snoc (f : Compass → Compass) : ∀ (cs : List Compass) (c : Compass), (cs ++ [c]).map f = cs.map f ++ [f c] | [], _ => rfl | d :: cs, c => congrArg (f d :: ·) (map_snoc f cs c) theorem zipPull_turns : ∀ v w : List Compass, zipPull (v.map Compass.step) (w.map Compass.step) = (zipPull v w).map Compass.step | [], _ => rfl | _ :: _, [] => rfl | c :: cs, d :: ds => by show pull c.step d.step :: zipPull (cs.map Compass.step) (ds.map Compass.step) = (pull c d).step :: (zipPull cs ds).map Compass.step rw [pull_turns, zipPull_turns cs ds] theorem rotate_turns : ∀ v : List Compass, rotateLeft (v.map Compass.step) = (rotateLeft v).map Compass.step | [] => rfl | c :: cs => (map_snoc Compass.step cs c).symm theorem the_round_turns_as_one (v : List Compass) : round (v.map Compass.step) = (round v).map Compass.step := by show zipPull (v.map Compass.step) (rotateLeft (v.map Compass.step)) = (zipPull v (rotateLeft v)).map Compass.step rw [rotate_turns, zipPull_turns] theorem len_cons_eq_len_snoc {A : Type} (t : List A) (c d : A) : (d :: t).length = (t ++ [c]).length := by show t.length + 1 = (t ++ [c]).length rw [len_append] rfl theorem zipPull_append : ∀ (a b c d : List Compass), a.length = b.length → zipPull (a ++ c) (b ++ d) = zipPull a b ++ zipPull c d | [], [], _, _, _ => rfl | [], _ :: _, _, _, h => nomatch h | _ :: _, [], _, _, h => nomatch h | x :: a, y :: b, c, d, h => by show pull x y :: zipPull (a ++ c) (b ++ d) = pull x y :: (zipPull a b ++ zipPull c d) rw [zipPull_append a b c d (Nat.succ.inj h)] theorem the_round_hears_no_first_voice : ∀ v : List Compass, round (rotateLeft v) = rotateLeft (round v) | [] => rfl | [_] => rfl | c :: d :: t => by show zipPull ((d :: t) ++ [c]) ((t ++ [c]) ++ [d]) = rotateLeft (pull c d :: zipPull (d :: t) (t ++ [c])) rw [zipPull_append (d :: t) (t ++ [c]) [c] [d] (len_cons_eq_len_snoc t c d)] rfl theorem mem_rotateLeft : ∀ (v : List Compass) (x : Compass), x ∈ rotateLeft v → x ∈ v | [], _, h => nomatch h | c :: cs, _, h => match mem_append_split cs [c] h with | .inl hcs => .tail c hcs | .inr hc => match hc with | .head _ => .head cs | .tail _ h' => nomatch h' theorem mem_zipPull : ∀ (v w : List Compass) (x : Compass), x ∈ zipPull v w → ∃ p q, p ∈ v ∧ q ∈ w ∧ x = pull p q | [], _, _, h => nomatch h | _ :: _, [], _, h => nomatch h | c :: cs, d :: ds, x, h => by have h' : x ∈ pull c d :: zipPull cs ds := h cases h' with | head => exact ⟨c, d, .head cs, .head ds, rfl⟩ | tail _ h'' => obtain ⟨p, q, hp, hq, he⟩ := mem_zipPull cs ds x h'' exact ⟨p, q, .tail c hp, .tail d hq, he⟩ theorem the_round_keeps_unison : ∀ v : List Compass, (∀ x, x ∈ v → ∀ y, y ∈ v → x = y) → ∀ x, x ∈ round v → ∀ y, y ∈ round v → x = y | [], _, _, hx, _, _ => nomatch hx | c :: cs, h, x, hx, y, hy => match mem_zipPull (c :: cs) (rotateLeft (c :: cs)) x hx, mem_zipPull (c :: cs) (rotateLeft (c :: cs)) y hy with | ⟨p, q, hp, hq, hex⟩, ⟨p', q', hp', hq', hey⟩ => (hex.trans (congr (congrArg pull (h p hp c (.head cs))) (h q (mem_rotateLeft (c :: cs) q hq) c (.head cs)))).trans ((hey.trans (congr (congrArg pull (h p' hp' c (.head cs))) (h q' (mem_rotateLeft (c :: cs) q' hq') c (.head cs)))).symm) theorem the_split_round_carries (a : Compass) : round [a, a, a.step.step, a.step.step] = [a.step, a.step, a.step.step.step, a.step.step.step] := by cases a <;> rfl /-- info: 'Foam.pull_turns' does not depend on any axioms -/ #guard_msgs in #print axioms pull_turns /-- info: 'Foam.the_quarter_turn_moves' does not depend on any axioms -/ #guard_msgs in #print axioms the_quarter_turn_moves /-- info: 'Foam.the_half_turn_parts' does not depend on any axioms -/ #guard_msgs in #print axioms the_half_turn_parts /-- info: 'Foam.map_snoc' does not depend on any axioms -/ #guard_msgs in #print axioms map_snoc /-- info: 'Foam.zipPull_turns' does not depend on any axioms -/ #guard_msgs in #print axioms zipPull_turns /-- info: 'Foam.rotate_turns' does not depend on any axioms -/ #guard_msgs in #print axioms rotate_turns /-- info: 'Foam.the_round_turns_as_one' does not depend on any axioms -/ #guard_msgs in #print axioms the_round_turns_as_one /-- info: 'Foam.len_cons_eq_len_snoc' does not depend on any axioms -/ #guard_msgs in #print axioms len_cons_eq_len_snoc /-- info: 'Foam.zipPull_append' does not depend on any axioms -/ #guard_msgs in #print axioms zipPull_append /-- info: 'Foam.the_round_hears_no_first_voice' does not depend on any axioms -/ #guard_msgs in #print axioms the_round_hears_no_first_voice /-- info: 'Foam.mem_rotateLeft' does not depend on any axioms -/ #guard_msgs in #print axioms mem_rotateLeft /-- info: 'Foam.mem_zipPull' does not depend on any axioms -/ #guard_msgs in #print axioms mem_zipPull /-- info: 'Foam.the_round_keeps_unison' does not depend on any axioms -/ #guard_msgs in #print axioms the_round_keeps_unison /-- info: 'Foam.the_split_round_carries' does not depend on any axioms -/ #guard_msgs in #print axioms the_split_round_carries end Foam