/- Copyright (c) 2019 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.list init.coe universes u namespace BinomialHeapImp structure HeapNodeAux (α : Type u) (h : Type u) := (val : α) (rank : Nat) (children : List h) inductive Heap (α : Type u) : Type u | empty {} : Heap | heap (ns : List (HeapNodeAux α Heap)) : Heap abbrev HeapNode (α) := HeapNodeAux α (Heap α) variables {α : Type u} instance : Inhabited (Heap α) := ⟨Heap.empty⟩ def hRank : List (HeapNode α) → Nat | [] := 0 | (h::_) := h.rank def isEmpty : Heap α → Bool | Heap.empty := true | _ := false def singleton (a : α) : Heap α := Heap.heap [{ val := a, rank := 1, children := [] }] @[specialize] def combine (lt : α → α → Bool) (n₁ n₂ : HeapNode α) : HeapNode α := if lt n₂.val n₁.val then { rank := n₂.rank + 1, children := n₂.children ++ [Heap.heap [n₁]], .. n₂ } else { rank := n₁.rank + 1, children := n₁.children ++ [Heap.heap [n₂]], .. n₁ } @[specialize] partial def mergeNodes (lt : α → α → Bool) : List (HeapNode α) → List (HeapNode α) → List (HeapNode α) | [] h := h | h [] := h | f@(h₁ :: t₁) s@(h₂ :: t₂) := if h₁.rank < h₂.rank then h₁ :: mergeNodes t₁ s else if h₂.rank < h₁.rank then h₂ :: mergeNodes t₂ f else let merged := combine lt h₁ h₂; let r := merged.rank; if r != hRank t₁ then if r != hRank t₂ then merged :: mergeNodes t₁ t₂ else mergeNodes (merged :: t₁) t₂ else if r != hRank t₂ then mergeNodes t₁ (merged :: t₂) else merged :: mergeNodes t₁ t₂ @[specialize] def merge (lt : α → α → Bool) : Heap α → Heap α → Heap α | Heap.empty h := h | h Heap.empty := h | (Heap.heap h₁) (Heap.heap h₂) := Heap.heap (mergeNodes lt h₁ h₂) @[specialize] def headOpt (lt : α → α → Bool) : Heap α → Option α | Heap.empty := none | (Heap.heap h) := h.foldl (fun r n => match r with | none => n.val | some v => if lt v n.val then v else n.val) none /- O(log n) -/ @[specialize] def head [Inhabited α] (lt : α → α → Bool) : Heap α → α | Heap.empty := default α | (Heap.heap []) := default α | (Heap.heap (h::hs)) := hs.foldl (fun r n => if lt r n.val then r else n.val) h.val @[specialize] def findMin (lt : α → α → Bool) : List (HeapNode α) → Nat → HeapNode α × Nat → HeapNode α × Nat | [] _ r := r | (h::hs) idx (h', idx') := if lt h.val h'.val then findMin hs (idx+1) (h, idx) else findMin hs (idx+1) (h', idx') def tail (lt : α → α → Bool) : Heap α → Heap α | Heap.empty := Heap.empty | (Heap.heap []) := Heap.empty | (Heap.heap [h]) := match h.children with | [] => Heap.empty | (h::hs) => hs.foldl (merge lt) h | (Heap.heap hhs@(h::hs)) := let (min, minIdx) := findMin lt hs 1 (h, 0); let rest := hhs.eraseIdx minIdx; min.children.foldl (merge lt) (Heap.heap rest) partial def toList (lt : α → α → Bool) : Heap α → List α | Heap.empty := [] | h := match headOpt lt h with | none => [] | some a => a :: toList (tail lt h) inductive WellFormed (lt : α → α → Bool) : Heap α → Prop | emptyWff : WellFormed Heap.empty | singletonWff (a : α) : WellFormed (singleton a) | mergeWff (h₁ h₂ : Heap α) : WellFormed h₁ → WellFormed h₂ → WellFormed (merge lt h₁ h₂) | tailWff (h : Heap α) : WellFormed h → WellFormed (tail lt h) end BinomialHeapImp open BinomialHeapImp def BinomialHeap (α : Type u) (lt : α → α → Bool) := { h : Heap α // WellFormed lt h } @[inline] def mkBinomialHeap (α : Type u) (lt : α → α → Bool) : BinomialHeap α lt := ⟨Heap.empty, WellFormed.emptyWff lt⟩ namespace BinomialHeap variables {α : Type u} {lt : α → α → Bool} @[inline] def empty : BinomialHeap α lt := mkBinomialHeap α lt @[inline] def isEmpty : BinomialHeap α lt → Bool | ⟨b, _⟩ := BinomialHeapImp.isEmpty b /- O(1) -/ @[inline] def singleton (a : α) : BinomialHeap α lt := ⟨BinomialHeapImp.singleton a, WellFormed.singletonWff lt a⟩ /- O(log n) -/ @[inline] def merge : BinomialHeap α lt → BinomialHeap α lt → BinomialHeap α lt | ⟨b₁, h₁⟩ ⟨b₂, h₂⟩ := ⟨BinomialHeapImp.merge lt b₁ b₂, WellFormed.mergeWff b₁ b₂ h₁ h₂⟩ /- O(log n) -/ @[inline] def head [Inhabited α] : BinomialHeap α lt → α | ⟨b, _⟩ := BinomialHeapImp.head lt b /- O(log n) -/ @[inline] def headOpt : BinomialHeap α lt → Option α | ⟨b, _⟩ := BinomialHeapImp.headOpt lt b /- O(log n) -/ @[inline] def tail : BinomialHeap α lt → BinomialHeap α lt | ⟨b, h⟩ := ⟨BinomialHeapImp.tail lt b, WellFormed.tailWff b h⟩ /- O(log n) -/ @[inline] def insert (a : α) (h : BinomialHeap α lt) : BinomialHeap α lt := merge (singleton a) h /- O(n log n) -/ @[inline] def toList : BinomialHeap α lt → List α | ⟨b, _⟩ := BinomialHeapImp.toList lt b end BinomialHeap