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

Intervention manager skeleton and facemask example #31

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

KOVALW
Copy link
Collaborator

@KOVALW KOVALW commented Dec 17, 2024

Currently out of date overview, see comment below and documentation here. Keeping for record purposes

Intervention skeleton

This PR introduces a generalized intervention manager that maps an intentionally ambiguous intervention type to an effect on relative transmission. The intervention manager has a register function and a query function to accomplish this. The InterventionPlugin uses a nested HashMap to relate infectious status to the intervention - relative transmission effect, and thus query can obtain both the relative risk of Susceptible individuals and the relative infectiousness of Infectious individuals. The register function therefore requires an InfectiousStatus to properly register the relative transmission, defaulting to 1.0 if not specified by the user.

Other changes

Transmission success is now no longer guaranteed; success depends on the additive effects of relative risk and infectiousness of the contact and transmitter involved in the infection attempt. During infection attempts we take a uniform draw and consider the attempt a success if the draw is less than the aggregate relative transmission.

Facemask intervention example

This manager is an example of defining an enum intervention type and registering it using the intervention manager. The facemask manager assigns each person a status of Wearing, at a rate defined in the parameters input, or None. Included in the tests of the facemask manager are some experiments to test that the epidemic size in a population of 500 is approximately what we would expect from the effective $R_0$ generated by the intrinsic rate of reproduction and the impact of facemasks.

Next steps

  • The intervention manager will need to be extended to allow the manager to query for infection attempts that are impacted by contact rate modifying interventions, not just infection success modifying interventions. This would preferably be done in a way that allows us to use the same query function, but accepting a boolean transmission attempt effect (contact or transmission success) that modifies a different function.
  • The tests in the facemask example will need to be safeguarded against changes to the transmission manager, meaning that user-specified functions will need to allow for the current implementation.
  • Facemask manager will likely need to read in a CSV of relative transmission effects rather than leaving them to be hard-coded.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Before going into a more in-depth review of the code, I have some comments about the description. Mainly, I think we should plan to incorporate facemasks based the isolation guidance instead of randomly assigning them to people at the beginning of the simulation. This means that we need to think of how to incorporate masking under previous and updated isolation guidance, which is triggered by exiting isolation after symptoms.

Perhaps the important piece for us to figure out with this PR is the intervention manager and how we are going to figure out multiple interventions happening at the same time. In that case, assigning facemasks at random could be a particular case for a test or something like that?

@KOVALW
Copy link
Collaborator Author

KOVALW commented Jan 7, 2025

Overview

Updated docs to reflect desired API (infection.md) along with skeleton code (transmission_modifiers.rs). All of the detailed description of implementation lives in the infection.md.

Facemasks as an instance of transmission modifiers can be put in once feedback is received on current skeleton, tests are made for transmission_modifiers.rs, and the hook to transmission_manager through evaluate_transmission is created.

Open concerns

  • Are transmission modifier or intervention the terms we want to use? Current naming is a mix of InterventionContainer (with inner components of the data container following that naming convention, such as intervention_map) and ContextTransmissionModifierExt (with some functions and the documentation referring to relative transmission potential modifications). I would propose one of the following three terminologies be used, but I'm willing to hear other options
  1. Transmission Modifier (TransmissionModifierContainer, modifier_map, ContextTransmissionModifierExt, transmission_modifier.rs)
  2. Intervention Modifier (InterventionContainer, intervention_map, ContextInterventionExt, intervention_modifier.rs)
  3. Infection Attempt Manager (InfectionAttemptContainer, infection_attempt_map, ContextInfectionAttemptExt, infection_attempt_manager.rs)
  • The instance_map currently throws a mismatched type error that doesn't allow a closure to be placed where the intervention_map expects an InterventionFn
  • Related is that a default analogous to that supplied for the aggregator should be supplied for the intervention_map function. The implementation will have to be different due to the call in compute_intervention.

@KOVALW KOVALW requested a review from jasonasher January 7, 2025 19:14
Copy link
Collaborator

@ChiragKumar9 ChiragKumar9 left a comment

Choose a reason for hiding this comment

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

Partial review on the design doc. Will review code tomorrow.

if context.get_person_property(contact_id, InfectiousStatus)
== InfectiousStatusType::Susceptible
{
let relative_transmission = query_modifiers(&context, transmitter_id, contact_id)
Copy link
Collaborator

@ChiragKumar9 ChiragKumar9 Jan 10, 2025

Choose a reason for hiding this comment

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

You haven't yet introduced your transmission_modifiers API (and, let's please make query_modifiers() a method that is part of the ContextTransmissionModifierExt trait extension). I think it's challenging for your reader to follow if you throw them head first into code that has new methods without any prior context.

@@ -0,0 +1,163 @@
# Overview
Infection attempts are not always successful (i.e. result in transmission). This module provides a framework to incorporate the many factors that modify the probability of infection attempt success. In this module, we assume that an interaction between an infectious transmitter (I) and a susceptible contact (S) has already occured and we want to `evaluate_transmission` using the registered modifiers of both I and S.
Copy link
Collaborator

Choose a reason for hiding this comment

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

You use the word "modifiers" in this intro snippet. However, you haven't really introduced what a modifier is or what it means. I think a little bit more context, potentially through a simple motivating example is necessary. I also noticed that you don't talk about what an intervention is, and that is of course the main use case of this module.

I also think it's critical to explain why this module is necessary. Why shouldn't a user just try to do all the tabulation for each intervention by hand? And, how can this module be generalized to be useful for modeling even more, like waning immunity or even variant effects?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think explaining why the transmission manager shouldn't just tabulate all interventions by hand is important to do up front because it also provides a nice transition into your code snippet below. Please also reference that this code snippet is in the transmission manager and not in code you propose to write in the transmission modifiers manager.

The API hook to `evaluate_transmission` is independent of innate transmissiveness, which determines the number and timing of infection attempts made by infecitous individual I.

## Modifier scope
In this module, we ignore behaviors and modifications not directly relevant to changing the transmission potential of an infection attempt. The separation of contact selection and contact rates is apparent, but other distinctions may be less clear.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't follow what this first sentence means at all. It sounds like you are saying that you ignore things not relevant to modifying transmission.

## Modifier scope
In this module, we ignore behaviors and modifications not directly relevant to changing the transmission potential of an infection attempt. The separation of contact selection and contact rates is apparent, but other distinctions may be less clear.
For example, facemasks modify the relative transmission potential of an infection attempt. The decision to wear a facemask based on a person's risk category or symptom category is an intervention-level behavior that does not directly modify relative transmission potential, meaning that such choices are excluded from this module. In contrast, symptoms may also modify the efficacy of wearing a facemask, which is a higher order modification that would need to be accounted for in the changes to relative transmission potential caused by facemasks.
Compare this higher order modification to the instance in which an individual may be less likely to wear a mask at home, or may wear it for less time. This is a modifier created by the location of the infection attempt, and is thus separate from the relative transmission modifiers module.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am confused. Intervention efficacy varies based on the site of the transmission event. I think that is very relevant to the transmission modifiers module because its express purpose is to calculate the efficacy of an intervention, conditioned on the nature of the contact. However, I agree that whether an agent changes the amount of time they spend in their home or not because of an intervention being present should not to be handled by the transmission modifiers module. Is that what you mean here?


## Modifier scope
In this module, we ignore behaviors and modifications not directly relevant to changing the transmission potential of an infection attempt. The separation of contact selection and contact rates is apparent, but other distinctions may be less clear.
For example, facemasks modify the relative transmission potential of an infection attempt. The decision to wear a facemask based on a person's risk category or symptom category is an intervention-level behavior that does not directly modify relative transmission potential, meaning that such choices are excluded from this module. In contrast, symptoms may also modify the efficacy of wearing a facemask, which is a higher order modification that would need to be accounted for in the changes to relative transmission potential caused by facemasks.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This feels too detail-oriented for being this high up in the document. It seems to what you are trying to say is that the transmission modifiers module does not control whether a person uses an intervention. Is that correct? I would explain at a high level that there is a difference between the manager that controls whether an intervention is turned on or not (what in GCM lingo would be an "actor") and the manager that holds the efficacy of the intervention (in GCM lingo, a "data manager").


let intervention_container = self.get_data_container_mut(InterventionPlugin);

// mismatched types: instance_map is of type {closure} but expected {dyn Fn(...)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

?

}
```

To register the `aggregator` functions, because we only can only have as many aggregators as there are `InfectiousStatusType` values, the user provides a `Vec` of all aggregator functions desired to the register function.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand how the requirement that we have as many aggregators as infectious status types means we should provide a vector?


We already defined the default aggregator through `impl InterventionContainer` so that the user does not need to specify all or even any aggregators in order to `run_aggregator` in `compute_intervention`.

To calculate the total relative trasnmission potential change for an individual during an infection attempt, `Context` and the `PersonId` are supplied to `compute_intervention`, which is agnostic of the `InfectiousStatus` of the `PersonId` supplied.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
To calculate the total relative trasnmission potential change for an individual during an infection attempt, `Context` and the `PersonId` are supplied to `compute_intervention`, which is agnostic of the `InfectiousStatus` of the `PersonId` supplied.
To calculate the total relative transmission potential change for an individual during an infection attempt, `Context` and the `PersonId` are supplied to `compute_intervention`, which is agnostic of the `InfectiousStatus` of the `PersonId` supplied.

Are we calculating a "change" in relative transmission potential? I also don't think the function is agnostic to the infectious status -- it just knows to query the infectious status from the person's ID.

intervention_plugin.run_aggregator(infectious_status, &registered_interventions)
}
```
We use automatic detection of all the modifications applied to a person, which is necessary to remove multiple manual calls to query particular interventions that would otherwise be error-prone and inflexible.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we automatically detect the modifications applied to a person. We just iterate through all available interventions that have been registered and see if any of them are applicable to the person. If there is an intervention that hasn't been registered, we don't "automatically" detect it.

I also think the point made in this sentence is really about creating a structure that encourages model modularity.


```rust

pub fn query_modifers(context: &mut Context, transmitter_id: PersonId, contact_id: PersonId) -> f64 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comment about this being part of the trait extension.

Copy link
Collaborator

@ekr-cfa ekr-cfa left a comment

Choose a reason for hiding this comment

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

At a high level, I don't think having a big design that describes the implementation separate from the code is that helpful. This is reasonably straightforward code and so inline comments should be sufficient. To the extent to which they are not, I would prefer whole file docs, either as API doc or just at the top of the file. That keeps it with the code.

If you want to have a document which describes the model structure rather than the code, I think that's reasonable.

@@ -0,0 +1,14 @@
# Interventions
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please spell check this file.

# Interventions

## Overview
Introducing interventions that affect the relative transmission potential in a given infection attempt, either through relative risk of the susceptible individual or through realtive infecitousness of the transmitter individual.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please wrap this to 80 columns

);

trait ContextTransmissionModifierExt {
fn register_intervention<T: PersonProperty + 'static + std::cmp::Eq + std::hash::Hash>(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think you need Eq and Hash here.

fn register_aggregator(
&mut self,
agg_functions: Vec<(InfectiousStatusType, Box<AggregatorFn>)>,
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't love this. IMO you should either:

  1. Have people specify one.
  2. Force them to specify all of them.

The Vec seems like false sugar, especially as you don't let people supply a vec of infectiousstatustype for registering interventions.

Copy link
Collaborator Author

@KOVALW KOVALW Jan 17, 2025

Choose a reason for hiding this comment

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

I like the option of having to specify each over all. Agreed that the difference between registering modifiers and aggregators was confusing. Changed to be a single call per InfectiousStatusType (your option # 1)

person_property: T,
instance_dict: Vec<(T::Value, f64)>,
);
fn register_aggregator(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would call this register_intervention_aggregator.

&mut self,
agg_functions: Vec<(InfectiousStatusType, Box<AggregatorFn>)>,
);
fn compute_intervention(&mut self, person_id: PersonId) -> f64;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you computing the intervention or computing the effect of the interventions?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The effect across interventions - is compute_relative_transmission clearer?

if property_val == item.0 {
return item.1;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are there any cases in which you would have a lot of values? If so, I would use a hashmap here. You can just convert it from the vec

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think that we would have more than a few. Robert's comments made it seem like several hundred would be the turning point for preferring Hash. I don't think we would ever have a case where something like PersonId is a key

fn compute_intervention(&mut self, person_id: PersonId) -> f64 {
let infectious_status = self.get_person_property(person_id, InfectiousStatus);

let mut registered_interventions: Vec<(TypeId, f64)> = Vec::new();
Copy link
Collaborator

Choose a reason for hiding this comment

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

You don't need to type hint here. Rust can infer it.

&mut self,
infectious_status: InfectiousStatusType,
person_property: T,
instance_dict: Vec<(T::Value, f64)>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are you calling this an instance_dict

Copy link
Collaborator

@ChiragKumar9 ChiragKumar9 left a comment

Choose a reason for hiding this comment

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

I think the document could use one more clean up to better articulate that we are modifying relative probability of transmission. I put a bunch of changes here to help guide it in that direction, but I acknowledge that part of this is taste and how we are each independently choosing to conceptualize the idea between an infection attempt, reduction in infection, etc.

- Mask wearing
- Isolation
- Vaccines
- [Transmission modifiers](infection.md)
Copy link
Collaborator

Choose a reason for hiding this comment

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

We shouldn't link to a document that doesn't yet exist (infection.md).

# Overview
Infection attempts are not always successful (i.e. result in transmission) and many factors modify
the probability of infection attempt success. These "transmission modifiers" can originate from the
natural history of infection or from interventions, which are measures that are aimed to reduce
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am having trouble of thinking of an example beyond immunity or a new variant (which we agree is not a "good" use case) for how natural history of infection could impact transmission. Since we are trying to make clear that the transmission modifiers do not impact intrinsic infectiousness, could you specify what you mean by natural history here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
natural history of infection or from interventions, which are measures that are aimed to reduce
natural history of infection or from interventions aimed at reducing

of a natural modifiers, or wearing a facemask, in the case of intervention-based transmission
modifiers, can lower the relative transmission potential of an infection attempt interaction.
Transmission modifiers are not strictly independent, nor is it convenient to repeatedly define
their specific use cases, which would require independent querying that is repetitive and
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't follow what you're trying to say in this sentence. I don't think the concern is specific use cases but rather that we want interventions to be modular from transmission. If module A defines an intervention that modifies transmission, the transmission module shouldn't have to know about it and explicitly need to query it, a code structure that is prone to forgetting things.

Transmission modifiers are not strictly independent, nor is it convenient to repeatedly define
their specific use cases, which would require independent querying that is repetitive and
error-prone. To avoid these pitfalls, this module provides a framework to incorporate transmission
modifiers in a flexible and generalized manner, such that all modifiers are detected and aggregated
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, basically I think the point you get to here by the end of this chunk of text is sufficient for what you're trying to say in this paragraph.

We assume that the infectiousness of transmitter I is independent of, and therefore additive
to, the risk of infection of contact S.

The API hook to `evaluate_transmission` is independent of innate transmissiveness, which determines
Copy link
Collaborator

Choose a reason for hiding this comment

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

To me, a "hook" implies that when the function is called, the transmission modifiers manager automatically knows that and executes a function. Instead, we call the methods in the transmission modifier in the function body of evaluate_transmission.

`modifier_key` is one, meaning there is no change in the relative risk for unregistered types. This
functional format is acceptable because we `define_person_property_with_default!`, and don't allow
`PersonId`s without a `RiskCategory` to also default to one. Without a default for the
`PersonProperty`, all individuals would be effectively in the `RiskCateogryType::High` group in
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
`PersonProperty`, all individuals would be effectively in the `RiskCateogryType::High` group in
`PersonProperty`, all individuals would effectively be in the `RiskCateogryType::High` group in

}
```

We define a default aggregator so that the user does not need to specify all or even any
Copy link
Collaborator

Choose a reason for hiding this comment

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

One design caveat I see here is that the aggregator function registration is not modular. If a user wants to register their own custom modifier function, they need to be aware of all other interventions and their TypeIds. In the short term, we should write this down as a caveat. In the long term, I wonder if we can design an interface so that you can specify how two (or some subset of all interventions) interact with a custom aggregator and then the rest of the interventions default to using the independence aggregator.


### Hook to aggregator from PersonId
To calculate the total relative transmission potential change for an individual during an infection
attempt, `Context` and the `PersonId` are supplied to `compute_relative_transmission`, which
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: Context isn't provided as an argument. The method is implemented as part of a trait extension on Context.

}
```

We use automatic iteration through all the modifications applied to a person, which is necessary to
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
We use automatic iteration through all the modifications applied to a person, which is necessary to
We automatically apply each transmission modifier function to determine all the modifications applied to a person, which is necessary to

Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you think about naming this file transmission_modifiers_manager.rs? transmission_modifiers on its own sounds like it is a list of transmission modifiers, not that it manages those modifiers.

Copy link
Collaborator

@confunguido confunguido left a comment

Choose a reason for hiding this comment

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

I only reviewed the markdown document. See my comments. I am not entirely sure how this module should, if at all, connect with what we call now natural history module. For instance, how would anti-virals change transmissibility, is this at the instantaneous transmission attempt or does it modify the infectiousness over time that will result in changes in the timing of infection attempts?

of a natural modifiers, or wearing a facemask, in the case of intervention-based transmission
modifiers, can lower the relative transmission potential of an infection attempt interaction.
Transmission modifiers are not strictly independent, nor is it convenient to repeatedly define
their specific use cases, which would require independent querying that is repetitive and
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure what you mean by this sentence "which would require independent querying that is repetitive and error-prone"

## Hook to transmission manager
In this module, we assume that an interaction between an infectious transmitter (I) and a
susceptible contact (S) has already occured. We alter the [transmission manager](transmission.md)
function `evaluate_transmission` that is conditioned on such an interaction. This is done using the
Copy link
Collaborator

Choose a reason for hiding this comment

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

So transmission.rs will use evaluate_transmission provided by transmission_modifiers.rs? That's not quite clear to me.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Describe here how evaluate_transmission connects to this module


```rust
fn query_infection_modifers(&mut self, transmitter_id: PersonId, contact_id: PersonId) -> f64 {
self.compute_relative_transmission(transmitter_id) * self.compute_relative_transmission(contact_id)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm a bit confused here, shouldn't we find modifiers of infection for transmitter and of susceptibility for contact?

{
let relative_transmission = context.query_infection_modifiers(transmitter_id, contact_id)
let transmission_success =
context.sample_range(TransmissionRng, 0.0..1.0) < relative_transmission;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe ixa has a sample_bool method

potential between I and S during an infection attempt, we need to register relative infectiousness
and risk, respectively, of each modifier. We therefore use a `HashMap` to relate
`InfectiousStatusType` to transmission modifiers with `TypeId`. These `TypeId` values then map to
supplied relative transmission function that takes in `Context` and a `PersonId`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

What does the relative transmission function do?

Before obtaining the total effect of all transmission modifiers acting on the relative transmission
potential between I and S during an infection attempt, we need to register relative infectiousness
and risk, respectively, of each modifier. We therefore use a `HashMap` to relate
`InfectiousStatusType` to transmission modifiers with `TypeId`. These `TypeId` values then map to
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you elaborate on what TypeId means?

}
```

## Modifier registration
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it would help if you write first a motivating example using these functions and then describe the functions.

```rust
fn register_transmission_modifier<T: PersonProperty + 'static + std::cmp::Eq + std::hash::Hash>(
&mut self,
infectious_status: InfectiousStatusType,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this mean that someone could register an intervention that modifies the recovery status or something like that? Is infectious status only susceptible or infectious? I guess if we only have those two components, it seems to me confusing to save as "infection_status".

type TransmissionAggregatorFn = dyn Fn(&Vec<(TypeId, f64)>) -> f64;
```

Other modules will implement particular instances of transmission modifiers and the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you elaborate? It isn't clear to me what you mean by "other modules will implement..."

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think overall throughout the document it would be more readable if there was a motivating example

@KOVALW KOVALW mentioned this pull request Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants