///| fn main raise { // S+I -> 2I, I -> R. Volume N gives propensity beta*S*I/N. // This is an educational well-mixed process, not a clinical predictor. let net = @k.Network::new( ["S", "I", "R"], [ @k.Reaction::new([1, 1, 0], [0, 2, 0], 2.0), @k.Reaction::new([0, 1, 0], [0, 0, 1], 1.0), ], volume=100.0, ) let initial = [95, 5, 0] let times = @k.regular_grid(8.0, 40) let path = net.simulate(initial, 8.0, seed=2026, max_events=200) let ode = net.integrate(net.concentrations(initial), times, max_step=0.002) let counts = path.count_states() for k in 0.. 0 { assert_true(counts[k][0] <= counts[k - 1][0]) assert_true(counts[k][2] >= counts[k - 1][2]) } } for row in ode.samples() { assert_true((row[0] + row[1] + row[2] - 1.0).abs() < 1.0e-12) } let events = net.event_counts(path) let last = path.last_counts() assert_eq(events[0], 95 - last[0]) assert_eq(events[1], last[2]) let sampled = path.sample(times) assert_eq(sampled.last(), last.map(n => n.to_double())) println( "epidemic: conserved=100 infections=\{events[0]} recoveries=\{events[1]} final_I=\{last[1]} ODE_I=\{100.0*ode.last()[1]}", ) println(path.to_json().stringify()) }