Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 8 additions & 2 deletions docs/book/src/appendix_rust/turbo-fish.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,21 @@ let status: InfectionStatus = context.get_property(person_id);
context.set_property(other_person_id, status);
```

The generic types for querying and sampling
methods can usually be inferred by the compiler:
The generic types for querying, sampling, and entity initialization can usually
be inferred by the compiler:

```rust
// A silly example, but no turbo fish is required.
context.with_query_results(
with!(Person, Age(30), Alive(true)),
|people_set| println("{:?}", people_set)
);

let person_id = context
.add_entity(with!(Person, Age(30), Alive(true)))
.unwrap();

let population = context.query_entity_count(Person);
```

A few methods always require the user to specify the generic type when they are
Expand Down
2 changes: 1 addition & 1 deletion docs/book/src/first_model/transmission.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ accomplishes the three tasks above. A few observations:
which can have the value of `Some(PersonId)` or `None`. In this case, we use
`Person` and no property filters, which means we want to sample from the
entire population. If we wanted to, we could pass filters with the `with!` macro
(e.g., `with!(Person, Region("California"))`) The population will
(e.g., `with!(Person, Region("California"))`). The population will
never be empty, so the result will never be `None`, and so we just call
`unwrap()` on the `Some(PersonId)` value to get the `PersonId`.
- If the sampled person is not susceptible, then the only thing this function
Expand Down
13 changes: 13 additions & 0 deletions docs/book/src/migration_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,25 @@ property values. The properties must be distinct, of course, and there must be
a value for every "required" property, that is, for every (non-derived)
property that doesn't have a default value.

Public entity initialization no longer accepts naked tuples such as
`(Age(25), InfectionStatus::Infected)`. Use `with!(Person, ...)` when you want
to provide one or more property values.

Adding a new entity with just one property value:

```rust
let person_id = context.add_entity(with!(Person, Age(25))).unwrap();
```

To initialize an entity with only default values, pass the entity type directly:

```rust
let person_id = context.add_entity(Person).unwrap();
```

The same pattern applies to queries. Use `with!(Person, ...)` to filter by property values, or use `Person` when you
want to work with the entire population. Public query APIs no longer accept naked tuples such as `(Age(25),)`.

### Getting a property value for an entity

```rust
Expand Down
6 changes: 4 additions & 2 deletions examples/basic-infection/src/infection_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ mod test {
use ixa::prelude::*;

use crate::infection_manager::InfectionStatusEvent;
use crate::people::InfectionStatus;
use crate::people::{InfectionStatus, Person};

define_data_plugin!(RecoveryPlugin, usize, 0);

Expand All @@ -66,7 +66,9 @@ mod test {

let population_size = 10;
for _ in 0..population_size {
let person_id = context.add_entity((InfectionStatus::S,)).unwrap();
let person_id = context
.add_entity(with!(Person, InfectionStatus::S))
.unwrap();
context.set_property(person_id, InfectionStatus::I);
}

Expand Down
32 changes: 28 additions & 4 deletions examples/network-hhmodel/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ struct PeopleRecord {

fn create_person_from_record(context: &mut Context, record: &PeopleRecord) -> PersonId {
context
.add_entity((record.id, record.age_group, record.sex, record.household_id))
.add_entity(with!(
Person,
record.id,
record.age_group,
record.sex,
record.household_id
))
.unwrap()
}

Expand Down Expand Up @@ -94,19 +100,37 @@ mod tests {
let person = people[0];
assert!(context.match_entity(
person,
(Id(676), AgeGroup::Age18to64, Sex::Female, HouseholdId(1))
with!(
Person,
Id(676),
AgeGroup::Age18to64,
Sex::Female,
HouseholdId(1)
)
));

let person = people[246];
assert!(context.match_entity(
person,
(Id(213), AgeGroup::AgeUnder5, Sex::Female, HouseholdId(162))
with!(
Person,
Id(213),
AgeGroup::AgeUnder5,
Sex::Female,
HouseholdId(162)
)
));

let person = people[1591];
assert!(context.match_entity(
person,
(Id(1591), AgeGroup::Age65Plus, Sex::Male, HouseholdId(496))
with!(
Person,
Id(1591),
AgeGroup::Age65Plus,
Sex::Male,
HouseholdId(496)
)
));
}
}
6 changes: 3 additions & 3 deletions examples/network-hhmodel/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn create_household_networks(context: &mut Context, people: &[PersonId]) {
let household_id: HouseholdId = context.get_property(*person_id);
if households.insert(household_id) {
let mut members: Vec<PersonId> = Vec::new();
context.with_query_results((household_id,), &mut |results| {
context.with_query_results(with!(Person, household_id), &mut |results| {
members = results.to_owned_vec()
});
// create a dense network
Expand All @@ -43,13 +43,13 @@ fn load_edge_list<ET: EdgeType<Person>>(context: &mut Context, file_name: &str,
for result in reader.deserialize() {
let record: EdgeRecord = result.expect("Failed to parse edge");
let mut p1_vec = Vec::new();
context.with_query_results((Id(record.v1),), &mut |people| {
context.with_query_results(with!(Person, Id(record.v1)), &mut |people| {
p1_vec = people.to_owned_vec()
});
assert_eq!(p1_vec.len(), 1);
let p1 = p1_vec[0];
let mut p2_vec = Vec::new();
context.with_query_results((Id(record.v2),), &mut |people| {
context.with_query_results(with!(Person, Id(record.v2)), &mut |people| {
p2_vec = people.to_owned_vec()
});
assert_eq!(p2_vec.len(), 1);
Expand Down
16 changes: 9 additions & 7 deletions examples/network-hhmodel/seir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ fn calculate_waiting_time(context: &Context, shape: f64, mean_period: f64) -> f6
}

fn expose_network<ET: EdgeType<Person>>(context: &mut Context, beta: f64) {
let infectious_people = context.query((DiseaseStatus::I,)).to_owned_vec();
let infectious_people = context
.query(with!(Person, DiseaseStatus::I))
.to_owned_vec();

for infectious in infectious_people {
let edges = context.get_matching_edges::<Person, ET>(infectious, |context, edge| {
context.match_entity(edge.neighbor, (DiseaseStatus::S,))
context.match_entity(edge.neighbor, with!(Person, DiseaseStatus::S))
});

for e in edges {
Expand Down Expand Up @@ -187,7 +189,7 @@ mod tests {
network::init(&mut context, &people);

let mut to_infect = Vec::<PersonId>::new();
context.with_query_results((Id(71),), &mut |people| {
context.with_query_results(with!(Person, Id(71)), &mut |people| {
to_infect.extend(people);
});

Expand All @@ -196,19 +198,19 @@ mod tests {
context.execute();

assert_eq!(
context.query_entity_count::<Person, _>((DiseaseStatus::S,)),
context.query_entity_count::<Person, _>(with!(Person, DiseaseStatus::S)),
399
);
assert_eq!(
context.query_entity_count::<Person, _>((DiseaseStatus::E,)),
context.query_entity_count::<Person, _>(with!(Person, DiseaseStatus::E)),
0
);
assert_eq!(
context.query_entity_count::<Person, _>((DiseaseStatus::I,)),
context.query_entity_count::<Person, _>(with!(Person, DiseaseStatus::I)),
0
);
assert_eq!(
context.query_entity_count::<Person, _>((DiseaseStatus::R,)),
context.query_entity_count::<Person, _>(with!(Person, DiseaseStatus::R)),
1207
);
}
Expand Down
6 changes: 3 additions & 3 deletions integration-tests/ixa-runner-tests/bin/runner_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ define_entity!(Person);

fn main() {
run_with_args(|context, _args, _| {
let _: PersonId = context.add_entity(()).unwrap();
let _: PersonId = context.add_entity(()).unwrap();
let _: PersonId = context.add_entity(()).unwrap();
let _: PersonId = context.add_entity(Person).unwrap();
let _: PersonId = context.add_entity(Person).unwrap();
let _: PersonId = context.add_entity(Person).unwrap();

trace!("A TRACE message");
debug!("A DEBUG message");
Expand Down
7 changes: 4 additions & 3 deletions integration-tests/ixa-runner-tests/tests/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ mod tests {

// Entity properties: add a Person with TestPropU32
let pid: EntityId<Person> = ctx
.add_entity((
.add_entity(with!(
Person,
TestPropU32(10u32),
TestPropU32b(20u32),
TestPropOpt(Some(3u8)),
Expand Down Expand Up @@ -192,10 +193,10 @@ mod tests {

// Edge type (entity-based network): create two people and add an edge of type TestEdge
let p1 = ctx
.add_entity((TestPropU32(1u32), TestPropU32b(1u32)))
.add_entity(with!(Person, TestPropU32(1u32), TestPropU32b(1u32)))
.unwrap();
let p2 = ctx
.add_entity((TestPropU32(2u32), TestPropU32b(2u32)))
.add_entity(with!(Person, TestPropU32(2u32), TestPropU32b(2u32)))
.unwrap();
ctx.add_edge::<Person, TestEdge>(p1, p2, 1.0, TestEdge)
.unwrap();
Expand Down
6 changes: 4 additions & 2 deletions integration-tests/ixa-wasm-tests/src/infection_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ mod test {
use ixa::prelude::*;

use crate::infection_manager::InfectionStatusEvent;
use crate::people::InfectionStatus;
use crate::people::{InfectionStatus, Person};

define_data_plugin!(RecoveryPlugin, usize, 0);

Expand All @@ -68,7 +68,9 @@ mod test {

let population_size = 10;
for _ in 0..population_size {
let person_id = context.add_entity((InfectionStatus::S,)).unwrap();
let person_id = context
.add_entity(with!(Person, InfectionStatus::S))
.unwrap();
context.set_property(person_id, InfectionStatus::I);
}

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/ixa-wasm-tests/src/people.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ define_property!(
pub fn init(context: &mut Context) {
trace!("Initializing people");
for _ in 0..POPULATION {
let _: PersonId = context.add_entity(()).unwrap();
let _: PersonId = context.add_entity(Person).unwrap();
}
}
4 changes: 2 additions & 2 deletions integration-tests/ixa-wasm-tests/src/transmission_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ define_rng!(TransmissionRng);
fn attempt_infection(context: &mut Context) {
trace!("Attempting infection");
let population_size: usize = context.get_entity_count::<Person>();
let person_to_infect: PersonId = context.sample_entity(TransmissionRng, ()).unwrap(); //.sample_range(TransmissionRng, 0..population_size);
let person_to_infect: PersonId = context.sample_entity(TransmissionRng, Person).unwrap(); //.sample_range(TransmissionRng, 0..population_size);

let person_status: InfectionStatus = context.get_property(person_to_infect);

Expand Down Expand Up @@ -52,7 +52,7 @@ mod test {
fn test_attempt_infection() {
let mut context = Context::new();
context.init_random(SEED);
let person_id: PersonId = context.add_entity(()).unwrap();
let person_id: PersonId = context.add_entity(Person).unwrap();
attempt_infection(&mut context);
let person_status: InfectionStatus = context.get_property(person_id);
assert_eq!(person_status, InfectionStatus::I);
Expand Down
26 changes: 16 additions & 10 deletions ixa-bench/criterion/counts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ fn populate_entities(context: &mut Context, n: usize) {
context.init_random(SEED);

for person in generate_population_with_seed(n, 0.2, 10.0, Some(SEED)) {
let _ = context.add_entity((
let _ = context.add_entity(with!(
Person,
Age(person.age),
HomeId(person.home_id as u32),
SchoolId(person.school_id as u32),
Expand All @@ -59,40 +60,45 @@ pub fn criterion_benchmark(c: &mut Criterion) {
// Unindexed single property
group.bench_function("single_property_unindexed_entities", |bencher| {
bencher.iter(|| {
black_box(context.query_entity_count(black_box((HomeId(HOME_VAL),))));
black_box(context.query_entity_count(black_box(with!(Person, HomeId(HOME_VAL)))));
});
});

// Unindexed concrete + unindexed derived property
group.bench_function("concrete_plus_derived_unindexed_entities", |bencher| {
bencher.iter(|| {
black_box(context.query_entity_count(black_box((HomeId(HOME_VAL), AgeGroupFoi(1)))));
black_box(context.query_entity_count(black_box(with!(
Person,
HomeId(HOME_VAL),
AgeGroupFoi(1)
))));
});
});

// Indexed single property
context.index_property::<Person, HomeId>();
group.bench_function("single_property_indexed_entities", |bencher| {
bencher.iter(|| {
black_box(context.query_entity_count(black_box((HomeId(HOME_VAL),))));
black_box(context.query_entity_count(black_box(with!(Person, HomeId(HOME_VAL)))));
});
});

// Unindexed multi-property
group.bench_function("multi_property_unindexed_entities", |bencher| {
bencher.iter(|| {
black_box(context.query_entity_count(black_box((Age(30), SchoolId(1)))));
black_box(context.query_entity_count(black_box(with!(Person, Age(30), SchoolId(1)))));
});
});

// Indexed multi-property
context.index_property::<Person, (Age, SchoolId, WorkplaceId)>();
group.bench_function("multi_property_indexed_entities", |bencher| {
bencher.iter(|| {
black_box(context.query_entity_count(black_box((
black_box(context.query_entity_count(black_box(with!(
Person,
Age(30),
SchoolId(1),
WorkplaceId(1),
WorkplaceId(1)
))));
});
});
Expand All @@ -107,7 +113,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
},
|mut ctx| {
ctx.index_property::<Person, HomeId>();
black_box(ctx.query_entity_count(black_box((HomeId(HOME_VAL),))));
black_box(ctx.query_entity_count(black_box(with!(Person, HomeId(HOME_VAL)))));
},
);
});
Expand All @@ -119,13 +125,13 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let mut ctx = Context::new();
populate_entities(&mut ctx, 5_000);
ctx.index_property::<Person, HomeId>();
black_box(ctx.query_entity_count(black_box((HomeId(HOME_VAL),))));
black_box(ctx.query_entity_count(black_box(with!(Person, HomeId(HOME_VAL)))));
ctx
},
|mut ctx| {
populate_entities(&mut ctx, 2_000);
ctx.index_property::<Person, HomeId>();
black_box(ctx.query_entity_count(black_box((HomeId(HOME_VAL),))));
black_box(ctx.query_entity_count(black_box(with!(Person, HomeId(HOME_VAL)))));
},
);
});
Expand Down
Loading