1 import Base 2 import ../../../spec/containers/queue.bend as S 3 import ../../../src/containers/queue.bend as Q 4 import ../../../src/containers/types/queue.bend as E 5 import ./state.bend as ST 6 import ./steps.bend as PS 7 import ./trace.bend as FT 8 import ../../lib/logic.bend as L 9 import ../../../spec/lib/common.bend as SC 10 import ../../../spec/lib/sequence.bend as V 11 import ../../lib/sequence.bend as VL 12 13 # FIFO queue (two lists, src/containers/queue.bend): public proof entry point. 14 # shadow ST.Sh{front, back}: the queue QU{front, back, |front| + 15 # |back|} 16 # abstraction ST.model(sh) = front ++ reverse(back), oldest first 17 # ready PS.ready: reversing the back into an empty front keeps the 18 # model and leaves the front nonempty unless the queue is empty 19 # operations PS.step_ok: every public operation, errors included 20 # (dequeue or peek on an empty queue is Fail{EmptyQueue}, queue 21 # unchanged) 22 # traces trace_from / trace_new: any finite operation list, no 23 # premise on its length or on the queue's size 24 25 def new_abs(~T: Data) -> {ST.model(T, ST.initial(T)) == Nil{} : List<&2, T>}: 26 {==} 27 28 def new_real(~T: Data) -> {Q.new(~T) == ST.real(T, ST.initial(T)) : Q.Queue}: 29 {==} 30 31 def step_ok(~T: Data, +sh: ST.Shadow, +op: E.Op) -> PS.StepOK(~T, sh, op): 32 PS.step_ok(~T, sh, op) 33 34 # a queue determines its shadow 35 def shadow_unique(~T: Data, +a: ST.Shadow, +b: ST.Shadow, +e: {ST.real(T, a) == ST.real(T, b) : Q.Queue}) -> {a == b : ST.Shadow}: 36 ST.real_inj(T, a, b, e) 37 38 def trace_from(~T: Data, +ops: List<&2, E.Op>, +sh0: ST.Shadow) -> FT.TraceOK(~T, ops, sh0): 39 FT.trace_from(~T, ops, sh0) 40 41 # arbitrary finite operation traces from the real constructor 42 def trace_new(~T: Data, +ops: List<&2, E.Op>) -> FT.TraceOK(~T, ops, ST.initial(T)): 43 FT.trace_from(~T, ops, ST.initial(T)) 44 45 # ==== the contract of queue (stated in spec/containers/queue.bend) ==================== 46 47 # ---- the implementation ---- 48 def Impl(~T: Data, sh: ST.Shadow, op: E.Op, Post: (List<&2, T> & E.Obs) -> Type) -> Type: 49 Sigma<&1, &1, ST.Shadow, sh2 => Sigma<&1, &1, E.Obs, o => {Q.step(~T, ST.real(T, sh), op) == (ST.real(T, sh2), o) : Q.Queue & E.Obs} & Post((ST.model(T, sh2), o))>> 50 51 def impl_of(~T: Data, -sh: ST.Shadow, -op: E.Op, -Post: (List<&2, T> & E.Obs) -> Type, k: PS.StepOK(~T, sh, op), pf: Post(S.step(T, ST.model(T, sh), op))) -> Impl(~T, sh, op, Post): 52 match k: 53 case Tuple{sh2, Tuple{o, Tuple{e1, e2}}}: 54 (sh2, (o, (e1, L.subst(List<&2, T> & E.Obs, Post, S.step(T, ST.model(T, sh), op), (ST.model(T, sh2), o), Equal.sym(List<&2, T> & E.Obs, (ST.model(T, sh2), o), S.step(T, ST.model(T, sh), op), e2), pf)))) 55 56 def impl(~T: Data, +sh: ST.Shadow, +op: E.Op, -Post: (List<&2, T> & E.Obs) -> Type, pf: Post(S.step(T, ST.model(T, sh), op))) -> Impl(~T, sh, op, Post): 57 impl_of(~T, sh, op, Post, step_ok(~T, sh, op), pf) 58 59 # ---- Length, iteration ---- 60 def length_result(-T: Data, +xs: List<&2, T>) -> S.Length.length_result(T, xs): 61 {==} 62 63 def length_frame(-T: Data, +xs: List<&2, T>) -> S.Length.length_frame(T, xs): 64 {==} 65 66 def to_list_model(-T: Data, +xs: List<&2, T>) -> S.Iteration.to_list_model(T, xs): 67 {==} 68 69 def to_list_frame(-T: Data, +xs: List<&2, T>) -> S.Iteration.to_list_frame(T, xs): 70 {==} 71 72 # ---- Empty_Vector ---- 73 def new_empty(~T: Data) -> {SC.length(T, ST.model(T, ST.initial(T))) == 0n : Nat}: 74 %Equal.sym(List<&2, T>, ST.model(T, ST.initial(T)), Nil{}, new_abs(~T)) : {SC.length(T, _) == 0n : Nat} 75 {==} 76 77 def new_impl(~T: Data) -> {Q.new(~T) == ST.real(T, ST.initial(T)) : Q.Queue}: 78 new_real(~T) 79 80 # ---- Append: Length + 1, Equal_Prefix (Model'Old, Model), Element (Last'Old + 1) = New_Item ---- 81 def enqueue_length(-T: Data, +xs: List<&2, T>, +v: T) -> S.Append.enqueue_length(T, xs, v): 82 VL.snoc_length(T, xs, v) 83 84 def enqueue_prefix(-T: Data, +xs: List<&2, T>, +v: T) -> S.Append.enqueue_prefix(T, xs, v): 85 VL.snoc_prefix(T, xs, v) 86 87 def enqueue_element(-T: Data, +xs: List<&2, T>, +v: T) -> S.Append.enqueue_element(T, xs, v): 88 VL.snoc_last(T, xs, v) 89 90 # ---- Delete_First: Length - 1, Range_Shifted (New, Old, First, Last, 1); dequeue returns First_Element'Old ---- 91 def dequeue_length(-T: Data, +h: T, +t: List<&2, T>) -> S.Delete_First.dequeue_length(T, h, t): 92 {==} 93 94 def dequeue_shifted(-T: Data, +h: T, +t: List<&2, T>) -> S.Delete_First.dequeue_shifted(T, h, t): 95 VL.tail_shifted(T, h, t) 96 97 def dequeue_result(-T: Data, +h: T, +t: List<&2, T>) -> S.Delete_First.dequeue_result(T, h, t): 98 {==} 99 100 def dequeue_empty(-T: Data) -> S.Delete_First.dequeue_empty(T): 101 {==} 102 103 # ---- First_Element: Element (Model, First); nothing changes ---- 104 def peek_first(-T: Data, +h: T, +t: List<&2, T>) -> S.First_Element.peek_first(T, h, t): 105 ({==}, {==}) 106 107 def peek_frame(-T: Data, +xs: List<&2, T>) -> S.First_Element.peek_frame(T, xs): 108 {==} 109 110 def peek_empty(-T: Data) -> S.First_Element.peek_empty(T): 111 {==}