Skip to content

feat(gui): implement Network Propagation tool for Epidemiology tab#656

Merged
fderuiter merged 2 commits intomainfrom
feature/epidemiology-network-propagation-377825193403949821
Mar 18, 2026
Merged

feat(gui): implement Network Propagation tool for Epidemiology tab#656
fderuiter merged 2 commits intomainfrom
feature/epidemiology-network-propagation-377825193403949821

Conversation

@fderuiter
Copy link
Owner

This PR fulfills the "Network Propagation" feature request from todo_gui.md while adhering to the Glassblower persona's strict architectural directives:

  • No math logic in the GUI: Abstracted the network generation and state propagation into NetworkEpidemicModel within math_explorer.
  • Separation of Concerns: The GUI tool (NetworkPropagationTool) cleanly implements EpidemiologyTool, importing backend states for its UI.
  • Graceful Error Handling: Replaced raw gen calls to prevent 2024 rust edition keywords bugs, keeping types strongly coupled.

PR created automatically by Jules for task 377825193403949821 started by @fderuiter

- Add `NetworkEpidemicModel` backend to `math_explorer/src/epidemiology/networks.rs`
- Generate random geometric graphs based on threshold distance.
- Implement step simulation with $\beta$ (transmission) and $\gamma$ (recovery).
- Expose node states (Susceptible, Infected, Recovered).
- Add `NetworkPropagationTool` to `math_explorer_gui/src/tabs/epidemiology/network_propagation.rs`.
- Render nodes, edges, and statistics dynamically using `egui`.
- Encapsulate parameters natively through the new tool struct.
- Mark 'Network Propagation' as completed in `todo_gui.md`.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

…agation

- Change the `step` method loop to use `next_states.iter_mut().enumerate()` to adhere to strict CI clippy standards.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@fderuiter fderuiter marked this pull request as ready for review March 18, 2026 23:58
Copilot AI review requested due to automatic review settings March 18, 2026 23:58
@fderuiter fderuiter merged commit 3b1f48b into main Mar 18, 2026
2 checks passed
@fderuiter fderuiter deleted the feature/epidemiology-network-propagation-377825193403949821 branch March 18, 2026 23:58
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements the requested “Network Propagation” feature in the Epidemiology GUI by adding a new tool that visualizes and steps a simple network-based epidemic simulation, backed by new network-generation/propagation logic in math_explorer.

Changes:

  • Add NetworkPropagationTool to the Epidemiology tab and mark the roadmap item complete.
  • Introduce NetworkEpidemicModel + NodeState in math_explorer::epidemiology::networks for geometric graph initialization and S/I/R propagation steps.
  • Minor formatting-only changes in unrelated GUI files (imports / line wrapping).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
todo_gui.md Marks “Network Propagation” feature as completed.
math_explorer_gui/src/tabs/epidemiology/network_propagation.rs New GUI tool: controls + network visualization + stepping the backend model.
math_explorer_gui/src/tabs/epidemiology/mod.rs Registers the new tool in the Epidemiology tab tool list.
math_explorer/src/epidemiology/networks.rs Adds the backend network epidemic model and node state enum.
math_explorer_gui/src/tabs/battery_degradation/lifetime_estimator.rs Import formatting only.
math_explorer_gui/src/tabs/ai/attention_maps.rs Formatting only (line wrapping).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +28 to +35
pub struct NetworkEpidemicModel {
pub num_nodes: usize,
pub states: Vec<NodeState>,
pub positions: Vec<[f32; 2]>,
pub adjacency: Vec<Vec<usize>>,
pub beta: f64,
pub gamma: f64,
}
Comment on lines +37 to +49
impl NetworkEpidemicModel {
pub fn new(num_nodes: usize, beta: f64, gamma: f64) -> Self {
let mut model = Self {
num_nodes,
states: vec![NodeState::Susceptible; num_nodes],
positions: vec![[0.0, 0.0]; num_nodes],
adjacency: vec![vec![]; num_nodes],
beta,
gamma,
};
model.initialize_geometric_graph();
model
}
Comment on lines +65 to +76
let connection_radius = 60.0;
for i in 0..self.num_nodes {
for j in (i + 1)..self.num_nodes {
let dx = self.positions[i][0] - self.positions[j][0];
let dy = self.positions[i][1] - self.positions[j][1];
let dist = (dx * dx + dy * dy).sqrt();
if dist < connection_radius {
self.adjacency[i].push(j);
self.adjacency[j].push(i);
}
}
}
Comment on lines +51 to +113
pub fn initialize_geometric_graph(&mut self) {
let mut rng = rand::thread_rng();
self.states = vec![NodeState::Susceptible; self.num_nodes];
self.positions = vec![[0.0, 0.0]; self.num_nodes];
self.adjacency = vec![vec![]; self.num_nodes];

// Random geometric graph
let radius = 200.0;
for i in 0..self.num_nodes {
let angle = rng.r#gen_range(0.0..TAU);
let r = radius * rng.r#gen_range(0.0f32..1.0f32).sqrt();
self.positions[i] = [r * angle.cos(), r * angle.sin()];
}

let connection_radius = 60.0;
for i in 0..self.num_nodes {
for j in (i + 1)..self.num_nodes {
let dx = self.positions[i][0] - self.positions[j][0];
let dy = self.positions[i][1] - self.positions[j][1];
let dist = (dx * dx + dy * dy).sqrt();
if dist < connection_radius {
self.adjacency[i].push(j);
self.adjacency[j].push(i);
}
}
}

// Start with one infected
if self.num_nodes > 0 {
let start_idx = rng.r#gen_range(0..self.num_nodes);
self.states[start_idx] = NodeState::Infected;
}
}

pub fn step(&mut self) {
let mut next_states = self.states.clone();
let mut rng = rand::thread_rng();

for (i, next_state) in next_states.iter_mut().enumerate().take(self.num_nodes) {
match self.states[i] {
NodeState::Susceptible => {
// Check infected neighbors
let infected_neighbors = self.adjacency[i]
.iter()
.filter(|&&j| self.states[j] == NodeState::Infected)
.count();
for _ in 0..infected_neighbors {
if rng.r#gen::<f64>() < self.beta {
*next_state = NodeState::Infected;
break;
}
}
}
NodeState::Infected => {
if rng.r#gen::<f64>() < self.gamma {
*next_state = NodeState::Recovered;
}
}
NodeState::Recovered => {}
}
}
self.states = next_states;
}
Comment on lines +21 to +35
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum NodeState {
Susceptible,
Infected,
Recovered,
}

pub struct NetworkEpidemicModel {
pub num_nodes: usize,
pub states: Vec<NodeState>,
pub positions: Vec<[f32; 2]>,
pub adjacency: Vec<Vec<usize>>,
pub beta: f64,
pub gamma: f64,
}
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.

2 participants