Skip to content

Commit

Permalink
Merge pull request #13 from lsd-ucsc/projector-available-locations
Browse files Browse the repository at this point in the history
  • Loading branch information
ihaveint authored Sep 17, 2023
2 parents 8e5416f + 07730da commit f7c2c1f
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 102 deletions.
18 changes: 9 additions & 9 deletions chorus_book/src/guide-choreography.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct HelloWorldChoreography;

// 2. Implement the `Choreography` trait
impl Choreography for HelloWorldChoreography {
type L = hlist!(Alice);
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
// 3. Use the `op` parameter to access operators
op.locally(Alice, |_| {
Expand All @@ -21,7 +21,7 @@ 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 type `L`, which is the set of `ChoreographyLocation`s it can operate on. To build a set of locations, you can use the macro `hlist!`.
Also, each `Choreography` has an associated type `L`, called it's location set; this is the set of `ChoreographyLocation`s that the `Choreography` can operate on. To build a location set, you can use the macro `LocationSet!`.

## Choreographic Operators

Expand All @@ -36,7 +36,7 @@ The `locally` operator is used to perform a computation at a single location. It
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = hlist!(Alice);
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
op.locally(Alice, |_| {
println!("Hello, World!");
Expand All @@ -52,7 +52,7 @@ The closure can return a value to create a located value. Located values are val
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = hlist!(Alice);
# 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, |_| {
Expand All @@ -69,7 +69,7 @@ The computation closure takes `Unwrapper`. Using the `Unwrapper`, you can get a
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = hlist!(Alice);
# 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 @@ -90,7 +90,7 @@ Note that you can unwrap a located value only at the location where the located
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = hlist!(Alice, Bob);
# 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 });
Expand All @@ -113,7 +113,7 @@ The `comm` operator is used to perform a communication between two locations. It
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = hlist!(Alice, Bob);
# 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, |_| {
Expand All @@ -139,7 +139,7 @@ The `broadcast` operator is used to perform a broadcast from a single location t
#
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = hlist!(Alice);
# 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, |_| {
Expand Down Expand Up @@ -173,7 +173,7 @@ You'll get a compile error if you try to work with a `ChoreographyLocation` that
# // 2. Implement the `Choreography` trait
// ...
impl Choreography for HelloWorldChoreography {
type L = hlist!(Alice);
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
// this will fail
op.locally(Bob, |_| {
Expand Down
12 changes: 6 additions & 6 deletions chorus_book/src/guide-colocally.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This protocol can be implemented as follows:
struct DemoChoreography;

impl Choreography for DemoChoreography {
type L = hlist!(Alice, Bob, Carol);
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 @@ -52,7 +52,7 @@ struct BobCarolChoreography {
x_at_bob: Located<u32, Bob>,
};
impl Choreography for BobCarolChoreography {
type L = hlist!(Bob, Carol);
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);
Expand Down Expand Up @@ -81,7 +81,7 @@ Notice that `BobCarolChoreography` only describes the behavior of Bob and Carol
# x_at_bob: Located<u32, Bob>,
# };
# impl Choreography for BobCarolChoreography {
# type L = hlist!(Bob, Carol);
# 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);
Expand All @@ -99,7 +99,7 @@ Notice that `BobCarolChoreography` only describes the behavior of Bob and Carol
# }
struct MainChoreography;
impl Choreography for MainChoreography {
type L = hlist!(Alice, Bob, Carol);
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 @@ -135,7 +135,7 @@ struct BobCarolChoreography {
};

impl Choreography<BobCarolResult> for BobCarolChoreography {
type L = hlist!(Bob, Carol);
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);
Expand All @@ -159,7 +159,7 @@ impl Choreography<BobCarolResult> for BobCarolChoreography {
struct MainChoreography;

impl Choreography for MainChoreography {
type L = hlist!(Alice, Bob, Carol);
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
8 changes: 4 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,8 @@ When you implement the `Choreography` trait, you have access to the `sub_choreo`
# struct HigherOrderChoreography<C: Choreography> {
# sub_choreo: C,
# };
impl<C: Choreography<(), L = hlist!(Alice, Bob)>> Choreography for HigherOrderChoreography<C> {
type L = hlist!(Alice, Bob);
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 @@ -46,8 +46,8 @@ struct HigherOrderChoreography<C: Choreography<Located<bool, Alice>> + SubChoreo
_marker: PhantomData<C>,
};

impl<C: Choreography<Located<bool, Alice>, L = hlist!(Alice)> + SubChoreography> Choreography for HigherOrderChoreography<C> {
type L = hlist!(Alice);
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
27 changes: 14 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,7 @@ struct DemoChoreography {
}

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

let projector = projector!(LocationSet!(Alice), Alice, transport);
projector.epp_and_run(choreo);
```

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

impl Choreography for DemoChoreography {
type L = hlist!(Alice);
type L = LocationSet!(Alice);
fn run(self, op: &impl ChoreoOp<Self::L>) {
op.locally(Alice, |un| {
let input = un.unwrap(&self.input);
Expand All @@ -84,15 +85,15 @@ To run the sample choreography above at Alice, we use the `local` method to cons
# }
#
# impl Choreography for DemoChoreography {
# type L = hlist!(Alice);
# 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!(LocationSet!(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 @@ -111,15 +112,15 @@ For Bob, we use the `remote` method to construct the located value.
# }
#
# impl Choreography for DemoChoreography {
# type L = hlist!(Alice);
# 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!(LocationSet!(Alice, 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 @@ -140,7 +141,7 @@ To do so, we specify the output type to the `Choreography` trait and return the
struct DemoChoreography;

impl Choreography<String> for DemoChoreography {
type L = hlist!();
type L = LocationSet!();
fn run(self, op: &impl ChoreoOp<Self::L>) -> String {
"Hello, World!".to_string()
}
Expand All @@ -154,13 +155,13 @@ impl Choreography<String> for DemoChoreography {
# struct DemoChoreography;
#
# impl Choreography<String> for DemoChoreography {
# type L = hlist!(Alice);
# 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!(LocationSet!(Alice), Alice, transport);
let output = projector.epp_and_run(choreo);
assert_eq!(output, "Hello, World!".to_string());
```
Expand All @@ -174,15 +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 {
type L = hlist!(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!(LocationSet!(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
2 changes: 1 addition & 1 deletion chorus_book/src/guide-location-polymorphism.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct LocationPolymorphicChoreography<L1: ChoreographyLocation> {
}

impl<L1: ChoreographyLocation> Choreography for LocationPolymorphicChoreography<L1> {
type L = hlist!(L1);
type L = LocationSet!(L1);
fn run(self, op: &impl ChoreoOp<Self::L>) {
op.locally(self.location, |_| {
println!("Hello, World!");
Expand Down
41 changes: 35 additions & 6 deletions chorus_book/src/guide-projector.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ Projector is responsible for performing the end-point projection and executing t

## Creating a Projector

To create a `Projector`, you need to provide the location and the transport.
To create a `Projector`, you need to provide the set of locations it can work with, the target location, and the transport. You should use the `projector!` macro instead of directly instantiating a Projector.

```rust
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use chorus_lib::core::{ChoreographyLocation, Projector};
# use chorus_lib::{LocationSet, projector};
# let transport = LocalTransport::from(&[Alice::name(), Bob::name()]);
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
# struct Bob;
#
let projector = Projector::new(Alice, transport);

let projector = projector!(LocationSet!(Alice, Bob), Alice, transport);
```

Notice that the `Projector` is parameterized by the location type. You will need one projector for each location to execute choreography.
Notice that the `Projector` is parameterized by its target location type. You will need one projector for each location to execute choreography.

## Executing a Choreography

Expand All @@ -28,21 +30,48 @@ To execute a choreography, you need to call the `epp_and_run` method on the `Pro
```rust
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use chorus_lib::core::{ChoreographyLocation, Projector, Choreography, ChoreoOp, HNil};
# use chorus_lib::core::{ChoreographyLocation, Projector, Choreography, ChoreoOp};
# use chorus_lib::{LocationSet, projector};
# let transport = LocalTransport::from(&[Alice::name(), Bob::name()]);
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
# struct Bob;
# struct HelloWorldChoreography;
# impl Choreography for HelloWorldChoreography {
# type L = HNil;
# type L = LocationSet!(Alice);
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# }
# }
#
# let projector = Projector::new(Alice, transport);

# let projector = projector!(LocationSet!(Alice), Alice, transport);
projector.epp_and_run(HelloWorldChoreography);
```

If the choreography has a return value, the `epp_and_run` method will return the value. We will discuss the return values in the [Input and Output](./guide-input-and-output.md) section.

### Note on the location set of the Choreography

Keep in mind that when calling `epp_and_run`, you will get a compile error if the location set of the `Choreography` is not a subset of the location set of the `Projector`. In other words, the `Projector` should be allowed to do end-point projection into every `ChoreographyLocation` that `Choreography` can talk about. So this will fail:

```rust, compile_fail
# extern crate chorus_lib;
# use chorus_lib::transport::local::LocalTransport;
# use chorus_lib::core::{ChoreographyLocation, Projector, Choreography, ChoreoOp};
# use chorus_lib::{LocationSet, projector};
# let transport = LocalTransport::from(&[Alice::name(), Bob::name()]);
# #[derive(ChoreographyLocation)]
# struct Alice;
# #[derive(ChoreographyLocation)]
# struct Bob;
struct HelloWorldChoreography;
impl Choreography for HelloWorldChoreography {
type L = LocationSet!(Alice, Bob);
fn run(self, op: &impl ChoreoOp<Self::L>) {
}
}
let projector = projector!(LocationSet!(Alice), Alice, transport);
projector.epp_and_run(HelloWorldChoreography);
```
4 changes: 2 additions & 2 deletions chorus_book/src/guide-runner.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To use `Runner`, construct an instance using the `new` constructor, and then cal
{{#include ./header.txt}}
# struct DemoChoreography;
# impl Choreography for DemoChoreography {
# type L = hlist!();
# type L = LocationSet!();
# fn run(self, op: &impl ChoreoOp<Self::L>) {
# }
# }
Expand All @@ -27,7 +27,7 @@ struct SumChoreography {
y_at_bob: Located<u32, Bob>,
}
impl Choreography<Located<u32, Carol>> for SumChoreography {
type L = hlist!(Alice, Bob, Carol);
type L = LocationSet!(Alice, Bob, Carol);
fn run(self, op: &impl ChoreoOp<Self::L>) -> Located<u32, Carol> {
let x_at_carol = op.comm(Alice, Carol, &self.x_at_alice);
let y_at_carol = op.comm(Bob, Carol, &self.y_at_bob);
Expand Down
Loading

0 comments on commit f7c2c1f

Please sign in to comment.