11// RUN: %parallel-boogie -lib:base -lib:node -timeLimit:0 -vcsSplitOnEveryAssert "%s" > "%t"
22// RUN: %diff "%s.expect" "%t"
33
4- datatype LocPiece { Left(), Right() }
5- function {:inline} AllLocPieces(): Set LocPiece {
6- Set_Add(Set_Add(Set_Empty(), Left()), Right())
7- }
8-
9- type LocTreiberStack = KeyedLoc LocPiece;
10- type LocTreiberNode = KeyedLoc LocPiece;
4+ type LocTreiberStack = Loc;
5+ type LocTreiberNode = Loc;
116type StackElem T = Node LocTreiberNode T;
127type StackMap T = Map LocTreiberNode (StackElem T);
138datatype Treiber< T> { Treiber(top: Option LocTreiberNode, {:linear} nodes: StackMap T) }
149
15- function {:inline} LeftLocPiece(loc_piece: KeyedLoc LocPiece): KeyedLoc LocPiece {
16- KeyedLoc(loc_piece-> l, Left())
17- }
18-
1910type X; // module type parameter
2011
21- var {:layer 4 , 5 } TreiberPool: Map LocTreiberStack (Vec X);
22- var {:layer 0 , 4 } {:linear} TreiberPoolLow: Map LocTreiberStack (Treiber X);
12+ var {:layer 4 , 5 } TreiberPool: Map Loc (Vec X);
13+ var {:layer 0 , 4 } {:linear} TreiberPoolLow: Map Loc (Treiber X);
14+
15+ /// Proof outline
16+ /*
17+ Layer 1: Simplify LoadNode and convert its mover type to right mover
18+ Layer 2: Create abstractions of ReadTopOfStack for Push and Pop separately
19+ - right mover ReadTopOfStack#Push
20+ - atomic ReadTopOfStack#Pop
21+ Layer 3:
22+ - Convert PopIntermediate to atomic action using right mover LoadNode
23+ - Convert CreateNewTopOfStack to atomic action using right mover ReadTopOfStack#Push
24+ Layer 4: Introduce TreiberPool and abstract TreiberPoolLow to TreiberPool
25+ */
2326
2427/// Yield invariants
2528
@@ -48,60 +51,52 @@ invariant Map_Contains(TreiberPoolLow, loc_t);
4851invariant (var t := TreiberPoolLow-> val[loc_t]; Between(t-> nodes-> val, t-> top, t-> top, None()));
4952invariant (var t := TreiberPoolLow-> val[loc_t]; IsSubset(BetweenSet(t-> nodes-> val, t-> top, None()), Domain(TreiberPoolLow, loc_t)-> val));
5053invariant (var loc_n := Map_At(TreiberPoolLow, loc_t)-> top; loc_n is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n-> t));
51- invariant (forall {:pool "A" } loc_n: LocTreiberNode :: {:add_to_pool "A" , loc_n} Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n) ==> loc_n == KeyedLoc(loc_n-> l, Left()));
5254invariant Map_At(TreiberPool, loc_t) == Abs(Map_At(TreiberPoolLow, loc_t));
5355
5456yield invariant {:layer 4 } StackDom();
5557invariant TreiberPool-> dom == TreiberPoolLow-> dom;
5658
57- yield invariant {:layer 4 } PushLocInStack(loc_t: LocTreiberStack, node: StackElem X, new_loc_n: LocTreiberNode, {:linear} right_loc_piece : One LocTreiberNode );
59+ yield invariant {:layer 4 } PushLocInStack(loc_t: LocTreiberStack, node: StackElem X, new_loc_n: LocTreiberNode, {:linear} tagged_loc : One (TaggedLoc Unit) );
5860invariant Map_Contains(TreiberPoolLow, loc_t);
5961invariant Set_Contains(Domain(TreiberPoolLow, loc_t), new_loc_n);
60- invariant new_loc_n == KeyedLoc(new_loc_n-> l, Left());
61- invariant right_loc_piece-> val == KeyedLoc(new_loc_n-> l, Right());
62+ invariant tagged_loc-> val == TaggedLoc(new_loc_n, Unit());
6263invariant (var t := TreiberPoolLow-> val[loc_t]; Map_At(t-> nodes, new_loc_n) == node && ! BetweenSet(t-> nodes-> val, t-> top, None())[new_loc_n]);
6364
6465/// Layered implementation
6566
66- atomic action {:layer 5 } AtomicAlloc() returns ({:linear} one_loc_t: One LocTreiberStack)
67- modifies TreiberPool;
67+ atomic action {:layer 5 } AtomicAlloc() returns ({:linear} tagged_loc: One (TaggedLoc Unit))
6868{
69- var loc: Loc;
70- var {:linear} loc_pieces: Set LocTreiberNode;
71- var {:linear} left_loc_piece: One LocTreiberNode;
72-
73- call loc, loc_pieces := KeyedLocSet_New(AllLocPieces());
74- call one_loc_t := One_Get(loc_pieces, KeyedLoc(loc, Right()));
75- call left_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Left()));
76- assume ! Map_Contains(TreiberPool, left_loc_piece-> val);
77- TreiberPool := Map_Update(TreiberPool, left_loc_piece-> val, Vec_Empty());
69+ var {:linear} one_loc_t: One LocTreiberStack;
70+ var {:linear} tagged_locs: Set (TaggedLoc Unit);
71+
72+ call one_loc_t, tagged_locs := TaggedLocSet_New(UnitSet());
73+ call tagged_loc := One_Get(tagged_locs, TaggedLoc(one_loc_t-> val, Unit()));
74+ assume ! Map_Contains(TreiberPool, one_loc_t-> val);
75+ TreiberPool := Map_Update(TreiberPool, one_loc_t-> val, Vec_Empty());
7876}
79- yield procedure {:layer 4 } Alloc() returns ({:linear} one_loc_t : One LocTreiberStack )
77+ yield procedure {:layer 4 } Alloc() returns ({:linear} tagged_loc : One (TaggedLoc Unit) )
8078refines AtomicAlloc;
81- ensures call TopInStack(LeftLocPiece(one_loc_t -> val) );
82- ensures call ReachInStack(LeftLocPiece(one_loc_t -> val) );
79+ ensures call TopInStack(tagged_loc -> val- > loc );
80+ ensures call ReachInStack(tagged_loc -> val- > loc );
8381preserves call StackDom();
8482{
85- var loc: Loc;
86- var {:linear} loc_pieces: Set LocTreiberNode;
87- var {:linear} left_loc_piece: One LocTreiberNode;
83+ var {:linear} one_loc_t: One LocTreiberStack;
84+ var {:linear} tagged_locs: Set (TaggedLoc Unit);
8885 var top: Option LocTreiberNode;
8986 var {:linear} stack: StackMap X;
9087 var {:linear} treiber: Treiber X;
9188
9289 top := None();
9390 call stack := Map_MakeEmpty();
9491 treiber := Treiber(top, stack);
95- call loc, loc_pieces := KeyedLocSet_New(AllLocPieces());
96- call one_loc_t := One_Get(loc_pieces, KeyedLoc(loc, Right()));
97- call left_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Left()));
98- call AllocTreiber#0 (left_loc_piece, treiber);
99- call {:layer 4 } TreiberPool := Copy(Map_Update(TreiberPool, left_loc_piece-> val, Vec_Empty()));
92+ call one_loc_t, tagged_locs := TaggedLocSet_New(UnitSet());
93+ call tagged_loc := One_Get(tagged_locs, TaggedLoc(one_loc_t-> val, Unit()));
94+ call AllocTreiber#0 (one_loc_t, treiber);
95+ call {:layer 4 } TreiberPool := Copy(Map_Update(TreiberPool, one_loc_t-> val, Vec_Empty()));
10096 call {:layer 4 } AbsLemma(treiber);
10197}
10298
10399atomic action {:layer 5 } AtomicPush(loc_t: LocTreiberStack, x: X) returns (success: bool)
104- modifies TreiberPool;
105100{
106101 if (*) {
107102 TreiberPool := Map_Update(TreiberPool, loc_t, Vec_Append(Map_At(TreiberPool, loc_t), x));
@@ -118,13 +113,13 @@ preserves call StackDom();
118113{
119114 var loc_n: Option LocTreiberNode;
120115 var new_loc_n: LocTreiberNode;
121- var {:linear} right_loc_piece : One LocTreiberNode ;
116+ var {:linear} tagged_loc : One (TaggedLoc Unit) ;
122117 var {:layer 4 } old_treiber: Treiber X;
123118
124119 call {:layer 4 } old_treiber := Copy(TreiberPoolLow-> val[loc_t]);
125- call loc_n, new_loc_n, right_loc_piece := AllocNode# 3 (loc_t, x);
120+ call loc_n, new_loc_n, tagged_loc := CreateNewTopOfStack (loc_t, x);
126121 call {:layer 4 } FrameLemma(old_treiber, TreiberPoolLow-> val[loc_t]);
127- par ReachInStack(loc_t) | StackDom() | PushLocInStack(loc_t, Node(loc_n, x), new_loc_n, right_loc_piece );
122+ par ReachInStack(loc_t) | StackDom() | PushLocInStack(loc_t, Node(loc_n, x), new_loc_n, tagged_loc );
128123 call success := WriteTopOfStack#0 (loc_t, loc_n, Some(new_loc_n));
129124 if (success) {
130125 call {:layer 4 } TreiberPool := Copy(Map_Update(TreiberPool, loc_t, Vec_Append(Map_At(TreiberPool, loc_t), x)));
@@ -134,7 +129,6 @@ preserves call StackDom();
134129}
135130
136131atomic action {:layer 5 } AtomicPop(loc_t: LocTreiberStack) returns (success: bool, x_opt: Option X)
137- modifies TreiberPool;
138132{
139133 var stack: Vec X;
140134
@@ -166,50 +160,44 @@ preserves call StackDom();
166160 }
167161}
168162
169- atomic action {:layer 4 } AtomicAllocNode#3 (loc_t: LocTreiberStack, x: X)
170- returns (loc_n: Option LocTreiberNode, new_loc_n: LocTreiberNode, {:linear} right_loc_piece: One LocTreiberNode)
171- modifies TreiberPoolLow;
163+ atomic action {:layer 4 } AtomicCreateNewTopOfStack(loc_t: LocTreiberStack, x: X)
164+ returns (loc_n: Option LocTreiberNode, new_loc_n: LocTreiberNode, {:linear} tagged_loc: One (TaggedLoc Unit))
172165asserts Map_Contains(TreiberPoolLow, loc_t);
173166{
174167 var {:linear} one_loc_t: One LocTreiberStack;
175168 var {:linear} treiber: Treiber X;
176169 var top: Option LocTreiberNode;
177170 var {:linear} stack: StackMap X;
178- var loc: Loc;
179- var {:linear} loc_pieces: Set LocTreiberNode;
180- var {:linear} left_loc_piece: One LocTreiberNode;
171+ var {:linear} one_loc_n: One LocTreiberNode;
172+ var {:linear} tagged_locs: Set (TaggedLoc Unit);
181173
182174 call one_loc_t, treiber := Map_Get(TreiberPoolLow, loc_t);
183175 Treiber(top, stack) := treiber;
184176 assume loc_n is None || Map_Contains(stack, loc_n-> t);
185- call loc, loc_pieces := KeyedLocSet_New(AllLocPieces());
186- call left_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Left()));
187- new_loc_n := left_loc_piece-> val;
188- call right_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Right()));
189- call Map_Put(stack, left_loc_piece, Node(loc_n, x));
177+ call one_loc_n, tagged_locs := TaggedLocSet_New(UnitSet());
178+ new_loc_n := one_loc_n-> val;
179+ call tagged_loc := One_Get(tagged_locs, TaggedLoc(new_loc_n, Unit()));
180+ call Map_Put(stack, one_loc_n, Node(loc_n, x));
190181 treiber := Treiber(top, stack);
191182 call Map_Put(TreiberPoolLow, one_loc_t, treiber);
192183}
193- yield procedure {:layer 3 } AllocNode# 3 (loc_t: LocTreiberStack, x: X)
194- returns (loc_n: Option LocTreiberNode, new_loc_n: LocTreiberNode, {:linear} right_loc_piece : One LocTreiberNode )
184+ yield procedure {:layer 3 } CreateNewTopOfStack (loc_t: LocTreiberStack, x: X)
185+ returns (loc_n: Option LocTreiberNode, new_loc_n: LocTreiberNode, {:linear} tagged_loc : One (TaggedLoc Unit) )
195186preserves call TopInStack(loc_t);
196187ensures call LocInStackOrNone(loc_t, Some(new_loc_n));
197- refines AtomicAllocNode# 3 ;
188+ refines AtomicCreateNewTopOfStack ;
198189{
199- var loc: Loc;
200- var {:linear} loc_pieces: Set LocTreiberNode;
201- var {:linear} left_loc_piece: One LocTreiberNode;
190+ var {:linear} one_loc_n: One LocTreiberNode;
191+ var {:linear} tagged_locs: Set (TaggedLoc Unit);
202192
203193 call loc_n := ReadTopOfStack#Push(loc_t);
204- call loc, loc_pieces := KeyedLocSet_New(AllLocPieces());
205- call left_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Left()));
206- new_loc_n := left_loc_piece-> val;
207- call right_loc_piece := One_Get(loc_pieces, KeyedLoc(loc, Right()));
208- call AllocNode#0 (loc_t, left_loc_piece, Node(loc_n, x));
194+ call one_loc_n, tagged_locs := TaggedLocSet_New(UnitSet());
195+ new_loc_n := one_loc_n-> val;
196+ call tagged_loc := One_Get(tagged_locs, TaggedLoc(new_loc_n, Unit()));
197+ call AllocNode#0 (loc_t, one_loc_n, Node(loc_n, x));
209198}
210199
211200atomic action {:layer 4 } AtomicPopIntermediate(loc_t: LocTreiberStack) returns (success: bool, x_opt: Option X)
212- modifies TreiberPoolLow;
213201{
214202 var {:linear} one_loc_t: One LocTreiberStack;
215203 var loc_n: Option LocTreiberNode;
@@ -264,28 +252,25 @@ preserves call TopInStack(loc_t);
264252 }
265253}
266254
267- right action {:layer 3 } AtomicReadTopOfStack#Push(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
268- {
269- assert Map_Contains(TreiberPoolLow, loc_t);
270- assume loc_n is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n-> t);
271- }
272255yield procedure {:layer 2 } ReadTopOfStack#Push(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
273256preserves call TopInStack(loc_t);
274257ensures call LocInStackOrNone(loc_t, loc_n);
275- refines AtomicReadTopOfStack#Push;
258+ refines right action {:layer 3 } _ {
259+ assert Map_Contains(TreiberPoolLow, loc_t);
260+ assume loc_n is None || Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n-> t);
261+ }
276262{
277263 call loc_n := ReadTopOfStack#0 (loc_t);
278264}
279265
280- atomic action {:layer 3 } AtomicReadTopOfStack#Pop(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
266+ yield procedure {:layer 2 } ReadTopOfStack#Pop(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
267+ preserves call TopInStack(loc_t);
268+ ensures call LocInStackOrNone(loc_t, loc_n);
269+ refines atomic action {:layer 3 } _
281270{
282271 assert Map_Contains(TreiberPoolLow, loc_t);
283272 assume if loc_n is None then Map_At(TreiberPoolLow, loc_t)-> top is None else Set_Contains(Domain(TreiberPoolLow, loc_t), loc_n-> t);
284273}
285- yield procedure {:layer 2 } ReadTopOfStack#Pop(loc_t: LocTreiberStack) returns (loc_n: Option LocTreiberNode)
286- preserves call TopInStack(loc_t);
287- ensures call LocInStackOrNone(loc_t, loc_n);
288- refines AtomicReadTopOfStack#Pop;
289274{
290275 call loc_n := ReadTopOfStack#0 (loc_t);
291276}
@@ -300,7 +285,6 @@ right action {:layer 2,3} AtomicLoadNode#1(loc_t: LocTreiberStack, loc_n: LocTre
300285/// Primitives
301286
302287atomic action {:layer 1 } AtomicLoadNode#0 (loc_t: LocTreiberStack, loc_n: LocTreiberNode) returns (node: StackElem X)
303- modifies TreiberPoolLow;
304288refines AtomicLoadNode#1 ;
305289{
306290 var {:linear} one_loc_t: One LocTreiberStack;
@@ -347,14 +331,14 @@ refines atomic action {:layer 1,4} _
347331 call Map_Put(TreiberPoolLow, one_loc_t, treiber);
348332}
349333
350- yield procedure {:layer 0 } AllocNode#0 (loc_t: LocTreiberStack, {:linear_in} loc_piece : One LocTreiberNode, node: StackElem X);
334+ yield procedure {:layer 0 } AllocNode#0 (loc_t: LocTreiberStack, {:linear_in} one_loc_n : One LocTreiberNode, node: StackElem X);
351335refines atomic action {:layer 1 ,3 } _
352336{
353337 var {:linear} one_loc_t: One LocTreiberStack;
354338 var {:linear} treiber: Treiber X;
355339
356340 call one_loc_t, treiber := Map_Get(TreiberPoolLow, loc_t);
357- call Map_Put(treiber-> nodes, loc_piece , node);
341+ call Map_Put(treiber-> nodes, one_loc_n , node);
358342 call Map_Put(TreiberPoolLow, one_loc_t, treiber);
359343}
360344
0 commit comments