void Tree::copySubtree(Tree& subtree, std::shared_ptr<Node>& subtree_node, Node& original_node, int breaking_branch_anc, int breaking_branch_desc) { /* If this node == breaking_branch_anc */ /* Then join the other descendent of this node with this node's ancestor */ /* And skip to the other descendent */ if (original_node.get_id() == breaking_branch_anc) { // Find node that is the sibling of the breaking branck Node& grand_descendent = *(original_node.desc1); if (original_node.desc1->get_id() == breaking_branch_desc) { // TODO: assert that desc2 == breaking_branch_anc instead grand_descendent = *(original_node.desc2); } auto breaking_branch_sibling = std::make_shared<Node>(grand_descendent.get_id()); if (subtree_node->anc == nullptr) { // If the breaking branch ancestor is the root of the original tree, // then delete the node and set its other descendent as the root subtree.root_node = breaking_branch_sibling; } else { // If not the root, then "delete" the node by joining its ancestor with its other descendent breaking_branch_sibling->anc = subtree_node->anc; if (subtree_node->anc->desc1 == subtree_node) { subtree_node->anc->desc1 = breaking_branch_sibling; } else { subtree_node->anc->desc2 = breaking_branch_sibling; } } copySubtree(subtree, breaking_branch_sibling, grand_descendent, breaking_branch_anc, breaking_branch_desc); } /* Otherwise, add each descendent and recursively parse them. */ /* TODO: Need to increment/decrement subtree values */ else { if (subtree_node->get_id() > subtree.max_id) { subtree.max_id = subtree_node->get_id(); } if (original_node.hasDescendents()) { auto desc1_copy = std::make_shared<Node>(original_node.desc1->get_id()); subtree_node->desc1 = desc1_copy; desc1_copy->anc = subtree_node; copySubtree(subtree, desc1_copy, *(original_node.desc1), breaking_branch_anc, breaking_branch_desc); auto desc2_copy = std::make_shared<Node>(original_node.desc2->get_id()); subtree_node->desc2 = desc2_copy; desc2_copy->anc = subtree_node; copySubtree(subtree, desc2_copy, *(original_node.desc2), breaking_branch_anc, breaking_branch_desc); subtree.nnodes += 2; subtree.nbranches += 2; } else { subtree.ntips++; } } }
TreeNode<Token> *ExpTree::copySubtree(TreeNode<Token> *current) { if (current == nullptr) //base case to end recursion when at tree end return nullptr; //create the node and set the new key to original TreeNode<Token> *copy = new TreeNode<Token>; size++; //used for dot copy->setInfo(current->getInfo()); copy->setKey(size); //just call recursively to copy the subtrees: copy->setLeft(copySubtree(current->getLeft())); copy->setRight(copySubtree(current->getRight())); return copy; }//copySubtree
void Tree::splitTree(int anc_id, int desc_id, std::array<std::unique_ptr<Tree>, 2>& subtrees) { /* Check that anc and desc form a branch in the tree */ std::shared_ptr<Node> anc_node = getNode(anc_id, root_node); if (anc_node->desc1->get_id() != desc_id && anc_node->desc2->get_id() != desc_id) { throw std::logic_error("Non-existent branch"); } /* Parse the first subtree */ subtrees[0] = std::make_unique<Tree>(); subtrees[0]->addTipFrom(root_node->get_id(), 0); // TODO: easier just to add constructor that takes a root_node id as param? subtrees[0]->nnodes++; subtrees[0]->max_id = root_node->get_id(); copySubtree(*subtrees[0], subtrees[0]->root_node, *root_node, anc_id, desc_id); /* Parse the second subtree */ subtrees[1] = std::make_unique<Tree>(); subtrees[1]->addTipFrom(desc_id, 0); // TODO: easier just to add constructor that takes a root_node id as param? subtrees[1]->nnodes++; subtrees[1]->max_id = desc_id; Node& break_desc_node = anc_node->desc1->get_id() == desc_id ? *(anc_node->desc1) : *(anc_node->desc2); copySubtree(*subtrees[1], subtrees[1]->root_node, break_desc_node, anc_id, desc_id); }
void ExpTree::diffNode(TreeNode<Token> *current) { //recursive function to differentiate if (current == nullptr)//recursion guard return; Token temp;//var to set info if (current->getInfo().type == Token::NUMBER || current->getInfo().type == Token::PI) {//constants have derivative 0 temp.number = 0; temp.type = Token::NUMBER; current->setInfo(temp); }//number derivative if (current->getInfo().type == Token::VARIABLE) {//differentiating w.r.t. x so that has derivative 1 others have 0 temp.type = Token::NUMBER; if (current->getInfo().variable == 'x') temp.number = 1; else temp.number = 0; current->setInfo(temp); }//variable derivative if (current->getInfo().type == Token::PLUS || current->getInfo().type == Token::MINUS) {//derivative of sum is sum of derivatives diffNode(current->getRight()); diffNode(current->getLeft()); }//sum rule if (current->getInfo().type == Token::PRODUCT) {//product rule d(fg) = d(f)g + fd(g) current->setRight(copySubtree(current)); //copy subtrees to differentiate current->setLeft(copySubtree(current->getRight())); temp.type = Token::PLUS;//set plus in current current->setInfo(temp); diffNode(current->getRight()->getRight());//differentiate the correct subtrees diffNode(current->getLeft()->getLeft()); }//product rule if (current->getInfo().type == Token::SIN) {//derivative of sin current->setRight(copySubtree(current)); temp.type = Token::PRODUCT; current->setInfo(temp); current->setLeft(copySubtree(current->getRight()->getRight()));//chain rule diffNode(current->getLeft()); temp.type = Token::COS; current->getRight()->setInfo(temp); }//sin if (current->getInfo().type == Token::COS) {//derivative of cos current->setRight(copySubtree(current)); //copy subtree TreeNode<Token> *left = new TreeNode<Token>; //extra node is needed for the extra * -1 current->setLeft(left); size++; //set tree size for dot current->getLeft()->setKey(size); temp.type = Token::NUMBER; temp.number = -1; current->getLeft()->setInfo(temp); temp.type = Token::PRODUCT; current->setInfo(temp); current->getRight()->setRight(copySubtree(current->getRight()));//copy subtree to the correct place current->getRight()->setLeft(copySubtree(current->getRight()->getRight()->getRight())); diffNode(current->getRight()->getLeft()); //chain rule current->getRight()->setInfo(temp); temp.type = Token::SIN; current->getRight()->getRight()->setInfo(temp); }//cos if (current->getInfo().type == Token::POW) { //power current->setLeft(copySubtree(current));//copy relevant subtrees current->setLeft(copySubtree(current)); temp.type = Token::NUMBER; temp.number = current->getRight()->getInfo().number - 1; //d(x^C)=x^{C-1}*C current->getLeft()->getLeft()->getRight()->setInfo(temp); temp.type = Token::PRODUCT; current->setInfo(temp); current->getLeft()->setInfo(temp); current->setRight(copySubtree(current->getLeft()->getLeft()->getLeft())); diffNode(current->getRight()); }//POW if (current->getInfo().type == Token::DIVIDE) {//d(f/g)=(d(f)*g-f*d(g))/(g^2) current->setLeft(copySubtree(current)); current->getLeft()->setLeft(copySubtree(current->getLeft()));//copy relevant subtrees current->getLeft()->setRight(copySubtree(current->getLeft()->getLeft())); current->getRight()->setLeft(copySubtree(current->getRight())); temp.type = Token::NUMBER; temp.number = 2; TreeNode<Token> *right = new TreeNode<Token>; //new nodes are needed so create them and set them appropriately current->getRight()->setRight(right); size++; current->getRight()->getRight()->setKey(size); current->getRight()->getRight()->setInfo(temp); temp.type = Token::POW; current->getRight()->setInfo(temp); temp.type = Token::MINUS; current->getLeft()->setInfo(temp); temp.type = Token::PRODUCT; current->getLeft()->getLeft()->setInfo(temp); current->getLeft()->getRight()->setInfo(temp); diffNode(current->getLeft()->getLeft()->getLeft()); //differentiate the subtrees diffNode(current->getLeft()->getRight()->getRight()); }//DIVIDE }//diffNode