|
| 1 | +// RUN: %parallel-boogie -lib:base -lib:node -vcsSplitOnEveryAssert "%s" > "%t" |
| 2 | +// RUN: %diff "%s.expect" "%t" |
| 3 | + |
| 4 | +type ListElem T = Node Loc T; |
| 5 | + |
| 6 | +datatype Queue<T> { Queue(head: Loc, tail: Loc, {:linear} nodes: Map Loc (ListElem T)) } |
| 7 | + |
| 8 | +var {:linear} {:layer 0, 1} lists: Map Loc (Queue int); |
| 9 | + |
| 10 | +var {:linear} {:layer 0, 1} pos: One (TaggedLoc Unit); |
| 11 | +var {:linear} {:layer 0, 1} neg: One (TaggedLoc Unit); |
| 12 | + |
| 13 | +yield procedure {:layer 0} ReadPos() returns (loc: Loc); |
| 14 | +refines both action {:layer 1} _ { |
| 15 | + loc := pos->val->loc; |
| 16 | +} |
| 17 | + |
| 18 | +yield procedure {:layer 0} ReadNeg() returns (loc: Loc); |
| 19 | +refines both action {:layer 1} _ { |
| 20 | + loc := neg->val->loc; |
| 21 | +} |
| 22 | + |
| 23 | +yield procedure {:layer 0} Enqueue(loc_q: Loc, i: int); |
| 24 | +refines action {:layer 1} _ |
| 25 | +{ |
| 26 | + var {:linear} one_loc_q: One Loc; |
| 27 | + var {:linear} queue: Queue int; |
| 28 | + var head, tail: Loc; |
| 29 | + var {:linear} nodes: Map Loc (ListElem int); |
| 30 | + var {:linear} one_loc_n, new_one_loc_n: One Loc; |
| 31 | + var node: ListElem int; |
| 32 | + |
| 33 | + call one_loc_q, queue := Map_Get(lists, loc_q); |
| 34 | + Queue(head, tail, nodes) := queue; |
| 35 | + |
| 36 | + call new_one_loc_n := Loc_New(); |
| 37 | + call Map_Put(nodes, new_one_loc_n, Node(None(), 0)); |
| 38 | + |
| 39 | + call one_loc_n, node := Map_Get(nodes, tail); |
| 40 | + node := Node(Some(new_one_loc_n->val), i); |
| 41 | + call Map_Put(nodes, one_loc_n, node); |
| 42 | + |
| 43 | + queue := Queue(head, new_one_loc_n->val, nodes); |
| 44 | + call Map_Put(lists, one_loc_q, queue); |
| 45 | +} |
| 46 | + |
| 47 | +yield procedure {:layer 0} Dequeue(loc_q: Loc) returns (i: int); |
| 48 | +refines action {:layer 1} _ |
| 49 | +{ |
| 50 | + var {:linear} one_loc_q: One Loc; |
| 51 | + var {:linear} queue: Queue int; |
| 52 | + var head, tail: Loc; |
| 53 | + var {:linear} nodes: Map Loc (ListElem int); |
| 54 | + var {:linear} one_loc_n: One Loc; |
| 55 | + var node: ListElem int; |
| 56 | + var next: Option Loc; |
| 57 | + |
| 58 | + call one_loc_q, queue := Map_Get(lists, loc_q); |
| 59 | + Queue(head, tail, nodes) := queue; |
| 60 | + |
| 61 | + assume head != tail; |
| 62 | + call one_loc_n, node := Map_Get(nodes, head); |
| 63 | + Node(next, i) := node; |
| 64 | + |
| 65 | + assert next is Some; |
| 66 | + queue := Queue(next->t, tail, nodes); |
| 67 | + call Map_Put(lists, one_loc_q, queue); |
| 68 | +} |
| 69 | + |
| 70 | + |
| 71 | +function {:inline} IsAcyclic(q: Queue int): bool |
| 72 | +{ |
| 73 | + Between(q->nodes->val, Some(q->head), Some(q->tail), None()) |
| 74 | +} |
| 75 | + |
| 76 | +function {:inline} QueueElems(q: Queue int): [Loc]bool |
| 77 | +{ |
| 78 | + BetweenSet(q->nodes->val, Some(q->head), Some(q->tail)) |
| 79 | +} |
| 80 | + |
| 81 | +yield invariant {:layer 1} PosInv(); |
| 82 | +invariant Map_Contains(lists, pos->val->loc); |
| 83 | +invariant (var q := Map_At(lists, pos->val->loc); IsAcyclic(q) && |
| 84 | + (forall loc_n: Loc:: QueueElems(q)[loc_n] ==> |
| 85 | + Map_Contains(q->nodes, loc_n) && |
| 86 | + (loc_n == q->tail || (var node := Map_At(q->nodes, loc_n); node->val > 0)))); |
| 87 | + |
| 88 | +yield invariant {:layer 1} NegInv(); |
| 89 | +invariant Map_Contains(lists, neg->val->loc); |
| 90 | +invariant (var q := Map_At(lists, neg->val->loc); IsAcyclic(q) && |
| 91 | + (forall loc_n: Loc:: QueueElems(q)[loc_n] ==> |
| 92 | + Map_Contains(q->nodes, loc_n) && |
| 93 | + (loc_n == q->tail || (var node := Map_At(q->nodes, loc_n); node->val < 0)))); |
| 94 | + |
| 95 | + |
| 96 | +yield procedure {:layer 1} Producer(i: int) |
| 97 | +preserves call PosInv(); |
| 98 | +preserves call NegInv(); |
| 99 | +{ |
| 100 | + var loc: Loc; |
| 101 | + |
| 102 | + assert {:layer 1} pos->val->loc != neg->val->loc; |
| 103 | + if (i == 0) { |
| 104 | + return; |
| 105 | + } |
| 106 | + if (i > 0) { |
| 107 | + call loc := ReadPos(); |
| 108 | + } else { |
| 109 | + call loc := ReadNeg(); |
| 110 | + } |
| 111 | + call Enqueue(loc, i); |
| 112 | +} |
| 113 | + |
| 114 | +yield procedure {:layer 1} PosConsumer() |
| 115 | +preserves call PosInv(); |
| 116 | +{ |
| 117 | + var loc: Loc; |
| 118 | + var i: int; |
| 119 | + |
| 120 | + call loc := ReadPos(); |
| 121 | + call i := Dequeue(loc); |
| 122 | + assert {:layer 1} i > 0; |
| 123 | +} |
| 124 | + |
| 125 | +yield procedure {:layer 1} NegConsumer() |
| 126 | +preserves call NegInv(); |
| 127 | +{ |
| 128 | + var loc: Loc; |
| 129 | + var i: int; |
| 130 | + |
| 131 | + call loc := ReadNeg(); |
| 132 | + call i := Dequeue(loc); |
| 133 | + assert {:layer 1} i < 0; |
| 134 | +} |
0 commit comments