Skip to content

Commit 2bb48b8

Browse files
authored
Merge pull request #395 from AngieHinrichs/move_node
matUtils mask --move-nodes: allow move to parent with mutation(s) of node to be moved
2 parents 67ff2b1 + 6f07224 commit 2bb48b8

1 file changed

Lines changed: 98 additions & 36 deletions

File tree

src/matUtils/mask.cpp

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -884,33 +884,31 @@ void restrictSamples (std::string samples_filename, MAT::Tree& T) {
884884
}
885885
}
886886

887-
std::unordered_set<std::string> mutation_set_from_node(MAT::Tree* T, MAT::Node* node, bool include_node, bool include_ancestors) {
888-
std::unordered_set<std::string> mutations;
887+
std::vector<MAT::Mutation> mutation_set_from_node(MAT::Tree* T, MAT::Node* node, bool include_node, bool include_ancestors) {
888+
std::vector<MAT::Mutation> mutations;
889889
if (include_ancestors) {
890-
for (auto an: T->rsearch(node->identifier, include_node)) {
890+
std::vector<MAT::Node*> ancestors = T->rsearch(node->identifier, include_node);
891+
// Reverse so we proceed from root to node.
892+
std::reverse(ancestors.begin(), ancestors.end());
893+
// Make a node so we can use the logic in Node::add_mutation to deal with multiple mutations at the same position.
894+
MAT::Node tmp_node = MAT::Node();
895+
for (auto an: ancestors) {
891896
for (auto mut: an->mutations) {
892897
if (mut.is_masked()) {
893898
continue;
894899
}
895-
MAT::Mutation mut_opposite = mut.copy();
896-
//we check for whether this mutation is going to negate with something in the set
897-
//by identifying its opposite and checking whether the opposite is already present on the traversal.
898-
mut_opposite.par_nuc = mut.mut_nuc;
899-
mut_opposite.mut_nuc = mut.par_nuc;
900-
auto cml = mutations.find(mut_opposite.get_string());
901-
if (cml != mutations.end()) {
902-
mutations.erase(cml);
903-
} else {
904-
mutations.insert(mut.get_string());
905-
}
900+
tmp_node.add_mutation(mut);
906901
}
907902
}
903+
for (auto mut: tmp_node.mutations) {
904+
mutations.push_back(mut.copy());
905+
}
908906
} else if (include_node) {
909907
for (auto mut: node->mutations) {
910908
if (mut.is_masked()) {
911909
continue;
912910
}
913-
mutations.insert(mut.get_string());
911+
mutations.push_back(mut.copy());
914912
}
915913
} else {
916914
fprintf(stderr, "ERROR: mutation_set_from_node: at least one of include_node and include_ancestors should be true.\n");
@@ -919,7 +917,32 @@ std::unordered_set<std::string> mutation_set_from_node(MAT::Tree* T, MAT::Node*
919917
return mutations;
920918
}
921919

920+
void remove_mutation_from_node(MAT::Node *node, MAT::Mutation &mut) {
921+
// Find and remove the element of node->mutations that has the same position and mut_nuc as mut.
922+
std::vector<MAT::Mutation>::iterator to_remove = node->mutations.end();
923+
for (auto iter = node->mutations.begin(); iter != node->mutations.end(); iter++) {
924+
MAT::Mutation nodemut = *iter;
925+
if (nodemut.position == mut.position && nodemut.mut_nuc == mut.mut_nuc) {
926+
to_remove = iter;
927+
break;
928+
}
929+
}
930+
if (to_remove == node->mutations.end()) {
931+
fprintf(stderr, "ERROR: remove_mutation_from_node: node %s does not have mutation %s\n",
932+
node->identifier.c_str(), mut.get_string().c_str());
933+
exit(1);
934+
}
935+
node->mutations.erase(to_remove);
936+
}
922937

938+
bool mutation_vec_has_position(std::vector<MAT::Mutation>& mutations, int position) {
939+
for (auto mut: mutations) {
940+
if (mut.position == position) {
941+
return true;
942+
}
943+
}
944+
return false;
945+
}
923946

924947
void moveNodes (std::string node_filename, MAT::Tree* T) {
925948
// Function to move nodes between two identical placement paths. That is, move the target node so that is a child of the indicated new parent node,
@@ -959,9 +982,9 @@ void moveNodes (std::string node_filename, MAT::Tree* T) {
959982
}
960983
//accumulate the set of mutations belonging to the current and the new placement
961984
//not counting mutations belonging to the target, but counting ones to the putative new parent.
962-
std::unordered_set<std::string> curr_mutations = mutation_set_from_node(T, mn, false, true);
963-
std::unordered_set<std::string> new_mutations = mutation_set_from_node(T, np, true, true);
964-
if (curr_mutations == new_mutations) {
985+
std::vector<MAT::Mutation> curr_parent_mutations = mutation_set_from_node(T, mn, false, true);
986+
std::vector<MAT::Mutation> new_mutations = mutation_set_from_node(T, np, true, true);
987+
if (curr_parent_mutations == new_mutations) {
965988
//we can now proceed with the move.
966989
T->move_node(mn->identifier, np->identifier);
967990
fprintf(stderr, "Move of node %s to node %s successful.\n", words[0].c_str(), words[1].c_str());
@@ -970,45 +993,84 @@ void moveNodes (std::string node_filename, MAT::Tree* T) {
970993
fprintf(stderr, "The current (%s) and new (%s) node paths do not involve the same set of mutations.\n",
971994
mn->identifier.c_str(), np->identifier.c_str());
972995

973-
std::unordered_set<std::string> extra_mutations;
974-
size_t curr_in_new_count = 0;
975-
for (auto mut: curr_mutations) {
976-
if (new_mutations.find(mut) != new_mutations.end()) {
977-
curr_in_new_count++;
978-
} else {
979-
extra_mutations.insert(mut);
996+
// Find mutations in the new parent but not in the current parent
997+
std::vector<MAT::Mutation> new_parent_extra_muts;
998+
for (auto mut: new_mutations) {
999+
if (std::find(curr_parent_mutations.begin(), curr_parent_mutations.end(), mut) == curr_parent_mutations.end()) {
1000+
new_parent_extra_muts.push_back(mut);
1001+
}
1002+
}
1003+
// Find mutations in mn relative to its parent. Can't just call mutation_set_from_node
1004+
// with true, false because mn might have a mutation at the same position as one of its
1005+
// parent's mutations -- we need those combined to get the reference allele as the
1006+
// ref_nuc/par_nuc for comparison with new_parent_extra_muts. So get all muts, and then
1007+
// erase all parental muts to get only the (collapsed) muts on mn.
1008+
std::vector<MAT::Mutation> curr_node_extra_muts = mutation_set_from_node(T, mn, true, true);
1009+
for (MAT::Mutation parent_mut: curr_parent_mutations) {
1010+
auto iter = std::find(curr_node_extra_muts.begin(), curr_node_extra_muts.end(), parent_mut);
1011+
if (iter != curr_node_extra_muts.end()) {
1012+
curr_node_extra_muts.erase(iter);
1013+
}
1014+
}
1015+
// Find mutations in the current parent (mn's parent) but not in the new parent
1016+
std::vector<MAT::Mutation> curr_parent_extra_muts;
1017+
for (auto mut: curr_parent_mutations) {
1018+
if (std::find(new_mutations.begin(), new_mutations.end(), mut) == new_mutations.end()) {
1019+
// but discard parental mutations at the same position as in curr_node_extra_muts
1020+
// because those were overridden in the node to be moved.
1021+
if (! mutation_vec_has_position(curr_node_extra_muts, mut.position)) {
1022+
curr_parent_extra_muts.push_back(mut);
1023+
}
9801024
}
9811025
}
982-
if (extra_mutations.size() == 0 || curr_in_new_count != new_mutations.size()) {
983-
fprintf(stderr, "ERROR: the new parent (%s) has mutations not found in the current node (%s); %ld in common, %ld in new\n",
984-
np->identifier.c_str(), mn->identifier.c_str(), curr_in_new_count, new_mutations.size());
985-
exit(1);
1026+
// If new parent has mutation(s) not found in current parent: if they are already in
1027+
// curr_node_extra_muts, then remove from curr_node_extra_muts and mn, otherwise error.
1028+
for (auto mut: new_parent_extra_muts) {
1029+
auto iter = std::find(curr_node_extra_muts.begin(), curr_node_extra_muts.end(), mut);
1030+
if (iter != curr_node_extra_muts.end()) {
1031+
curr_node_extra_muts.erase(iter);
1032+
remove_mutation_from_node(mn, mut);
1033+
fprintf(stderr, "mut %s is in new parent %s but not current parent, but is in current node %s; removed it.\n",
1034+
mut.get_string().c_str(), np->identifier.c_str(), mn->identifier.c_str());
1035+
} else {
1036+
fprintf(stderr, "ERROR: new parent %s has mutation %s not found in the current node %s's path.\n",
1037+
np->identifier.c_str(), mut.get_string().c_str(), mn->identifier.c_str());
1038+
for (auto m: curr_node_extra_muts) {
1039+
fprintf(stderr, "%s,", m.get_string().c_str());
1040+
}
1041+
fprintf(stderr, "\n");
1042+
exit(1);
1043+
}
9861044
}
987-
// Look for a child of np that already has extra_mutations. If there is such a child
1045+
// Look for a child of np that already has curr_parent_extra_muts. If there is such a child
9881046
// then move mn to that child. Otherwise add those mutations to mn and move it to np.
9891047
MAT::Node *child_with_muts = NULL;
9901048
for (auto child: np->children) {
991-
std::unordered_set<std::string> mut_set = mutation_set_from_node(T, child, true, false);
992-
if (mut_set == extra_mutations) {
1049+
std::vector<MAT::Mutation> mut_set = mutation_set_from_node(T, child, true, false);
1050+
if (mut_set == curr_parent_extra_muts) {
9931051
child_with_muts = child;
994-
fprintf(stderr, "Found child with extra_mutations: %s\n", child->identifier.c_str());
1052+
fprintf(stderr, "Found child with curr_parent_extra_muts: %s\n", child->identifier.c_str());
9951053
break;
9961054
}
9971055
}
9981056
if (child_with_muts != NULL) {
9991057
T->move_node(mn->identifier, child_with_muts->identifier);
10001058
} else {
10011059
// Preserve chronological order expected by add_mutation by adding mn's mutations
1002-
// after extra_mutations instead of vice versa.
1060+
// after curr_parent_extra_muts instead of vice versa.
10031061
std::vector<MAT::Mutation>mn_mutations;
10041062
for (auto mut: mn->mutations) {
10051063
mn_mutations.push_back(mut);
10061064
}
10071065
mn->mutations.clear();
1008-
for (auto mut: extra_mutations) {
1009-
mn->add_mutation(*(MAT::mutation_from_string(mut)));
1066+
for (auto mut: curr_parent_extra_muts) {
1067+
fprintf(stderr, "Added current parent's extra mutation %s to node to be moved (%s)\n",
1068+
mut.get_string().c_str(), mn->identifier.c_str());
1069+
mn->add_mutation(mut);
10101070
}
10111071
for (auto mut: mn_mutations) {
1072+
fprintf(stderr, "Layering on node to be moved (%s)'s mutation %s\n",
1073+
mn->identifier.c_str(), mut.get_string().c_str());
10121074
mn->add_mutation(mut);
10131075
}
10141076
T->move_node(mn->identifier, np->identifier);

0 commit comments

Comments
 (0)