feat(library/init/data/persistentarray/basic): PersistentArray.pop

This commit is contained in:
Leonardo de Moura 2019-08-04 11:50:05 -07:00
parent 4181f35546
commit 4bd347de3a
2 changed files with 66 additions and 1 deletions

View file

@ -131,6 +131,49 @@ if r.tail.size < branching.toNat || t.size >= tooBig then
else else
mkNewTail r mkNewTail r
private def emptyArray {α : Type u} : Array (PersistentArrayNode α) :=
Array.mkEmpty PersistentArray.branching.toNat
partial def popLeaf : PersistentArrayNode α → Option (Array α) × Array (PersistentArrayNode α)
| n@(node cs) :=
if h : cs.size ≠ 0 then
let idx : Fin cs.size := ⟨cs.size - 1, Nat.predLt h⟩;
let last := cs.fget idx;
match popLeaf last with
| (none, _) => (none, emptyArray)
| (some l, newLast) =>
if newLast.size == 0 then
let cs := cs.pop;
if cs.isEmpty then (some l, emptyArray) else (some l, cs)
else
(some l, cs.fset idx (node newLast))
else
(none, emptyArray)
| (leaf vs) := (some vs, emptyArray)
def pop (t : PersistentArray α) : PersistentArray α :=
if t.tail.size > 0 then
{ tail := t.tail.pop, size := t.size - 1, .. t }
else
match popLeaf t.root with
| (none, _) => t
| (some last, newRoots) =>
let last := last.pop;
let newSize := t.size - 1;
let newTailOff := newSize - last.size;
if newRoots.size == 1 then
{ root := newRoots.get 0,
shift := t.shift - initShift,
size := newSize,
tail := last,
tailOff := newTailOff }
else
{ root := node newRoots,
size := newSize,
tail := last,
tailOff := newTailOff,
.. t }
section section
variables {m : Type u → Type v} [Monad m] variables {m : Type u → Type v} [Monad m]
variable {β: Type u} variable {β: Type u}
@ -183,7 +226,7 @@ def stats (r : PersistentArray α) : Stats :=
collectStats r.root { numNodes := 0, depth := 0, tailSize := r.tail.size } 0 collectStats r.root { numNodes := 0, depth := 0, tailSize := r.tail.size } 0
def Stats.toString (s : Stats) : String := def Stats.toString (s : Stats) : String :=
toString [s.numNodes, s.depth, s.tailSize] "{nodes := " ++ toString s.numNodes ++ ", depth := " ++ toString s.depth ++ ", tail size := " ++ toString s.tailSize ++ "}"
instance : HasToString Stats := ⟨Stats.toString⟩ instance : HasToString Stats := ⟨Stats.toString⟩

View file

@ -16,6 +16,17 @@ n.fold (λ i s => s.set i (s.get i + 1)) s
def checkId (n : Nat) (s : MyArray) : IO Unit := def checkId (n : Nat) (s : MyArray) : IO Unit :=
check n (fun a b => a == b) s check n (fun a b => a == b) s
def popTest (n : Nat) (p : Nat → Nat → Bool) (s : MyArray) : IO MyArray :=
n.mfold (λ i s => do
-- IO.println i;
check (n - i) p s;
let s := s.pop;
-- IO.println s.stats;
-- IO.println ("size: " ++ toString s.size ++ ", tailOff " ++ toString s.tailOff ++ ", shift: " ++ toString s.shift);
-- IO.println s.tail;
pure s)
s
def main (xs : List String) : IO Unit := def main (xs : List String) : IO Unit :=
do do
let n := xs.head.toNat; let n := xs.head.toNat;
@ -25,4 +36,15 @@ let t := inc1 n t;
check n (λ i v => v == i + 1) t; check n (λ i v => v == i + 1) t;
IO.println t.size; IO.println t.size;
IO.println t.stats; IO.println t.stats;
IO.println "popping...";
t ← popTest (n - 33) (λ i v => v == i + 1) t;
IO.println t.size;
check 33 (λ i v => v == i + 1) t;
let t : MyArray := (1000 : Nat).fold (fun i s => s.push i) t;
check t.size (λ i v => if i < 33 then v == i + 1 else v == i - 33) t;
IO.println t.size;
IO.println t.stats;
t ← popTest t.size (λ i v => if i < 33 then v == i + 1 else v == i - 33) t;
IO.println t.size;
IO.println t.stats;
pure () pure ()