@@ -315,20 +315,27 @@ public SimulationResult simulateSIR(Collection<String> seeds,
315315 List <RoundSnapshot > snapshots = new ArrayList <>();
316316 List <InfectionEvent > timeline = new ArrayList <>();
317317
318+ // Track currently infected nodes explicitly to avoid iterating
319+ // all V vertices each round just to find the infected subset.
320+ // For large graphs with low infection rates, this reduces per-round
321+ // cost from O(V) to O(|infected| * avg_degree).
322+ Set <String > currentlyInfected = new LinkedHashSet <>();
323+ for (String seed : seeds ) {
324+ if (graph .containsVertex (seed )) currentlyInfected .add (seed );
325+ }
326+
318327 int round = 0 ;
319328 snapshots .add (createSnapshot (round , state ));
320329
321- boolean hasInfected = true ;
322- while (hasInfected ) {
330+ while (!currentlyInfected .isEmpty ()) {
323331 round ++;
324332 if (maxRounds > 0 && round > maxRounds ) break ;
325333
326334 Set <String > toRecover = new LinkedHashSet <>();
327335 Set <String > toInfect = new LinkedHashSet <>();
328336 Map <String , String > infectedBy = new LinkedHashMap <>();
329337
330- for (String node : graph .getVertices ()) {
331- if (state .get (node ) != NodeState .INFECTED ) continue ;
338+ for (String node : currentlyInfected ) {
332339 for (String neighbor : getNeighbors (node )) {
333340 if (state .get (neighbor ) == NodeState .SUSCEPTIBLE &&
334341 !toInfect .contains (neighbor )) {
@@ -341,31 +348,26 @@ public SimulationResult simulateSIR(Collection<String> seeds,
341348 }
342349 }
343350
344- for (String node : graph .getVertices ()) {
345- if (state .get (node ) == NodeState .INFECTED ) {
346- if (random .nextDouble () < recoveryRate ) {
347- toRecover .add (node );
348- }
351+ for (String node : currentlyInfected ) {
352+ if (random .nextDouble () < recoveryRate ) {
353+ toRecover .add (node );
349354 }
350355 }
351356
352357 for (String node : toInfect ) {
353358 state .put (node , NodeState .INFECTED );
359+ currentlyInfected .add (node );
354360 String source = infectedBy .get (node );
355361 if (source != null ) {
356362 timeline .add (new InfectionEvent (source , node , round ));
357363 }
358364 }
359365 for (String node : toRecover ) {
360366 state .put (node , NodeState .RECOVERED );
367+ currentlyInfected .remove (node );
361368 }
362369
363370 snapshots .add (createSnapshot (round , state ));
364-
365- hasInfected = false ;
366- for (NodeState s : state .values ()) {
367- if (s == NodeState .INFECTED ) { hasInfected = true ; break ; }
368- }
369371 }
370372
371373 return new SimulationResult (Model .SIR , seeds ,
0 commit comments