///| fn main raise { // Immigration-death population, concentration birth b and per-capita death d. let b = 4.0 let d = 0.5 let net = @k.Network::new(["population"], [ @k.Reaction::new([0], [1], b), @k.Reaction::new([1], [0], d), ]) let grid = @k.regular_grid(2.0, 10) let ensemble = net.ensemble([10], grid, 2000, seed=731, max_events=200) let means = ensemble.means() let final_mean = means.last()[0] let variance = ensemble.covariances()[10][0][0] let q = @math.exp(-d * 2.0) let expected = 10.0 * q + b / d * (1.0 - q) let expected_variance = 10.0 * q * (1.0 - q) + b / d * (1.0 - q) let se = ensemble.standard_errors()[10][0] assert_true((final_mean - expected).abs() < 6.0 * se) assert_true((variance - expected_variance).abs() < 1.0) let path = net.simulate([10], 2.0, seed=42) let likelihood = net.log_likelihood(path) let score = net.path_score(path) assert_true(!likelihood.is_nan() && !likelihood.is_inf()) assert_eq(score.length(), 2) let exposure = net.integrated_propensities(path) assert_eq(exposure[0], 8.0) println( "population: runs=\{ensemble.runs()} mean=\{final_mean} analytic=\{expected} variance=\{variance} analytic_variance=\{expected_variance} standard_error=\{se}", ) println( "path_log_likelihood=\{likelihood} birth_score=\{score[0]} death_score=\{score[1]}", ) println(means.to_csv()) }