void AdmixtureEdgeReplaceResidualsFNPR::findNewBrothers(std::vector<AdmixtureNode *> &b, AdmixtureNode &p, AdmixtureNode *n) {
    
    if (&p != n) {
        
        size_t numChildren = n->getNumberOfChildren();
        AdmixtureNode* child;
        
        for (size_t i = 0; i < numChildren; i++)
        {
            child = &n->getChild( i );
            if ( child->getAge() < p.getAge() && child->getNumberOfChildren() != 1) { // && child != &q ) {
                b.push_back( child );
            } else {
                findNewBrothers(b, p, child);
            }
        }
    }
}
void AdmixtureShiftNodeAgeAndRate::rejectSimpleMove( void ) {

    
    // undo the ages
    storedNode->setAge( storedAge );
    
    if (&storedNode->getAdmixtureParent() != NULL)
        storedNode->getAdmixtureParent().setAge( storedAge );
    else if (&storedNode->getAdmixtureChild() != NULL)
        storedNode->getAdmixtureChild().setAge( storedAge );

    // undo the rates
    branchRates[storedNode->getIndex()]->setValue(new double(storedRates[storedNode]));
    
    for (size_t i = 0; i < storedNode->getNumberOfChildren(); i++)
    {
        AdmixtureNode* ch = &storedNode->getTopologyChild(i);
        branchRates[ch->getIndex()]->setValue(new double(storedRates[ch]));
    }
}
void AdmixtureEdgeReplaceResidualsFNPR::storeAdmixtureEventsForLineage(AdmixtureNode* p)
{
    AdmixtureTree& tau = variable->getValue();
    AdmixtureNode* q_it = &p->getParent();
    while (q_it->getNumberOfChildren() == 1)
    {
        AdmixtureNode* qp = q_it;
        
        // adm parent
        if (&q_it->getAdmixtureChild() != NULL)
            ;
        
        // adm child
        else if (&q_it->getAdmixtureParent() != NULL)
            qp = &q_it->getAdmixtureParent();
        
        // divergence
        else
            break;
        
        AdmixtureNode* qc = &qp->getAdmixtureChild();
        AdmixtureNode* qpc = &qp->getChild(0);
        AdmixtureNode* qcc = &qc->getChild(0);
        
        //std::cout << "rem " << qp << " " << qc << " " << qpc << " " << qcc << "\n";
        AdmixtureEdgePosition ap(qp, qc, qpc, qcc, qc->getAge(), qc->getWeight());
        
        storedAdmixtureEdges.push_front(ap);
        
        tau.removeAdmixtureEdge(qp);
        tau.eraseAdmixtureNode(qp);
        tau.eraseAdmixtureNode(qc);
        
        q_it = &p->getParent();
    }
}
/** Perform the move */
double AdmixtureEdgeReplaceResidualWeights::performSimpleMove( void ) {
    
  //  std::cout << "Admix Node Repl RW\n";
    failed = false;
    failedAdd = false;
        
    // Get random number generator
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    AdmixtureTree& tau = variable->getValue();
    AdmixtureNode* root = &tau.getRoot();
    size_t numTaxa = tau.getNumberOfTips();

    std::vector<AdmixtureNode*> admixtureParents = tau.getAdmixtureParents();
    
    // if no admixtureParent exists, the proposal fails
    if (admixtureParents.size() == 0)
    {
        failed = true;
    //    std::cout << "no admixture evts\n";
        return RbConstants::Double::neginf;
    }
    
    // otherwise, proceed
    else
    {

        storedResiduals = residuals->getValue();
        
//        std::cout << "\nBEFORE\n";
//        for (size_t i = 0; i < numTaxa; i++)
//        {
//            for (size_t j = 0; j < numTaxa; j++)
//            {
//                double r = storedResiduals[i * numTaxa + j];
//                std::cout << r << " ";
//            }
//            std::cout << "\n";
//        }
        
        // proposal densities
//        double fwdProposal = 1.0;
//        double bwdProposal = 1.0;
        
        failed = false;
        failedAdd = false;

        // sample a random admixture parent node
        double u = rng->uniform01();
        size_t index = std::floor(admixtureParents.size() * u);
//        size_t numAdmixtureEdges = admixtureParents.size();
        
        // store admixture edge position
        storedAdmixtureParent = admixtureParents[index];
        storedAdmixtureChild = &storedAdmixtureParent->getAdmixtureChild();
        storedAdmixtureChildParent = &storedAdmixtureChild->getParent();
        storedAdmixtureChildChild = &storedAdmixtureChild->getChild(0);
        storedAdmixtureParentParent = &storedAdmixtureParent->getParent();
        storedAdmixtureParentChild = &storedAdmixtureParent->getChild(0);


//        std::cout << "rem " << tau.getAdmixtureEdgeStr(storedAdmixtureParent, storedAdmixtureChild) << "\n";
       
//        int oldChildBranchIdx = (int)storedAdmixtureChild->getTopologyChild(0).getIndex();
//        int oldParentBranchIdx = (int)storedAdmixtureParent->getTopologyChild(0).getIndex();
        
        // remove admixture edge from graph
        storedAdmixtureChild->removeChild(storedAdmixtureChildChild);
        storedAdmixtureChildChild->setParent(storedAdmixtureChildParent);
        storedAdmixtureChildParent->removeChild(storedAdmixtureChild);
        storedAdmixtureChildParent->addChild(storedAdmixtureChildChild);
        
        storedAdmixtureParent->removeChild(storedAdmixtureParentChild);
        storedAdmixtureParentChild->setParent(storedAdmixtureParentParent);
        storedAdmixtureParentParent->removeChild(storedAdmixtureParent);
        storedAdmixtureParentParent->addChild(storedAdmixtureParentChild);
        
        // get age for admixture event
        storedAdmixtureAge = storedAdmixtureChild->getAge();
        storedAdmixtureWeight = storedAdmixtureChild->getWeight();
        
        // initialize NA__
        newAdmixtureChildChild = storedAdmixtureChildChild;
        newAdmixtureChildParent = storedAdmixtureChildParent;
        newAdmixtureParentChild = storedAdmixtureParentChild;
        newAdmixtureParentParent = storedAdmixtureParentParent;
        
        variable->touch();

//        std::cout << "\nSAMPLE\n";
//        storedResiduals = residuals->getValue();
//        for (size_t i = 0; i < numTaxa; i++)
//        {
//            for (size_t j = 0; j < numTaxa; j++)
//            {
//                double r = storedResiduals[i * numTaxa + j];
//                std::cout << r << " ";
//            }
//            std::cout << "\n";
//        }
        
        //tau.checkAllEdgesRecursively(root);
        
        //////////////////////////////////////////////////
        // add event ...
        //std::cout << "\n\treplace, add\n";
        
        double maxStoredResidual = 0.0;
        for (size_t i = 0; i < storedResiduals.size(); i++)
            if (storedResiduals[i] > maxStoredResidual)
                maxStoredResidual = storedResiduals[i];
        double lambda = delta / maxStoredResidual;
        //double lambda = 10.0;
        
       
        AdmixtureNode* nodeSrc = NULL;
        AdmixtureNode* nodeDst = NULL;
        size_t k_a = 0;
        size_t k_b = 0;
       // std::cout << "numTaxa\t" << numTaxa << "\n";
        
        //double v = rng->uniform01();
        
//        if (v < 0.5)
//        if (true)
//        {
        
            // get sum of positive residuals for each taxon against all other taxa
            std::vector<double> residualWeights_a(numTaxa,0.0);
            
            double sumResidualWeights_a = 0.0;
            for (size_t i = 0; i < numTaxa; i++)
            {
                for (size_t j = 0; j < numTaxa; j++)
                {
                    double r = storedResiduals[i * numTaxa + j];
                    r = exp(lambda*r);
                    if (r > 0.0 && i != j)
                    //if (i != j)
                    {
                        residualWeights_a[i] += r;
                        sumResidualWeights_a += r;
                    }
                }
            }
            
            // if there are no positive residuals, abort move
            if (sumResidualWeights_a == 0.0)
            {
      //          std::cout << "no pos residuals\n";
                failedAdd = true;
                return RbConstants::Double::neginf;
            }

            
            
            
            // sample taxon A from weights
            double u_a = rng->uniform01() * sumResidualWeights_a;
            double m_a = 0.0;
            //size_t k_a = 0;
            
            for (size_t i = 0; i < numTaxa; i++)
            {
                m_a += residualWeights_a[i];
                if (m_a > u_a)
                {
                    k_a = i;
                    nodeDst = &tau.getNode(k_a);
                    break;
                }
            }
            
            //fwdProposal *= (residualWeights_a[k_a] / sumResidualWeights_a);
            
            // get sum of positive residuals for each taxon wrt taxon A
            std::vector<double> residualWeights_b(numTaxa,0.0);
            double sumResidualWeights_b = 0.0;
            for (size_t i = 0; i < numTaxa; i++)
            {
                double r = storedResiduals[k_a * numTaxa + i];
                r = exp(lambda*r);
                if (r > 0.0 && k_a != i)
                //if (k_a != i)
                {
                    residualWeights_b[i] += r;
                    sumResidualWeights_b += r;
                }
            }
            
            // sample taxon B from weights
            double u_b = rng->uniform01() * sumResidualWeights_b;
            double m_b = 0.0;
            //size_t k_b = 0;
            
            for (size_t i = 0; i < numTaxa; i++)
            {
                m_b += residualWeights_b[i];
                if (m_b > u_b)
                {
                    k_b = i;
                    nodeSrc = &tau.getNode(k_b);
                    break;
                }
            }
//            
//            std::cout << "rw_a\t";
//            for (size_t i = 0; i < numTaxa; i++)
//                std::cout << residualWeights_a[i] / sumResidualWeights_a << "\t";
//            std::cout << "\n";
//            std::cout << "pick " << k_a << " " << (residualWeights_a[k_a] / sumResidualWeights_a) << "\n";
//
//            
//            
//            std::cout << "rw_b\t";
//            for (size_t i = 0; i < numTaxa; i++)
//                std::cout << residualWeights_b[i] / sumResidualWeights_b << "\t";
//            std::cout << "\n";
//            std::cout << "pick " << k_b << " " <<  (residualWeights_b[k_b] / sumResidualWeights_b) << "\n";
//            
        
            
            //fwdProposal *= (residualWeights_b[k_b] / sumResidualWeights_b);
//        }
//        else
//        {
//            //std::cout << "random\n";
//            k_a = rng->uniform01() * numTaxa;
//            do
//            {
//                k_b = rng->uniform01() * numTaxa;
//            } while(k_a == k_b);
//            nodeDst = &tau.getNode(k_a);
//            nodeSrc = &tau.getNode(k_b);
//        }
//        
//        std::cout << "taxa pair\t" << k_a << "\t" << k_b << "\n";
        //std::cout << "fwdProposal\t" << fwdProposal << "\tlnFwdProposal\t" << log(fwdProposal) << "\n";
        
        // get path from tip to root for both nodes
        AdmixtureNode* nd_a = nodeDst;
        std::list<AdmixtureNode*> path_a;
    //    std::cout << "path_a : tip -> root\t" << nd_a << "\n";
        while (nd_a != NULL)
        {
    //        std::cout << "\t" << nd_a << "\t" << nd_a->getAge() << "\n";
            path_a.push_back(nd_a);
            nd_a = &nd_a->getParent();
        }
        nd_a = path_a.back();
        
        AdmixtureNode* nd_b = nodeSrc;
        std::list<AdmixtureNode*> path_b;
    //    std::cout << "path_b : tip -> root\t" << nd_b << "\n";
        while (nd_b != NULL)
        {
     //       std::cout << "\t" << nd_b << "\t" << nd_b->getAge() << "\n";
            path_b.push_back(nd_b);
            nd_b = &nd_b->getParent();
        }
        nd_b = path_b.back();
        
        // find the node where the paths diverge by traversing both paths from root to tip
        AdmixtureNode* mrca = nd_a;
     //   std::cout << "mrca : root -> tip\n";
        while (nd_a == nd_b && !path_a.empty() && !path_b.empty())
        {
            mrca = nd_a;
     //       std::cout << "\t" << mrca << "\t" << mrca->getAge() << "\n";
            nd_a = path_a.back();
            nd_b = path_b.back();
            path_a.pop_back();
            path_b.pop_back();
        }
        
        // sample u.a.r. between nd_b and present
        double minAge = nodeSrc->getAge();
        if (minAge < nodeDst->getAge())
            minAge = nodeDst->getAge();
        double maxAge = mrca->getAge();
        
        int mrcaChIdx = 0;
        // if (allowSisterAdmixture == false)
//        if (allowSisterAdmixture == false && mrca->getTopologyChild(0).isTip() == false && mrca->getTopologyChild(1).isTip() == false)
        if (allowSisterAdmixture == false)// && mrca->getTopologyChild(0).isTip() == false && mrca->getTopologyChild(1).isTip() == false)
        {
            maxAge = mrca->getTopologyChild(0).getAge();
            if (maxAge < mrca->getTopologyChild(1).getAge())
            {
                maxAge = mrca->getTopologyChild(1).getAge();
                mrcaChIdx = 1;
            }
        }
        if (maxAge <= minAge)
        {
     //       std::cout << "maxAge <= minAge\t" << maxAge << " < " << minAge << "\n";
            failedAdd = true;
            return RbConstants::Double::neginf;
        }
        //maxAge = mrca->getAge();
        //double admixtureAge = rng->uniform01() * (maxAge - minAge) + minAge;
        double exp_lambda = 2.0;
        double admixtureAge = RbStatistics::Beta::rv(1.0,exp_lambda, *rng) * (maxAge - minAge) + minAge;
        
        
        double a = 1.0;
        double b = 2.0;
        double admixtureWeight = RbStatistics::Beta::rv(a, b, *rng);
        //admixtureWeight /= 2;
            
        // attach edge as appropriate from aPath to bPath
        // front=0, back=1
        
     //   std::cout << "a_path : find admixtureAge\n";
        while (nd_a->getAge() > admixtureAge && !path_a.empty())
        {
            nd_a = path_a.back();
       //     std::cout << "\t" << nd_a << "\t" << nd_a->getAge() << "\n";
            path_a.pop_back();
            
            if (nd_a->getParent().getAge() > admixtureAge && nd_a->getAge() < admixtureAge)
                break;
        }
        
        // ... prob of selecting a certain source branch
        // double t_a = nd_a->getParent().getAge();
        // fwdProposal *= t_a / (t_a - nodeSrc->getAge());
        
       // std::cout << "b_path : find admixtureAge\n";
        while (nd_b->getAge() > admixtureAge && !path_b.empty())
        {
            nd_b = path_b.back();
        //    std::cout << "\t" << nd_b << "\t" << nd_b->getAge() << "\n";
            path_b.pop_back();
            
            if (nd_b->getParent().getAge() > admixtureAge && nd_b->getAge() < admixtureAge)
                break;
        }
        
        
        //////////////////////////////////////////////////
        
        
        
        
        // placeholder for add
        // nd_a = storedAdmixtureParentChild;
        // nd_b = storedAdmixtureChildChild;
        double newAge = admixtureAge;
        double newWeight = admixtureWeight;
        //newWeight = storedAdmixtureWeight;
//        if (storedAdmixtureAge < maxAge && storedAdmixtureAge > minAge)
//            newAge = storedAdmixtureAge;
//        double newWeight = storedAdmixtureWeight;
       // std::cout << "age\t" << newAge << "\n";
      //  std::cout << "wt \t" << newWeight << "\n";

        // add into graph
        
        
        if (rng->uniform01() < 0.5)
        {
            AdmixtureNode* tmp = nd_a;
            nd_a = nd_b;
            nd_b = tmp;
        }
        
        
        // store adjacent nodes to new parent node
        newAdmixtureParentChild = nd_a;
        newAdmixtureParentParent = &nd_a->getParent();
        
        // insert admixtureParent into graph
        storedAdmixtureParent->setAge(newAge);
        storedAdmixtureParent->setParent(root);
        newAdmixtureParentChild->setParent(storedAdmixtureParent);
        newAdmixtureParentParent->addChild(storedAdmixtureParent);
        newAdmixtureParentParent->removeChild(newAdmixtureParentChild); // 
        storedAdmixtureParent->addChild(newAdmixtureParentChild);
        storedAdmixtureParent->setParent(newAdmixtureParentParent);
        
        // store adjacent nodes to new child node
        newAdmixtureChildChild = nd_b;
        newAdmixtureChildParent = &nd_b->getParent();
        
        // insert admixtureChild into graph
        storedAdmixtureChild->setAge(newAge);
        storedAdmixtureChild->setWeight(newWeight);
        storedAdmixtureChild->setParent(root);
        newAdmixtureChildChild->setParent(storedAdmixtureChild);
        newAdmixtureChildParent->addChild(storedAdmixtureChild);
        newAdmixtureChildParent->removeChild(newAdmixtureChildChild);
        storedAdmixtureChild->addChild(newAdmixtureChildChild);
        storedAdmixtureChild->setParent(newAdmixtureChildParent);
        
        // update with outgroup settings
        storedAdmixtureChild->setOutgroup(newAdmixtureChildChild->isOutgroup());
        storedAdmixtureParent->setOutgroup(newAdmixtureParentChild->isOutgroup());
        
//        std::cout << "add " << tau.getAdmixtureEdgeStr(storedAdmixtureParent, storedAdmixtureChild) << "\n";
//        variable->touch();
//        std::cout << "\nAFTER\n";
//        storedResiduals = residuals->getValue();
//        for (size_t i = 0; i < numTaxa; i++)
//        {
//            for (size_t j = 0; j < numTaxa; j++)
//            {
//                double r = storedResiduals[i * numTaxa + j];
//                std::cout << r << " ";
//            }
//            std::cout << "\n";
//        }

        
        // update branch rates
        //double lnBwdPropRates = 0.0;
        
        
        /*
        storedBranchRates.clear();
        double delta = 0.0;
        // ... have oldBranchIdx already
        int newChildBranchIdx = (int)storedAdmixtureChild->getTopologyChild(0).getIndex();
        int newParentBranchIdx = (int)storedAdmixtureParent->getTopologyChild(0).getIndex();
        std::set<int> idxSet;
        idxSet.insert(oldChildBranchIdx);
        idxSet.insert(oldParentBranchIdx);
        idxSet.insert(newChildBranchIdx);
        idxSet.insert(newParentBranchIdx);

        //for (size_t i = 0; i < idxSet.size(); i++)
        for (std::set<int>::iterator it = idxSet.begin(); it != idxSet.end(); it++)
        {
            int idx = *it;
            double v = branchRates[idx]->getValue();
            storedBranchRates[idx] = v;
            double u = exp(delta*(GLOBAL_RNG->uniform01() - 0.5));
            branchRates[idx]->setValue(new double(u * v));
  //          std::cout << "br " << idx << " " << v << " -> " << u*v << "\n";
            lnBwdPropRates += log(u);
        }        
     //   tau.checkAllEdgesRecursively(root);
        
        // ln hastings ratio
        //bwdProposal = 1.0 / numAdmixtureEdges;
        //fwdProposal = (residualWeights_a[k_a] / sumResidualWeights_a) * (residualWeights_b[k_b] / sumResidualWeights_b);
        
        double lnFwdProposal = log(fwdProposal);
        double lnBwdProposal = log(bwdProposal);
        */
        
        return 0.0;
    }
}
void AdmixtureBipartitionSummaryMonitor::updateBipartitions(void)
{

    if (delayTimer->getValue() <= 0)
    {

        // get tree object
        AdmixtureTree* tau = &tree->getValue();
        std::vector<AdmixtureNode*> nodes;
        for (unsigned i = 0; i < tree->getValue().getNumberOfNodes(); i++)
            nodes.push_back(&tau->getNode(i));

        // map key iterator used for find()
        std::map<std::vector<bool>, std::vector<AdmixtureEdgeRecord> >::iterator it;

        // get partitions for all nodes
        bool firstRootHit = false;
        for (size_t i = 0; i < nodes.size(); i++)
        {
            AdmixtureNode* p = nodes[i];
            if (p->isRoot())
                continue;
            else if (&p->getParent() == &tau->getRoot() && firstRootHit)
            {
                firstRootHit = false;
                continue;
            }

            std::vector<bool> p_key = std::vector<bool>(numTaxa,false);
            std::vector<bool> c_key;

            AdmixtureEdgeRecord er(0,false,0,0,0,0);
            findTaxonBipartition(p_key, p);

            if (&p->getAdmixtureParent() != NULL)
            {
                // admixture children are handled by the admixture parent case
                continue;
            }
            else if (&p->getAdmixtureChild() == NULL && &p->getAdmixtureParent() == NULL)
            {
                // skip tips for tree partitions
                if (p->getNumberOfChildren() == 0)
                    continue;

                // topology nodes have complementary disjoint bipartitions
                //flipTaxonBipartitionToMinor(p_key);

                er = AdmixtureEdgeRecord((int)numSamples,false,p->getWeight(),p->getAge(),p->getBranchLength(),branchRates->getValue()[p->getIndex()]);

                // if key exists, push on to existing value as copy of original node
                if (treeBipartitions.find(p_key) != treeBipartitions.end())
                {
                    treeBipartitions[p_key].push_back(er);
                    //std::cout << "\tpush\n";
                }

                // otherwise, create new vector
                else
                {
                    std::vector<AdmixtureEdgeRecord> tmp(1,er);
                    treeBipartitions[p_key] = tmp;
                    //std::cout << "\tinsert\n";
                }
            }

            else if (&p->getAdmixtureChild() != NULL)
            {
                // admixture parent-child pairs have disjoint bipartitions
                AdmixtureNode* c = &p->getAdmixtureChild();
                c_key = std::vector<bool>(numTaxa,false);
                findTaxonBipartition(c_key, c);
                er = AdmixtureEdgeRecord((int)numSamples,true,c->getWeight(),c->getAge(),c->getBranchLength(),branchRates->getValue()[c->getTopologyChild(0).getIndex()]);

                // if key exists, push on to existing value as copy of original node
                if (AdmixtureBipartitionSummarys.find(p_key) != AdmixtureBipartitionSummarys.end() && AdmixtureBipartitionSummarys.at(p_key).find(c_key) != AdmixtureBipartitionSummarys.at(p_key).end())
                {
                    AdmixtureBipartitionSummarys[p_key][c_key].push_back(er);
                }

                // otherwise, create new vector
                else
                {
                    std::vector<AdmixtureEdgeRecord> tmp(1,er);
                    AdmixtureBipartitionSummarys[p_key][c_key] = tmp;
                }
            }
        }
        numSamples++;
    }
}
/** Perform the move */
double AdmixtureShiftNodeAgeAndRate::performSimpleMove( void ) {
    
    
    failed = false;
    
    //std::cout << "\nAge-Rate Shift\n";
    
    // clear old rates
    storedRates.clear();
    
    // Get random number generator
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    AdmixtureTree& tau = variable->getValue();
    AdmixtureNode* node = &tau.getNode(nodeIndex);
    AdmixtureNode& parent = node->getParent();
        
    // we need to work with the times
    double parent_age  = parent.getAge();
    double my_age      = node->getAge();
    double child_Age   = node->getChild( 0 ).getAge();
    if ( node->getNumberOfChildren() > 1 && child_Age < node->getChild( 1 ).getAge()) {
        child_Age = node->getChild( 1 ).getAge();
    }
    
    // admixture node ages are further constrained by their partner's time
    if (&node->getAdmixtureChild() != NULL)
    {
        AdmixtureNode& admixtureChild = node->getAdmixtureChild();
        double other_parent_age = admixtureChild.getParent().getAge();
        if (parent_age > other_parent_age)
            parent_age = other_parent_age;
        double other_child_age = admixtureChild.getChild(0).getAge();
        if (child_Age < other_child_age)
            child_Age = other_child_age;
    }
    else if (&node->getAdmixtureParent() != NULL)
    {
        AdmixtureNode& admixtureParent = node->getAdmixtureParent();
        double other_parent_age = admixtureParent.getParent().getAge();
        if (parent_age > other_parent_age)
            parent_age = other_parent_age;
        double other_child_age = admixtureParent.getChild(0).getAge();
        if (child_Age < other_child_age)
            child_Age = other_child_age;
    }
    
    // now we store all necessary values
    storedNode = node;
    storedAge = my_age;
  
    // draw new age
    double ageRange = parent_age - child_Age;
    double unitAge = (storedAge - child_Age) / ageRange;
    double a = delta * unitAge + 1.0;
    double b = delta * (1.0 - unitAge) + 1.0;
    double newUnitAge = RbStatistics::Beta::rv(a, b, *rng);
    double fwdProposal = RbStatistics::Beta::lnPdf(a, b, newUnitAge);
    double my_new_age = newUnitAge * ageRange + child_Age;
    double new_a = delta * newUnitAge + 1.0;
    double new_b = delta * (1.0 - newUnitAge) + 1.0;
    double bwdProposal = RbStatistics::Beta::lnPdf(new_a, new_b, unitAge);

    // double get branch length
    double old_brlen = node->getTopologyParent().getAge() - my_age;
    double new_brlen = node->getTopologyParent().getAge() - my_new_age;
    double brlen_ratio = old_brlen / new_brlen;
    
    // update branch rate leading to node
    double node_rate = branchRates[node->getIndex()]->getValue();
    //branchRates[node->getIndex()]->touch();
    //std::cout << "br_name" << branchRates[node->getIndex()]->getName() << "\n";
    storedRates[node] = node_rate;
    
    //std::cout << "brlen\t" << old_brlen << " -> " << new_brlen << "   " << brlen_ratio << "\n";
    //std::cout << "node_rate " << node_rate << " -> " << node_rate * brlen_ratio <<"\n";
    node_rate = node_rate * brlen_ratio;
    branchRates[node->getIndex()]->setValue(new double(node_rate));
    
    // update branch rates following from node
    for (size_t i = 0; i < storedNode->getNumberOfChildren(); i++)
    {
        AdmixtureNode* ch = &storedNode->getTopologyChild(i);
        //AdmixtureNode* ch = &storedNode->getChild(i);
        //double ch_ratio = (storedAge - ch->getAge()) / (my_new_age - ch->getAge());
        double ch_ratio = (storedAge - ch->getAge()) / (my_new_age - ch->getAge());
        double ch_rate = branchRates[ch->getIndex()]->getValue();
//        branchRates[ch->getIndex()]->touch();
        storedRates[ch] = ch_rate;
        //branchRates[node->getIndex()]->setValue(new double(ch_rate * ch_ratio));
        //std::cout << "ch_brlen " << i << "  " << (storedAge - ch->getAge()) << " -> " << (my_new_age - ch->getAge()) << "   " << ch_ratio << "\n";
        //std::cout << "ch_rate  " << i << "  " << ch_rate << " -> " << ch_rate * ch_ratio << "\n";
        ch_rate = ch_rate * ch_ratio;
        branchRates[ch->getIndex()]->setValue(new double(ch_rate));
    }
    
    // set the age
    node->setAge( my_new_age );
    
    // set age of admixture partner
    if (&node->getAdmixtureParent() != NULL)
        node->getAdmixtureParent().setAge( my_new_age );
    else if (&node->getAdmixtureChild() != NULL)
        node->getAdmixtureChild().setAge( my_new_age );
    
    
    return bwdProposal - fwdProposal;
}
std::string AdmixtureBipartitionMonitor::buildBipartitionString(void)
{
    // return buffer
    std::stringstream ss;
    
    // get tree object
    AdmixtureTree* tau = &tree->getValue();
    std::vector<AdmixtureNode*> nodes;
    for (unsigned i = 0; i < tree->getValue().getNumberOfNodes(); i++)
        nodes.push_back(&tau->getNode(i));
    
   // bool firstRootHit = false; // necessary?
    for (size_t i = 0; i < nodes.size(); i++)
    {

        AdmixtureNode* p = nodes[i];
                /*
        if (p->isRoot())
            continue;
        else if (&p->getParent() == &tau->getRoot() && firstRootHit)
        {
            firstRootHit = false;
            continue;
        }
         */
        
        std::vector<bool> pbp = std::vector<bool>(numTaxa,false);
        findTaxonBipartition(pbp, p);
        
        // look like s_0,s_1,r_0,r_1,t,w
        
        if (&p->getAdmixtureParent() != NULL)
        {
            // admixture children are handled by the admixture parent case
            continue;
        }
        else if (p->isRoot())
        {
            for (size_t i = 0; i < pbp.size(); i++)
            {
                //std::cout << std::noboolalpha << pbp[i];
                ss << std::noboolalpha << pbp[i];
            }
            //std::cout << "\n";
            ss << ",";
            ss << "," << p->getAge();
            ss << ",";
            ss << ",";
            ss << ",1";
            ss << separator;
        }
        else if (&p->getAdmixtureChild() == NULL && &p->getAdmixtureParent() == NULL)
        {
            // skip tips for divergence partitions
            // actually, keep 'em for pop-size params...
            //if (p->getNumberOfChildren() == 0)
            //    continue;

            //ss << "D";
            // print bitstring for divergence partition
            for (size_t i = 0; i < pbp.size(); i++)
                ss << std::noboolalpha << pbp[i];
            ss << ",";
            ss << "," << p->getAge();
            ss << "," << branchRates->getValue()[p->getIndex()];
            ss << ",";
            ss << ",1";
            ss << separator;
        }
        
        else if (&p->getAdmixtureChild() != NULL)
        {
            AdmixtureNode* c = &p->getAdmixtureChild();
            std::vector<bool> cbp = std::vector<bool>(numTaxa,false);
            findTaxonBipartition(cbp, c);
            
            for (size_t i = 0; i < pbp.size(); i++)
                ss << std::noboolalpha << pbp[i];
            ss << ",";
            for (size_t i = 0; i < cbp.size(); i++)
                ss << std::noboolalpha << cbp[i];
            ss << "," << p->getAge();
            ss << "," << branchRates->getValue()[p->getTopologyChild(0).getIndex()];
            ss << "," << branchRates->getValue()[c->getTopologyChild(0).getIndex()];
            ss << "," << c->getWeight();
            ss << separator;
        }
    }
    return ss.str();
}
/** Perform the move */
double AdmixtureEdgeReplaceResidualsFNPR::performSimpleMove( void ) {
    
    
    storedAdmixtureEdges.clear();
    newAdmixtureEdges.clear();
    failed = false;
    numEvents = 0;
    AdmixtureTree& tau = variable->getValue();
    
    // Get random number generator
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    // stage FNPR pointers
    size_t numIntNodes = tau.getNumberOfInteriorNodes();
    size_t numTaxa = tau.getNumberOfTips();
    pruneNode = NULL;
    while (pruneNode == NULL || pruneNode == &tau.getRoot() || pruneNode->getNumberOfChildren() != 2)
    {
        pruneNode = &tau.getNode(rng->uniform01() * numIntNodes + numTaxa - 1);
    }
    pruneParent = &pruneNode->getParent();
    //    for (size_t i = 0; i < pruneParent->getNumberOfChildren(); i++)
    //        std::cout << "\t" << &pruneParent->getChild(i) << "\n";
    
    pruneChild = &pruneNode->getTopologyChild(rng->uniform01() * 2);
    //    pruneNephew = &pruneNode->getChild(nphIdx);
    //std::cout << chIdx << " " << nphIdx << "\n";
    
    // get regraft point
    std::vector<AdmixtureNode*> new_brothers;
    findNewBrothers(new_brothers, *pruneNode, &tau.getRoot());
    int index = int(rng->uniform01() * new_brothers.size());
    regraftChild = new_brothers[index];
    if (pruneChild->isOutgroup() != regraftChild->isOutgroup())
    {
        failed = true;
        return RbConstants::Double::neginf;
    }
    regraftParent = &regraftChild->getTopologyParent();
    
    //        std::cout << "\n";
    //        std::cout << "pch  " << pruneChild << " <- " << &pruneChild->getTopologyParent() << "\n";
    //        //std::cout << "pnpw " << pruneNephew << " <- " << &pruneNephew->getTopologyParent() << "\n";
    //  //      std::cout << "pnd  " << pruneNode << " -> " << &pruneNode->getTopologyChild(chIdx) << " " << &pruneNode->getChild(nphIdx) << "\n";
    //        std::cout << "ppa  " << pruneParent << " -> " << pruneNode << "\n";
    //        std::cout << "rch  " << regraftChild << " <- " << &regraftChild->getTopologyParent() << "\n";
    //        std::cout << "rpa  " << regraftParent << " -> " << &regraftParent->getTopologyChild(0) << " " << &regraftParent->getTopologyChild(1) << "\n";
    //
    //        std::cout << "\n";
    
    // clear and store adm events on prune child lineage
    //std::cout << &pruneChild->getParent() << " " << &regraftChild->getParent() << " " << &pruneNephew->getParent() << "\n";
    
    //    for (size_t i = 0; i < pruneParent->getNumberOfChildren(); i++)
    //        std::cout << "0\t" << &pruneParent->getChild(i) << "\n";
    
    
    storeAdmixtureEventsForLineage(pruneChild);
    //std::cout << &pruneChild->getParent() << " " << &regraftChild->getParent() << " " << &pruneNephew->getParent() << "\n";
    //    for (size_t i = 0; i < pruneParent->getNumberOfChildren(); i++)
    //        std::cout << "1\t" << &pruneParent->getChild(i) << "\n";
    
    
    // clear and store adm events on regraft child lineage
    storeAdmixtureEventsForLineage(regraftChild);
    //std::cout << &pruneChild->getParent() << " " << &regraftChild->getParent() << " " << &pruneNephew->getParent() << "\n";
    //    for (size_t i = 0; i < pruneParent->getNumberOfChildren(); i++)
    //        std::cout << "2\t" << &pruneParent->getChild(i) << "\n";
    
    
    // perform FNPR
    //std::cout << "ppa  " << pruneParent << " -> " << &pruneParent->getChild(0) << " " << &pruneParent->getChild(1) << "    " << &pruneNode->getParent() << "\n";
    
    int nphIdx = 0;
    if (pruneChild == &pruneNode->getTopologyChild(nphIdx))
        nphIdx = 1;
    
    pruneNephew = &pruneNode->getChild(nphIdx);
    pruneParent = &pruneNode->getParent();
    
    //    std::cout << &pruneChild->getParent() << " " << &regraftChild->getParent() << " " << &pruneNephew->getParent() << "\n";
    //            std::cout << "ppa  " << pruneParent << " -> " << pruneNode << "\n";
    
    //    for (size_t i = 0; i < pruneParent->getNumberOfChildren(); i++)
    //        std::cout << "\t" << &pruneParent->getChild(i) << "\n";
    
    pruneParent->removeChild(pruneNode,false);
    pruneNode->removeChild(pruneNephew,false);
    pruneParent->addChild(pruneNephew,false);
    pruneNephew->setParent(pruneParent,false);
    
    regraftParent->removeChild(regraftChild,false);
    regraftParent->addChild(pruneNode,false);
    pruneNode->addChild(regraftChild,false);
    pruneNode->setParent(regraftParent,false);
    pruneNode->setOutgroup(regraftChild->isOutgroup());
    regraftChild->setParent(pruneNode,false);
    
    
    // get new age
    double maxRegraftAge = regraftParent->getAge();
    double minRegraftAge = regraftChild->getAge();
    if (minRegraftAge < pruneChild->getAge())
        minRegraftAge = pruneChild->getAge();
    storedPruneAge = pruneNode->getAge();
    double newPruneAge = rng->uniform01() * (maxRegraftAge - minRegraftAge) + minRegraftAge;
    pruneNode->setAge(newPruneAge);
    
    
    // draw new admixture edges
    //double fwdProposal = 1.0;
    //int numEvents = storedAdmixtureEdges.size();
    for (unsigned i = 0; i < storedAdmixtureEdges.size(); i++)
    {
        residuals->touch();
        storedResiduals = residuals->getValue();
        
        size_t numTaxa = tau.getNumberOfTips();
        AdmixtureNode* nodeSrc = NULL;
        AdmixtureNode* nodeDst = NULL;
        size_t k_a = 0;
        size_t k_b = 0;
        
        /*
         if (tau.getNumberOfAdmixtureParents() >= maxEvents)
         {
         failed = true;
         return RbConstants::Double::neginf;
         }
         */
        
        double maxStoredResidual = 0.0;
        for (size_t i = 0; i < storedResiduals.size(); i++)
            if (storedResiduals[i] > maxStoredResidual)
                maxStoredResidual = storedResiduals[i];
        double lambda = delta / maxStoredResidual;
        
        // get sum of positive residuals for each taxon against all other taxa
        std::vector<double> residualWeights_a(numTaxa,0.0);
        
        double sumResidualWeights_a = 0.0;
        for (size_t i = 0; i < numTaxa; i++)
        {
            for (size_t j = 0; j < numTaxa; j++)
            {
                double r = storedResiduals[i * numTaxa + j];
                r = exp(lambda*r);
                if (r > 0.0 && i != j)
                    //if (i != j)
                {
                    residualWeights_a[i] += r;
                    sumResidualWeights_a += r;
                }
                
            }
        }
        
        // if there are no positive residuals, abort move
        if (sumResidualWeights_a == 0.0)
        {
            //std::cout << "no pos residuals\n";
            failed = true;
            return RbConstants::Double::neginf;
        }
        
        
        //        std::cout << "rw_a\t";
        //        for (size_t i = 0; i < numTaxa; i++)
        //            std::cout << residualWeights_a[i] / sumResidualWeights_a << "\t";
        //        std::cout << "\n";
        
        
        // sample taxon A from weights
        double u_a = rng->uniform01() * sumResidualWeights_a;
        double m_a = 0.0;
        //size_t k_a = 0;
        
        for (size_t i = 0; i < numTaxa; i++)
        {
            m_a += residualWeights_a[i];
            if (m_a > u_a)
            {
                k_a = i;
                nodeDst = &tau.getNode(k_a);
                break;
            }
        }
        //std::cout << "pick " << k_a << "\n";
        //fwdProposal *= (residualWeights_a[k_a] / sumResidualWeights_a);
        
        // get sum of positive residuals for each taxon wrt taxon A
        std::vector<double> residualWeights_b(numTaxa,0.0);
        double sumResidualWeights_b = 0.0;
        for (size_t i = 0; i < numTaxa; i++)
        {
            double r = storedResiduals[k_a * numTaxa + i];
            r = exp(lambda*r);
            if (r > 0.0 && k_a != i)
                //if (k_a != i)
            {
                residualWeights_b[i] += r;
                sumResidualWeights_b += r;
            }
        }
        
        
        //        std::cout << "rw_b\t";
        //        for (size_t i = 0; i < numTaxa; i++)
        //            std::cout << residualWeights_b[i] / sumResidualWeights_b << "\t";
        //        std::cout << "\n";
        
        
        // sample taxon B from weights
        double u_b = rng->uniform01() * sumResidualWeights_b;
        double m_b = 0.0;
        //size_t k_b = 0;
        
        for (size_t i = 0; i < numTaxa; i++)
        {
            m_b += residualWeights_b[i];
            if (m_b > u_b)
            {
                k_b = i;
                nodeSrc = &tau.getNode(k_b);
                break;
            }
        }
        //        std::cout << "pick " << k_b << "\n\n";
        //fwdProposal *= (residualWeights_b[k_b] / sumResidualWeights_b);
        
        // get path from tip to root for both nodes
        AdmixtureNode* nd_a = nodeSrc;
        std::list<AdmixtureNode*> path_a;
        //std::cout << "path_a : tip -> root\n";
        while (nd_a != NULL)
        {
            //std::cout << "\tnd_a\t" << nd_a->getIndex() << "\t" << nd_a << "\t" << nd_a->getAge() << "\t" << &nd_a->getParent() << "\n";
            path_a.push_back(nd_a);
            nd_a = &nd_a->getParent();
        }
        nd_a = path_a.back();
        
        AdmixtureNode* nd_b = nodeDst;
        std::list<AdmixtureNode*> path_b;
        //std::cout << "path_b : tip -> root\n";
        while (nd_b != NULL)
        {
            //std::cout << "\tnd_b\t" << nd_b->getIndex() << "\t" << nd_b << "\t" << nd_b->getAge() << "\n";
            path_b.push_back(nd_b);
            nd_b = &nd_b->getParent();
        }
        nd_b = path_b.back();
        
        // find the node where the paths diverge by traversing both paths from root to tip
        AdmixtureNode* mrca = nd_a;
        //std::cout << "mrca : root -> tip\n";
        while (nd_a == nd_b && !path_a.empty() && !path_b.empty())
        {
            mrca = nd_a;
            //    std::cout << "\t" << mrca << "\t" << mrca->getAge() << "\n";
            nd_a = path_a.back();
            nd_b = path_b.back();
            path_a.pop_back();
            path_b.pop_back();
        }
        
        // sample u.a.r. between nd_b and present (we disallow sister branches to admix...)
        double minAge = nodeSrc->getAge();
        if (minAge < nodeDst->getAge())
            minAge = nodeDst->getAge();
        double maxAge = mrca->getAge();
        
        int mrcaChIdx = 0;
        
        if (allowSisterAdmixture == false)// && mrca->getTopologyChild(0).isTip() == false && mrca->getTopologyChild(1).isTip() == false)
        {
            maxAge = mrca->getTopologyChild(0).getAge();
            if (maxAge < mrca->getTopologyChild(1).getAge())
            {
                maxAge = mrca->getTopologyChild(1).getAge();
                mrcaChIdx = 1;
            }
        }
        if (maxAge <= minAge)
        {
            failed = true;
            return RbConstants::Double::neginf;
        }
        //maxAge = mrca->getAge();
        //double admixtureAge = rng->uniform01() * (maxAge - minAge) + minAge;
        double exp_lambda = 2.0;
        double admixtureAge = RbStatistics::Beta::rv(1.0,exp_lambda, *rng) * (maxAge - minAge) + minAge;
        
        
        while (nd_a->getAge() > admixtureAge && !path_a.empty())
        {
            nd_a = path_a.back();
            path_a.pop_back();
            
            if (nd_a->getParent().getAge() > admixtureAge && nd_a->getAge() < admixtureAge)
                break;
        }
        
        while (nd_b->getAge() > admixtureAge && !path_b.empty())
        {
            nd_b = path_b.back();
            path_b.pop_back();
            
            if (nd_b->getParent().getAge() > admixtureAge && nd_b->getAge() < admixtureAge)
                break;
        }
        
        if (GLOBAL_RNG->uniform01() < 0.5)
        {
            AdmixtureNode* tmp = nd_a;
            nd_a = nd_b;
            nd_b = tmp;
        }
        
        //std::cout << "ok\n";
        
        // get admixture weight
        double a = 1.0;
        double b = 2.0;
        double admixtureWeight = RbStatistics::Beta::rv(a, b, *rng);
        //double lnW = 0.0;
        admixtureWeight /= 2;
        
        // add nodes to tree
        AdmixtureNode* storedAdmixtureParent = new AdmixtureNode((int)tau.getNumberOfNodes());
        tau.pushAdmixtureNode(storedAdmixtureParent);
        AdmixtureNode* storedAdmixtureChild = new AdmixtureNode((int)tau.getNumberOfNodes());
        tau.pushAdmixtureNode(storedAdmixtureChild);
        
        // add edge
        tau.addAdmixtureEdge(storedAdmixtureParent, storedAdmixtureChild, nd_a, nd_b, admixtureAge, admixtureWeight, true);
        
        AdmixtureEdgePosition ap(storedAdmixtureParent, storedAdmixtureChild, nd_a, nd_b, admixtureAge, admixtureWeight);
        newAdmixtureEdges.push_front(ap);
        
    }
    
    tau.getRoot().flagNewickRecomputation();
    
    return 0.0;
}
/** Perform the move */
double AdmixtureEdgeRemoveResidualWeights::performSimpleMove( void ) {
    
    //std::cout << "\nAdmix Node Rem RW\n";
    
    // Get random number generator
    failed = false;
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    AdmixtureTree& tau = variable->getValue();
    std::vector<AdmixtureNode*> admixtureParents = tau.getAdmixtureParents();
    
    // if no admixtureParent exists, the proposal fails
    if (admixtureParents.size() == 0)
    {
        failed = true;
        return RbConstants::Double::neginf;
    }
    
    // otherwise, proceed
    else
    {
        failed = false;
        
        // sample a random admixture parent node
        double u = rng->uniform01();
        size_t index = std::floor(admixtureParents.size() * u);
        AdmixtureNode* admixtureParent = admixtureParents[index];
        AdmixtureNode* admixtureChild = &admixtureParent->getAdmixtureChild();
        //double w = admixtureChild->getWeight();
        
        // get all nodes adjacent to proposal
        storedAdmixtureChild = admixtureChild;
        storedAdmixtureChildChild = &admixtureChild->getChild(0);
        storedAdmixtureChildParent = &admixtureChild->getParent();
              
        storedAdmixtureParent = admixtureParent;
        storedAdmixtureParentChild = &admixtureParent->getChild(0);
        storedAdmixtureParentParent = &admixtureParent->getParent();
        
        // update edges to remove admixtureChild in graph
        storedAdmixtureChildChild->setParent(storedAdmixtureChildParent);
        storedAdmixtureChildParent->removeChild(admixtureChild);
        storedAdmixtureChildParent->addChild(storedAdmixtureChildChild);
        
        // update edges to remove admixtureParent in graph
        storedAdmixtureParentParent->removeChild(admixtureParent);
        storedAdmixtureParentParent->addChild(storedAdmixtureParentChild);
        storedAdmixtureParentChild->setParent(storedAdmixtureParentParent);
        
        
        /*
         
        // get set of tips descendant from AC and AP
        //std::cout << "tips_ap\n";
        std::set<AdmixtureNode*> tips_ap;
        findDescendantTips(tips_ap, storedAdmixtureParent);
        //std::cout << "tips_ac\n";
        std::set<AdmixtureNode*> tips_ac;
        findDescendantTips(tips_ac, storedAdmixtureChild);
*/
        
        
        // remove nodes from admixtureTree vector
        tau.eraseAdmixtureNode(storedAdmixtureParent);
        tau.eraseAdmixtureNode(storedAdmixtureChild);
        
        // get sum of positive residuals for each taxon against all other taxa
        storedResiduals = residuals->getValue();
        size_t numTaxa = tau.getNumberOfTips();
        double bwdProposal = 0.0;
        
        double maxStoredResidual = 0.0;
        for (size_t i = 0; i < storedResiduals.size(); i++)
            if (storedResiduals[i] > maxStoredResidual)
                maxStoredResidual = storedResiduals[i];
        double lambda = delta / maxStoredResidual;
        
        // get sum of positive residuals for each taxon against all other taxa
        std::vector<double> residualWeights_a(numTaxa,0.0);
        
        double sumResidualWeights_a = 0.0;
        for (size_t i = 0; i < numTaxa; i++)
        {
            for (size_t j = 0; j < numTaxa; j++)
            {
                double r = storedResiduals[i * numTaxa + j];
                r = exp(lambda*r);
                if (r > 0.0 && i != j)
                    //if (i != j)
                {
                    residualWeights_a[i] += r;
                    sumResidualWeights_a += r;
                }
                
            }
        }
        
        size_t k_a = admixtureParent->getIndex();
        bwdProposal *= (residualWeights_a[k_a] / sumResidualWeights_a);
        
        // get sum of positive residuals for each taxon wrt taxon A
        std::vector<double> residualWeights_b(numTaxa,0.0);
        double sumResidualWeights_b = 0.0;
        for (size_t i = 0; i < numTaxa; i++)
        {
            double r = storedResiduals[k_a * numTaxa + i];
            r = exp(lambda*r);
            if (r > 0.0 && k_a != i)
                //if (k_a != i)
            {
                residualWeights_b[i] += r;
                sumResidualWeights_b += r;
            }
        }
        
        size_t k_b = admixtureChild->getIndex();
        bwdProposal *= (residualWeights_b[k_b] / sumResidualWeights_b);
        
        // prior & propsal admixture weights cancel...
        //double lnW = 0.0;
        
        // prior * proposal ratio
        numEvents = (int)tau.getNumberOfAdmixtureChildren();
        admixtureCount->setValue(new int(numEvents));

        return 0.0;
        //double lnFwdProposal = -log(numEvents+1);
        //return lnW + log(bwdProposal) - lnFwdProposal;
    }
}
/* Build newick string */
std::string ExtendedNewickAdmixtureTreeMonitor::buildExtendedNewick( AdmixtureNode* n ) {
    // create the newick string
    std::stringstream o;
    
    // extended data is only found on admixture nodes
    std::string additionalInfo = "";
    
    // loop over admixture nodes per branch
    std::stringstream admixturestream;
    
    double br = 1.0;
    if (!n->isRoot())
    {
        if (showRates)
            br = branchRates->getValue()[n->getIndex()];
        //std::cout << "hmm\n";
        // [{s=&srcPtr,d=&dstPtr,t=double,w=double},{...},...,{...}]
        
    
        if (showMetadata)
        {
            admixturestream << "[";
            AdmixtureNode* p = &n->getParent();
            while (p->getNumberOfChildren() == 1)
            {
        //        std::cout << "ok\n";

                admixturestream << "{s=";
                if (&p->getAdmixtureParent() == NULL)
                    admixturestream << p;
                else
                    admixturestream << &p->getAdmixtureParent();
                
                admixturestream << ",d=";
                if (&p->getAdmixtureChild() == NULL)
                    admixturestream << p;
                else
                    admixturestream << &p->getAdmixtureChild();
                
                admixturestream << ",t=" << p->getAge();
                admixturestream << ",w=" << p->getWeight();
                admixturestream << "}";
                
                p = &p->getParent();
                
                if (p->getNumberOfChildren() == 1)
                    admixturestream << ",";

            }
            admixturestream << "]";
            additionalInfo = admixturestream.str();
        }
    }
//    std::cout << br << "\n";
    //std::cout << additionalInfo << "\n";
    
    // test whether this is a internal or external node
    if (n->isTip()) {
        //std::cout << "tipnode\t" << additionalInfo << "\n";
        // this is a tip so we just return the name of the node
        o << n->getName() << additionalInfo << ":" << n->getTopologyBranchLength() * br;
    }
    else {
        //std::cout << "intnode\t" << additionalInfo << "\n";
        o << "(";
        for (size_t i=0; i<(n->getNumberOfChildren()-1); i++) {
            o << buildExtendedNewick( &n->getTopologyChild(i) ) << ",";
        }
        o << buildExtendedNewick( &n->getTopologyChild(n->getNumberOfChildren()-1) ) << ")" << additionalInfo << ":" << n->getTopologyBranchLength() * br;
    }
    
    return o.str();
}
/** Perform the move */
double AdmixtureNearestNeighborInterchangeAndRateShift::performSimpleMove( void ) {
    
    //std::cout << "\nDiv Node NNI & Rate Rescale\n";
    
    failed = false;
    
    // Get random number generator
    RandomNumberGenerator* rng     = GLOBAL_RNG;
    
    AdmixtureTree& tau = variable->getValue();
    
    // pick a random node which is not the root and neithor the direct descendant of the root
    AdmixtureNode* node;
    do {
        double u = rng->uniform01();
        size_t index = std::floor(tau.getNumberOfNodes() * u);
        node = &tau.getNode(index);
    } while ( node->isRoot() || node->getTopologyParent().isRoot() ||  node->getNumberOfChildren() != 2);
    
    int nodeChildMoveIdx = (int)std::floor(rng->uniform01() * 2.0);
    int nodeBrotherIdx = 0;
    
    
    //std::cout << "nodeChildeMoveIdx  " << nodeChildMoveIdx << "\n";
    // divergence location
    AdmixtureNode* childMove = &node->getChild(nodeChildMoveIdx);
    AdmixtureNode* parent = &node->getTopologyParent();
    AdmixtureNode* brother = &parent->getTopologyChild( nodeBrotherIdx );
  
    // check if we got the correct child lineage
    if ( brother == node )
    {
        if (nodeBrotherIdx == 0)
            nodeBrotherIdx = 1;
        else
            nodeBrotherIdx = 0;
    }
    
    // get brother of node (not divergence child node)
    brother = &parent->getChild(nodeBrotherIdx);
    
    if (brother->getAge() > node->getAge())
    {
        //std::cout << "failed, bro > node\n";
        failed = true;
        return RbConstants::Double::neginf;
    }
    else if (childMove->getAge() > parent->getAge())
    {
        //std::cout << "failed, child > parent\n";
        failed = true;
        return RbConstants::Double::neginf;
    }
    else if (childMove->isOutgroup() != brother->isOutgroup())
    {
        //std::cout << "failed, outgroup mismatch\n";
        failed = true;
        return RbConstants::Double::neginf;
    }
    
    
    // update parent clade
    storedNodeParent = parent;
    storedNodeChildMove = childMove;
    storedBrother = brother;
    storedNode = node;

    // swap
    storedNode->removeChild(storedNodeChildMove);
    storedNodeParent->removeChild(storedBrother);
    
    storedNode->addChild(storedBrother);
    storedNodeParent->addChild(storedNodeChildMove);
    
    storedBrother->setParent(storedNode);
    storedNodeChildMove->setParent(storedNodeParent);

    // get branch rate index
    storedChildRateIndex = (int)node->getTopologyChild(nodeChildMoveIdx).getIndex();
    storedBrotherRateIndex = (int)parent->getTopologyChild(nodeBrotherIdx).getIndex();
//    storedNodeRateIndex = node->getIndex();

    
    // store branch rate values
    storedChildRate = branchRates[storedChildRateIndex]->getValue();
 //   storedNodeRate = branchRates[storedNodeRateIndex]->getValue();
    storedBrotherRate = branchRates[storedBrotherRateIndex]->getValue();
    
    // update
    //double cnr = 0.0;
    //double snr = 0.0;
    //double sbr = 0.0;
    
    double scaleChildRate = exp(delta*(rng->uniform01() - 0.5));
 //   double scaleNodeRate = exp(delta*(rng->uniform01() - 0.5));
    double scaleBrotherRate = exp(delta*(rng->uniform01() - 0.5));
    branchRates[storedChildRateIndex]->setValue(new double(storedChildRate*scaleChildRate));
  //  branchRates[storedNodeRateIndex]->setValue(new double(storedNodeRate * scaleNodeRate));
    branchRates[storedBrotherRateIndex]->setValue(new double(storedBrotherRate * scaleBrotherRate));
    //branchRates[storedChildRateIndex]->touch();
    
    //std::cout << "chld rate  " << storedChildRate << " -> " << storedChildRate*scaleChildRate << "\n";
   // std::cout << "node rate  " << storedNodeRate << " -> " << storedNodeRate*scaleNodeRate << "\n";
    //std::cout << "bro  rate  " << storedBrotherRate << " -> " << storedBrotherRate*scaleBrotherRate << "\n";
    
    if (storedChildRate * scaleChildRate == 0.0)
    {
        ;//std::cout << "new scaledChildRate == 0.0\n";
    }
    
    //if (storedNodeRate * scaleNodeRate == 0.0)
    //{
     //   std::cout << "new scaledNodeRate == 0.0\n";
    //}
    if (storedBrotherRate * scaleBrotherRate == 0.0)
    {
        ;//std::cout << "new scaledBrotherRate == 0.0\n";
    }
    //std::cout << scaleChildRate*scaleBrotherRate << "  " << log(scaleChildRate*scaleBrotherRate) << "\n";

    
    // MH
    
  // return 0.0;
    return log(scaleChildRate*scaleBrotherRate);
}