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();
}
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 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);
}