Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: OrderedAssocList #556

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions Std.lean
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import Std.Data.MLList
import Std.Data.Nat
import Std.Data.Option
import Std.Data.Ord
import Std.Data.OrderedAssocList
import Std.Data.PairingHeap
import Std.Data.Prod
import Std.Data.RBMap
Expand Down
24 changes: 24 additions & 0 deletions Std/Classes/Order.lean
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,20 @@ import Std.Tactic.Simpa

namespace Std

/-- Construct a `BEq` instance from a comparator function. -/
def beqOfCmp (cmp : α → α → Ordering) : BEq α where
beq x y := cmp x y = .eq

/-- `TotalBLE le` asserts that `le` has a total order, that is, `le a b ∨ le b a`. -/
class TotalBLE (le : α → α → Bool) : Prop where
/-- `le` is total: either `le a b` or `le b a`. -/
total : le a b ∨ le b a

/-- `AntisymmCmp cmp` asserts that `cmp x y = .eq` only if `x = y`. -/
class AntisymmCmp (cmp : α → α → Ordering) : Prop where
/-- If two terms compare as `.eq`, then they are equal. -/
eq_of_cmp_eq : cmp x y = .eq → x = y

/-- `OrientedCmp cmp` asserts that `cmp` is determined by the relation `cmp x y = .lt`. -/
class OrientedCmp (cmp : α → α → Ordering) : Prop where
/-- The comparator operation is symmetric, in the sense that if `cmp x y` equals `.lt` then
Expand All @@ -42,6 +51,21 @@ theorem cmp_refl [OrientedCmp cmp] : cmp x x = .eq :=

end OrientedCmp

/--
The `BEq` instance from a comparator `cmp : α → α → Ordering` with `[AntisymmCmp cmp]` and
`[OrientedCmp cmp]` is a `LawfulBEq`.
-/
def lawfulBEqOfCmp (cmp : α → α → Ordering) [AntisymmCmp cmp] [OrientedCmp cmp] :
let i := beqOfCmp cmp
LawfulBEq α :=
let _ := beqOfCmp cmp
{ eq_of_beq := fun h => by
apply AntisymmCmp.eq_of_cmp_eq (cmp := cmp)
simpa [beqOfCmp] using h
rfl := by
intro a
simpa [beqOfCmp] using OrientedCmp.cmp_refl }

/-- `TransCmp cmp` asserts that `cmp` induces a transitive relation. -/
class TransCmp (cmp : α → α → Ordering) extends OrientedCmp cmp : Prop where
/-- The comparator operation is transitive. -/
Expand Down
41 changes: 39 additions & 2 deletions Std/Data/AssocList.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Mario Carneiro
-/
import Std.Data.List.Basic
import Std.Data.List.Lemmas
kim-em marked this conversation as resolved.
Show resolved Hide resolved

namespace Std

Expand Down Expand Up @@ -113,6 +113,43 @@ def toListTR (as : AssocList α β) : List (α × β) :=
@[simp] theorem length_mapVal : (mapVal f l).length = l.length := by
induction l <;> simp_all


/-- `O(n)`. Map a function `f` over the values of the list, dropping `none`. -/
def filterMapVal (f : α → β → Option δ) : AssocList α β → AssocList α δ
| nil => nil
| cons k v t => match f k v with
| none => filterMapVal f t
| some d => cons k d (filterMapVal f t)

@[simp] theorem filterMapVal_nil : filterMapVal f nil = nil := rfl

theorem filterMapVal_cons (f : α → β → Option γ) (k) (v) (t) :
filterMapVal f (.cons k v t) =
match f k v with
| none => filterMapVal f t
| some d => .cons k d (filterMapVal f t) := rfl

@[simp] theorem toList_filterMapVal (f : α → β → Option δ) (l : AssocList α β) :
(filterMapVal f l).toList =
l.toList.filterMap (fun (a, b) => (f a b).map fun v => (a, v)) := by
induction l with
| nil => simp
| cons k v t ih =>
revert ih
simp only [filterMapVal, toList, List.filterMap_cons]
match f k v with
| none
| some d => simp

theorem length_filterMapVal : (filterMapVal f l).length ≤ l.length := by
induction l with
| nil => simp
| cons k v t ih =>
simp_all only [filterMapVal, length_cons]
match f k v with
| none => exact Nat.le_trans ih (Nat.le_succ _)
| some _ => exact Nat.succ_le_succ ih

/-- `O(n)`. Returns the first entry in the list whose entry satisfies `p`. -/
@[specialize] def findEntryP? (p : α → β → Bool) : AssocList α β → Option (α × β)
| nil => none
Expand Down Expand Up @@ -140,7 +177,7 @@ theorem find?_eq_findEntry? [BEq α] (a : α) (l : AssocList α β) :
find? a l = (l.findEntry? a).map (·.2) := by
induction l <;> simp [find?, List.find?_cons]; split <;> simp [*]

@[simp] theorem find?_eq [BEq α] (a : α) (l : AssocList α β) :
theorem find?_eq [BEq α] (a : α) (l : AssocList α β) :
find? a l = (l.toList.find? (·.1 == a)).map (·.2) := by simp [find?_eq_findEntry?]

/-- `O(n)`. Returns true if any entry in the list satisfies `p`. -/
Expand Down
Loading
Loading