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