Skip to content
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

Draft
wants to merge 45 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
31afc77
Just Action trait (doesn’t verify yet)
robin-aws May 20, 2024
9ed2550
Use DynamicArray in ArrayAggregator
robin-aws Jun 8, 2024
c7a97c7
Fix verification
robin-aws Jun 9, 2024
813912f
Another type characteristic requirement bites the dust
robin-aws Jun 9, 2024
4162f32
—function-syntax
robin-aws Jun 10, 2024
02ebe4b
More function-syntax
robin-aws Jun 10, 2024
6f7fa28
Sketching out Enumerable<T> trait
robin-aws Jul 4, 2024
a6a245f
Merge branch 'master' of github.com:dafny-lang/dafny into actions-and…
robin-aws Nov 5, 2024
83fc0f3
Fresh snapshot
robin-aws Nov 5, 2024
9d71295
Fixed loop
robin-aws Nov 5, 2024
56776c8
Very cool SetEnumerator example
robin-aws Nov 5, 2024
d5aaabc
Tweaks
robin-aws Nov 5, 2024
5395c16
Aggregators and Enumerators mostly verifying
robin-aws Nov 6, 2024
1732277
ProducesSetProof
robin-aws Nov 7, 2024
a320930
Disable verification in a few places for now
robin-aws Nov 9, 2024
9ed029a
Another one
robin-aws Nov 22, 2024
b25c48a
Lift some common things up
robin-aws Nov 28, 2024
38702a2
Missing postconditions
robin-aws Nov 29, 2024
5e91c5f
Comment
robin-aws Nov 29, 2024
d57c9ea
Missing ghost
robin-aws Dec 11, 2024
153a282
Commenting out some code that doesn't work for Rust
robin-aws Dec 19, 2024
7f583cd
Merge branch 'master' of github.com:dafny-lang/dafny into actions-and…
robin-aws Jan 7, 2025
0dadc06
Add streams as well
robin-aws Jan 9, 2025
3482109
Fix names
robin-aws Jan 10, 2025
fb6199e
Merge branch 'master' of github.com:dafny-lang/dafny into actions-and…
robin-aws Jan 13, 2025
d9c5fcb
Fix verification after CanCall change
robin-aws Jan 13, 2025
ad032b0
Uncomment Folder
robin-aws Jan 13, 2025
0184e8f
CanCall fixes
robin-aws Jan 13, 2025
4abfd81
One more
robin-aws Jan 20, 2025
66cd68d
Typo
robin-aws Jan 20, 2025
fc39970
Progress
robin-aws Jan 21, 2025
d3902b1
Restoring code that doesn’t build for Rust yet
robin-aws Jan 22, 2025
b225c2b
Merge branch 'actions-and-streaming-stdlibs' of github.com:dafny-lang…
robin-aws Jan 22, 2025
218761b
Remove termination false, more axioms for now
robin-aws Jan 24, 2025
2625b51
Partial documentation
robin-aws Jan 24, 2025
e634148
update binaries
robin-aws Jan 24, 2025
5a49fa2
Formatting
robin-aws Jan 24, 2025
8198531
More comments
robin-aws Jan 24, 2025
df2a87c
Extract examples
robin-aws Jan 24, 2025
241da1f
Comment
robin-aws Jan 30, 2025
c04ba47
rename Folder
robin-aws Feb 6, 2025
699a357
More comments
robin-aws Feb 8, 2025
70831a8
Axiom for now to work on 4.9.1
robin-aws Feb 8, 2025
988ef64
Merge branch 'actions-and-streaming-stdlibs' of github.com:dafny-lang…
robin-aws Feb 19, 2025
46e818a
Remove Frames and Examples from top-level namespace
robin-aws Feb 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Source/DafnyStandardLibraries/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ When using this option with commands like `dafny translate`, `dafny build`, or `
the contents of the standard libraries will be automatically included in the translated source code as well.
This causes conflicts when multiple such translated projects are combined. When combining such projects, please ensure that only one of them has `--translate-standard-library` set to true.

To combine multiple Dafny projects that were separately built, and were

Some libraries are dependent on target language utilities, such as `FileIO`.
When `--standard-libraries` is on,
the translation process will also include some additional supporting target language source files,
Expand All @@ -47,13 +45,15 @@ In particular, `--standard-libraries` currently cannot be used together with `--

The sections below describe how to use each library:

- [Std.Actions](src/Std/Actions/README.md) -- utilities for abstract imperative actions, including enumerating and streaming values
- [Std.Arithmetic](src/Std/Arithmetic/README.md) -- utilities and lemmas related to basic operations, such as multiplication and exponentiation
- [Std.Base64](src/Std/Base64.md) -- base-64 encoding and decoding
- [Std.BoundedInts](src/Std/BoundedInts.md) -- definitions of types and constants for fixed-bit-width integers
- [Std.Collections](src/Std/Collections/Collections.md) -- properties of the built-in collection types (seq, set, iset, map, imap, array)
- [Std.Concurrent](src/Std/TargetSpecific) -- types for using Dafny in concurrent environments
- [Std.DynamicArray](src/Std/DynamicArray.dfy) -- an array that can grow and shrink
- [Std.FileIO](src/Std/TargetSpecific) -- basic file I/O operations
- [Std.Frames](src/Std/Frames.md) -- utilities related to working with dynamic framing, often related to reads and modifies clauses
- [Std.Functions](src/Std/Functions.md) -- properties of functions
- [Std.JSON](src/Std/JSON/JSON.md) -- JSON serialization and deserialization
- [Std.Math](src/Std/Math.md) -- common mathematical functions, such as Min and Abs
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
177 changes: 177 additions & 0 deletions Source/DafnyStandardLibraries/examples/Actions/ActionsExamples.dfy
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)
Copy link
Collaborator

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 that CanProduce ought to be separate from Valid

decreases height, 0
{
&& this in Repr
&& CanProduce(history)
&& nextValue == |history|
}

constructor()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code style: constructor() looks like JavaScript to me. I would have written it with a space before the (), just like a named constructor constructor Init() but with an empty-string name.

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))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is old@before(e.Repr) all fresh as well? If so, you could just write fresh(e.Repr).

{
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);
}
}
}
}
Loading
Loading