lean4-htt/library/init/data/rbmap/basic.lean
2019-08-09 09:13:49 -07:00

305 lines
11 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.

/-
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import init.data.repr init.data.option.basic
universes u v w w'
inductive Rbcolor
| red | black
inductive RBNode (α : Type u) (β : α → Type v)
| leaf {} : RBNode
| node (color : Rbcolor) (lchild : RBNode) (key : α) (val : β key) (rchild : RBNode) : RBNode
namespace RBNode
variables {α : Type u} {β : α → Type v} {σ : Type w}
open Rbcolor Nat
def depth (f : Nat → Nat → Nat) : RBNode α β → Nat
| leaf => 0
| node _ l _ _ r => succ (f (depth l) (depth r))
protected def min : RBNode α β → Option (Sigma (fun k => β k))
| leaf => none
| node _ leaf k v _ => some ⟨k, v⟩
| node _ l k v _ => min l
protected def max : RBNode α β → Option (Sigma (fun k => β k))
| leaf => none
| node _ _ k v leaf => some ⟨k, v⟩
| node _ _ k v r => max r
@[specialize] def fold (f : σ → ∀ (k : α), β k → σ) : σ → RBNode α β → σ
| b, leaf => b
| b, node _ l k v r => fold (f (fold b l) k v) r
@[specialize] def mfold {m : Type w → Type w'} [Monad m] (f : σ → ∀ (k : α), β k → m σ) : σ → RBNode α β → m σ
| b, leaf => pure b
| b, node _ l k v r => do
b ← mfold b l;
b ← f b k v;
mfold b r
@[specialize] def revFold (f : σ → ∀ (k : α), β k → σ) : σ → RBNode α β → σ
| b, leaf => b
| b, node _ l k v r => revFold (f (revFold b r) k v) l
@[specialize] def all (p : ∀ k, β k → Bool) : RBNode α β → Bool
| leaf => true
| node _ l k v r => p k v && all l && all r
@[specialize] def any (p : ∀ k, β k → Bool) : RBNode α β → Bool
| leaf => false
| node _ l k v r => p k v || any l || any r
def singleton (k : α) (v : β k) : RBNode α β :=
node red leaf k v leaf
@[inline] def balance1 : ∀ a, β a → RBNode α β → RBNode α β → RBNode α β
| kv, vv, t, node _ (node red l kx vx r₁) ky vy r₂ => node red (node black l kx vx r₁) ky vy (node black r₂ kv vv t)
| kv, vv, t, node _ l₁ ky vy (node red l₂ kx vx r) => node red (node black l₁ ky vy l₂) kx vx (node black r kv vv t)
| kv, vv, t, node _ l ky vy r => node black (node red l ky vy r) kv vv t
| _, _, _, _ => leaf -- unreachable
@[inline] def balance2 : RBNode α β → ∀ a, β a → RBNode α β → RBNode α β
| t, kv, vv, node _ (node red l kx₁ vx₁ r₁) ky vy r₂ => node red (node black t kv vv l) kx₁ vx₁ (node black r₁ ky vy r₂)
| t, kv, vv, node _ l₁ ky vy (node red l₂ kx₂ vx₂ r₂) => node red (node black t kv vv l₁) ky vy (node black l₂ kx₂ vx₂ r₂)
| t, kv, vv, node _ l ky vy r => node black t kv vv (node red l ky vy r)
| _, _, _, _ => leaf -- unreachable
def isRed : RBNode α β → Bool
| node red _ _ _ _ => true
| _ => false
def isBlack : RBNode α β → Bool
| node black _ _ _ _ => true
| _ => false
section Insert
variables (lt : αα → Bool)
@[specialize] def ins : RBNode α β → ∀ k, β k → RBNode α β
| leaf, kx, vx => node red leaf kx vx leaf
| node red a ky vy b, kx, vx =>
if lt kx ky then node red (ins a kx vx) ky vy b
else if lt ky kx then node red a ky vy (ins b kx vx)
else node red a kx vx b
| node black a ky vy b, kx, vx =>
if lt kx ky then
if isRed a then balance1 ky vy b (ins a kx vx)
else node black (ins a kx vx) ky vy b
else if lt ky kx then
if isRed b then balance2 a ky vy (ins b kx vx)
else node black a ky vy (ins b kx vx)
else
node black a kx vx b
def setBlack : RBNode α β → RBNode α β
| node _ l k v r => node black l k v r
| e => e
@[specialize] def insert (t : RBNode α β) (k : α) (v : β k) : RBNode α β :=
if isRed t then setBlack (ins lt t k v)
else ins lt t k v
end Insert
def balance₃ : RBNode α β → ∀ k, β k → RBNode α β → RBNode α β
| node red (node red a kx vx b) ky vy c, k, v, d => node red (node black a kx vx b) ky vy (node black c k v d)
| node red a kx vx (node red b ky vy c), k, v, d => node red (node black a kx vx b) ky vy (node black c k v d)
| a, k, v, node red b ky vy (node red c kz vz d) => node red (node black a k v b) ky vy (node black c kz vz d)
| a, k, v, node red (node red b ky vy c) kz vz d => node red (node black a k v b) ky vy (node black c kz vz d)
| l, k, v, r => node black l k v r
def setRed : RBNode α β → RBNode α β
| node _ a k v b => node red a k v b
| e => e
def balLeft : RBNode α β → ∀ k, β k → RBNode α β → RBNode α β
| node red a kx vx b, k, v, r => node red (node black a kx vx b) k v r
| l, k, v, node black a ky vy b => balance₃ l k v (node red a ky vy b)
| l, k, v, node red (node black a ky vy b) kz vz c => node red (node black l k v a) ky vy (balance₃ b kz vz (setRed c))
| l, k, v, r => node red l k v r -- unreachable
def balRight (l : RBNode α β) (k : α) (v : β k) (r : RBNode α β) : RBNode α β :=
match r with
| (node red b ky vy c) => node red l k v (node black b ky vy c)
| _ => match l with
| node black a kx vx b => balance₃ (node red a kx vx b) k v r
| node red a kx vx (node black b ky vy c) => node red (balance₃ (setRed a) kx vx b) ky vy (node black c k v r)
| _ => node red l k v r -- unreachable
-- TODO: use wellfounded recursion
partial def appendTrees : RBNode α β → RBNode α β → RBNode α β
| leaf, x => x
| x, leaf => x
| node red a kx vx b, node red c ky vy d =>
match appendTrees b c with
| node red b' kz vz c' => node red (node red a kx vx b') kz vz (node red c' ky vy d)
| bc => node red a kx vx (node red bc ky vy d)
| node black a kx vx b, node black c ky vy d =>
match appendTrees b c with
| node red b' kz vz c' => node red (node black a kx vx b') kz vz (node black c' ky vy d)
| bc => balLeft a kx vx (node black bc ky vy d)
| a, node red b kx vx c => node red (appendTrees a b) kx vx c
| node red a kx vx b, c => node red a kx vx (appendTrees b c)
section Erase
variables (lt : αα → Bool)
@[specialize] def del (x : α) : RBNode α β → RBNode α β
| leaf => leaf
| node _ a y v b =>
if lt x y then
if a.isBlack then balLeft (del a) y v b
else node red (del a) y v b
else if lt y x then
if b.isBlack then balRight a y v (del b)
else node red a y v (del b)
else appendTrees a b
@[specialize] def erase (x : α) (t : RBNode α β) : RBNode α β :=
let t := del lt x t;
t.setBlack
end Erase
section Membership
variable (lt : αα → Bool)
@[specialize] def findCore : RBNode α β → ∀ (k : α), Option (Sigma (fun k => β k))
| leaf, x => none
| node _ a ky vy b, x =>
if lt x ky then findCore a x
else if lt ky x then findCore b x
else some ⟨ky, vy⟩
@[specialize] def find {β : Type v} : RBNode α (fun _ => β) → α → Option β
| leaf, x => none
| node _ a ky vy b, x =>
if lt x ky then find a x
else if lt ky x then find b x
else some vy
@[specialize] def lowerBound : RBNode α β → α → Option (Sigma β) → Option (Sigma β)
| leaf, x, lb => lb
| node _ a ky vy b, x, lb =>
if lt x ky then lowerBound a x lb
else if lt ky x then lowerBound b x (some ⟨ky, vy⟩)
else some ⟨ky, vy⟩
end Membership
inductive WellFormed (lt : αα → Bool) : RBNode α β → Prop
| leafWff : WellFormed leaf
| insertWff {n n' : RBNode α β} {k : α} {v : β k} : WellFormed n → n' = insert lt n k v → WellFormed n'
| eraseWff {n n' : RBNode α β} {k : α} : WellFormed n → n' = erase lt k n → WellFormed n'
end RBNode
open RBNode
/- TODO(Leo): define dRBMap -/
def RBMap (α : Type u) (β : Type v) (lt : αα → Bool) : Type (max u v) :=
{t : RBNode α (fun _ => β) // t.WellFormed lt }
@[inline] def mkRBMap (α : Type u) (β : Type v) (lt : αα → Bool) : RBMap α β lt :=
⟨leaf, WellFormed.leafWff lt⟩
@[inline] def RBMap.empty {α : Type u} {β : Type v} {lt : αα → Bool} : RBMap α β lt :=
mkRBMap _ _ _
instance (α : Type u) (β : Type v) (lt : αα → Bool) : HasEmptyc (RBMap α β lt) :=
⟨RBMap.empty⟩
namespace RBMap
variables {α : Type u} {β : Type v} {σ : Type w} {lt : αα → Bool}
def depth (f : Nat → Nat → Nat) (t : RBMap α β lt) : Nat :=
t.val.depth f
@[inline] def fold (f : σα → β → σ) : σ → RBMap α β lt → σ
| b, ⟨t, _⟩ => t.fold f b
@[inline] def revFold (f : σα → β → σ) : σ → RBMap α β lt → σ
| b, ⟨t, _⟩ => t.revFold f b
@[inline] def mfold {m : Type w → Type w'} [Monad m] (f : σα → β → m σ) : σ → RBMap α β lt → m σ
| b, ⟨t, _⟩ => t.mfold f b
@[inline] def mfor {m : Type w → Type w'} [Monad m] (f : α → β → m σ) (t : RBMap α β lt) : m PUnit :=
t.mfold (fun _ k v => f k v *> pure ⟨⟩) ⟨⟩
@[inline] def isEmpty : RBMap α β lt → Bool
| ⟨leaf, _⟩ => true
| _ => false
@[specialize] def toList : RBMap α β lt → List (α × β)
| ⟨t, _⟩ => t.revFold (fun ps k v => (k, v)::ps) []
@[inline] protected def min : RBMap α β lt → Option (α × β)
| ⟨t, _⟩ =>
match t.min with
| some ⟨k, v⟩ => some (k, v)
| none => none
@[inline] protected def max : RBMap α β lt → Option (α × β)
| ⟨t, _⟩ =>
match t.max with
| some ⟨k, v⟩ => some (k, v)
| none => none
instance [HasRepr α] [HasRepr β] : HasRepr (RBMap α β lt) :=
⟨fun t => "rbmapOf " ++ repr t.toList⟩
@[inline] def insert : RBMap α β lt → α → β → RBMap α β lt
| ⟨t, w⟩, k, v => ⟨t.insert lt k v, WellFormed.insertWff w rfl⟩
@[inline] def erase : RBMap α β lt → α → RBMap α β lt
| ⟨t, w⟩, k => ⟨t.erase lt k, WellFormed.eraseWff w rfl⟩
@[specialize] def ofList : List (α × β) → RBMap α β lt
| [] => mkRBMap _ _ _
| ⟨k,v⟩::xs => (ofList xs).insert k v
@[inline] def findCore : RBMap α β lt → α → Option (Sigma (fun (k : α) => β))
| ⟨t, _⟩, x => t.findCore lt x
@[inline] def find : RBMap α β lt → α → Option β
| ⟨t, _⟩, x => t.find lt x
/-- (lowerBound k) retrieves the kv pair of the largest key smaller than or equal to `k`,
if it exists. -/
@[inline] def lowerBound : RBMap α β lt → α → Option (Sigma (fun (k : α) => β))
| ⟨t, _⟩, x => t.lowerBound lt x none
@[inline] def contains (t : RBMap α β lt) (a : α) : Bool :=
(t.find a).isSome
@[inline] def fromList (l : List (α × β)) (lt : αα → Bool) : RBMap α β lt :=
l.foldl (fun r p => r.insert p.1 p.2) (mkRBMap α β lt)
@[inline] def all : RBMap α β lt → (α → β → Bool) → Bool
| ⟨t, _⟩, p => t.all p
@[inline] def any : RBMap α β lt → (α → β → Bool) → Bool
| ⟨t, _⟩, p => t.any p
def size (m : RBMap α β lt) : Nat :=
m.fold (fun sz _ _ => sz+1) 0
def maxDepth (t : RBMap α β lt) : Nat :=
t.val.depth Nat.max
end RBMap
def rbmapOf {α : Type u} {β : Type v} (l : List (α × β)) (lt : αα → Bool) : RBMap α β lt :=
RBMap.fromList l lt