diff --git a/Invariant.lean b/Invariant.lean index 3e45c8b..45f096a 100644 --- a/Invariant.lean +++ b/Invariant.lean @@ -1,124 +1 @@ -import Mathlib.Data.List.Sort - -abbrev NatSet := { xs : List ℕ // List.Sorted (·<·) xs } - -namespace NatSet - -def empty : NatSet := ⟨[], List.sorted_nil⟩ -def singleton (x : ℕ) : NatSet := ⟨[x], List.sorted_singleton x⟩ - -def remove (x : ℕ) : NatSet → NatSet -| ⟨[], _⟩ => empty -| ⟨n::ns, h⟩ => - let tail := ⟨ns, List.Sorted.of_cons h⟩ - if n = x - then tail - else ⟨n::tail, h⟩ - -def list_insert (x : ℕ) : List ℕ → List ℕ -| [] => [x] -| a::as => - if x = a - then a::as - else if x < a - then x::a::as - else a::(list_insert x as) - -theorem list_insert_mem : b ∈ list_insert x xs → b = x ∨ b ∈ xs := by - induction xs with simp [list_insert] - | cons a as ih => - split - next heq => - intro hmem - simp_all only [List.mem_cons, or_true] - next hne => - split - · simp - next hnlt => - simp [*] - intro h - cases h - · right; left; assumption - cases ih ‹_› - · left; assumption - · right; right; assumption - -theorem list_insert_sorted (hs : List.Sorted (·<·) xs) - : List.Sorted (·<·) (list_insert x xs) := by - induction xs with simp [list_insert] - | cons a as ih => - split - · simp_all only [List.sorted_cons, implies_true, and_self] - · split - · exact List.Sorted.cons ‹_› hs - · have : a < x := by - rename_i hne hnlt - apply Nat.lt_of_le_of_ne - exact Nat.le_of_not_lt hnlt - exact fun a_1 => hne (Eq.symm a_1) - - simp only [List.sorted_cons] - - constructor - · intro b hmem - cases list_insert_mem hmem - <;> simp_all only [imp_self, List.sorted_cons, and_true, not_lt] - · simp_all only [imp_self, List.sorted_cons, and_true, not_lt] - -def insert (x : ℕ) (s : NatSet) : NatSet := - ⟨list_insert x s.val, list_insert_sorted s.prop⟩ - -instance : EmptyCollection NatSet where - emptyCollection := empty - -instance : Singleton ℕ NatSet where - singleton := singleton - -instance : Insert ℕ NatSet where - insert := insert - -instance : LawfulSingleton ℕ NatSet where - insert_empty_eq := by intro; rfl - -instance : Membership ℕ NatSet where - -- this is still an optimization over typical list membership, but - -- TODO: binary search - mem s n := n ∈ s.val.takeWhile (· ≤ n) - -instance (n : ℕ) (s : NatSet) : Decidable (n ∈ s) := - List.instDecidableMemOfLawfulBEq n (s.val.takeWhile (· ≤ n)) - -theorem mem_insert_cons (hmem : x ∈ insert x ⟨ns, h₁⟩) - : x ∈ insert x ⟨n::ns, h₂⟩ := by - induction ns - <;> ( - simp only [Membership.mem, insert, list_insert] - split - next heq => - simp [heq] - exact List.Mem.head _ - next hne => - split - · simp - exact List.Mem.head .. - next hnlt => - have hle : n ≤ x := by simp at hnlt; assumption - simp only [List.takeWhile, hle, decide_true, le_refl] - apply List.Mem.tail n - try exact List.Mem.head [] - try exact hmem - ) - -theorem mem_insert (x : ℕ) (s : NatSet) : x ∈ s.insert x := by - let ⟨xs, h⟩ := s - induction xs with - | nil => - simp [Membership.mem, insert, list_insert, List.Mem.head] - | cons a as ih => - rw [List.sorted_cons] at h - have hmem := ih h.right - exact mem_insert_cons hmem - --- TODO: set operation instances - -end NatSet +import Invariant.NatSet diff --git a/Invariant/NatSet.lean b/Invariant/NatSet.lean new file mode 100644 index 0000000..8cad502 --- /dev/null +++ b/Invariant/NatSet.lean @@ -0,0 +1,146 @@ +import Mathlib.Data.List.Sort + +abbrev NatSet := { xs : List ℕ // List.Sorted (·<·) xs } + +namespace NatSet + +def empty : NatSet := ⟨[], List.sorted_nil⟩ +def singleton (x : ℕ) : NatSet := ⟨[x], List.sorted_singleton x⟩ + +def remove (x : ℕ) : NatSet → NatSet +| ⟨[], _⟩ => empty +| ⟨n::ns, h⟩ => + let tail := ⟨ns, List.Sorted.of_cons h⟩ + if n = x + then tail + else ⟨n::tail, h⟩ + +def list_insert (x : ℕ) : List ℕ → List ℕ +| [] => [x] +| a::as => + if x = a + then a::as + else if x < a + then x::a::as + else a::(list_insert x as) + +theorem list_insert_mem : b ∈ list_insert x xs → b = x ∨ b ∈ xs := by + induction xs with simp [list_insert] + | cons a as ih => + split + next heq => + intro hmem + simp_all only [List.mem_cons, or_true] + next hne => + split + · simp + next hnlt => + simp [*] + intro h + cases h + · right; left; assumption + cases ih ‹_› + · left; assumption + · right; right; assumption + +theorem list_insert_sorted (hs : List.Sorted (·<·) xs) + : List.Sorted (·<·) (list_insert x xs) := by + induction xs with simp [list_insert] + | cons a as ih => + split + · simp_all only [List.sorted_cons, implies_true, and_self] + · split + · exact List.Sorted.cons ‹_› hs + · have : a < x := by + rename_i hne hnlt + apply Nat.lt_of_le_of_ne + exact Nat.le_of_not_lt hnlt + exact fun a_1 => hne (Eq.symm a_1) + + simp only [List.sorted_cons] + + constructor + · intro b hmem + cases list_insert_mem hmem + <;> simp_all only [imp_self, List.sorted_cons, and_true, not_lt] + · simp_all only [imp_self, List.sorted_cons, and_true, not_lt] + +def insert (x : ℕ) (s : NatSet) : NatSet := + ⟨list_insert x s.val, list_insert_sorted s.prop⟩ + +instance : EmptyCollection NatSet where + emptyCollection := empty + +instance : Singleton ℕ NatSet where + singleton := singleton + +instance : Insert ℕ NatSet where + insert := insert + +instance : LawfulSingleton ℕ NatSet where + insert_empty_eq := by intro; rfl + +instance : Membership ℕ NatSet where + -- this is still an optimization over typical list membership, but + -- TODO: binary search + mem s n := n ∈ s.val.takeWhile (· ≤ n) + +instance (n : ℕ) (s : NatSet) : Decidable (n ∈ s) := + List.instDecidableMemOfLawfulBEq n (s.val.takeWhile (· ≤ n)) + +theorem mem_insert_cons (hmem : x ∈ insert x ⟨ns, h₁⟩) + : x ∈ insert x ⟨n::ns, h₂⟩ := by + induction ns + <;> ( + simp only [Membership.mem, insert, list_insert] + split + next heq => + simp [heq] + exact List.Mem.head _ + next hne => + split + · simp + exact List.Mem.head .. + next hnlt => + have hle : n ≤ x := by simp at hnlt; assumption + simp only [List.takeWhile, hle, decide_true, le_refl] + apply List.Mem.tail n + try exact List.Mem.head [] + try exact hmem + ) + +theorem mem_insert (x : ℕ) (s : NatSet) : x ∈ s.insert x := by + let ⟨xs, h⟩ := s + induction xs with + | nil => + simp [Membership.mem, insert, list_insert, List.Mem.head] + | cons a as ih => + rw [List.sorted_cons] at h + have hmem := ih h.right + exact mem_insert_cons hmem + +theorem insert_orderless (a b : ℕ) (s : NatSet) + : (s.insert a).insert b = (s.insert b).insert a := by + let ⟨xs, h⟩ := s + induction xs with + | nil => + simp [insert, list_insert] + split + · simp [*] + · have hne : a ≠ b := by + intro + simp_all only [not_true_eq_false] + simp only [↓reduceIte, hne] + split + · have hnlt : ¬a < b := Nat.not_lt_of_gt ‹_› + exact Eq.symm (if_neg hnlt) + · have hlt : a < b := Nat.lt_of_le_of_ne (Nat.le_of_not_lt ‹_›) hne + exact Eq.symm (if_pos hlt) + | cons a as ih => + + sorry + +example : a ∈ ({a, b, c} : NatSet) := mem_insert a _ +-- example : a ∈ ({c, b, a} : NatSet) := mem_insert a _ + +-- TODO: set operation instances