Proofs: Real-time queue
These are the human proofs of Real-time queue, at full length.
The real-time queue implements a persistent queue with O(1) worst-case operations full
This proof shows: correctness.
Values. A stream denotes a finite sequence: the empty stream denotes , and a stream whose suspension yields the cell denotes . Forcing a suspension does not change what it denotes, because the stored cell is the one its code yields. Write for the length of . For a list write for its items in reverse order. The items of a queue are .
Lemma 1 (rotate). If , then ROTATE denotes .
Proof. By induction on . If is empty, then and the result is , which is right. Otherwise yields with , and with . The result is followed by ROTATE, which by induction denotes .
Invariant. Call good if (I1) and (I2) is a suffix of (the same stream object reached after tails) and every cell of before is forced.
Lemma 2 (exec). Let and satisfy (I2) for , and let . Then EXEC returns a good queue with the same items as .
Proof. If yields a cell (line L2), then the result is with the tail of , so , which is (I1). The head cell of is now forced, so every cell of before is forced, which is (I2). The items are unchanged. If is empty (line L3), then , and by (I2) all of is forced. By Lemma 1, $f' = $ ROTATE denotes , so the result has the same items, , and is a suffix of itself with no cells before it.
Theorem 1 (correctness and persistence). Every queue made by the operations is good, and its items are those that the abstract queue gives to it. FRONT and POP return the first item. No operation changes the items of an existing version.
Proof. The empty queue is good. Let be good. PUSH calls EXEC with , and ; then , and (I2) holds for and , so by Lemma 2 the result is good with items , which is with at the back. For FRONT and POP, if is not empty then , because by (I1) and . So yields and is the first item. POP calls EXEC with , and . By (I1) and (I2), is a suffix of of length . If , then is also a suffix of , the cells of before are cells of before and so are forced, and ; Lemma 2 applies. If , then and ; EXEC finds that yields the cell (line L2) and returns , which is good. The items are , which is without . No procedure writes a cell, and forcing does not change values, so old versions keep their items.
Theorem 2 (worst-case time). Each operation forces at most two suspensions that were not forced before, and each such force does work.
Proof. FRONT and POP force the head of . If , that head is before and is forced by (I2). If , it may be unforced, and forcing it is one step. EXEC forces the head of , at most one step. A step of ROTATE forces the head of its argument and makes cells. For the outermost call made in line L3, the argument is fully forced by (I2), since there. The inner calls receive tails of that same fully forced stream. So every step forces only cells that are already forced, which costs each, and builds new cells. A suspension shared by several versions is evaluated once, and later forces return the stored cell in . Hence each operation costs in the worst case, on every version.