diff --git a/core/species.cpp b/core/species.cpp index 9f7438daa..3f8013fdd 100644 --- a/core/species.cpp +++ b/core/species.cpp @@ -8727,6 +8727,7 @@ void Species::__CreateSubpopulationsFromTabulation(std::unordered_map pedigree_id_check; + std::vector haplosome_id_check; gSLiM_next_pedigree_id = 0; @@ -8806,12 +8807,16 @@ void Species::__CreateSubpopulationsFromTabulation(std::unordered_mapspatial_z_ = subpop_info.spatial_z_[tabulation_index]; p_nodeToHaplosomeMap.emplace(node_id_0, individual->haplosomes_[first_haplosome_index]); - individual->haplosomes_[first_haplosome_index]->haplosome_id_ = pedigree_id * 2; + slim_haplosomeid_t haplosome_id = pedigree_id * 2; + individual->haplosomes_[first_haplosome_index]->haplosome_id_ = haplosome_id; + haplosome_id_check.emplace_back(haplosome_id); // we will test for collisions below if (last_haplosome_index != first_haplosome_index) { p_nodeToHaplosomeMap.emplace(node_id_1, individual->haplosomes_[last_haplosome_index]); - individual->haplosomes_[last_haplosome_index]->haplosome_id_ = pedigree_id * 2 + 1; + haplosome_id = pedigree_id * 2 + 1; + individual->haplosomes_[last_haplosome_index]->haplosome_id_ = haplosome_id; + haplosome_id_check.emplace_back(haplosome_id); // we will test for collisions below } // check the referenced nodes; right now this is not essential for re-creating the saved state, but is just a crosscheck @@ -9814,13 +9819,12 @@ void Species::__CheckNodePedigreeIDs(__attribute__((unused)) EidosInterpreter *p // could be nodes in the node table with haplosome pedigree IDs greater than those in use by individuals, in nonWF models. // See https://github.com/MesserLab/SLiM/pull/420 for an example model that does this very easily. - // Also, check for duplicate pedigree IDs, just in case. __CreateSubpopulationsFromTabulation() does this for individual - // pedigree IDs; we do it for node pedigree IDs. I decided to use a vector with std::sort() to check even though it is - // O(n log n), rather than a hash table for O(n), because I'm nervous about hitting a bad edge case with the hash table - // due to the nature of the values being inserted. Shouldn't be a big deal in the grand scheme of things. + // Previously, we checked for duplicate haplosome IDs here as well, just in case. + // __CreateSubpopulationsFromTabulation() does this in living individuals + // already; however, it was found to be overly restrictive, in situations + // involving merging of parallel simulations; see https://github.com/MesserLab/SLiM/issues/538 tsk_node_table_t &node_table = tables.nodes; tsk_size_t node_count = node_table.num_rows; - std::vector haplosome_id_check; for (tsk_size_t j = 0; (size_t)j < node_count; j++) { @@ -9833,11 +9837,7 @@ void Species::__CheckNodePedigreeIDs(__attribute__((unused)) EidosInterpreter *p { // get the metadata record and check the haplosome pedigree ID HaplosomeMetadataRec *metadata_rec = (HaplosomeMetadataRec *)(node_table.metadata + offset1); - slim_haplosomeid_t haplosome_id = metadata_rec->haplosome_id_; - - haplosome_id_check.emplace_back(haplosome_id); // we will test for collisions below - - slim_pedigreeid_t pedigree_id = haplosome_id / 2; // rounds down to integer + slim_pedigreeid_t pedigree_id = metadata_rec->haplosome_id_ / 2; // rounds down to integer if (pedigree_id >= gSLiM_next_pedigree_id) { @@ -9854,13 +9854,6 @@ void Species::__CheckNodePedigreeIDs(__attribute__((unused)) EidosInterpreter *p } } } - - // Check for haplosome pedigree ID collisions by sorting and looking for duplicates - std::sort(haplosome_id_check.begin(), haplosome_id_check.end()); - const auto duplicate = std::adjacent_find(haplosome_id_check.begin(), haplosome_id_check.end()); - - if (duplicate != haplosome_id_check.end()) - EIDOS_TERMINATION << "ERROR (Species::__CheckNodePedigreeIDs): the haplosome pedigree ID value " << *duplicate << " was used more than once; haplosome pedigree IDs must be unique." << EidosTerminate(); } void Species::_ReadAncestralSequence(const char *p_file, Chromosome &p_chromosome)