-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Actions and streaming standard libraries #6074
base: master
Are you sure you want to change the base?
Changes from 39 commits
31afc77
9ed2550
c7a97c7
813912f
4162f32
02ebe4b
6f7fa28
a6a245f
83fc0f3
9d71295
56776c8
d5aaabc
5395c16
1732277
a320930
9ed029a
b25c48a
38702a2
5e91c5f
d57c9ea
153a282
7f583cd
0dadc06
3482109
fb6199e
d9c5fcb
ad032b0
0184e8f
4abfd81
66cd68d
fc39970
d3902b1
b225c2b
218761b
2625b51
e634148
5a49fa2
8198531
df2a87c
241da1f
c04ba47
699a357
70831a8
988ef64
46e818a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
module ActionsExamples { | ||
import opened Std.Actions | ||
import opened Std.Enumerators | ||
import opened Std.Aggregators | ||
import opened Std.Wrappers | ||
|
||
class Box { | ||
const i: nat | ||
|
||
constructor(i: nat) | ||
reads {} | ||
ensures this.i == i | ||
{ | ||
this.i := i; | ||
} | ||
} | ||
|
||
function SeqRange(n: nat): seq<nat> { | ||
seq(n, i => i) | ||
} | ||
|
||
lemma SeqRangeIncr(prefix: seq<nat>, n: nat) | ||
requires prefix == SeqRange(n) | ||
ensures prefix + [n] == SeqRange(n + 1) | ||
{} | ||
|
||
@AssumeCrossModuleTermination | ||
class BoxEnumerator extends Action<(), Box> { | ||
|
||
var nextValue: nat | ||
|
||
ghost predicate Valid() | ||
reads this, Repr | ||
ensures Valid() ==> this in Repr | ||
ensures Valid() ==> CanProduce(history) | ||
decreases height, 0 | ||
{ | ||
&& this in Repr | ||
&& CanProduce(history) | ||
&& nextValue == |history| | ||
} | ||
|
||
constructor() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code style: |
||
ensures Valid() | ||
ensures fresh(Repr) | ||
ensures history == [] | ||
{ | ||
nextValue := 0; | ||
history := []; | ||
Repr := {this}; | ||
height := 1; | ||
} | ||
|
||
ghost predicate CanConsume(history: seq<((), Box)>, next: ()) | ||
decreases height | ||
{ | ||
true | ||
} | ||
ghost predicate CanProduce(history: seq<((), Box)>) | ||
decreases height | ||
{ | ||
Seq.Map((b: Box) => b.i, Outputs(history)) == SeqRange(|history|) | ||
} | ||
|
||
method Invoke(t: ()) returns (r: Box) | ||
requires Requires(t) | ||
reads Reads(t) | ||
modifies Modifies(t) | ||
decreases Decreases(t).Ordinal() | ||
ensures Ensures(t, r) | ||
{ | ||
assert Requires(t); | ||
ghost var producedBefore := Produced(); | ||
|
||
r := new Box(nextValue); | ||
Update(t, r); | ||
Repr := {this}; | ||
nextValue := nextValue + 1; | ||
|
||
SeqRangeIncr(Seq.Map((b: Box) => b.i, producedBefore), |producedBefore|); | ||
assert Valid(); | ||
} | ||
|
||
method RepeatUntil(t: (), stop: Box -> bool, ghost eventuallyStopsProof: ProducesTerminatedProof<(), Box>) | ||
requires Valid() | ||
requires eventuallyStopsProof.Action() == this | ||
requires eventuallyStopsProof.FixedInput() == t | ||
requires eventuallyStopsProof.StopFn() == stop | ||
requires forall i <- Consumed() :: i == t | ||
reads Repr | ||
modifies Repr | ||
decreases Repr | ||
ensures Valid() | ||
{ | ||
DefaultRepeatUntil(this, t, stop, eventuallyStopsProof); | ||
} | ||
} | ||
|
||
method {:rlimit 0} BoxEnumeratorExample() { | ||
var enum: BoxEnumerator := new BoxEnumerator(); | ||
assert |enum.Produced()| == 0; | ||
var a := enum.Invoke(()); | ||
|
||
assert enum.Produced() == [a]; | ||
assert Seq.Map((b: Box) => b.i, enum.Produced()) == SeqRange(1) == [0]; | ||
// assert a.i == 0; | ||
|
||
// var b := enum.Invoke(()); | ||
// var c := enum.Invoke(()); | ||
// var d := enum.Invoke(()); | ||
// var e := enum.Invoke(()); | ||
} | ||
|
||
method SetEnumeratorExample() { | ||
var s: set<nat> := {1, 2, 3, 4, 5}; | ||
var copy: set<nat> := {}; | ||
var e: SetEnumerator<nat> := new SetEnumerator(s); | ||
|
||
label before: | ||
for enumerated := 0 to 5 | ||
invariant e.Valid() | ||
invariant enumerated == |e.history| | ||
invariant fresh(e.Repr - old@before(e.Repr)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
{ | ||
var x := e.Invoke(()); | ||
copy := copy + {x}; | ||
} | ||
|
||
// TODO: cool enough that we can statically invoke | ||
// the enumerator the right number of times! | ||
// But now prove that copy == s! | ||
// assert |copy| == 5; | ||
// assert copy == s; | ||
} | ||
|
||
method {:rlimit 0} AggregatorExample() { | ||
var a: ArrayAggregator<nat> := new ArrayAggregator(); | ||
var _ := a.Invoke(1); | ||
var _ := a.Invoke(2); | ||
var _ := a.Invoke(3); | ||
var _ := a.Invoke(4); | ||
var _ := a.Invoke(5); | ||
var _ := a.Invoke(6); | ||
assert a.Consumed() == [1, 2, 3, 4, 5, 6]; | ||
assert a.storage.items == [1, 2, 3, 4, 5, 6]; | ||
} | ||
|
||
@AssumeCrossModuleTermination | ||
class ExamplePipeline<T> extends Pipeline<T, T> { | ||
constructor(upstream: Enumerator<T>) | ||
requires upstream.Valid() | ||
ensures Valid() | ||
{ | ||
this.upstream := upstream; | ||
var buffer := new Collector<T>(); | ||
|
||
Repr := {this} + upstream.Repr + buffer.Repr; | ||
history := []; | ||
this.buffer := buffer; | ||
this.height := upstream.height + buffer.height + 1; | ||
} | ||
|
||
method Process(u: Option<T>, a: Accumulator<T>) | ||
requires a.Valid() | ||
reads a.Repr | ||
modifies a.Repr | ||
ensures a.ValidAndDisjoint() | ||
{ | ||
assert a.Valid(); | ||
|
||
if u.Some? { | ||
a.CanConsumeAll(a.history, u.value); | ||
a.Accept(u.value); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This is the first occurrences of
CanProduce
I see, so maybe the answer to my thought will be clear to me later, but) my first impression is thatCanProduce
ought to be separate fromValid