lean4-htt/tests/elab/grind_indexmap_pre.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

160 lines
5.4 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module
-- This is a companion file for `grind_indexmap.lean`,
-- showing what an outline of this file might look like before any proofs are written.
import Std.Data.HashMap
open Std
/--
An `IndexMap α β` is a map from keys of type `α` to values of type `β`,
which also maintains the insertion order of keys.
Internally `IndexMap` is implementented redundantly as a `HashMap` from keys to indices
(and hence the key type must be `Hashable`), along with `Array`s of keys and values.
These implementation details are private, and hidden from the user.
-/
structure IndexMap (α : Type u) (β : Type v) [BEq α] [Hashable α] where
private indices : HashMap α Nat
private keys : Array α
private values : Array β
private size_keys' : keys.size = values.size
private WF : ∀ (i : Nat) (a : α), keys[i]? = some a ↔ indices[a]? = some i
namespace IndexMap
variable {α : Type u} {β : Type v} [BEq α] [Hashable α]
variable {m : IndexMap α β} {a : α} {b : β} {i : Nat}
@[inline] def size (m : IndexMap α β) : Nat :=
m.values.size
def emptyWithCapacity (capacity := 8) : IndexMap α β where
indices := HashMap.emptyWithCapacity capacity
keys := Array.emptyWithCapacity capacity
values := Array.emptyWithCapacity capacity
size_keys' := sorry
WF := sorry
instance : EmptyCollection (IndexMap α β) where
emptyCollection := emptyWithCapacity
instance : Inhabited (IndexMap α β) where
default := ∅
@[inline] def contains (m : IndexMap α β) (a : α) : Bool :=
m.indices.contains a
instance : Membership α (IndexMap α β) where
mem m a := a ∈ m.indices
instance {m : IndexMap α β} {a : α} : Decidable (a ∈ m) :=
inferInstanceAs (Decidable (a ∈ m.indices))
@[inline] def findIdx? (m : IndexMap α β) (a : α) : Option Nat := m.indices[a]?
@[inline] def findIdx (m : IndexMap α β) (a : α) (h : a ∈ m := by get_elem_tactic) : Nat := m.indices[a]
@[inline] def getIdx? (m : IndexMap α β) (i : Nat) : Option β := m.values[i]?
@[inline] def getIdx (m : IndexMap α β) (i : Nat) (h : i < m.size := by get_elem_tactic) : β :=
m.values[i]
variable [LawfulBEq α] [LawfulHashable α]
instance : GetElem? (IndexMap α β) α β (fun m a => a ∈ m) where
getElem m a h := m.values[m.indices[a]'h]'(by sorry)
getElem? m a := m.indices[a]?.bind (fun i => (m.values[i]?))
getElem! m a := m.indices[a]?.bind (fun i => (m.values[i]?)) |>.getD default
instance : LawfulGetElem (IndexMap α β) α β (fun m a => a ∈ m) where
getElem?_def := sorry
getElem!_def := sorry
@[inline] def insert (m : IndexMap α β) (a : α) (b : β) : IndexMap α β :=
match h : m.indices[a]? with
| some i =>
{ indices := m.indices
keys := m.keys.set i a sorry
values := m.values.set i b sorry
size_keys' := sorry
WF := sorry }
| none =>
{ indices := m.indices.insert a m.size
keys := m.keys.push a
values := m.values.push b
size_keys' := sorry
WF := sorry }
instance : Singleton (α × β) (IndexMap α β) :=
⟨fun ⟨a, b⟩ => (∅ : IndexMap α β).insert a b⟩
instance : Insert (α × β) (IndexMap α β) :=
⟨fun ⟨a, b⟩ s => s.insert a b⟩
instance : LawfulSingleton (α × β) (IndexMap α β) :=
⟨fun _ => rfl⟩
/--
Erase the key-value pair with the given key, moving the last pair into its place in the order.
If the key is not present, the map is unchanged.
-/
@[inline] def eraseSwap (m : IndexMap α β) (a : α) : IndexMap α β :=
match h : m.indices[a]? with
| some i =>
if w : i = m.size - 1 then
{ indices := m.indices.erase a
keys := m.keys.pop
values := m.values.pop
size_keys' := sorry
WF := sorry }
else
let lastKey := m.keys.back sorry
let lastValue := m.values.back sorry
{ indices := (m.indices.erase a).insert lastKey i
keys := m.keys.pop.set i lastKey sorry
values := m.values.pop.set i lastValue sorry
size_keys' := sorry
WF := sorry }
| none => m
-- TODO: similarly define `eraseShift`, etc.
/-! ### Verification theorems (not exhaustive) -/
theorem mem_insert (m : IndexMap α β) (a a' : α) (b : β) :
a' ∈ m.insert a b ↔ a' = a a' ∈ m := by
sorry
theorem getElem_insert (m : IndexMap α β) (a a' : α) (b : β) (h : a' ∈ m.insert a b) :
(m.insert a b)[a']'h = if h' : a' == a then b else m[a']'sorry := by
sorry
theorem findIdx_lt (m : IndexMap α β) (a : α) (h : a ∈ m) :
m.findIdx a h < m.size := by
sorry
theorem findIdx_insert_self (m : IndexMap α β) (a : α) (b : β) :
(m.insert a b).findIdx a sorry = if h : a ∈ m then m.findIdx a h else m.size := by
sorry
theorem findIdx?_eq (m : IndexMap α β) (a : α) :
m.findIdx? a = if h : a ∈ m then some (m.findIdx a h) else none := by
sorry
theorem getIdx_findIdx (m : IndexMap α β) (a : α) (h : a ∈ m) :
m.getIdx (m.findIdx a h) sorry = m[a] := sorry
theorem getIdx?_eq (m : IndexMap α β) (i : Nat) :
m.getIdx? i = if h : i < m.size then some (m.getIdx i h) else none := sorry
theorem getElem?_eraseSwap (m : IndexMap α β) (a a' : α) :
(m.eraseSwap a)[a']? = if a' == a then none else m[a']? := sorry
theorem mem_eraseSwap (m : IndexMap α β) (a a' : α) :
a' ∈ m.eraseSwap a ↔ a' ≠ a ∧ a' ∈ m := sorry
theorem getElem_eraseSwap (m : IndexMap α β) (a a' : α) (h : a' ∈ m.eraseSwap a) :
(m.eraseSwap a)[a'] = m[a']'sorry := sorry
end IndexMap