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

Type-Level Location Set #12

Merged
merged 82 commits into from
Oct 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
545b4ea
encode locations as HList
shumbo Aug 17, 2023
b9518ad
add location polymorphism example
shumbo Aug 22, 2023
cd7ac29
add `Equal` trait, correct signature for `call`
shumbo Aug 31, 2023
ae97f02
update location polymorphic example
shumbo Aug 31, 2023
1a83cf8
Remove Equal trait
ihaveint Sep 14, 2023
e2cab46
Update examples
ihaveint Sep 14, 2023
3548b47
Update book
ihaveint Sep 14, 2023
e9b0cf4
Fix some formatting issues
ihaveint Sep 15, 2023
c94b725
Add subset requirement for call method
ihaveint Sep 16, 2023
1830bb9
Fix examples of higher order choreography
ihaveint Sep 16, 2023
d5054f4
Update choreography guide
ihaveint Sep 16, 2023
d239c35
Use name as an associated function instead of method
ihaveint Sep 16, 2023
0d40d18
Use hlist!() instead of HNil
ihaveint Sep 16, 2023
8aacea5
Merge pull request #10 from lsd-ucsc/available-locations-docs
shumbo Sep 16, 2023
cd3a288
rewrite colocally document
shumbo Sep 16, 2023
8e5416f
fix warnings
shumbo Sep 16, 2023
6f4b913
Add available-locations to Projector
ihaveint Sep 16, 2023
66fd891
Update the book to use available locations for Projector
ihaveint Sep 16, 2023
a2696b5
Format code
ihaveint Sep 16, 2023
ee676e5
Remove old comment
ihaveint Sep 16, 2023
fbc4cab
Make the set of available-locations of Choreography be a subset of th…
ihaveint Sep 16, 2023
2f49ded
Use a macro (projector) to instantiate Projectors
ihaveint Sep 16, 2023
0df1edc
Update the book to use the new projector macro
ihaveint Sep 16, 2023
a18ee92
Format code
ihaveint Sep 16, 2023
03262ea
Update the book for Projector
ihaveint Sep 16, 2023
11d74a1
Change the the wording from available locations to location set
ihaveint Sep 16, 2023
07730da
Update projector guide
ihaveint Sep 17, 2023
f7c2c1f
Merge pull request #13 from lsd-ucsc/projector-available-locations
ihaveint Sep 17, 2023
2bd32d5
Add location-set as a generic type to Transport
ihaveint Sep 18, 2023
24ad199
Change the book examples. The text itself still needs to be updated
ihaveint Sep 18, 2023
3fee760
Update the book
ihaveint Sep 18, 2023
140e431
Refactor HttpConfig
ihaveint Sep 18, 2023
f992cf0
Fix import for PhantomData
ihaveint Sep 18, 2023
c4feb9c
Simplify User-API for building TransportConfig
ihaveint Sep 19, 2023
642b971
WIP: program doesn't terminate
ihaveint Sep 19, 2023
e486a7d
WIP: the library tests work
ihaveint Sep 19, 2023
5df2e94
Simplify things a bit
ihaveint Sep 19, 2023
d7e593c
Remove redundant target-location argument
ihaveint Sep 19, 2023
d835717
Fix some warnings and remove an extra layer of Arc
ihaveint Sep 19, 2023
65096dd
Use Equal trait instead of assuming equality of the location sets
ihaveint Sep 19, 2023
9db4537
Update examples
ihaveint Sep 19, 2023
1f42d17
Remove the TransportChannel from HttpTransport
ihaveint Sep 19, 2023
1739b1b
Move TransportChannel to LocalTransport and rename it to LocalTranspo…
ihaveint Sep 19, 2023
07f5021
Update examples and the book
ihaveint Sep 19, 2023
5bf932a
Merge pull request #15 from lsd-ucsc/target-specific-info
ihaveint Sep 20, 2023
ab005b2
Use std::marker::PhantomData instead of core::marker::PhantomData
ihaveint Sep 20, 2023
9c99e5c
Change some imports
ihaveint Sep 20, 2023
0b91d60
Change the API for building a TransportConfig; now we use builder pat…
ihaveint Sep 21, 2023
62f4a59
Change the examples and the book to reflect the new API
ihaveint Sep 21, 2023
b5dfba0
Remove a bunch of unnecessary Arcs
ihaveint Sep 21, 2023
2b379cd
Update the guide for Transport
ihaveint Sep 21, 2023
2597d37
Remove some empty spaces in the book
ihaveint Sep 21, 2023
f0b8461
Remove redundant comments
ihaveint Sep 21, 2023
83a5212
Change the API so that we have a builder pattern for LocalTransportCh…
ihaveint Sep 28, 2023
6509a2c
Merge pull request #14 from lsd-ucsc/transport-location-set
shumbo Sep 30, 2023
3542ebb
export `LocationSet` under the `core` module
shumbo Sep 30, 2023
be86cb3
hide internal structures from the documentation
shumbo Sep 30, 2023
feb84a2
fix docs
shumbo Sep 30, 2023
8c02c24
update comments in `hello.rs`
shumbo Oct 1, 2023
34e44dd
LocalTransportChannelBuilder
shumbo Oct 1, 2023
e75b8f1
refactor `TransportConfig` with a separate builder struct
shumbo Oct 1, 2023
cc6eed1
fix test
shumbo Oct 1, 2023
0c419a5
public fields on `TransportConfig`
shumbo Oct 1, 2023
59bbab4
fix failing example
shumbo Oct 2, 2023
de87e46
remove unnecessary comment
shumbo Oct 2, 2023
1a0f0e1
remove more unnecessary comments
shumbo Oct 2, 2023
5c90775
adjust comment
shumbo Oct 2, 2023
d4f96a4
remove underscore for better hints
shumbo Oct 2, 2023
4663697
fix import path
shumbo Oct 2, 2023
e499079
Merge pull request #16 from lsd-ucsc/available-locations-tweaks
shumbo Oct 2, 2023
0de1a30
rename HList into `LocationSet`
shumbo Oct 3, 2023
8f8f81a
Merge pull request #18 from lsd-ucsc/call-hlist-location-set
shumbo Oct 3, 2023
68ca499
improve inlay hint
shumbo Oct 4, 2023
8ff0269
Add a section for LocationSet in the book
ihaveint Oct 5, 2023
8868303
Change the documentation for custom transports
ihaveint Oct 5, 2023
fc1b4cd
Remove unnecessary informations about LocationSet
ihaveint Oct 6, 2023
23b6079
Update chorus_book/src/guide-locations.md
ihaveint Oct 6, 2023
2ba79a3
Add a note on how to build a LocationSet using the LocationSet macro
ihaveint Oct 6, 2023
c2f4ebb
Merge pull request #21 from lsd-ucsc/improved-doc
shumbo Oct 6, 2023
9b57b3c
bump version to 0.2.0
shumbo Oct 6, 2023
dbfe6f2
update chorus_derive version
shumbo Oct 7, 2023
897104c
review the use of `String` and switch to `&str` when possible (#22)
shumbo Oct 7, 2023
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
members = ["chorus_lib", "chorus_derive"]

[workspace.package]
version = "0.1.3"
version = "0.2.0"
edition = "2021"
authors = ["Shun Kashiwa <[email protected]>"]
homepage = "https://lsd-ucsc.github.io/ChoRus/"
Expand Down
50 changes: 41 additions & 9 deletions chorus_book/src/guide-choreography.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ struct HelloWorldChoreography;

// 2. Implement the `Choreography` trait
impl Choreography for HelloWorldChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
// 3. Use the `op` parameter to access operators
op.locally(Alice, |_| {
println!("Hello, World!");
Expand All @@ -20,6 +21,8 @@ impl Choreography for HelloWorldChoreography {

`Choreography` must implement the `run` method which defines the behavior of the system. The `run` method takes a reference to an object that implements the `ChoreoOp` trait. The `ChoreoOp` trait provides choreographic operators such as `locally` and `comm`.

Also, each `Choreography` has an associated `LocationSet` type, `L`; this is the `LocationSet` that the `Choreography` can operate on.

## Choreographic Operators

Inside the `run` method, you can use the `op` parameter to access choreographic operators.
Expand All @@ -33,7 +36,8 @@ The `locally` operator is used to perform a computation at a single location. It
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
op.locally(Alice, |_| {
println!("Hello, World!");
});
Expand All @@ -48,7 +52,8 @@ The closure can return a value to create a located value. Located values are val
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
// This value is only available at Alice
let num_at_alice: Located<i32, Alice> = op.locally(Alice, |_| {
42
Expand All @@ -64,7 +69,8 @@ The computation closure takes `Unwrapper`. Using the `Unwrapper`, you can get a
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
let num_at_alice: Located<i32, Alice> = op.locally(Alice, |_| {
42
});
Expand All @@ -79,12 +85,13 @@ op.locally(Alice, |un| {

Note that you can unwrap a located value only at the location where the located value is available. If you try to unwrap a located value at a different location, the program will fail to compile.

```rust,compile_fail
```rust, compile_fail
{{#include ./header.txt}}
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice, Bob);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
// This code will fail to compile
let num_at_alice = op.locally(Alice, |_| { 42 });
op.locally(Bob, |un| {
Expand All @@ -106,7 +113,8 @@ The `comm` operator is used to perform a communication between two locations. It
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice, Bob);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
// This value is only available at Alice
let num_at_alice: Located<i32, Alice> = op.locally(Alice, |_| {
42
Expand All @@ -131,7 +139,8 @@ The `broadcast` operator is used to perform a broadcast from a single location t
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
// This value is only available at Alice
let num_at_alice: Located<i32, Alice> = op.locally(Alice, |_| {
42
Expand All @@ -144,10 +153,33 @@ let num: i32 = op.broadcast(Alice, num_at_alice);

Because all locations receive the value, the return type of the `broadcast` operator is a normal value, not a located value. This means that the value can be used for control flow.

```rust,ignore
```rust, ignore
if num == 42 {
println!("The number is 42!");
} else {
println!("The number is not 42!");
}
```

### Note on invalid values for Choreography::L

You'll get a compile error if you try to work with a `ChoreographyLocation` that is not a member of `L`.

```rust, compile_fail
# {{#include ./header.txt}}
# // 1. Define a struct
# struct HelloWorldChoreography;

# // 2. Implement the `Choreography` trait
// ...
impl Choreography for HelloWorldChoreography {
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
// this will fail
op.locally(Bob, |_| {
println!("Hello, World!");
});
}
}
```

24 changes: 15 additions & 9 deletions chorus_book/src/guide-colocally.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ This protocol can be implemented as follows:
struct DemoChoreography;

impl Choreography for DemoChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(Alice, Bob, Carol);
fn run(self, op: &impl ChoreoOp<Self::L>) {
let x_at_alice = op.locally(Alice, |_| {
get_random_number()
});
Expand Down Expand Up @@ -51,7 +52,8 @@ struct BobCarolChoreography {
x_at_bob: Located<u32, Bob>,
};
impl Choreography for BobCarolChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(Bob, Carol);
fn run(self, op: &impl ChoreoOp<Self::L>) {
let is_even_at_bob: Located<bool, Bob> = op.locally(Bob, |un| {
let x = un.unwrap(&self.x_at_bob);
x % 2 == 0
Expand All @@ -68,7 +70,7 @@ impl Choreography for BobCarolChoreography {
}
```

Notice that the `BobCarolChoreography` only describes the behavior of Bob and Carol. Since Alice does not appear in this choreography, we can use the `colocally` operator in the main choreography to execute the sub-choreography only on Bob and Carol.
Notice that `BobCarolChoreography` only describes the behavior of Bob and Carol (see its location set `L`). `colocally` is an operator to execute a choreography only at locations that is included in the location set. In this case, if we invoke `BobCarolChoreography` with `colocally` in the main choreography, it will only be executed at Bob and Carol and not at Alice.

```rust
{{#include ./header.txt}}
Expand All @@ -79,7 +81,8 @@ Notice that the `BobCarolChoreography` only describes the behavior of Bob and Ca
# x_at_bob: Located<u32, Bob>,
# };
# impl Choreography for BobCarolChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Bob, Carol);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# let is_even_at_bob: Located<bool, Bob> = op.locally(Bob, |un| {
# let x = un.unwrap(&self.x_at_bob);
# x % 2 == 0
Expand All @@ -96,12 +99,13 @@ Notice that the `BobCarolChoreography` only describes the behavior of Bob and Ca
# }
struct MainChoreography;
impl Choreography for MainChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(Alice, Bob, Carol);
fn run(self, op: &impl ChoreoOp<Self::L>) {
let x_at_alice = op.locally(Alice, |_| {
get_random_number()
});
let x_at_bob = op.comm(Alice, Bob, &x_at_alice);
op.colocally(&[Bob.name(), Carol.name()], BobCarolChoreography {
op.colocally(BobCarolChoreography {
x_at_bob,
});
}
Expand Down Expand Up @@ -131,7 +135,8 @@ struct BobCarolChoreography {
};

impl Choreography<BobCarolResult> for BobCarolChoreography {
fn run(self, op: &impl ChoreoOp) -> BobCarolResult {
type L = LocationSet!(Bob, Carol);
fn run(self, op: &impl ChoreoOp<Self::L>) -> BobCarolResult {
let is_even_at_bob: Located<bool, Bob> = op.locally(Bob, |un| {
let x = un.unwrap(&self.x_at_bob);
x % 2 == 0
Expand All @@ -154,15 +159,16 @@ impl Choreography<BobCarolResult> for BobCarolChoreography {
struct MainChoreography;

impl Choreography for MainChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(Alice, Bob, Carol);
fn run(self, op: &impl ChoreoOp<Self::L>) {
let x_at_alice = op.locally(Alice, |_| {
get_random_number()
});
let x_at_bob = op.comm(Alice, Bob, &x_at_alice);
let BobCarolResult {
is_even_at_bob,
is_even_at_carol,
} = op.colocally(&[Bob.name(), Carol.name()], BobCarolChoreography {
} = op.colocally(BobCarolChoreography {
x_at_bob,
});
// can access is_even_at_bob and is_even_at_carol using `locally` on Bob and Carol
Expand Down
10 changes: 6 additions & 4 deletions chorus_book/src/guide-higher-order-choreography.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ When you implement the `Choreography` trait, you have access to the `sub_choreo`
# struct HigherOrderChoreography<C: Choreography> {
# sub_choreo: C,
# };
impl<C: Choreography> Choreography for HigherOrderChoreography<C> {
fn run(self, op: &impl ChoreoOp) {
impl<C: Choreography<(), L = LocationSet!(Alice, Bob)>> Choreography for HigherOrderChoreography<C> {
type L = LocationSet!(Alice, Bob);
fn run(self, op: &impl ChoreoOp<Self::L>) {
op.call(self.sub_choreo);
}
}
Expand All @@ -45,8 +46,9 @@ struct HigherOrderChoreography<C: Choreography<Located<bool, Alice>> + SubChoreo
_marker: PhantomData<C>,
};

impl<C: Choreography<Located<bool, Alice>> + SubChoreography> Choreography for HigherOrderChoreography<C> {
fn run(self, op: &impl ChoreoOp) {
impl<C: Choreography<Located<bool, Alice>, L = LocationSet!(Alice)> + SubChoreography> Choreography for HigherOrderChoreography<C> {
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
let num_at_alice = op.locally(Alice, |_| {
42
});
Expand Down
35 changes: 22 additions & 13 deletions chorus_book/src/guide-input-and-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ struct DemoChoreography {
}

impl Choreography for DemoChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!();
fn run(self, op: &impl ChoreoOp<Self::L>) {
println!("Input: {}", self.input);
}
}
Expand All @@ -32,15 +33,17 @@ You can construct an instance of the choreography with the input and pass it to
# input: String,
# }
# impl Choreography for DemoChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# println!("Input: {}", self.input);
# }
# }
#
let choreo = DemoChoreography {
input: "World".to_string(),
};
let projector = Projector::new(Alice, transport);

let projector = Projector::new(Alice, alice_transport);
projector.epp_and_run(choreo);
```

Expand All @@ -55,7 +58,8 @@ struct DemoChoreography {
}

impl Choreography for DemoChoreography {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
op.locally(Alice, |un| {
let input = un.unwrap(&self.input);
println!("Input at Alice: {}", input);
Expand All @@ -81,14 +85,15 @@ To run the sample choreography above at Alice, we use the `local` method to cons
# }
#
# impl Choreography for DemoChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# op.locally(Alice, |un| {
# let input = un.unwrap(&self.input);
# println!("Input at Alice: {}", input);
# });
# }
# }
let projector_for_alice = Projector::new(Alice, transport);
let projector_for_alice = Projector::new(Alice, alice_transport);
// Because the target of the projector is Alice, the located value is available at Alice.
let string_at_alice: Located<String, Alice> = projector_for_alice.local("Hello, World!".to_string());
// Instantiate the choreography with the located value
Expand All @@ -107,14 +112,15 @@ For Bob, we use the `remote` method to construct the located value.
# }
#
# impl Choreography for DemoChoreography {
# fn run(self, op: &impl ChoreoOp) {
# type L = LocationSet!(Alice, Bob);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# op.locally(Alice, |un| {
# let input = un.unwrap(&self.input);
# println!("Input at Alice: {}", input);
# });
# }
# }
let projector_for_bob = Projector::new(Bob, transport);
let projector_for_bob = Projector::new(Bob, bob_transport);
// Construct a remote located value at Alice. The actual value is not required.
let string_at_alice = projector_for_bob.remote(Alice);
// Instantiate the choreography with the located value
Expand All @@ -135,7 +141,8 @@ To do so, we specify the output type to the `Choreography` trait and return the
struct DemoChoreography;

impl Choreography<String> for DemoChoreography {
fn run(self, op: &impl ChoreoOp) -> String {
type L = LocationSet!();
fn run(self, op: &impl ChoreoOp<Self::L>) -> String {
"Hello, World!".to_string()
}
}
Expand All @@ -148,12 +155,13 @@ impl Choreography<String> for DemoChoreography {
# struct DemoChoreography;
#
# impl Choreography<String> for DemoChoreography {
# fn run(self, op: &impl ChoreoOp) -> String {
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) -> String {
# "Hello, World!".to_string()
# }
# }
let choreo = DemoChoreography;
let projector = Projector::new(Alice, transport);
let projector = Projector::new(Alice, alice_transport);
let output = projector.epp_and_run(choreo);
assert_eq!(output, "Hello, World!".to_string());
```
Expand All @@ -167,14 +175,15 @@ You can use the `Located<V, L1>` as a return type of the `run` method to return
struct DemoChoreography;

impl Choreography<Located<String, Alice>> for DemoChoreography {
fn run(self, op: &impl ChoreoOp) -> Located<String, Alice> {
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) -> Located<String, Alice> {
op.locally(Alice, |_| {
"Hello, World!".to_string()
})
}
}

let projector = Projector::new(Alice, transport);
let projector = Projector::new(Alice, alice_transport);
let output = projector.epp_and_run(DemoChoreography);
let string_at_alice = projector.unwrap(output);
assert_eq!(string_at_alice, "Hello, World!".to_string());
Expand Down
3 changes: 2 additions & 1 deletion chorus_book/src/guide-location-polymorphism.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ struct LocationPolymorphicChoreography<L1: ChoreographyLocation> {
}

impl<L1: ChoreographyLocation> Choreography for LocationPolymorphicChoreography<L1> {
fn run(self, op: &impl ChoreoOp) {
type L = LocationSet!(L1);
fn run(self, op: &impl ChoreoOp<Self::L>) {
op.locally(self.location, |_| {
println!("Hello, World!");
});
Expand Down
19 changes: 18 additions & 1 deletion chorus_book/src/guide-locations.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ The `ChoreographyLocation` trait provides the `name` method, which returns the n
# #[derive(ChoreographyLocation)]
# struct Bob;
#
let name = Alice.name();
let name = Alice::name();
assert_eq!(name, "Alice");
```

## Location Set

A `LocationSet` is a special type representing a set of `ChoreographyLocation` types. It's used to ensure type safety within the system, and you'll see its application in future sections. To build a `LocationSet` type, you can use the `LocationSet` macro from the `chorus_lib` crate.

```rust
# extern crate chorus_lib;
# use chorus_lib::core::ChoreographyLocation;
# #[derive(ChoreographyLocation)]
# struct Alice;
#
# #[derive(ChoreographyLocation)]
# struct Bob;
use chorus_lib::core::LocationSet;

type L = LocationSet!(Alice, Bob);
```
Loading
Loading