Finite Maps #

We next study finite maps, implemented as list of key-value pairs. We need finite maps to represent the context in provability relation.

abbrev FinMap V := List V

def FinMap.lookup {V}: Nat -> FinMap V -> Option V
  | i, l =>
    let l': List V := l
    l'[i]?

Auto Simplification #

It is obvious if we lookup anything in an empty map, we get none.

example {V n}:
  FinMap.lookup (V := V) n [] = none
:= by
  simp [FinMap.lookup]

To prove it, we simply unfold the definition of FinMap.lookup. The definition are not expanded by default, since sometimes we don't want to look into the implementation details of FinMap.lookup and just treat it as a black box with desired properties.

However, a lot of Lean tactics depend heavily on simplification. Sometimes, we want to unfold definitions in order to make progress in the proof. For example, in the above example, it is simpler to have a none by unfolding the definition of FinMap.lookup. In this case, we use @[simp] to hint Lean to unfold the definition of FinMap.lookup when we call simp.

@[simp]
theorem FinMap.lookup_nil {V} {n: Nat}:
  FinMap.lookup (V := V) n [] = none
:= by
  simp [lookup]

example {V n}:
  FinMap.lookup (V := V) n [] = none
:= by
  simp  -- you don't need to specify `FinMap.lookup` here, since we have marked it as a `simp` rule.

Similarly, we prove some other equalities that help us to simplify expressions involving FinMap.lookup.

@[simp]
theorem FinMap.lookup_zero {V} {M: FinMap V} {x: V}:
  FinMap.lookup 0 (x :: M) = x
:= by
  simp [lookup]

@[simp]
theorem FinMap.lookup_succ {V} {M: FinMap V} {v: V} {i: Nat}:
  FinMap.lookup (i + 1) (v :: M) = FinMap.lookup i M
:= by
  induction M with
  | nil =>
    simp [lookup]
  | cons =>
    simp [lookup]

@[simp]
theorem FinMap.lookup_concat_length {V} {M: FinMap V} {v: V}:
  FinMap.lookup M.length (M ++ [v]) = some v
:= by
  apply List.getElem?_concat_length

@[simp]
theorem FinMap.lookup_len_app {V} {M M': FinMap V} {i: Nat}:
  FinMap.lookup (i + M'.length) (M' ++ M) = FinMap.lookup i M
:= by
  induction M' with
  | nil =>
    simp [lookup]
  | cons x xs IH =>
    simp
    conv =>
      lhs
      lhs
      rewrite [<-Nat.add_assoc]
    simp
    exact IH

theorem FinMap.lookup_some_lt {V} {M: FinMap V} {i: Nat} {v}:
  M.lookup i = some v -> i < M.length
:= by
  intro H
  have H := List.getElem?_eq_some_iff.mp H
  exact H.choose

theorem FinMap.lookup_lt_some {V} {M: FinMap V} {i: Nat}:
  (h: i < M.length) -> M.lookup i = M[i]'h
:= by
  intro H
  apply List.getElem?_eq_getElem H

theorem FinMap.lookup_ge {V} {M: FinMap V} {i: Nat}:
  i  M.length -> M.lookup i = none
:= by
  intro H
  apply List.getElem?_eq_none
  simp_all

theorem FinMap.lookup_left {V} {M M': FinMap V} {i: Nat}:
  (i < M.length) ->
  FinMap.lookup i (M ++ M') = FinMap.lookup i M
:= by
  intro H
  apply List.getElem?_append_left
  exact H

theorem FinMap.lookup_right {V} {M M': FinMap V} {i: Nat}:
  (i  M.length) ->
  FinMap.lookup i (M ++ M') = FinMap.lookup (i - M.length) M'
:= by
  intro H
  apply List.getElem?_append_right
  exact H

def FinMap.update {V} (v: V): FinMap V -> FinMap V := List.cons v

@[simp]
theorem FinMap.lookup_cons_concat_length {V} {M M': FinMap V} {v: V}:
  FinMap.lookup M.length (M ++ v :: M') = some v
:= by
  have H: M.length  M.length := by omega
  simp [FinMap.lookup_right H]

def FinMap.lookupD {V} (n: Nat) (d: V) (M: FinMap V): V :=
  match M.lookup n with
  | .some v => v
  | .none => d

@[simp]
theorem FinMap.lookupD_nil {V} {n: Nat} {d: V}:
  FinMap.lookupD n d [] = d
:= by
  simp [lookupD]

@[simp]
theorem FinMap.lookupD_zero {V} {M: FinMap V} {x: V} {d}:
  FinMap.lookupD 0 d (x :: M) = x
:= by
  simp [lookupD]

@[simp]
theorem FinMap.lookupD_succ {V} {M: FinMap V} {x: V} {d} {i}:
  FinMap.lookupD (i + 1) d (x :: M) = FinMap.lookupD i d M
:= by
  simp [lookupD]

theorem FinMap.lookupD_lt {V} {M: FinMap V} {i: Nat} {d}:
  (h: i < M.length) -> M.lookupD i d = M[i]
:= by
  intro H
  unfold lookupD
  simp [FinMap.lookup_lt_some H]

theorem FinMap.lookupD_ge {V} {M: FinMap V} {i: Nat} {d}:
  (h: i  M.length) -> M.lookupD i d = d
:= by
  intro H
  unfold lookupD
  simp [FinMap.lookup_ge H]