import Base import ./logic.bend as L import ./nat.bend as N import ./u32.bend as U import ./list.bend as LL import ./array.bend as AR import ../../spec/lib/common.bend as SC # Functional correctness of the installed Base.Array swap/set algorithms at a # NESTED element type: `Array>`, the block of adjacency blocks the # graph uses. # # proofs/lib/array.bend states its laws about `AR.thaw(T, t)` for a Data # mirror `T`. That does not cover this case, because the element type here is # `Array`, which is linear (not `Data`), so `Array.get` is not even # applicable and `AR.thaw` cannot produce the outer array. The MIRROR, # however, is still Data: `AR.Tree>`. So every mirror-level # lemma of proofs/lib/array.bend (perfect, slots, upd, nth) is reused as is at # `T = AR.Tree`, and only the realization function and the two Base # algorithms that touch it (`Array.swap`, and `Array.set` on top of it) are # proved again here, by the same induction. def thaw2(t: AR.Tree>) -> Array>: match t: case AR.TLeaf{b}: ALeaf{AR.thaw(U32, b)} case AR.TNode{l, r}: ANode{thaw2(l), thaw2(r)} def size_thaw2(+d: Nat, +t: AR.Tree>, +pf: {AR.perfect(AR.Tree, d, t) == True{} : Bool}) -> {Array.size(Array, thaw2(t)) == (thaw2(t), U.pow2u(d)) : Array> & U32}: match d t: case 0n AR.TLeaf{b}: {==} case 0n AR.TNode{l, r}: Empty.absurd({Array.size(Array, thaw2(AR.TNode{l, r})) == (thaw2(AR.TNode{l, r}), 1) : Array> & U32}, L.false_true(pf)) case 1n+p AR.TLeaf{b}: Empty.absurd({Array.size(Array, ALeaf{AR.thaw(U32, b)}) == (ALeaf{AR.thaw(U32, b)}, U.pow2u(1n+p)) : Array> & U32}, L.false_true(pf)) case 1n+ +p AR.TNode{+l, +r}: %Equal.sym(Array> & U32, Array.size(Array, thaw2(l)), (thaw2(l), U.pow2u(p)), size_thaw2(p, l, AR.pf_left(AR.Tree, p, l, r, pf))) : {Array.size.node(Array, thaw2(r), _) == (ANode{thaw2(l), thaw2(r)}, U32.shl(U.pow2u(p))) : Array> & U32} {==} def swap_go2(+d: Nat, +t: AR.Tree>, +i: U32, +vt: AR.Tree, +xt: AR.Tree, +hd: {Nat.is_lt(d, 32n) == True{} : Bool}, +hi: {Nat.is_lt(U32.to_nat(i), SC.pow2(d)) == True{} : Bool}, +hx: {SC.nth(AR.Tree, AR.slots(AR.Tree, t), U32.to_nat(i)) == Some{xt} : Maybe<&2, AR.Tree>}, +b: Bool, +eb: {U32.is_lt(i, U32.shr(U.pow2u(d))) == b : Bool}, +pf: {AR.perfect(AR.Tree, d, t) == True{} : Bool}) -> {Array.swap.go(Array, thaw2(t), U.pow2u(d), i, AR.thaw(U32, vt), b) == (thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)), AR.thaw(U32, xt)) : Array> & Array}: match d t b: case 0n AR.TLeaf{+y} _: %AR.leaf_value(AR.Tree, y, U32.to_nat(i), xt, hi, hx) : {(ALeaf{AR.thaw(U32, vt)}, AR.thaw(U32, y)) == (ALeaf{AR.thaw(U32, vt)}, AR.thaw(U32, _)) : Array> & Array} {==} case 0n AR.TNode{l, r} _: Empty.absurd({Array.swap.go(Array, thaw2(AR.TNode{l, r}), 1, i, AR.thaw(U32, vt), b) == (thaw2(AR.upd(AR.Tree, 0n, AR.TNode{l, r}, U32.to_nat(i), vt)), AR.thaw(U32, xt)) : Array> & Array}, L.false_true(pf)) case 1n+p AR.TLeaf{y} _: Empty.absurd({Array.swap.go(Array, ALeaf{AR.thaw(U32, y)}, U.pow2u(1n+p), i, AR.thaw(U32, vt), b) == (thaw2(AR.upd(AR.Tree, 1n+p, AR.TLeaf{y}, U32.to_nat(i), vt)), AR.thaw(U32, xt)) : Array> & Array}, L.false_true(pf)) case 1n+ +p AR.TNode{+l, +r} True{}: +hp = N.lt_trans(p, 1n+p, 32n, N.lt_succ(p), hd) +pl = AR.pf_left(AR.Tree, p, l, r, pf) +hil = AR.lt_bridge(i, p, hp, True{}, L.subst(U32, w => {U32.is_lt(i, w) == True{} : Bool}, U32.shr(U.pow2u(1n+p)), U.pow2u(p), U.shr_pow2u(p, hd), eb)) +ti = U32.to_nat(i) %Equal.sym(U32, U32.shr(U.pow2u(1n+p)), U.pow2u(p), U.shr_pow2u(p, hd)) : {Array.swap.lo(Array, thaw2(r), Array.swap.go(Array, thaw2(l), _, i, AR.thaw(U32, vt), U32.is_lt(i, U32.shr(_)))) == (thaw2(AR.upd(AR.Tree, 1n+p, AR.TNode{l, r}, ti, vt)), AR.thaw(U32, xt)) : Array> & Array} %Equal.sym(Bool, Nat.is_lt(ti, SC.pow2(p)), True{}, hil) : {Array.swap.lo(Array, thaw2(r), Array.swap.go(Array, thaw2(l), U.pow2u(p), i, AR.thaw(U32, vt), U32.is_lt(i, U32.shr(U.pow2u(p))))) == (thaw2(AR.tupd(AR.Tree, 1n+p, AR.TNode{l, r}, ti, vt, _)), AR.thaw(U32, xt)) : Array> & Array} %Equal.sym(Array> & Array, Array.swap.go(Array, thaw2(l), U.pow2u(p), i, AR.thaw(U32, vt), U32.is_lt(i, U32.shr(U.pow2u(p)))), (thaw2(AR.upd(AR.Tree, p, l, ti, vt)), AR.thaw(U32, xt)), swap_go2(p, l, i, vt, xt, hp, hil, Equal.trans(Maybe<&2, AR.Tree>, SC.nth(AR.Tree, AR.slots(AR.Tree, l), ti), SC.nth(AR.Tree, SC.append(AR.Tree, AR.slots(AR.Tree, l), AR.slots(AR.Tree, r)), ti), Some{xt}, Equal.sym(Maybe<&2, AR.Tree>, SC.nth(AR.Tree, SC.append(AR.Tree, AR.slots(AR.Tree, l), AR.slots(AR.Tree, r)), ti), SC.nth(AR.Tree, AR.slots(AR.Tree, l), ti), LL.nth_append_left(AR.Tree, AR.slots(AR.Tree, l), AR.slots(AR.Tree, r), ti, AR.len_lt(AR.Tree, p, l, ti, pl, hil))), hx), U32.is_lt(i, U32.shr(U.pow2u(p))), {==}, pl)) : {Array.swap.lo(Array, thaw2(r), _) == (thaw2(AR.TNode{AR.tupd(AR.Tree, p, l, ti, vt, AR.ndec(p, ti)), r}), AR.thaw(U32, xt)) : Array> & Array} {==} case 1n+ +p AR.TNode{+l, +r} False{}: +hp = N.lt_trans(p, 1n+p, 32n, N.lt_succ(p), hd) +pl = AR.pf_left(AR.Tree, p, l, r, pf) +ti = U32.to_nat(i) +nb = AR.lt_bridge(i, p, hp, False{}, L.subst(U32, w => {U32.is_lt(i, w) == False{} : Bool}, U32.shr(U.pow2u(1n+p)), U.pow2u(p), U.shr_pow2u(p, hd), eb)) +le = N.not_lt_le(ti, SC.pow2(p), nb) +j = U32.sub(i, U.pow2u(p)) +k = Nat.sub(ti, SC.pow2(p)) +ej = AR.sub_bridge(i, p, hp, le) +hir = L.subst(Nat, n => {Nat.is_lt(n, SC.pow2(p)) == True{} : Bool}, k, U32.to_nat(j), Equal.sym(Nat, U32.to_nat(j), k, ej), AR.upper_lt(ti, p, hi, le)) +hxr = L.subst(Nat, n => {SC.nth(AR.Tree, AR.slots(AR.Tree, r), n) == Some{xt} : Maybe<&2, AR.Tree>}, k, U32.to_nat(j), Equal.sym(Nat, U32.to_nat(j), k, ej), Equal.trans(Maybe<&2, AR.Tree>, SC.nth(AR.Tree, AR.slots(AR.Tree, r), k), SC.nth(AR.Tree, SC.append(AR.Tree, AR.slots(AR.Tree, l), AR.slots(AR.Tree, r)), ti), Some{xt}, Equal.sym(Maybe<&2, AR.Tree>, SC.nth(AR.Tree, SC.append(AR.Tree, AR.slots(AR.Tree, l), AR.slots(AR.Tree, r)), ti), SC.nth(AR.Tree, AR.slots(AR.Tree, r), k), AR.right_nth(AR.Tree, p, l, r, ti, pl, le)), hx)) +ih = swap_go2(p, r, j, vt, xt, hp, hir, hxr, U32.is_lt(j, U32.shr(U.pow2u(p))), {==}, AR.pf_right(AR.Tree, p, l, r, pf)) +ih2 = L.subst(Nat, n => {Array.swap.go(Array, thaw2(r), U.pow2u(p), j, AR.thaw(U32, vt), U32.is_lt(j, U32.shr(U.pow2u(p)))) == (thaw2(AR.upd(AR.Tree, p, r, n, vt)), AR.thaw(U32, xt)) : Array> & Array}, U32.to_nat(j), k, ej, ih) %Equal.sym(U32, U32.shr(U.pow2u(1n+p)), U.pow2u(p), U.shr_pow2u(p, hd)) : {Array.swap.hi(Array, thaw2(l), Array.swap.go(Array, thaw2(r), _, U32.sub(i, _), AR.thaw(U32, vt), U32.is_lt(U32.sub(i, _), U32.shr(_)))) == (thaw2(AR.upd(AR.Tree, 1n+p, AR.TNode{l, r}, ti, vt)), AR.thaw(U32, xt)) : Array> & Array} %Equal.sym(Bool, Nat.is_lt(ti, SC.pow2(p)), False{}, nb) : {Array.swap.hi(Array, thaw2(l), Array.swap.go(Array, thaw2(r), U.pow2u(p), j, AR.thaw(U32, vt), U32.is_lt(j, U32.shr(U.pow2u(p))))) == (thaw2(AR.tupd(AR.Tree, 1n+p, AR.TNode{l, r}, ti, vt, _)), AR.thaw(U32, xt)) : Array> & Array} %Equal.sym(Array> & Array, Array.swap.go(Array, thaw2(r), U.pow2u(p), j, AR.thaw(U32, vt), U32.is_lt(j, U32.shr(U.pow2u(p)))), (thaw2(AR.upd(AR.Tree, p, r, k, vt)), AR.thaw(U32, xt)), ih2) : {Array.swap.hi(Array, thaw2(l), _) == (thaw2(AR.TNode{l, AR.tupd(AR.Tree, p, r, k, vt, AR.ndec(p, k))}), AR.thaw(U32, xt)) : Array> & Array} {==} # Public Base entry points at the nested element type. def swap2(+d: Nat, +t: AR.Tree>, +i: U32, +vt: AR.Tree, +xt: AR.Tree, +hd: {Nat.is_lt(d, 32n) == True{} : Bool}, +hi: {Nat.is_lt(U32.to_nat(i), SC.pow2(d)) == True{} : Bool}, +hx: {SC.nth(AR.Tree, AR.slots(AR.Tree, t), U32.to_nat(i)) == Some{xt} : Maybe<&2, AR.Tree>}, +pf: {AR.perfect(AR.Tree, d, t) == True{} : Bool}) -> {Array.swap(Array, thaw2(t), i, AR.thaw(U32, vt)) == (thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)), AR.thaw(U32, xt)) : Array> & Array}: %Equal.sym(Array> & U32, Array.size(Array, thaw2(t)), (thaw2(t), U.pow2u(d)), size_thaw2(d, t, pf)) : {Array.swap.at(Array, i, AR.thaw(U32, vt), _) == (thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)), AR.thaw(U32, xt)) : Array> & Array} %Equal.sym(U32, U32.and(i, U32.sub(U.pow2u(d), 1)), i, U.mask_pow2u(i, d, hd, hi)) : {Array.swap.go(Array, thaw2(t), U.pow2u(d), _, AR.thaw(U32, vt), U32.is_lt(_, U32.shr(U.pow2u(d)))) == (thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)), AR.thaw(U32, xt)) : Array> & Array} swap_go2(d, t, i, vt, xt, hd, hi, hx, U32.is_lt(i, U32.shr(U.pow2u(d))), {==}, pf) def set2(+d: Nat, +t: AR.Tree>, +i: U32, +vt: AR.Tree, +xt: AR.Tree, +hd: {Nat.is_lt(d, 32n) == True{} : Bool}, +hi: {Nat.is_lt(U32.to_nat(i), SC.pow2(d)) == True{} : Bool}, +hx: {SC.nth(AR.Tree, AR.slots(AR.Tree, t), U32.to_nat(i)) == Some{xt} : Maybe<&2, AR.Tree>}, +pf: {AR.perfect(AR.Tree, d, t) == True{} : Bool}) -> {Array.set(Array, thaw2(t), i, AR.thaw(U32, vt)) == thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)) : Array>}: %Equal.sym(Array> & Array, Array.swap(Array, thaw2(t), i, AR.thaw(U32, vt)), (thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)), AR.thaw(U32, xt)), swap2(d, t, i, vt, xt, hd, hi, hx, pf)) : {Array.set.fin(Array, _) == thaw2(AR.upd(AR.Tree, d, t, U32.to_nat(i), vt)) : Array>} {==} # Doubling on either side, as the vertex table grows. def node_lo(+lt: AR.Tree>, +rt: AR.Tree>) -> {ANode{thaw2(lt), thaw2(rt)} == thaw2(AR.TNode{lt, rt}) : Array>}: {==}