From b0401cd63cd23167e2ed258ce0d1f1ae7443a3d0 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 20:40:42 -0500 Subject: [PATCH 1/7] Switch to simpler kill top parasite load impl --- .../source/actions/PopulationActions.cc | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/avida-core/source/actions/PopulationActions.cc b/avida-core/source/actions/PopulationActions.cc index 1b9ce83f0..57c5b0d72 100644 --- a/avida-core/source/actions/PopulationActions.cc +++ b/avida-core/source/actions/PopulationActions.cc @@ -57,6 +57,7 @@ #include #include #include +#include #include "stdlib.h" @@ -5270,49 +5271,47 @@ class cActionKillDemesHighestParasiteLoad : public cAction { cPopulation& pop = m_world->GetPopulation(); const int num_demes = pop.GetNumDemes(); - std::vector parasite_loads(num_demes); - int num_eligible = 0; + std::vector deme_indices(num_demes); + std::iota(std::begin(deme_indices), std::end(deme_indices), 0); - const int deme_size = m_world->GetConfig().WORLD_X.Get() * (m_world->GetConfig().WORLD_Y.Get() / num_demes); - const double smudge_delta = 0.09 / deme_size; - int smudge_index = ctx.GetRandom().GetInt(0, num_demes - 1); - for (int d = 0; d < num_demes; d++) - { - cDeme &deme = pop.GetDeme(d); - if (not deme.IsEmpty()) - { - num_eligible++; - const auto parasite_load = deme.GetParasiteLoad(); - if (parasite_load == 0.0) continue; - // need to guarantee that parasite_loads are distinct to set threshold - parasite_loads[d] = parasite_load + smudge_delta * smudge_index; - ++smudge_index; - if (smudge_index >= num_demes) smudge_index -= num_demes; - } + const int num_eligible = std::count_if( + std::begin(deme_indices), std::end(deme_indices), + [&pop](const int d) { return not pop.GetDeme(d).IsEmpty(); } + ); + const int binomial_draw = ctx.GetRandom().GetRandBinomial( + num_eligible, + m_killmax + ); + const int kill_quota = std::min(num_eligible, binomial_draw); + if (kill_quota != binomial_draw) { + std::cout << "warning: capped kill quota at " << kill_quota << " from " << binomial_draw << " binomial sample with " << num_eligible << " eligible and kill prob " << m_killprob << std::endl; } - const int binomial_draw = ctx.GetRandom().GetRandBinomial( - num_eligible, - m_killprob + const std::vector parasite_loads = [&](){ + std::vector res(num_demes); + std::transform( + std::begin(deme_indices), std::end(deme_indices), + std::begin(res), + [&pop](const int d) { return pop.GetDeme(d).GetParasiteLoad(); } + ); + return res; + }(); + + std::partial_sort( + std::begin(deme_indices), + std::next(std::begin(deme_indices), kill_quota), + std::end(deme_indices), + [¶site_loads](const int d1, const int d2) { + return parasite_loads[d1] > parasite_loads[d2]; + } ); - const int kill_quota = std::min(binomial_draw, m_killmax); - if (kill_quota == 0) return; - - std::vector top_n(kill_quota); - const auto partial_sort_end = std::partial_sort_copy( - parasite_loads.begin(), parasite_loads.end(), - top_n.begin(), top_n.end(), - std::greater() + + std::for_each( + std::begin(deme_indices), + std::next(std::begin(deme_indices), kill_quota), + [&pop, &ctx](const int d) { pop.GetDeme(d).KillAll(ctx); } ); - const auto kill_thresh = *std::prev(partial_sort_end); - for (int d = 0; d < num_demes; d++) - { - if (parasite_loads[d] and parasite_loads[d] >= kill_thresh) - { - cDeme &deme = pop.GetDeme(d); - deme.KillAll(ctx); - } - } + } // End Process() }; From adb619f34558eafa464193868cc7875fdd1467cf Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 21:28:57 -0500 Subject: [PATCH 2/7] Bugfix: don't misuse killmax as killprob --- avida-core/source/actions/PopulationActions.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/avida-core/source/actions/PopulationActions.cc b/avida-core/source/actions/PopulationActions.cc index 57c5b0d72..1b92f8dcf 100644 --- a/avida-core/source/actions/PopulationActions.cc +++ b/avida-core/source/actions/PopulationActions.cc @@ -5280,9 +5280,9 @@ class cActionKillDemesHighestParasiteLoad : public cAction ); const int binomial_draw = ctx.GetRandom().GetRandBinomial( num_eligible, - m_killmax + m_killprob ); - const int kill_quota = std::min(num_eligible, binomial_draw); + const int kill_quota = std::min(m_killmax, binomial_draw); if (kill_quota != binomial_draw) { std::cout << "warning: capped kill quota at " << kill_quota << " from " << binomial_draw << " binomial sample with " << num_eligible << " eligible and kill prob " << m_killprob << std::endl; } From 6e517a9458f4f5b94d6c1a12d3b4b0956f38b9cc Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 21:29:33 -0500 Subject: [PATCH 3/7] Bugfix: make empty deme parasite load zero not nan --- avida-core/source/main/cDeme.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/avida-core/source/main/cDeme.h b/avida-core/source/main/cDeme.h index e557f638a..d7645f30d 100644 --- a/avida-core/source/main/cDeme.h +++ b/avida-core/source/main/cDeme.h @@ -187,7 +187,9 @@ class cDeme int GetNumParasites() const; double GetParasiteLoad() const { - return static_cast(GetNumParasites()) / GetOrgCount(); + const auto org_count = GetOrgCount(); + if (org_count == 0) return 0.0; + else return static_cast(GetNumParasites()) / GetOrgCount(); } void UpdateParasiteMemoryScore(const double decay) { From 3289ad8c3dbe08728b2b5a3afcf5307950bd55f2 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 21:33:39 -0500 Subject: [PATCH 4/7] Bugfix: actually apply immune protection Original diff must have gotten lost in the mix --- avida-core/source/main/cPopulation.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/avida-core/source/main/cPopulation.cc b/avida-core/source/main/cPopulation.cc index 592b83377..2dfbdd54d 100644 --- a/avida-core/source/main/cPopulation.cc +++ b/avida-core/source/main/cPopulation.cc @@ -1211,6 +1211,12 @@ bool cPopulation::ActivateParasite(cOrganism* host, Systematics::UnitPtr parent, ){ cDeme& deme = GetDeme(m_world->GetMigrationMatrix().GetProbabilisticDemeID(host_cell.GetDemeID(), m_world->GetRandom(),true)); const int infection_mode = m_world->GetConfig().DEMES_PARASITE_MIGRATION_TARGET_SELECTION_METHOD.Get(); + const auto immune_thresh = m_world->GetConfig().DEMES_PARASITE_MIGRATION_MEMORY_SCORE_PROTECTIVE_THRESHOLD.Get(); + if ( + immune_thresh != 0.0 + && deme.GetParasiteMemoryScore() >= immune_thresh + ) return false; + if (infection_mode == 0) { // Implementation #1 - Picks randomly of ALL cells in to-deme and then finds if the one it chose was occupied // -- Not ensured to infect an individual From 8eb1f6d0b71357aafb0858feef36bd5adac9f4a3 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 21:47:31 -0500 Subject: [PATCH 5/7] Simplify syntax for mac CI compiler --- avida-core/source/actions/PopulationActions.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/avida-core/source/actions/PopulationActions.cc b/avida-core/source/actions/PopulationActions.cc index 1b92f8dcf..c8318a210 100644 --- a/avida-core/source/actions/PopulationActions.cc +++ b/avida-core/source/actions/PopulationActions.cc @@ -5287,15 +5287,12 @@ class cActionKillDemesHighestParasiteLoad : public cAction std::cout << "warning: capped kill quota at " << kill_quota << " from " << binomial_draw << " binomial sample with " << num_eligible << " eligible and kill prob " << m_killprob << std::endl; } - const std::vector parasite_loads = [&](){ - std::vector res(num_demes); - std::transform( - std::begin(deme_indices), std::end(deme_indices), - std::begin(res), - [&pop](const int d) { return pop.GetDeme(d).GetParasiteLoad(); } - ); - return res; - }(); + std::vector parasite_loads(num_demes); + std::transform( + std::begin(deme_indices), std::end(deme_indices), + std::begin(parasite_loads), + [&pop](const int d) { return pop.GetDeme(d).GetParasiteLoad(); } + ); std::partial_sort( std::begin(deme_indices), From 21b6206d194ff0189e73557c84d16b986f884951 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 21:58:53 -0500 Subject: [PATCH 6/7] Simplify captures for early cxx compat --- avida-core/source/actions/PopulationActions.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avida-core/source/actions/PopulationActions.cc b/avida-core/source/actions/PopulationActions.cc index c8318a210..b407b9d72 100644 --- a/avida-core/source/actions/PopulationActions.cc +++ b/avida-core/source/actions/PopulationActions.cc @@ -5276,7 +5276,7 @@ class cActionKillDemesHighestParasiteLoad : public cAction const int num_eligible = std::count_if( std::begin(deme_indices), std::end(deme_indices), - [&pop](const int d) { return not pop.GetDeme(d).IsEmpty(); } + [&](const int d) { return not pop.GetDeme(d).IsEmpty(); } ); const int binomial_draw = ctx.GetRandom().GetRandBinomial( num_eligible, @@ -5291,14 +5291,14 @@ class cActionKillDemesHighestParasiteLoad : public cAction std::transform( std::begin(deme_indices), std::end(deme_indices), std::begin(parasite_loads), - [&pop](const int d) { return pop.GetDeme(d).GetParasiteLoad(); } + [&](const int d) { return pop.GetDeme(d).GetParasiteLoad(); } ); std::partial_sort( std::begin(deme_indices), std::next(std::begin(deme_indices), kill_quota), std::end(deme_indices), - [¶site_loads](const int d1, const int d2) { + [&](const int d1, const int d2) { return parasite_loads[d1] > parasite_loads[d2]; } ); @@ -5306,7 +5306,7 @@ class cActionKillDemesHighestParasiteLoad : public cAction std::for_each( std::begin(deme_indices), std::next(std::begin(deme_indices), kill_quota), - [&pop, &ctx](const int d) { pop.GetDeme(d).KillAll(ctx); } + [&](const int d) { pop.GetDeme(d).KillAll(ctx); } ); } // End Process() From a75dd474e98ffd49b7414e55b10638a5bdd7f626 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 23 Nov 2023 22:20:41 -0500 Subject: [PATCH 7/7] Switch to manual lambdas --- .../source/actions/PopulationActions.cc | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/avida-core/source/actions/PopulationActions.cc b/avida-core/source/actions/PopulationActions.cc index b407b9d72..947c0f259 100644 --- a/avida-core/source/actions/PopulationActions.cc +++ b/avida-core/source/actions/PopulationActions.cc @@ -5274,9 +5274,14 @@ class cActionKillDemesHighestParasiteLoad : public cAction std::vector deme_indices(num_demes); std::iota(std::begin(deme_indices), std::end(deme_indices), 0); + struct HasAny { + cPopulation& pop; + HasAny(cPopulation& pop) : pop(pop) {} + bool operator()(const int d){ return not pop.GetDeme(d).IsEmpty(); } + }; const int num_eligible = std::count_if( std::begin(deme_indices), std::end(deme_indices), - [&](const int d) { return not pop.GetDeme(d).IsEmpty(); } + HasAny(pop) ); const int binomial_draw = ctx.GetRandom().GetRandBinomial( num_eligible, @@ -5287,26 +5292,42 @@ class cActionKillDemesHighestParasiteLoad : public cAction std::cout << "warning: capped kill quota at " << kill_quota << " from " << binomial_draw << " binomial sample with " << num_eligible << " eligible and kill prob " << m_killprob << std::endl; } + struct GetParasiteLoad { + cPopulation& pop; + GetParasiteLoad(cPopulation& pop) : pop(pop) {} + double operator()(const int d){ return pop.GetDeme(d).GetParasiteLoad(); } + }; std::vector parasite_loads(num_demes); std::transform( std::begin(deme_indices), std::end(deme_indices), std::begin(parasite_loads), - [&](const int d) { return pop.GetDeme(d).GetParasiteLoad(); } + GetParasiteLoad(pop) ); - std::partial_sort( - std::begin(deme_indices), - std::next(std::begin(deme_indices), kill_quota), - std::end(deme_indices), - [&](const int d1, const int d2) { - return parasite_loads[d1] > parasite_loads[d2]; + struct Comp { + std::vector& loads; + Comp(std::vector &loads) : loads(loads) {} + bool operator()(const int d1, const int d2) { + return loads[d1] > loads[d2]; } + }; + std::partial_sort( + std::begin(deme_indices), + std::next(std::begin(deme_indices), kill_quota), + std::end(deme_indices), + Comp(parasite_loads) ); + struct DoKill { + cPopulation& pop; + cAvidaContext& ctx; + DoKill(cPopulation& pop, cAvidaContext& ctx) : pop(pop), ctx(ctx) {} + void operator()(const int d) { pop.GetDeme(d).KillAll(ctx); } + }; std::for_each( std::begin(deme_indices), std::next(std::begin(deme_indices), kill_quota), - [&](const int d) { pop.GetDeme(d).KillAll(ctx); } + DoKill(pop, ctx) ); } // End Process()