Least-recently-used cache
LRU cache
StructureLeast-recently-used cache#✓fully proved
For a type \(K\) of keys, a type \(V\) of values and a natural number \(c\), an LRU cache of capacity \(c\) is a list of key-value pairs in \(K \times V\), ordered from most to least recently used, whose keys are pairwise distinct and whose length is at most \(c\).
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
entries : List (K × V)
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:50
Used by 24
TheoremExtensionality of LRU caches#✓fully proved
Two LRU caches with the same key type, value type and capacity are equal if their lists of entries are equal.
@[ext]
theorem ext {K : Type u} {V : Type v} {cap : Nat} {a b : LruCache K V cap}
(h : a.entries = b.entries) : a = b
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 1
DefinitionErasing a key from a list of entries#✓fully proved
Given a key \(k\) and a list of key–value pairs, erasing \(k\) deletes every pair whose key is \(k\) and keeps the other pairs in their original order. When the keys in the list are pairwise distinct, at most one pair is deleted.
def eraseKey {K : Type u} {V : Type v} [DecidableEq K] (k : K)
(entries : List (K × V)) : List (K × V) :=
entries.filter fun p => decide (p.1 ≠ k)
Used by 11
DefinitionEmpty LRU cache#✓fully proved
For every capacity \(c\), the empty LRU cache of capacity \(c\) is the cache with no entries.
public def empty {K : Type u} {V : Type v} {cap : Nat} : LruCache K V cap where
entries := []
nodup_keys := by simp
length_le := Nat.zero_le cap
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 1
DefinitionKey list of an LRU cache#✓fully proved
The key list of an LRU cache is the list of the keys of its entries in the order of the cache, so the most recently used key comes first.
public def keys {K : Type u} {V : Type v} {cap : Nat} (cache : LruCache K V cap) : List K :=
cache.entries.map Prod.fst
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 1 · Used by 7
DefinitionSize of an LRU cache#✓fully proved
The size of an LRU cache is the number of entries it stores.
public def size {K : Type u} {V : Type v} {cap : Nat} (cache : LruCache K V cap) : Nat :=
cache.entries.length
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 1 · Used by 7
DefinitionLRU cache lookup#✓fully proved
Looking up a key \(k\) in an LRU cache returns an optional value together with a cache. If the cache stores a binding \((k, v)\), the result is \(v\) together with the cache in which that binding is moved to the front and the other entries keep their order; otherwise the result is no value together with the unchanged cache.
Cslib.Algorithms.Lean.LruCache.get · 18 lines
public def get {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) : Option V × LruCache K V cap :=
match hf : cache.entries.find? (fun q => decide (q.1 = k)) with
| some p =>
(some p.2,
⟨p :: eraseKey k cache.entries,
nodup_keys_cons_eraseKey cache.nodup_keys (fst_of_find?_eq_some hf),
by
have hmem : (k, p.2) ∈ cache.entries := by
have hp : (k, p.2) = p :=
Prod.ext (fst_of_find?_eq_some hf).symm rfl
rw [hp]
exact List.mem_of_find?_eq_some hf
have hlen := length_eraseKey_add_one hmem cache.nodup_keys
have hle := cache.length_le
simp only [List.length_cons]
omega⟩)
| none => (none, cache)
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
def eraseKey {K : Type u} {V : Type v} [DecidableEq K] (k : K)
(entries : List (K × V)) : List (K × V) :=
entries.filter fun p => decide (p.1 ≠ k)
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:68
theorem nodup_keys_cons_eraseKey {K : Type u} {V : Type v} [DecidableEq K] {k : K}
{entries : List (K × V)} (nodup : (entries.map Prod.fst).Nodup) {p : K × V}
(hp : p.1 = k) :
((p :: eraseKey k entries).map Prod.fst).Nodup
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:82
theorem fst_of_find?_eq_some {K : Type u} {V : Type v} [DecidableEq K] {k : K}
{p : K × V} {entries : List (K × V)}
(hf : entries.find? (fun q => decide (q.1 = k)) = some p) : p.1 = k
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:188
Uses 2 · Used by 10
DefinitionInsertion into an LRU cache#✓fully proved
Putting the binding \((k, v)\) into an LRU cache of capacity \(c\) removes any entry with key \(k\), places \((k, v)\) at the front as the most recently used entry, and then keeps only the first \(c\) entries, so the least recently used entries beyond the capacity are evicted.
public def put {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) (v : V) : LruCache K V cap where
entries := ((k, v) :: eraseKey k cache.entries).take cap
nodup_keys := by
rw [List.map_take]
exact (nodup_keys_cons_eraseKey cache.nodup_keys rfl).sublist
(List.take_sublist cap _)
length_le := by
rw [List.length_take]
exact Nat.min_le_left cap _
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
def eraseKey {K : Type u} {V : Type v} [DecidableEq K] (k : K)
(entries : List (K × V)) : List (K × V) :=
entries.filter fun p => decide (p.1 ≠ k)
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:68
Uses 2 · Used by 8
TheoremKeys of an LRU cache are distinct#✓fully proved
The keys stored in any LRU cache are pairwise distinct.
public theorem keys_nodup {K : Type u} {V : Type v} {cap : Nat} (cache : LruCache K V cap) :
cache.keys.Nodup
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 2 · Used by 2
TheoremAn LRU cache never exceeds its capacity#✓fully proved
Every LRU cache of capacity \(c\) has size at most \(c\).
public theorem size_le_cap {K : Type u} {V : Type v} {cap : Nat} (cache : LruCache K V cap) :
cache.size ≤ cap
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 2 · Used by 2
TheoremA lookup of an absent key misses#✓fully proved
If the key \(k\) is not stored in an LRU cache, then looking up \(k\) returns no value and leaves the cache unchanged.
public theorem get_miss {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
{cache : LruCache K V cap} {k : K} (hk : k ∉ cache.keys) :
(cache.get k).1 = none ∧ (cache.get k).2 = cache
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 4 · Used by 1
TheoremA lookup of a stored key returns its value#✓fully proved
If an LRU cache stores the pair \((k, v)\), then looking up \(k\) returns \(v\).
public theorem get_hit {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
{cache : LruCache K V cap} {k : K} {v : V} (hmem : (k, v) ∈ cache.entries) :
(cache.get k).1 = some v
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 3 · Used by 2
TheoremA successful lookup moves the entry to the front#✓fully proved
If an LRU cache stores the pair \((k, v)\), then after looking up \(k\) the most recently used (first) entry of the cache is \((k, v)\).
public theorem get_promotes {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
{cache : LruCache K V cap} {k : K} {v : V} (hmem : (k, v) ∈ cache.entries) :
(cache.get k).2.entries.head? = some (k, v)
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 3
TheoremLookup after insertion into an LRU cache#✓fully proved
For every LRU cache of positive capacity, every key \(k\) and every value \(v\), looking up \(k\) in the cache obtained by putting the binding \((k, v)\) returns \(v\).
public theorem get_put {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) (v : V) (hcap : 0 < cap) :
((cache.put k v).get k).1 = some v
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 5
TheoremInsertion respects the capacity of an LRU cache#✓fully proved
For every LRU cache \(C\) of capacity \(c\), key \(k\) and value \(v\), the cache obtained by putting the binding \((k, v)\) into \(C\) has size at most \(c\).
public theorem put_size_le {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) (v : V) : (cache.put k v).size ≤ cap
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 4
TheoremInsertion keeps the keys of an LRU cache distinct#✓fully proved
For every LRU cache \(C\), key \(k\) and value \(v\), the keys of the cache obtained by putting the binding \((k, v)\) into \(C\) are pairwise distinct.
public theorem put_keys_nodup {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) (v : V) : (cache.put k v).keys.Nodup
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 4
TheoremLookup respects the capacity#✓fully proved
For every LRU cache of capacity \(c\) and every key \(k\), the cache after looking up \(k\) holds at most \(c\) entries.
public theorem get_size_le {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) : (cache.get k).2.size ≤ cap
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 4
TheoremLookups keep keys distinct#✓fully proved
For every LRU cache and every key \(k\), the keys of the cache obtained by looking up \(k\) are pairwise distinct.
public theorem get_keys_nodup {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) : (cache.get k).2.keys.Nodup
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 4
TheoremEntries after insertion#✓fully proved
For every LRU cache, key \(k\) and value \(v\), every key-value pair \(p\) stored in the cache after putting the binding \((k, v)\) either equals \((k, v)\), or was stored before and has a key different from \(k\).
public theorem mem_put_entries {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
{cache : LruCache K V cap} {k : K} {v : V} {p : K × V}
(hp : p ∈ (cache.put k v).entries) :
p = (k, v) ∨ (p ∈ cache.entries ∧ p.1 ≠ k)
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 3
TheoremLookup preserves the stored bindings#✓fully proved
For every LRU cache and every key \(k\), a key-value pair is stored in the cache after looking up \(k\) if and only if it was stored in the cache before the lookup.
public theorem mem_get_entries_iff {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) (p : K × V) :
p ∈ (cache.get k).2.entries ↔ p ∈ cache.entries
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 3
TheoremA lookup permutes the entries#✓fully proved
For every LRU cache and every key \(k\), the list of entries of the cache after looking up \(k\) is a permutation of the list of entries before.
public theorem get_perm {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) :
(cache.get k).2.entries.Perm cache.entries
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 3 · Used by 1
TheoremLookup preserves the size#✓fully proved
For every LRU cache and every key \(k\), the cache after looking up \(k\) holds exactly as many entries as before.
public theorem get_size {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) :
(cache.get k).2.size = cache.size
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 4
TheoremInsertion without eviction#✓fully proved
Let an LRU cache of capacity \(c\) hold fewer than \(c\) entries or already store a binding for the key \(k\), and let \(v\) be a value. Then a key-value pair \(p\) is stored in the cache after putting the binding \((k, v)\) if and only if \(p = (k, v)\), or \(p\) was stored before and the key of \(p\) differs from \(k\).
public theorem mem_put_entries_iff_of_not_full {K : Type u} {V : Type v} {cap : Nat}
[DecidableEq K] {cache : LruCache K V cap} {k : K} {v : V} {p : K × V}
(hroom : cache.size < cap ∨ k ∈ cache.keys) :
p ∈ (cache.put k v).entries ↔ p = (k, v) ∨ (p ∈ cache.entries ∧ p.1 ≠ k)
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 5 · Used by 1
TheoremWith positive capacity, the inserted binding becomes the most recent entry#✓fully proved
Let \(C\) be an LRU cache of positive capacity, \(k\) a key and \(v\) a value. After the binding \((k, v)\) is put into \(C\), the first entry of the resulting cache, its most recently used entry, is \((k, v)\).
public theorem put_head? {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
(cache : LruCache K V cap) (k : K) (v : V) (hcap : 0 < cap) :
(cache.put k v).entries.head? = some (k, v)
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 2
TheoremA put without eviction preserves lookups of other keys#✓fully proved
Let \(C\) be an LRU cache of capacity \(c\) that holds fewer than \(c\) entries or already stores the key \(k\). Then for every key \(k' \ne k\) and every value \(v\), looking up \(k'\) in the cache obtained by putting the binding \((k, v)\) into \(C\) returns the same optional value as looking up \(k'\) in \(C\).
public theorem get_put_of_ne {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
{cache : LruCache K V cap} {k k' : K} {v : V} (hne : k' ≠ k)
(hroom : cache.size < cap ∨ k ∈ cache.keys) :
((cache.put k v).get k').1 = (cache.get k').1
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
TheoremThe evicted key is the least recently used one#✓fully proved
Let \(C\) be an LRU cache of capacity \(c\), let \(k'\) be a key not stored in \(C\), and let \(k\) be a key stored in \(C\). If \(k\) is no longer stored after putting \(k'\) with any value \(v\) into \(C\), then \(C\) held exactly \(c\) entries and \(k\) is the last key of \(C\), that is, the least recently used one.
public theorem evicted_is_least_recent {K : Type u} {V : Type v} {cap : Nat} [DecidableEq K]
{cache : LruCache K V cap} {k k' : K} {v : V}
(hnew : k' ∉ cache.keys) (hk : k ∈ cache.keys)
(hevicted : k ∉ (cache.put k' v).keys) :
cache.keys.getLast? = some k ∧ cache.size = cap
public structure LruCache (K : Type u) (V : Type v) (cap : Nat) where
/-- The stored key-value pairs, most recently used first. -/
entries : List (K × V)
/-- Keys are pairwise distinct. -/
nodup_keys : (entries.map Prod.fst).Nodup
/-- The cache holds at most `cap` entries. -/
length_le : entries.length ≤ cap
CSLibExt/Algorithms/Lean/DataStructures/LruCache.lean:48
Uses 5
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.