From 1e542a3e315dd0454fc7b6ee77b4717b2bead74c Mon Sep 17 00:00:00 2001 From: Emily Dolson Date: Thu, 29 Feb 2024 01:52:30 -0500 Subject: [PATCH] Reintegrate necessary changes to world.hpp --- include/emp/Evolve/Systematics.hpp | 4 +- include/emp/Evolve/World.hpp | 20 +- tests/Evolve/Systematics.cpp | 700 +++++++++++++++++------------ third-party/Catch | 2 +- third-party/force-cover | 2 +- 5 files changed, 429 insertions(+), 299 deletions(-) diff --git a/include/emp/Evolve/Systematics.hpp b/include/emp/Evolve/Systematics.hpp index 9286c68454..8d1cafc746 100644 --- a/include/emp/Evolve/Systematics.hpp +++ b/include/emp/Evolve/Systematics.hpp @@ -2160,7 +2160,7 @@ namespace emp { } else{ emp::File generation_percentiles(filename); //opens file - emp::vector< emp::vector >percentile_data = generation_percentiles.ToData(','); //turns file contents into vector + emp::vector< emp::vector >percentile_data = generation_percentiles.ToData(","); //turns file contents into vector for(int j = 0; j <= percentile_data[gen_value].size() - 2; j++){ //searches through vector for slot where phylo diversity fits @@ -2205,7 +2205,7 @@ namespace emp { // Load files emp::File in_file(file_path); - emp::vector header = in_file.ExtractRow(); + emp::vector header = in_file.ExtractRow(); // Find column ids auto id_pos_it = std::find(header.begin(), header.end(), "id"); diff --git a/include/emp/Evolve/World.hpp b/include/emp/Evolve/World.hpp index 762ddca409..ee539dac78 100644 --- a/include/emp/Evolve/World.hpp +++ b/include/emp/Evolve/World.hpp @@ -943,6 +943,7 @@ namespace emp { }; + #ifndef DOXYGEN_SHOULD_SKIP_THIS // ============================================================= // === === // === Out-of-class member function definitions from above === @@ -972,7 +973,7 @@ namespace emp { // Track the new systematics info for (Ptr > s : systematics) { - s->AddOrg(*new_org, pos, (int) update); + s->AddOrg(*new_org, pos); } SetupOrg(*new_org, pos, *random_ptr); @@ -996,7 +997,7 @@ namespace emp { } for (Ptr > s : systematics) { - s->RemoveOrgAfterRepro(pos, update); // Notify systematics about organism removal + s->RemoveOrgAfterRepro(pos); // Notify systematics about organism removal } } @@ -1489,6 +1490,13 @@ namespace emp { pop.resize(0); std::swap(pops[0], pops[1]); // Move next pop into place. + // Tell systematics manager to swap next population and population + // Needs to happen here so that you can refer to systematics in + // OnPlacement functions + for (Ptr> s : systematics) { + s->Update(); + } + // Update the active population. num_orgs = 0; for (size_t i = 0; i < pop.size(); i++) { @@ -1498,12 +1506,7 @@ namespace emp { } } - // 3. Handle systematics and any data files that need to be printed this update. - - // Tell systematics manager to swap next population and population - for (Ptr> s : systematics) { - s->Update(); - } + // 3. Handle any data files that need to be printed this update. for (auto file : files) file->Update(update); @@ -1734,6 +1737,7 @@ namespace emp { os << std::endl; } } + #endif // DOXYGEN_SHOULD_SKIP_THIS } #endif // #ifndef EMP_EVOLVE_WORLD_HPP_INCLUDE diff --git a/tests/Evolve/Systematics.cpp b/tests/Evolve/Systematics.cpp index 8ff6ae8467..2182c6d317 100644 --- a/tests/Evolve/Systematics.cpp +++ b/tests/Evolve/Systematics.cpp @@ -1,10 +1,9 @@ -/* - * This file is part of Empirical, https://github.com/devosoft/Empirical - * Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md - * date: 2021 -*/ /** - * @file + * @note This file is part of Empirical, https://github.com/devosoft/Empirical + * @copyright Copyright (C) Michigan State University, MIT Software license; see doc/LICENSE.md + * @date 2021 + * + * @file Systematics.cpp */ #include @@ -24,40 +23,37 @@ #include "emp/Evolve/World_output.hpp" #include "emp/hardware/AvidaGP.hpp" - -TEST_CASE("Test Systematics", "[Evolve]") -{ - +TEST_CASE("Test Systematics", "[Evolve]") { // Taxon emp::Taxon tx(0, "a"); - REQUIRE(tx.GetID() == 0); - REQUIRE(tx.GetParent() == nullptr); - REQUIRE(tx.GetInfo() == "a"); - REQUIRE(tx.GetNumOrgs() == 0); - REQUIRE(tx.GetTotOrgs() == 0); + CHECK(tx.GetID() == 0); + CHECK(tx.GetParent() == nullptr); + CHECK(tx.GetInfo() == "a"); + CHECK(tx.GetNumOrgs() == 0); + CHECK(tx.GetTotOrgs() == 0); tx.AddOrg(); - REQUIRE(tx.GetNumOrgs() == 1); + CHECK(tx.GetNumOrgs() == 1); tx.RemoveOrg(); - REQUIRE(tx.GetNumOrgs() == 0); - REQUIRE(tx.GetTotOrgs() == 1); - REQUIRE(tx.GetTotalOffspring() == 0); + CHECK(tx.GetNumOrgs() == 0); + CHECK(tx.GetTotOrgs() == 1); + CHECK(tx.GetTotalOffspring() == 0); emp::Ptr< emp::Taxon > parentPtr(&tx); emp::Taxon tx_1(1, "b", parentPtr); - REQUIRE(tx_1.GetParent() == parentPtr); + CHECK(tx_1.GetParent() == parentPtr); tx_1.AddTotalOffspring(); - REQUIRE(tx_1.GetTotalOffspring() == 1); - REQUIRE(tx.GetTotalOffspring() == 1); + CHECK(tx_1.GetTotalOffspring() == 1); + CHECK(tx.GetTotalOffspring() == 1); // Systematics std::function calc_taxon = [](double & o){ return o > 50.0 ? "large" : "small"; }; emp::Systematics sys1(calc_taxon); - REQUIRE(sys1.GetTrackSynchronous() == false); - REQUIRE(sys1.GetNumAncestors() == 0); - REQUIRE(sys1.GetNumActive() == 0); - REQUIRE(sys1.GetNumOutside() == 0); - REQUIRE(sys1.GetTreeSize() == 0); - REQUIRE(sys1.GetNumTaxa() == 0); + CHECK(sys1.GetTrackSynchronous() == false); + CHECK(sys1.GetNumAncestors() == 0); + CHECK(sys1.GetNumActive() == 0); + CHECK(sys1.GetNumOutside() == 0); + CHECK(sys1.GetTreeSize() == 0); + CHECK(sys1.GetNumTaxa() == 0); sys1.SetTrackSynchronous(true); CHECK(sys1.GetTrackSynchronous() == true); @@ -72,40 +68,45 @@ TEST_CASE("Test Systematics", "[Evolve]") CHECK(sys1.GetTaxonAt({1,1})->GetInfo() == "large"); CHECK(sys1.IsTaxonAt({1,1})); sys1.RemoveOrg({1,1}); - REQUIRE(sys1.GetNumActive() == 1); + CHECK(!sys1.IsTaxonAt({1,1})); + CHECK(sys1.GetNumActive() == 1); + sys1.AddOrg(56.0, {1,0}); + CHECK(sys1.IsTaxonAt({1,0})); + CHECK(!sys1.RemoveOrg({1,0})); + CHECK(!sys1.IsTaxonAt({1,0})); // Base setters and getters - REQUIRE(sys1.GetStoreActive() == true); - REQUIRE(sys1.GetStoreAncestors() == true); - REQUIRE(sys1.GetStoreOutside() == false); - REQUIRE(sys1.GetArchive() == true); - REQUIRE(sys1.GetStorePosition() == true); + CHECK(sys1.GetStoreActive() == true); + CHECK(sys1.GetStoreAncestors() == true); + CHECK(sys1.GetStoreOutside() == false); + CHECK(sys1.GetArchive() == true); + CHECK(sys1.GetStorePosition() == true); sys1.SetStoreActive(false); - REQUIRE(sys1.GetStoreActive() == false); + CHECK(sys1.GetStoreActive() == false); sys1.SetStoreAncestors(false); - REQUIRE(sys1.GetStoreAncestors() == false); + CHECK(sys1.GetStoreAncestors() == false); sys1.SetStoreOutside(true); - REQUIRE(sys1.GetStoreOutside() == true); + CHECK(sys1.GetStoreOutside() == true); sys1.SetArchive(false); - REQUIRE(sys1.GetArchive() == false); + CHECK(sys1.GetArchive() == false); sys1.SetStorePosition(false); - REQUIRE(sys1.GetStorePosition() == false); + CHECK(sys1.GetStorePosition() == false); #ifndef NDEBUG - sys1.AddDeleteriousStepDataNodeImpl(true); - REQUIRE(emp::assert_last_fail); + sys1.AddDeleteriousStepDataNode(); + CHECK(emp::assert_last_fail); emp::assert_clear(); - sys1.AddVolatilityDataNodeImpl(true); - REQUIRE(emp::assert_last_fail); + sys1.AddVolatilityDataNode(); + CHECK(emp::assert_last_fail); emp::assert_clear(); - sys1.AddUniqueTaxaDataNodeImpl(true); - REQUIRE(emp::assert_last_fail); + sys1.AddUniqueTaxaDataNode(); + CHECK(emp::assert_last_fail); emp::assert_clear(); - sys1.AddMutationCountDataNodeImpl(true); - REQUIRE(emp::assert_last_fail); + sys1.AddMutationCountDataNode(); + CHECK(emp::assert_last_fail); emp::assert_clear(); #endif @@ -114,138 +115,157 @@ TEST_CASE("Test Systematics", "[Evolve]") //emp::Systematics sys2(calc_taxon) my_taxon taxon1(1, "medium"); emp::Ptr ptr1 = &taxon1; - REQUIRE(emp::LineageLength(ptr1) == 1); + CHECK(emp::LineageLength(ptr1) == 1); my_taxon taxon2(1, "medium", ptr1); emp::Ptr ptr2 = &taxon2; - REQUIRE(emp::LineageLength(ptr1) == 1); - REQUIRE(emp::LineageLength(ptr2) == 2); + CHECK(emp::LineageLength(ptr1) == 1); + CHECK(emp::LineageLength(ptr2) == 2); std::unordered_map muts; muts["short"] = 12; muts["tall"] = 3; taxon2.GetData().RecordMutation(muts); - REQUIRE(taxon2.GetData().mut_counts.size() == 2); - REQUIRE(taxon2.GetData().mut_counts["tall"] == 3); + CHECK(taxon2.GetData().mut_counts.size() == 2); + CHECK(taxon2.GetData().mut_counts["tall"] == 3); emp::vector types; types.push_back("tall"); types.push_back("short"); - REQUIRE(emp::CountMuts(ptr2, types) == 15); - REQUIRE(emp::CountMutSteps(ptr2, types) == 2); - REQUIRE(emp::CountMutSteps(ptr2, "short") == 1); + CHECK(emp::CountMuts(ptr2, types) == 15); + CHECK(emp::CountMutSteps(ptr2, types) == 2); + CHECK(emp::CountMutSteps(ptr2, "short") == 1); muts["short"] = 4; taxon1.GetData().RecordMutation(muts); - REQUIRE(emp::CountMuts(ptr1, "short") == 4); - REQUIRE(emp::CountMuts(ptr2, "short") == 16); - REQUIRE(emp::CountMutSteps(ptr1, "short") == 1); - REQUIRE(emp::CountMutSteps(ptr2, "short") == 2); - - emp::Systematics sys([](const int & i){return i;}, true, true, true, false); - - std::cout << "\nAddOrg 25 (id1, no parent)\n"; - auto id1 = sys.AddOrg(25, nullptr, 0); - std::cout << "\nAddOrg -10 (id2; parent id1)\n"; - auto id2 = sys.AddOrg(-10, id1, 6); - std::cout << "\nAddOrg 26 (id3; parent id1)\n"; - auto id3 = sys.AddOrg(26, id1, 10); - std::cout << "\nAddOrg 27 (id4; parent id2)\n"; - auto id4 = sys.AddOrg(27, id2, 25); - std::cout << "\nAddOrg 28 (id5; parent id2)\n"; - auto id5 = sys.AddOrg(28, id2, 32); - std::cout << "\nAddOrg 29 (id6; parent id5)\n"; - auto id6 = sys.AddOrg(29, id5, 39); - std::cout << "\nAddOrg 30 (id7; parent id1)\n"; - auto id7 = sys.AddOrg(30, id1, 6); - - - std::cout << "\nRemoveOrg (id2)\n"; + CHECK(emp::CountMuts(ptr1, "short") == 4); + CHECK(emp::CountMuts(ptr2, "short") == 16); + CHECK(emp::CountMutSteps(ptr1, "short") == 1); + CHECK(emp::CountMutSteps(ptr2, "short") == 2); + + emp::Systematics sys([](const int & i){return i;}, true, true, true, false); + + // std::cout << "\nAddOrg 25 (id1, no parent)\n"; + sys.SetUpdate(0); + auto id1 = sys.AddOrg(25, nullptr); + // std::cout << "\nAddOrg -10 (id2; parent id1)\n"; + sys.SetUpdate(6); + auto id2 = sys.AddOrg(-10, id1); + // std::cout << "\nAddOrg 26 (id3; parent id1)\n"; + sys.SetUpdate(10); + auto id3 = sys.AddOrg(26, id1); + // std::cout << "\nAddOrg 27 (id4; parent id2)\n"; + sys.SetUpdate(25); + auto id4 = sys.AddOrg(27, id2); + // std::cout << "\nAddOrg 28 (id5; parent id2)\n"; + sys.SetUpdate(32); + auto id5 = sys.AddOrg(28, id2); + // std::cout << "\nAddOrg 29 (id6; parent id5)\n"; + sys.SetUpdate(39); + auto id6 = sys.AddOrg(29, id5); + // std::cout << "\nAddOrg 30 (id7; parent id1)\n"; + sys.SetUpdate(6); + auto id7 = sys.AddOrg(30, id1); + + CHECK(*id1 < *id2); + CHECK(sys.Parent(id2) == id1); + + // std::cout << "\nRemoveOrg (id2)\n"; sys.RemoveOrg(id1); sys.RemoveOrg(id2); double mpd = sys.GetMeanPairwiseDistance(); - std::cout << "MPD: " << mpd <GetNumOff() == 0); CHECK(outside_taxon->GetParent()->GetID() == 8); + CHECK(sys.GetMaxDepth() == 8); + auto active = sys.GetActive(); emp::vector>> active_vec(active.begin(), active.end()); emp::Sort(active_vec, [](emp::Ptr> & a, emp::Ptr> & b){ @@ -376,80 +398,92 @@ TEST_CASE("Test Systematics", "[Evolve]") CHECK(active_vec[10]->GetNumOrgs() == 1); CHECK(active_vec[10]->GetNumOff() == 0); CHECK(active_vec[10]->GetParent()->GetID() == 17); - } -TEST_CASE("Test not tracking ancestors", "[Evolve]") -{ +TEST_CASE("Test not tracking ancestors", "[Evolve]") { emp::Systematics sys([](const int & i){return i;}, true, false, false, false); - std::cout << "\nAddOrg 25 (id1, no parent)\n"; - auto id1 = sys.AddOrg(25, nullptr, 0); - std::cout << "\nAddOrg -10 (id2; parent id1)\n"; - auto id2 = sys.AddOrg(-10, id1, 6); - std::cout << "\nAddOrg 26 (id3; parent id1)\n"; - auto id3 = sys.AddOrg(26, id1, 10); - std::cout << "\nAddOrg 27 (id4; parent id2)\n"; - auto id4 = sys.AddOrg(27, id2, 25); - std::cout << "\nAddOrg 28 (id5; parent id2)\n"; - auto id5 = sys.AddOrg(28, id2, 32); - std::cout << "\nAddOrg 29 (id6; parent id5)\n"; - auto id6 = sys.AddOrg(29, id5, 39); - std::cout << "\nAddOrg 30 (id7; parent id1)\n"; - auto id7 = sys.AddOrg(30, id1, 6); - - - std::cout << "\nRemoveOrg (id2)\n"; + // std::cout << "\nAddOrg 25 (id1, no parent)\n"; + sys.SetUpdate(0); + auto id1 = sys.AddOrg(25, nullptr); + // std::cout << "\nAddOrg -10 (id2; parent id1)\n"; + sys.SetUpdate(6); + auto id2 = sys.AddOrg(-10, id1); + // std::cout << "\nAddOrg 26 (id3; parent id1)\n"; + sys.SetUpdate(10); + auto id3 = sys.AddOrg(26, id1); + // std::cout << "\nAddOrg 27 (id4; parent id2)\n"; + sys.SetUpdate(25); + auto id4 = sys.AddOrg(27, id2); + // std::cout << "\nAddOrg 28 (id5; parent id2)\n"; + sys.SetUpdate(32); + auto id5 = sys.AddOrg(28, id2); + // std::cout << "\nAddOrg 29 (id6; parent id5)\n"; + sys.SetUpdate(39); + auto id6 = sys.AddOrg(29, id5); + // std::cout << "\nAddOrg 30 (id7; parent id1)\n"; + sys.SetUpdate(6); + auto id7 = sys.AddOrg(30, id1); + + + // std::cout << "\nRemoveOrg (id2)\n"; sys.RemoveOrg(id1); sys.RemoveOrg(id2); - double mpd = sys.GetMeanPairwiseDistance(); - std::cout << "Mean Pairwise Distance = " << mpd << "\n"; - - std::cout << "\nAddOrg 31 (id8; parent id7)\n"; - auto id8 = sys.AddOrg(31, id7, 11); - std::cout << "\nAddOrg 32 (id9; parent id8)\n"; - auto id9 = sys.AddOrg(32, id8, 19); + // std::cout << "\nAddOrg 31 (id8; parent id7)\n"; + sys.SetUpdate(11); + auto id8 = sys.AddOrg(31, id7); + // std::cout << "\nAddOrg 32 (id9; parent id8)\n"; + sys.SetUpdate(19); + auto id9 = sys.AddOrg(32, id8); - std::cout << "\nAddOrg 33 (id10; parent id8)\n"; - auto id10 = sys.AddOrg(33, id8, 19); + // std::cout << "\nAddOrg 33 (id10; parent id8)\n"; + auto id10 = sys.AddOrg(33, id8); sys.RemoveOrg(id7); sys.RemoveOrg(id8); sys.RemoveOrg(id10); - - std::cout << "\nAddOrg 34 (id11; parent id9)\n"; - auto id11 = sys.AddOrg(34, id9, 22); - std::cout << "\nAddOrg 35 (id12; parent id10)\n"; - auto id12 = sys.AddOrg(35, id11, 23); + // std::cout << "\nAddOrg 34 (id11; parent id9)\n"; + sys.SetUpdate(22); + auto id11 = sys.AddOrg(34, id9); + // std::cout << "\nAddOrg 35 (id12; parent id10)\n"; + sys.SetUpdate(23); + auto id12 = sys.AddOrg(35, id11); sys.RemoveOrg(id9); - std::cout << "\nAddOrg 36 (id13; parent id12)\n"; - auto id13 = sys.AddOrg(36, id12, 27); - std::cout << "\nAddOrg 37 (id14; parent id13)\n"; - auto id14 = sys.AddOrg(37, id13, 30); + // std::cout << "\nAddOrg 36 (id13; parent id12)\n"; + sys.SetUpdate(27); + auto id13 = sys.AddOrg(36, id12); + // std::cout << "\nAddOrg 37 (id14; parent id13)\n"; + sys.SetUpdate(30); + auto id14 = sys.AddOrg(37, id13); sys.RemoveOrg(id13); - std::cout << "\nAddOrg 38 (id15; parent id14)\n"; - auto id15 = sys.AddOrg(38, id14, 33); + // std::cout << "\nAddOrg 38 (id15; parent id14)\n"; + sys.SetUpdate(33); + auto id15 = sys.AddOrg(38, id14); sys.RemoveOrg(id14); - std::cout << "\nAddOrg 39 (id16; parent id11)\n"; - auto id16 = sys.AddOrg(39, id11, 35); - std::cout << "\nAddOrg 40 (id17; parent id11)\n"; - auto id17 = sys.AddOrg(40, id11, 35); + // std::cout << "\nAddOrg 39 (id16; parent id11)\n"; + sys.SetUpdate(35); + auto id16 = sys.AddOrg(39, id11); + // std::cout << "\nAddOrg 40 (id17; parent id11)\n"; + auto id17 = sys.AddOrg(40, id11); - std::cout << "\nAddOrg 41 (id18; parent id17)\n"; - auto id18 = sys.AddOrg(41, id17, 36); + // std::cout << "\nAddOrg 41 (id18; parent id17)\n"; + sys.SetUpdate(36); + auto id18 = sys.AddOrg(41, id17); std::cout << "\nAddOrg 42 (id19; parent id17)\n"; - auto id19 = sys.AddOrg(42, id17, 37); - REQUIRE(id17->GetTotalOffspring() > 0); + sys.SetUpdate(37); + auto id19 = sys.AddOrg(42, id17); + + CHECK(id17->GetTotalOffspring() > 0); std::cout << "id3 = " << id3 << std::endl; std::cout << "id4 = " << id4 << std::endl; @@ -539,11 +573,14 @@ TEST_CASE("Pointer to systematics", "[evo]") { sys.Delete(); } -TEST_CASE("Test Data Struct", "[evo]") -{ +TEST_CASE("Test Data Struct", "[evo]") { emp::Ptr >> sys; sys.New([](const int & i){return i;}, true, true, true, false); + sys->AddMutationCountDataNode(); + sys->AddVolatilityDataNode(); + sys->AddUniqueTaxaDataNode(); + auto id1 = sys->AddOrg(1, nullptr); id1->GetData().fitness.Add(2); id1->GetData().phenotype = 6; @@ -565,36 +602,79 @@ TEST_CASE("Test Data Struct", "[evo]") id4->GetData().phenotype = 3; auto id5 = sys->AddOrg(5, id4); - id5->GetData().mut_counts["substitution"] = 1; - id5->GetData().fitness.Add(2); - id5->GetData().phenotype = 6; + std::unordered_map muts; + muts["substitution"] = 1; + id5->GetData().RecordMutation(muts); + id5->GetData().RecordFitness(2); + id5->GetData().RecordPhenotype(6); + CHECK(id5->GetData().GetPhenotype() == 6); + CHECK(id5->GetData().GetFitness() == 2); CHECK(CountMuts(id4) == 3); CHECK(CountDeleteriousSteps(id4) == 1); CHECK(CountPhenotypeChanges(id4) == 1); CHECK(CountUniquePhenotypes(id4) == 2); + CHECK(LineageLength(id4) == 3); CHECK(CountMuts(id3) == 5); CHECK(CountDeleteriousSteps(id3) == 1); CHECK(CountPhenotypeChanges(id3) == 0); CHECK(CountUniquePhenotypes(id3) == 1); + CHECK(LineageLength(id3) == 2); CHECK(CountMuts(id5) == 4); CHECK(CountDeleteriousSteps(id5) == 2); CHECK(CountPhenotypeChanges(id5) == 2); CHECK(CountUniquePhenotypes(id5) == 2); + CHECK(LineageLength(id5) == 4); + + CHECK(FindDominant(*sys) == id4); + + sys->GetDataNode("mutation_count")->PullData(); + CHECK(sys->GetDataNode("mutation_count")->GetMean() == Approx(2.8)); + + sys->GetDataNode("volatility")->PullData(); + CHECK(sys->GetDataNode("volatility")->GetMean() == Approx(0.6)); + + sys->GetDataNode("unique_taxa")->PullData(); + CHECK(sys->GetDataNode("unique_taxa")->GetMean() == Approx(1.4)); + sys.Delete(); -} + emp::Ptr> sys2; + sys2.New([](const int & i){return i;}, true, true, true, false); + sys2->AddDeleteriousStepDataNode(); + + auto new_tax = sys2->AddOrg(1, nullptr); + new_tax->GetData().RecordFitness(2); + CHECK(new_tax->GetData().GetFitness() == 2); + new_tax->GetData().RecordFitness(4); + CHECK(new_tax->GetData().GetFitness() == 3); + + emp::datastruct::fitness fit_data; + fit_data.RecordFitness(5); + new_tax->SetData(fit_data); + CHECK(new_tax->GetData().GetFitness() == 5); + + auto tax2 = sys2->AddOrg(2, new_tax); + tax2->GetData().RecordFitness(1); + + sys->GetDataNode("deleterious_steps")->PullData(); + CHECK(sys->GetDataNode("deleterious_steps")->GetMean() == Approx(.5)); + + sys2.Delete(); + + +} TEST_CASE("World systematics integration", "[evo]") { - // std::function, emp::datastruct::mut_landscape_info>>)> setup_phenotype = [](emp::Ptr, emp::datastruct::mut_landscape_info>> tax){ - // tax->GetData().phenotype = emp::Sum(tax->GetInfo()); - // }; + std::function, emp::datastruct::mut_landscape_info>>, emp::vector &)> setup_phenotype = [](emp::Ptr, emp::datastruct::mut_landscape_info>> tax, emp::vector & org){ + tax->GetData().phenotype = emp::Sum(tax->GetInfo()); + }; using systematics_t = emp::Systematics< emp::vector, @@ -609,13 +689,14 @@ TEST_CASE("World systematics integration", "[evo]") { world.SetMutFun([](emp::vector & org, emp::Random & r){return 0;}); - // world.GetSystematics().OnNew(setup_phenotype); + sys->OnNew(setup_phenotype); world.InjectAt(emp::vector({1,2,3}), 0); - sys->GetTaxonAt(0)->GetData().RecordPhenotype(6); - sys->GetTaxonAt(0)->GetData().RecordFitness(2); + CHECK(sys->GetTaxonAt(0)->GetData().phenotype == 6); + sys->GetTaxonAt(0)->GetData().RecordPhenotype(10); + CHECK(sys->GetTaxonAt(0)->GetData().phenotype == 10); - REQUIRE(sys->GetTaxonAt(0)->GetData().phenotype == 6); + sys->GetTaxonAt(0)->GetData().RecordFitness(2); std::unordered_map mut_counts; mut_counts["substitution"] = 3; @@ -624,10 +705,10 @@ TEST_CASE("World systematics integration", "[evo]") { auto old_taxon = sys->GetTaxonAt(0); world.DoBirth(new_org,0); - REQUIRE(old_taxon->GetNumOrgs() == 0); - REQUIRE(old_taxon->GetNumOff() == 1); - REQUIRE(sys->GetTaxonAt(0)->GetParent()->GetData().phenotype == 6); - REQUIRE((*sys->GetActive().begin())->GetNumOrgs() == 1); + CHECK(old_taxon->GetNumOrgs() == 0); + CHECK(old_taxon->GetNumOff() == 1); + CHECK(sys->GetTaxonAt(0)->GetParent()->GetData().phenotype == 10); + CHECK((*sys->GetActive().begin())->GetNumOrgs() == 1); } @@ -636,35 +717,64 @@ emp::DataFile AddDominantFile(WORLD_TYPE & world){ using mut_count_t [[maybe_unused]] = std::unordered_map; using data_t = emp::datastruct::mut_landscape_info>; using org_t = emp::AvidaGP; - using systematics_t = emp::Systematics; + using systematics_t = emp::Systematics; - auto & file = world.SetupFile("dominant.csv"); + auto & file = world.SetupFile("dominant.csv"); - std::function get_update = [&world](){return world.GetUpdate();}; - std::function dom_mut_count = [&world](){ - return CountMuts(dynamic_cast>(world.GetSystematics(0))->GetTaxonAt(0)); - }; - std::function dom_del_step = [&world](){ - return CountDeleteriousSteps(dynamic_cast>(world.GetSystematics(0))->GetTaxonAt(0)); - }; - std::function dom_phen_vol = [&world](){ - return CountPhenotypeChanges(dynamic_cast>(world.GetSystematics(0))->GetTaxonAt(0)); - }; - std::function dom_unique_phen = [&world](){ - return CountUniquePhenotypes(dynamic_cast>(world.GetSystematics(0))->GetTaxonAt(0)); - }; - - - file.AddFun(get_update, "update", "Update"); - file.AddFun(dom_mut_count, "dominant_mutation_count", "sum of mutations along dominant organism's lineage"); - file.AddFun(dom_del_step, "dominant_deleterious_steps", "count of deleterious steps along dominant organism's lineage"); - file.AddFun(dom_phen_vol, "dominant_phenotypic_volatility", "count of changes in phenotype along dominant organism's lineage"); - file.AddFun(dom_unique_phen, "dominant_unique_phenotypes", "count of unique phenotypes along dominant organism's lineage"); - file.PrintHeaderKeys(); - return file; + std::function get_update = [&world](){return world.GetUpdate();}; + std::function dom_mut_count = [&world](){ + emp::Ptr> sys = world.GetSystematics(0); + emp::Ptr full_sys = sys.DynamicCast(); + if (full_sys->GetNumActive() > 0) { + return emp::CountMuts(emp::FindDominant(*full_sys)); + } + return 0; + }; + std::function dom_del_step = [&world](){ + emp::Ptr> sys = world.GetSystematics(0); + emp::Ptr full_sys = sys.DynamicCast(); + if (full_sys->GetNumActive() > 0) { + return emp::CountDeleteriousSteps(emp::FindDominant(*full_sys)); + } + return 0; + }; + std::function dom_phen_vol = [&world](){ + emp::Ptr> sys = world.GetSystematics(0); + emp::Ptr full_sys = sys.DynamicCast(); + if (full_sys->GetNumActive() > 0) { + return emp::CountPhenotypeChanges(emp::FindDominant(*full_sys)); + } + return 0; + }; + std::function dom_unique_phen = [&world](){ + emp::Ptr> sys = world.GetSystematics(0); + emp::Ptr full_sys = sys.DynamicCast(); + if (full_sys->GetNumActive() > 0) { + return emp::CountUniquePhenotypes(emp::FindDominant(*full_sys)); + } + return 0; + }; + std::function lin_len = [&world](){ + emp::Ptr> sys = world.GetSystematics(0); + emp::Ptr full_sys = sys.DynamicCast(); + if (full_sys->GetNumActive() > 0) { + return emp::LineageLength(emp::FindDominant(*full_sys)); + } + return 0; + }; + + file.AddFun(get_update, "update", "Update"); + file.AddFun(dom_mut_count, "dominant_mutation_count", "sum of mutations along dominant organism's lineage"); + file.AddFun(dom_del_step, "dominant_deleterious_steps", "count of deleterious steps along dominant organism's lineage"); + file.AddFun(dom_phen_vol, "dominant_phenotypic_volatility", "count of changes in phenotype along dominant organism's lineage"); + file.AddFun(dom_unique_phen, "dominant_unique_phenotypes", "count of unique phenotypes along dominant organism's lineage"); + file.AddFun(lin_len, "lineage_length", "number of taxa dominant organism's lineage"); + file.PrintHeaderKeys(); + return file; } +// Integration test for using multiple systematics managers in a world and recording data TEST_CASE("Run world", "[evo]") { using mut_count_t = std::unordered_map; using data_t = emp::datastruct::mut_landscape_info>; @@ -702,6 +812,32 @@ TEST_CASE("Run world", "[evo]") { world.AddSystematics(gene_sys); world.AddSystematics(phen_sys); + std::function, emp::AvidaGP&)> check_update = [&gene_sys, &world](emp::Ptr tax, emp::AvidaGP & org){ + CHECK(tax->GetOriginationTime() == gene_sys->GetUpdate()); + CHECK(tax->GetOriginationTime() == world.GetUpdate()); + CHECK(tax->GetNumOff() == 0); + }; + + gene_sys->OnNew(check_update); + + std::function)> extinction_checks = [&gene_sys, &world](emp::Ptr tax){ + CHECK(tax->GetDestructionTime() == gene_sys->GetUpdate()); + CHECK(tax->GetDestructionTime() == world.GetUpdate()); + CHECK(tax->GetNumOrgs() == 0); + }; + + gene_sys->OnExtinct(extinction_checks); + + std::function)> prune_checks = [&world](emp::Ptr tax){ + CHECK(tax->GetNumOrgs() == 0); + CHECK(tax->GetNumOff() == 0); + CHECK(tax->GetOriginationTime() <= world.GetUpdate()); + CHECK(tax->GetDestructionTime() <= world.GetUpdate()); + }; + + gene_sys->OnPrune(prune_checks); + + emp::Signal on_mutate_sig; ///< Trigger signal before organism gives birth. emp::Signal record_fit_sig; ///< Trigger signal before organism gives birth. emp::Signal)> record_phen_sig; ///< Trigger signal before organism gives birth. @@ -718,9 +854,12 @@ TEST_CASE("Run world", "[evo]") { world.GetSystematics(1).Cast()->GetTaxonAt(pos)->GetData().RecordPhenotype(phen); }); - // world.OnOrgPlacement([&last_mutation, &world](size_t pos){ - // world.GetSystematics(0).Cast()->GetTaxonAt(pos)->GetData().RecordMutation(last_mutation); - // }); + emp::Ptr> sys0 = world.GetSystematics(0); + emp::Ptr sys0_cast = sys0.DynamicCast(); + std::function, emp::AvidaGP&)> capture_mut_fun = [&last_mutation](emp::Ptr tax, emp::AvidaGP & org){ + tax->GetData().RecordMutation(last_mutation); + }; + sys0_cast->OnNew(capture_mut_fun); world.SetupSystematicsFile().SetTimingRepeat(1); world.SetupFitnessFile().SetTimingRepeat(1); @@ -728,7 +867,7 @@ TEST_CASE("Run world", "[evo]") { emp::AddPhylodiversityFile(world, 0, "genotype_phylodiversity.csv").SetTimingRepeat(1); emp::AddPhylodiversityFile(world, 1, "phenotype_phylodiversity.csv").SetTimingRepeat(1); emp::AddLineageMutationFile(world).SetTimingRepeat(1); - // AddDominantFile(world).SetTimingRepeat(1); + AddDominantFile(world).SetTimingRepeat(1); // emp::AddMullerPlotFile(world).SetTimingOnce(1); @@ -767,15 +906,7 @@ TEST_CASE("Run world", "[evo]") { world.SetFitFun(fit_fun); - // emp::vector< std::function > fit_set(16); - // for (size_t out_id = 0; out_id < 16; out_id++) { - // // Setup the fitness function. - // fit_set[out_id] = [out_id](const emp::AvidaGP & org) { - // return (double) -std::abs(org.GetOutput((int)out_id) - (double) (out_id * out_id)); - // }; - // } - - // Build a random initial popoulation. + // Build a random initial population. for (size_t i = 0; i < 1; i++) { emp::AvidaGP cpu; cpu.PushRandom(random, 20); @@ -785,6 +916,12 @@ TEST_CASE("Run world", "[evo]") { for (size_t i = 0; i < 100; i++) { EliteSelect(world, 1, 1); } + + for (size_t i = 0; i < world.GetSize(); i++) { + record_fit_sig.Trigger(i, world.CalcFitnessID(i)); + record_phen_sig.Trigger(i, phen_fun(world.GetOrg(i))); + } + world.Update(); // Do the run... @@ -792,47 +929,34 @@ TEST_CASE("Run world", "[evo]") { // Update the status of all organisms. world.ResetHardware(); world.Process(200); - double fit0 = world.CalcFitnessID(0); - std::cout << (ud+1) << " : " << 0 << " : " << fit0 << std::endl; - - // Keep the best individual. - EliteSelect(world, 1, 1); + TournamentSelect(world, 2, 100); - // Run a tournament for the rest... - TournamentSelect(world, 2, 99); - // LexicaseSelect(world, fit_set, POP_SIZE-1); - // EcoSelect(world, fit_fun, fit_set, 100, 5, POP_SIZE-1); for (size_t i = 0; i < world.GetSize(); i++) { record_fit_sig.Trigger(i, world.CalcFitnessID(i)); record_phen_sig.Trigger(i, phen_fun(world.GetOrg(i))); } world.Update(); - + CHECK(world.GetUpdate() == gene_sys->GetUpdate()); + CHECK(world.GetUpdate() == phen_sys->GetUpdate()); + CHECK(gene_sys->GetTaxonAt(0)->GetOriginationTime() <= world.GetUpdate()); } - - // std::cout << std::endl; - // world[0].PrintGenome(); - // std::cout << std::endl; - // for (int i = 0; i < 16; i++) { - // std::cout << i << ":" << world[0].GetOutput(i) << " "; - // } - // std::cout << std::endl; } - - -TEST_CASE("Test GetCanopy", "[evo]") -{ +TEST_CASE("Test GetCanopy", "[evo]") { emp::Systematics sys([](const int & i){return i;}, true, true, true, false); - auto id1 = sys.AddOrg(1, nullptr, 0); - auto id2 = sys.AddOrg(2, id1, 2); - auto id3 = sys.AddOrg(3, id1, 3); - auto id4 = sys.AddOrg(4, id2, 3); + sys.SetUpdate(0); + auto id1 = sys.AddOrg(1, nullptr); + sys.SetUpdate(2); + auto id2 = sys.AddOrg(2, id1); + sys.SetUpdate(3); + auto id3 = sys.AddOrg(3, id1); + auto id4 = sys.AddOrg(4, id2); - sys.RemoveOrg(id1, 3); - sys.RemoveOrg(id2, 5); + sys.RemoveOrg(id1); + sys.SetUpdate(5); + sys.RemoveOrg(id2); auto can_set = sys.GetCanopyExtantRoots(4); @@ -849,7 +973,8 @@ TEST_CASE("Test GetCanopy", "[evo]") CHECK(Has(can_set, id1)); CHECK(Has(can_set, id2)); - sys.RemoveOrg(id3, 7); + sys.SetUpdate(7); + sys.RemoveOrg(id3); can_set = sys.GetCanopyExtantRoots(2); @@ -859,10 +984,14 @@ TEST_CASE("Test GetCanopy", "[evo]") CHECK(can_set.size() == 1); CHECK(Has(can_set, id2)); - auto id5 = sys.AddOrg(5, id4, 8); - sys.RemoveOrg(id4, 9); - auto id6 = sys.AddOrg(6, id5, 10); - sys.RemoveOrg(id5, 11); + sys.SetUpdate(8); + auto id5 = sys.AddOrg(5, id4); + sys.SetUpdate(9); + sys.RemoveOrg(id4); + sys.SetUpdate(10); + auto id6 = sys.AddOrg(6, id5); + sys.SetUpdate(11); + sys.RemoveOrg(id5); can_set = sys.GetCanopyExtantRoots(7); // Should only be 4 @@ -874,16 +1003,20 @@ TEST_CASE("Test GetCanopy", "[evo]") CHECK(can_set.size() == 1); CHECK(Has(can_set, id5)); - - auto id7 = sys.AddOrg(7, id6, 12); - auto id8 = sys.AddOrg(8, id7, 13); - auto id9 = sys.AddOrg(9, id8, 14); - auto id10 = sys.AddOrg(10, id9, 15); - - sys.RemoveOrg(id6, 20); - sys.RemoveOrg(id7, 20); - sys.RemoveOrg(id8, 20); - sys.RemoveOrg(id9, 20); + sys.SetUpdate(12); + auto id7 = sys.AddOrg(7, id6); + sys.SetUpdate(13); + auto id8 = sys.AddOrg(8, id7); + sys.SetUpdate(14); + auto id9 = sys.AddOrg(9, id8); + sys.SetUpdate(15); + auto id10 = sys.AddOrg(10, id9); + + sys.SetUpdate(20); + sys.RemoveOrg(id6); + sys.RemoveOrg(id7); + sys.RemoveOrg(id8); + sys.RemoveOrg(id9); can_set = sys.GetCanopyExtantRoots(22); // Should only be 10 @@ -912,13 +1045,6 @@ TEST_CASE("Test GetCanopy", "[evo]") CHECK(can_set.size() == 1); CHECK(Has(can_set, id5)); - - // auto id5 = sys.AddOrg(28, id2, 32); - // std::cout << "\nAddOrg 29 (id6; parent id5)\n"; - // auto id6 = sys.AddOrg(29, id5, 39); - // std::cout << "\nAddOrg 30 (id7; parent id1)\n"; - // auto id7 = sys.AddOrg(30, id1, 6); - } // Tests from Shao 1990 tree balance paper @@ -1537,10 +1663,10 @@ TEST_CASE("Test LoadFromFile and Snapshot behavior") { sys.Snapshot(temp_path); // load original systematics file - emp::File original{file.path()}; + emp::File original{emp::String(file.path())}; // load saved file - emp::File saved{temp_path}; + emp::File saved{emp::String(temp_path)}; CHECK(saved.AsSet() == original.AsSet()); } diff --git a/third-party/Catch b/third-party/Catch index 0f05c034c2..20ace55034 160000 --- a/third-party/Catch +++ b/third-party/Catch @@ -1 +1 @@ -Subproject commit 0f05c034c2cf4dd039b8ea375c70dbe657f21d97 +Subproject commit 20ace5503422a8511036aa9d486435041127e0cf diff --git a/third-party/force-cover b/third-party/force-cover index 7bd76e823f..d0e705cb15 160000 --- a/third-party/force-cover +++ b/third-party/force-cover @@ -1 +1 @@ -Subproject commit 7bd76e823f49030c145781bc15cf85d91c1e9324 +Subproject commit d0e705cb159267ff277bb0becb464dcae5c44218