proofs/containers/dynamic_array/layout.bend source
proofs/containers/dynamic_array/layout.bend on the hub · documented module
import Baseimport ../../lib/logic.bend as Limport ../../lib/nat.bend as Nimport ../../lib/list.bend as LLimport ../../../spec/lib/common.bend as SC# Slot layout of a dynamic array: the first n slots are Some, the rest None.def somes(-T: Data, xs: List<&2, Maybe<&2, T>>) -> List<&2, T>: match xs: case Nil{}: Nil{} case Con{None{}, r}: somes(T, r) case Con{Some{x}, r}: Con{x, somes(T, r)}def nones(-T: Data, xs: List<&2, Maybe<&2, T>>) -> Bool: match xs: case Nil{}: True{} case Con{None{}, r}: nones(T, r) case Con{Some{x}, r}: False{}def lay(-T: Data, xs: List<&2, Maybe<&2, T>>, n: Nat) -> Bool: match xs n: case Nil{} 0n: True{} case Nil{} 1n+m: False{} case Con{None{}, r} 0n: nones(T, r) case Con{None{}, r} 1n+m: False{} case Con{Some{x}, r} 0n: False{} case Con{Some{x}, r} 1n+m: lay(T, r, m)def nones_somes(-T: Data, +xs: List<&2, Maybe<&2, T>>, +h: {nones(T, xs) == True{} : Bool}) -> {somes(T, xs) == Nil{} : List<&2, T>}: match xs: case Nil{}: {==} case Con{None{}, +r}: nones_somes(T, r, h) case Con{Some{x}, r}: Empty.absurd({Con{x, somes(T, r)} == Nil{} : List<&2, T>}, L.false_true(h))def lay_len(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +h: {lay(T, xs, n) == True{} : Bool}) -> {SC.length(T, somes(T, xs)) == n : Nat}: match xs n: case Nil{} 0n: {==} case Nil{} 1n+m: Empty.absurd({0n == 1n+m : Nat}, L.false_true(h)) case Con{None{}, +r} 0n: %Equal.sym(List<&2, T>, somes(T, r), Nil{}, nones_somes(T, r, h)) : {SC.length(T, _) == 0n : Nat} {==} case Con{None{}, r} 1n+m: Empty.absurd({SC.length(T, somes(T, r)) == 1n+m : Nat}, L.false_true(h)) case Con{Some{x}, r} 0n: Empty.absurd({1n+SC.length(T, somes(T, r)) == 0n : Nat}, L.false_true(h)) case Con{Some{x}, +r} 1n+m: N.succ_cong(SC.length(T, somes(T, r)), m, lay_len(T, r, m, h))def lay_le(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +h: {lay(T, xs, n) == True{} : Bool}) -> {Nat.is_le(n, SC.length(Maybe<&2, T>, xs)) == True{} : Bool}: match xs n: case Nil{} 0n: {==} case Nil{} 1n+m: Empty.absurd({Nat.is_le(1n+m, 0n) == True{} : Bool}, L.false_true(h)) case Con{None{}, r} 0n: {==} case Con{None{}, r} 1n+m: Empty.absurd({Nat.is_le(1n+m, 1n+SC.length(Maybe<&2, T>, r)) == True{} : Bool}, L.false_true(h)) case Con{Some{x}, r} 0n: {==} case Con{Some{x}, +r} 1n+m: lay_le(T, r, m, h)def lay_nil_pos(-T: Data, +n: Nat, +i: Nat, +hi: {Nat.is_lt(i, n) == True{} : Bool}) -> {lay(T, Nil{}, n) == False{} : Bool}: match n: case 0n: Empty.absurd({True{} == False{} : Bool}, N.lt_zero_absurd(i, hi)) case 1n+m: {==}# Slot i (< n) holds exactly the i-th item.def lay_nth(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +i: Nat, +h: {lay(T, xs, n) == True{} : Bool}, +hi: {Nat.is_lt(i, n) == True{} : Bool}) -> {SC.nth(Maybe<&2, T>, xs, i) == Some{SC.nth(T, somes(T, xs), i)} : Maybe<&2, Maybe<&2, T>>}: match xs n i: case Nil{} _ _: Empty.absurd({None{} == Some{None{}} : Maybe<&2, Maybe<&2, T>>}, L.true_not_false(lay(T, Nil{}, n), h, lay_nil_pos(T, n, i, hi))) case Con{None{}, r} 0n _: Empty.absurd({SC.nth(Maybe<&2, T>, Con{None{}, r}, i) == Some{SC.nth(T, somes(T, r), i)} : Maybe<&2, Maybe<&2, T>>}, N.lt_zero_absurd(i, hi)) case Con{None{}, r} 1n+m _: Empty.absurd({SC.nth(Maybe<&2, T>, Con{None{}, r}, i) == Some{SC.nth(T, somes(T, r), i)} : Maybe<&2, Maybe<&2, T>>}, L.false_true(h)) case Con{Some{x}, r} 0n _: Empty.absurd({SC.nth(Maybe<&2, T>, Con{Some{x}, r}, i) == Some{SC.nth(T, Con{x, somes(T, r)}, i)} : Maybe<&2, Maybe<&2, T>>}, L.false_true(h)) case Con{Some{x}, r} 1n+m 0n: {==} case Con{Some{x}, +r} 1n+m 1n+j: lay_nth(T, r, m, j, h, hi)def nones_nth(-T: Data, +xs: List<&2, Maybe<&2, T>>, +i: Nat, +h: {nones(T, xs) == True{} : Bool}, +hi: {Nat.is_lt(i, SC.length(Maybe<&2, T>, xs)) == True{} : Bool}) -> {SC.nth(Maybe<&2, T>, xs, i) == Some{None{}} : Maybe<&2, Maybe<&2, T>>}: match xs i: case Nil{} _: Empty.absurd({None{} == Some{None{}} : Maybe<&2, Maybe<&2, T>>}, N.lt_zero_absurd(i, hi)) case Con{None{}, r} 0n: {==} case Con{None{}, +r} 1n+j: nones_nth(T, r, j, h, hi) case Con{Some{x}, r} _: Empty.absurd({SC.nth(Maybe<&2, T>, Con{Some{x}, r}, i) == Some{None{}} : Maybe<&2, Maybe<&2, T>>}, L.false_true(h))def nones_rep(-T: Data, +k: Nat) -> {nones(T, SC.replicate(Maybe<&2, T>, k, None{})) == True{} : Bool}: match k: case 0n: {==} case 1n+j: nones_rep(T, j)def somes_rep(-T: Data, +k: Nat) -> {somes(T, SC.replicate(Maybe<&2, T>, k, None{})) == Nil{} : List<&2, T>}: match k: case 0n: {==} case 1n+j: somes_rep(T, j)def lay_rep(-T: Data, +k: Nat) -> {lay(T, SC.replicate(Maybe<&2, T>, k, None{}), 0n) == True{} : Bool}: match k: case 0n: {==} case 1n+j: nones_rep(T, j)def nones_lay0(-T: Data, +xs: List<&2, Maybe<&2, T>>, +h: {nones(T, xs) == True{} : Bool}) -> {lay(T, xs, 0n) == True{} : Bool}: match xs: case Nil{}: {==} case Con{None{}, r}: h case Con{Some{x}, r}: hdef lay0_nones(-T: Data, +xs: List<&2, Maybe<&2, T>>, +h: {lay(T, xs, 0n) == True{} : Bool}) -> {nones(T, xs) == True{} : Bool}: match xs: case Nil{}: {==} case Con{None{}, r}: h case Con{Some{x}, r}: hdef nones_append(-T: Data, +xs: List<&2, Maybe<&2, T>>, +ys: List<&2, Maybe<&2, T>>, +hx: {nones(T, xs) == True{} : Bool}, +hy: {nones(T, ys) == True{} : Bool}) -> {nones(T, SC.append(Maybe<&2, T>, xs, ys)) == True{} : Bool}: match xs: case Nil{}: hy case Con{None{}, +r}: nones_append(T, r, ys, hx, hy) case Con{Some{x}, r}: hx# ---- set ----def lay_set(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +i: Nat, +v: T, +h: {lay(T, xs, n) == True{} : Bool}, +hi: {Nat.is_lt(i, n) == True{} : Bool}) -> {lay(T, SC.update(Maybe<&2, T>, xs, i, Some{v}), n) == True{} : Bool}: match xs n i: case Nil{} _ _: Empty.absurd({lay(T, Nil{}, n) == True{} : Bool}, L.true_not_false(lay(T, Nil{}, n), h, lay_nil_pos(T, n, i, hi))) case Con{None{}, r} 0n _: Empty.absurd({lay(T, SC.update(Maybe<&2, T>, Con{None{}, r}, i, Some{v}), 0n) == True{} : Bool}, N.lt_zero_absurd(i, hi)) case Con{None{}, r} 1n+m _: Empty.absurd({lay(T, SC.update(Maybe<&2, T>, Con{None{}, r}, i, Some{v}), 1n+m) == True{} : Bool}, L.false_true(h)) case Con{Some{x}, r} 0n _: Empty.absurd({lay(T, SC.update(Maybe<&2, T>, Con{Some{x}, r}, i, Some{v}), 0n) == True{} : Bool}, L.false_true(h)) case Con{Some{x}, r} 1n+m 0n: h case Con{Some{x}, +r} 1n+m 1n+j: lay_set(T, r, m, j, v, h, hi)def somes_set(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +i: Nat, +v: T, +h: {lay(T, xs, n) == True{} : Bool}, +hi: {Nat.is_lt(i, n) == True{} : Bool}) -> {somes(T, SC.update(Maybe<&2, T>, xs, i, Some{v})) == SC.update(T, somes(T, xs), i, v) : List<&2, T>}: match xs n i: case Nil{} _ _: Empty.absurd({Nil{} == Nil{} : List<&2, T>}, L.true_not_false(lay(T, Nil{}, n), h, lay_nil_pos(T, n, i, hi))) case Con{None{}, r} 0n _: Empty.absurd({somes(T, SC.update(Maybe<&2, T>, Con{None{}, r}, i, Some{v})) == SC.update(T, somes(T, r), i, v) : List<&2, T>}, N.lt_zero_absurd(i, hi)) case Con{None{}, r} 1n+m _: Empty.absurd({somes(T, SC.update(Maybe<&2, T>, Con{None{}, r}, i, Some{v})) == SC.update(T, somes(T, r), i, v) : List<&2, T>}, L.false_true(h)) case Con{Some{x}, r} 0n _: Empty.absurd({somes(T, SC.update(Maybe<&2, T>, Con{Some{x}, r}, i, Some{v})) == SC.update(T, Con{x, somes(T, r)}, i, v) : List<&2, T>}, L.false_true(h)) case Con{Some{x}, r} 1n+m 0n: {==} case Con{Some{+x}, +r} 1n+m 1n+j: LL.cons_cong(T, x, somes(T, SC.update(Maybe<&2, T>, r, j, Some{v})), SC.update(T, somes(T, r), j, v), somes_set(T, r, m, j, v, h, hi))# ---- push (slot n is the first free one) ----def push_free(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +h: {lay(T, xs, n) == True{} : Bool}, +hn: {Nat.is_lt(n, SC.length(Maybe<&2, T>, xs)) == True{} : Bool}) -> {SC.nth(Maybe<&2, T>, xs, n) == Some{None{}} : Maybe<&2, Maybe<&2, T>>}: match xs n: case Nil{} _: Empty.absurd({None{} == Some{None{}} : Maybe<&2, Maybe<&2, T>>}, N.lt_zero_absurd(n, hn)) case Con{None{}, r} 0n: {==} case Con{None{}, r} 1n+m: Empty.absurd({SC.nth(Maybe<&2, T>, r, m) == Some{None{}} : Maybe<&2, Maybe<&2, T>>}, L.false_true(h)) case Con{Some{x}, r} 0n: Empty.absurd({Some{Some{x}} == Some{None{}} : Maybe<&2, Maybe<&2, T>>}, L.false_true(h)) case Con{Some{x}, +r} 1n+m: push_free(T, r, m, h, hn)def lay_push(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +v: T, +h: {lay(T, xs, n) == True{} : Bool}, +hn: {Nat.is_lt(n, SC.length(Maybe<&2, T>, xs)) == True{} : Bool}) -> {lay(T, SC.update(Maybe<&2, T>, xs, n, Some{v}), 1n+n) == True{} : Bool}: match xs n: case Nil{} _: Empty.absurd({lay(T, Nil{}, 1n+n) == True{} : Bool}, N.lt_zero_absurd(n, hn)) case Con{None{}, +r} 0n: nones_lay0(T, r, h) case Con{None{}, r} 1n+m: Empty.absurd({lay(T, Con{None{}, SC.update(Maybe<&2, T>, r, m, Some{v})}, 2n+m) == True{} : Bool}, L.false_true(h)) case Con{Some{x}, r} 0n: Empty.absurd({lay(T, Con{Some{v}, r}, 1n) == True{} : Bool}, L.false_true(h)) case Con{Some{x}, +r} 1n+m: lay_push(T, r, m, v, h, hn)def somes_push(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +v: T, +h: {lay(T, xs, n) == True{} : Bool}, +hn: {Nat.is_lt(n, SC.length(Maybe<&2, T>, xs)) == True{} : Bool}) -> {somes(T, SC.update(Maybe<&2, T>, xs, n, Some{v})) == SC.snoc(T, somes(T, xs), v) : List<&2, T>}: match xs n: case Nil{} _: Empty.absurd({Nil{} == Con{v, Nil{}} : List<&2, T>}, N.lt_zero_absurd(n, hn)) case Con{None{}, +r} 0n: %Equal.sym(List<&2, T>, somes(T, r), Nil{}, nones_somes(T, r, h)) : {Con{v, _} == SC.snoc(T, _, v) : List<&2, T>} {==} case Con{None{}, r} 1n+m: Empty.absurd({somes(T, Con{None{}, SC.update(Maybe<&2, T>, r, m, Some{v})}) == SC.snoc(T, somes(T, r), v) : List<&2, T>}, L.false_true(h)) case Con{Some{x}, r} 0n: Empty.absurd({Con{v, somes(T, r)} == SC.snoc(T, Con{x, somes(T, r)}, v) : List<&2, T>}, L.false_true(h)) case Con{Some{+x}, +r} 1n+m: LL.cons_cong(T, x, somes(T, SC.update(Maybe<&2, T>, r, m, Some{v})), SC.snoc(T, somes(T, r), v), somes_push(T, r, m, v, h, hn))# ---- pop (slot m of a layout with m+1 items) ----def lay_pop(-T: Data, +xs: List<&2, Maybe<&2, T>>, +m: Nat, +h: {lay(T, xs, 1n+m) == True{} : Bool}) -> {lay(T, SC.update(Maybe<&2, T>, xs, m, None{}), m) == True{} : Bool}: match xs m: case Nil{} _: Empty.absurd({lay(T, Nil{}, m) == True{} : Bool}, L.false_true(h)) case Con{None{}, r} _: Empty.absurd({lay(T, SC.update(Maybe<&2, T>, Con{None{}, r}, m, None{}), m) == True{} : Bool}, L.false_true(h)) case Con{Some{x}, +r} 0n: lay0_nones(T, r, h) case Con{Some{x}, +r} 1n+k: lay_pop(T, r, k, h)def init_cons(-T: Data, +x: T, +ys: List<&2, T>, +k: Nat, +h: {SC.length(T, ys) == 1n+k : Nat}) -> {SC.init(T, Con{x, ys}) == Con{x, SC.init(T, ys)} : List<&2, T>}: match ys: case Nil{}: Empty.absurd({Nil{} == Con{x, Nil{}} : List<&2, T>}, N.zero_succ(k, h)) case Con{y, t}: {==}def somes_pop(-T: Data, +xs: List<&2, Maybe<&2, T>>, +m: Nat, +h: {lay(T, xs, 1n+m) == True{} : Bool}) -> {somes(T, SC.update(Maybe<&2, T>, xs, m, None{})) == SC.init(T, somes(T, xs)) : List<&2, T>}: match xs m: case Nil{} _: Empty.absurd({Nil{} == Nil{} : List<&2, T>}, L.false_true(h)) case Con{None{}, r} _: Empty.absurd({somes(T, SC.update(Maybe<&2, T>, Con{None{}, r}, m, None{})) == SC.init(T, somes(T, r)) : List<&2, T>}, L.false_true(h)) case Con{Some{x}, +r} 0n: %Equal.sym(List<&2, T>, somes(T, r), Nil{}, nones_somes(T, r, lay0_nones(T, r, h))) : {_ == SC.init(T, Con{x, _}) : List<&2, T>} {==} case Con{Some{+x}, +r} 1n+k: Equal.trans(List<&2, T>, Con{x, somes(T, SC.update(Maybe<&2, T>, r, k, None{}))}, Con{x, SC.init(T, somes(T, r))}, SC.init(T, Con{x, somes(T, r)}), LL.cons_cong(T, x, somes(T, SC.update(Maybe<&2, T>, r, k, None{})), SC.init(T, somes(T, r)), somes_pop(T, r, k, h)), Equal.sym(List<&2, T>, SC.init(T, Con{x, somes(T, r)}), Con{x, SC.init(T, somes(T, r))}, init_cons(T, x, somes(T, r), k, lay_len(T, r, 1n+k, h))))# nth at the last position is last.def nth_last(-T: Data, +ys: List<&2, T>, +m: Nat, +h: {SC.length(T, ys) == 1n+m : Nat}) -> {SC.nth(T, ys, m) == SC.last(T, ys) : Maybe<&2, T>}: match ys m: case Nil{} _: Empty.absurd({None{} == None{} : Maybe<&2, T>}, N.zero_succ(m, h)) case Con{y, Nil{}} 0n: {==} case Con{y, Con{y2, t2}} 0n: Empty.absurd({Some{y} == SC.last(T, Con{y2, t2}) : Maybe<&2, T>}, N.succ_zero(SC.length(T, t2), N.succ_inj(1n+SC.length(T, t2), 0n, h))) case Con{y, Nil{}} 1n+k: Empty.absurd({SC.nth(T, Nil{}, k) == Some{y} : Maybe<&2, T>}, N.zero_succ(k, N.succ_inj(0n, 1n+k, h))) case Con{y, Con{+y2, +t2}} 1n+k: nth_last(T, Con{y2, t2}, k, N.succ_inj(1n+SC.length(T, t2), 1n+k, h))# ---- growth (append free slots) and clear ----def lay_grow(-T: Data, +xs: List<&2, Maybe<&2, T>>, +n: Nat, +k: Nat, +h: {lay(T, xs, n) == True{} : Bool}) -> {lay(T, SC.append(Maybe<&2, T>, xs, SC.replicate(Maybe<&2, T>, k, None{})), n) == True{} : Bool}: match xs n: case Nil{} 0n: lay_rep(T, k) case Nil{} 1n+m: Empty.absurd({lay(T, SC.replicate(Maybe<&2, T>, k, None{}), 1n+m) == True{} : Bool}, L.false_true(h)) case Con{None{}, +r} 0n: nones_append(T, r, SC.replicate(Maybe<&2, T>, k, None{}), h, nones_rep(T, k)) case Con{None{}, r} 1n+m: h case Con{Some{x}, r} 0n: h case Con{Some{x}, +r} 1n+m: lay_grow(T, r, m, k, h)def somes_grow(-T: Data, +xs: List<&2, Maybe<&2, T>>, +k: Nat) -> {somes(T, SC.append(Maybe<&2, T>, xs, SC.replicate(Maybe<&2, T>, k, None{}))) == somes(T, xs) : List<&2, T>}: match xs: case Nil{}: somes_rep(T, k) case Con{None{}, +r}: somes_grow(T, r, k) case Con{Some{+x}, +r}: LL.cons_cong(T, x, somes(T, SC.append(Maybe<&2, T>, r, SC.replicate(Maybe<&2, T>, k, None{}))), somes(T, r), somes_grow(T, r, k))