// $Id: rectree.cpp,v 1.82 2018/01/03 21:33:04 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include <cassert>
#include <iostream>                     // debugging

#include "local_build.h"
#include "dynatracer.h"                 // Defines some debugging macros.

#include "branchbuffer.h"               // Used in SetCurTargetLinkweightFrom for BranchBuffer::ExtractConstBranches.
#include "errhandling.h"                // Can throw overrun_error.
#include "fc_status.h"                  // Used in Prune() to determine what recombinations can be removed.
#include "force.h"                      // For TimeSize object.
#include "mathx.h"
#include "range.h"
#include "runreport.h"
#include "tree.h"

#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

using namespace std;

//------------------------------------------------------------------------------------

typedef boost::shared_ptr<RBranch> RBranch_ptr;

//------------------------------------------------------------------------------------

RecTree::RecTree()
    : Tree(),
      m_pMovingLocusVec(),
      m_protoMovingCells()
{
    m_curTargetLinkweight = ZERO;
    m_newTargetLinkweight = ZERO;
}

//------------------------------------------------------------------------------------

RecTree::RecTree(const RecTree & tree, bool makestump)
    : Tree(tree, makestump),
      m_pMovingLocusVec(tree.m_pMovingLocusVec),
      m_protoMovingCells(tree.m_protoMovingCells)

{
    m_curTargetLinkweight = ZERO;
    m_newTargetLinkweight = ZERO;
}

//------------------------------------------------------------------------------------

Tree * RecTree::Clone() const
{
    RecTree * tree = new RecTree(*this, false);
    return tree;
} // RecTree::Clone

//------------------------------------------------------------------------------------

Tree * RecTree::MakeStump() const
{
    RecTree * tree = new RecTree(*this, true);
    return tree;
}

//------------------------------------------------------------------------------------

void RecTree::Clear()
{
    Tree::Clear();
    m_curTargetLinkweight = ZERO;
    m_newTargetLinkweight = ZERO;
}

//------------------------------------------------------------------------------------

void RecTree::CopyTips(const Tree * tree)
{
    Tree::CopyTips(tree);
    m_curTargetLinkweight = ZERO;
    m_newTargetLinkweight = ZERO;
    for (vector<Locus>::const_iterator locus = m_pMovingLocusVec->begin(); locus != m_pMovingLocusVec->end(); ++locus)
    {
        m_aliases.push_back(locus->GetDLCalc()->RecalculateAliases(*this, *locus));
    }
}

//------------------------------------------------------------------------------------

void RecTree::CopyBody(const Tree * tree)
{
    Tree::CopyBody(tree);
    m_curTargetLinkweight = ZERO;
    m_newTargetLinkweight = ZERO;
}

//------------------------------------------------------------------------------------

void RecTree::CopyPartialBody(const Tree * tree)
{
    Tree::CopyPartialBody(tree);
    m_curTargetLinkweight = ZERO;
    m_newTargetLinkweight = ZERO;
}

//------------------------------------------------------------------------------------

void RecTree::Break(Branch_ptr pBranch)
{
    Branch_ptr pParent = pBranch->Parent(0);

    if (pParent->CanRemove(pBranch))
    {
        Break(pParent);
        m_timeList.Remove(pParent);

        pParent = pBranch->Parent(1);
        if (pParent)
        {
            Break(pParent);
            m_timeList.Remove(pParent);
        }
    }
}

//------------------------------------------------------------------------------------

const vector<LocusCell> & RecTree::CollectMovingCells()
{
    if (m_protoMovingCells.empty())
    {
        unsigned long int i;
        for (i = 0; i < m_pMovingLocusVec->size(); ++i)
        {
            m_protoMovingCells.push_back((*m_pMovingLocusVec)[i].GetProtoCell());
        }
    }
    return m_protoMovingCells;
} // RecTree::CollectMovingCells

//------------------------------------------------------------------------------------

vector<Branch_ptr> RecTree::ActivateTips(Tree * othertree)
{
    vector<Branch_ptr> tips = Tree::ActivateTips(othertree);

#ifdef RUN_BIGLINKS
    m_curTargetLinkweight = m_timeList.GetNTips() * RecRange::AccumulatedLinkweight(RecRange::GetAllLinks());
#else
    m_curTargetLinkweight = m_timeList.GetNTips() * (m_totalSites - 1); // -1 because there is no link after last site.
#endif

    m_newTargetLinkweight = ZERO;

#if defined(EMULATE_LITTLELINKS) || ! defined(RUN_BIGLINKS)
#if 1
    DebugAssert2(m_curTargetLinkweight == m_timeList.GetNTips() * (m_totalSites - 1),
                 m_curTargetLinkweight,
                 m_timeList.GetNTips() * (m_totalSites - 1));
#else // Equivalent to DebugAssert2 above, in case it is removed later.
    assert(m_curTargetLinkweight == m_timeList.GetNTips() * (m_totalSites - 1));
#endif
#endif // defined(EMULATE_LITTLELINKS) || ! defined(RUN_BIGLINKS)

    return tips;
}

//------------------------------------------------------------------------------------

Branch_ptr RecTree::ActivateBranch(Tree * othertree)
{
    Branch_ptr pActive = Tree::ActivateBranch(othertree);
    m_curTargetLinkweight += pActive->GetRangePtr()->GetCurTargetLinkweight();
    return pActive;
}

//------------------------------------------------------------------------------------

Branch_ptr RecTree::ActivateRoot(FC_Status & fcstatus)
{
    Branch_ptr pRoot = Tree::ActivateRoot(fcstatus);
    m_curTargetLinkweight += pRoot->GetRangePtr()->GetCurTargetLinkweight();
    m_newTargetLinkweight = ZERO;
    return pRoot;
}

//------------------------------------------------------------------------------------

void RecTree::AttachBase(Branch_ptr newroot)
{
    Tree::AttachBase(newroot);
    m_curTargetLinkweight = ZERO;
}

//------------------------------------------------------------------------------------

vector<Branch_ptr> RecTree::FirstInterval(double eventT)
{
    Branch_ptr pBranch;

    vector<Branch_ptr> newinactives = Tree::FirstInterval(eventT);

    m_newTargetLinkweight = ZERO;       // Initialize the weight of active Links.

    return newinactives;
}

//------------------------------------------------------------------------------------

void RecTree::NextInterval(Branch_ptr pBranch)
{
    Branch_ptr pParent = pBranch->Parent(0);
    m_newTargetLinkweight -= pParent->Child(0)->GetRangePtr()->GetNewTargetLinkweight();

    // If the branch has a sibling, we must remove it as well (it's a coalescence event replaced by its parent).
    if (pParent->Child(1))
    {
        m_newTargetLinkweight -= pParent->Child(1)->GetRangePtr()->GetNewTargetLinkweight();
    }
    else if (pBranch->Parent(1))        // If the branch has a second parent, insert it.
    {
        m_newTargetLinkweight += pBranch->Parent(1)->GetRangePtr()->GetNewTargetLinkweight();
    }

    m_newTargetLinkweight += pParent->GetRangePtr()->GetNewTargetLinkweight();
}

//------------------------------------------------------------------------------------

void RecTree::Prune()
{
    // This routine DEMANDS that all current-state Range information in the tree is correct!  Thus:
    assert(m_timeList.RevalidateAllRanges());

    // This routine locates recombinations which are no longer relevant due to occuring at Links that
    // are no longer targetable.  It removes such recombinations and everything logically dependent
    // on them.  It also makes all "old state" information in the Ranges equal to the current
    // state, in preparation for the next cycle.

    m_newTargetLinkweight = ZERO;
    Branch_ptr pBranch, pChild;
    // The original cut branch never needs to be updated or removed by Prune().
    Branchiter start(m_timeList.NextNonTimeTiedBranch(m_firstInvalid));

    FC_Status fcstatus;
    vector<Branch_ptr> branches(FindBranchesImmediatelyTipwardOf(start));
    vector<Branch_ptr>::iterator branch;

#if FINAL_COALESCENCE_ON
    for (branch = branches.begin(); branch != branches.end(); ++branch)
    {
        fcstatus.Increment_FC_Counts((*branch)->GetLiveSites());
    }
#endif

    // Loop over pBranch starting from cut point.
    Branchiter brit;
    for (brit = start; brit != m_timeList.EndBranch(); /* increments inside loop */ )
    {
        pBranch = *brit;

#if FINAL_COALESCENCE_ON
        // If we're a fully functional, two-legged coalescence ...
        if (pBranch->Event() == btypeCoal && !pBranch->m_marked)
        {
            rangeset coalesced_sites =
                Intersection(pBranch->Child(0)->GetLiveSites(), pBranch->Child(1)->GetLiveSites());
            fcstatus.Decrement_FC_Counts(coalesced_sites);
        }
#endif

        rangeset fcsites;
#if FINAL_COALESCENCE_ON
        fcsites = fcstatus.Coalesced_Sites();
#endif

        // Update this branch's "m_oldTargetSites" info, which is no longer needed in this cycle,
        // so that it will be right for next cycle.  Done here because it requires FC information.
        pBranch->ResetOldTargetSites(fcsites);

        if (pBranch->IsRemovableRecombinationLeg(fcsites))
        {
#ifndef NDEBUG
            // Validation check.
            Range * childrangeptr = pBranch->Child(0)->GetRangePtr();
            rangeset childtargetsites(Union(childrangeptr->GetDiseaseSites(),
                                            RemoveRangeFromRange(fcsites, childrangeptr->GetLiveSites())));
            linkrangeset childtargetlinks(RecRange::LinksSpanningSites(childtargetsites));
            //
            if (!(childtargetlinks == childrangeptr->GetCurTargetLinks()))
            {
                cerr << "RecTree::Prune (invalid self or child CurTargetLinks) call to Self->RecRange::PrintInfo()" << endl << endl;
                pBranch->GetRangePtr()->PrintInfo();
                cerr << "RecTree::Prune (invalid self or child CurTargetLinks) call to Child->RecRange::PrintInfo()" << endl << endl;
                childrangeptr->PrintInfo();
                cerr << "RecRange::LinksSpanningSites(childtargetsites) (Supposed Child Current Target Links):  ";
                RecRange::PrintLinks(childtargetlinks);
                cerr << endl << "childrangeptr->GetCurTargetLinks() (Actual Child Current Target Links):  ";
                RecRange::PrintLinks(childrangeptr->GetCurTargetLinks());
                cerr << endl;
                assert(false);
            }
            //
#endif // NDEBUG

            Branch_ptr pSpouse = pBranch->GetRecPartner();
            Branch_ptr pRemove(pBranch), pRemain(pSpouse);
            // Which one to remove completely?
            if (pSpouse->IsRemovableRecombinationLeg(fcsites))
            {
                // They are both removable based on targetable sites.
                if (pBranch->GetRangePtr()->GetLiveSites().empty() && pSpouse->GetRangePtr()->GetLiveSites().empty())
                {
                    // ... and we can't break the tie on live sites, so we randomize.
                    bool removespouse = registry.GetRandom().Bool();
                    if (removespouse)
                    {
                        pRemove = pSpouse;
                        pRemain = pBranch;
                    }
                }
                else
                {
                    // ... and we break the tie on live sites.
                    if (pSpouse->GetRangePtr()->GetLiveSites().empty())
                    {
                        pRemove = pSpouse;
                        pRemain = pBranch;
                    }
                }
            }

            // Unhook branch which will be completely removed.
            Branch_ptr pChild = pRemove->Child(0);
            if (pChild->Parent(0) == pRemove)
            {
                pChild->SetParent(0, pChild->Parent(1));
            }
            pChild->SetParent(1, Branch::NONBRANCH);

            // Remove descending material below it.
            Break(pRemove);

            // Get an interator to the next still-valid interval.
            brit = m_timeList.NextBody(brit);
            if (*brit == pSpouse) brit = m_timeList.NextBody(brit);

            // Splice out branch which remains in tree.
            Branch_ptr pParent0 = pRemain->Parent(0);
            pParent0->ReplaceChild(pRemain, pRemain->Child(0));
            m_timeList.SetUpdateDLs(pParent0);
            Branch_ptr pParent1 = pRemain->Parent(1);
            if (pParent1)
            {
                pParent1->ReplaceChild(pRemain, pRemain->Child(0));
                m_timeList.SetUpdateDLs(pParent1);
            }

            // Remove the dead stuff.
            m_timeList.Remove(pRemove);
            m_timeList.Remove(pRemain);
        }
        else
        {
#if FINAL_COALESCENCE_ON
            pBranch->UpdateBranchRange(fcsites, true);
#else
            pBranch->UpdateBranchRange(fcsites, false);
#endif
            brit = m_timeList.NextBody(brit);
        }
    }

    Tree::Prune();

    // validating the ranges
    assert(m_timeList.RevalidateAllRanges());

} // RecTree::Prune

//------------------------------------------------------------------------------------

void RecTree::ReassignDLsFor(string lname, long int marker, long int ind)
{
    // Find out which locus we're dealing with.  We have its name.  If the locus in question
    // is in m_pLocusVec, we call through to Tree::ReassignDLsFor.
    long int locus = FLAGLONG;
    for (unsigned long int lnum = 0; lnum < m_pMovingLocusVec->size(); ++lnum)
    {
        if ((*m_pMovingLocusVec)[lnum].GetName() == lname)
        {
            locus = lnum;
        }
    }
    if (locus == FLAGLONG)
    {
        // The locus must be in m_pLocusVec--call the base function.
        return Tree::ReassignDLsFor(lname, marker, ind);
    }

    vector<Branch_ptr> haps = m_individuals[ind].GetAllTips();
    vector<LocusCell> cells = m_individuals[ind].GetLocusCellsFor(lname, marker);

    for (unsigned long int tip = 0; tip < haps.size(); ++tip)
    {
        Cell_ptr origcell = haps[tip]->GetDLCell(locus, markerCell, true);
        Cell_ptr newcell  = cells[tip][0];
        origcell->SetSiteDLs(marker, newcell->GetSiteDLs(marker));
        MarkForDLRecalc(haps[tip]);
    }

    // Don't recalculate aliases, since there are no aliases for the moving locus.
} // RecTree::ReassignDLsFor

//------------------------------------------------------------------------------------

Branch_ptr RecTree::CoalesceActive(double eventT, Branch_ptr active1, Branch_ptr active2, const rangeset & fcsites)
{
    Branch_ptr pBranch = Tree::CoalesceActive(eventT, active1, active2, fcsites);

    pBranch->SetMovingDLCells(CollectMovingCells());

    m_curTargetLinkweight -= active1->GetRangePtr()->GetCurTargetLinkweight();
    m_curTargetLinkweight -= active2->GetRangePtr()->GetCurTargetLinkweight();
    m_curTargetLinkweight += pBranch->GetRangePtr()->GetCurTargetLinkweight();

    return pBranch;
}

//------------------------------------------------------------------------------------

Branch_ptr RecTree::CoalesceInactive(double eventT, Branch_ptr active, Branch_ptr inactive, const rangeset & fcsites)
{
    Branch_ptr pBranch = Tree::CoalesceInactive(eventT, active, inactive, fcsites);

    pBranch->SetMovingDLCells(CollectMovingCells());

    m_newTargetLinkweight -= inactive->GetRangePtr()->GetNewTargetLinkweight();
    m_curTargetLinkweight -= active->GetRangePtr()->GetCurTargetLinkweight();
    m_newTargetLinkweight += pBranch->GetRangePtr()->GetNewTargetLinkweight();

    return pBranch;
}

//------------------------------------------------------------------------------------

Branch_ptr RecTree::Migrate(double eventT, long int topop, long int maxEvents, Branch_ptr active)
{
    Branch_ptr pBranch = Tree::Migrate(eventT, topop, maxEvents, active);

    //    pBranch->GetRangePtr()->SetMRange(pBranch->Child(0)->GetRangePtr());  // PRUNE?
    // A migration does not change the active or newly active Links.
    return pBranch;
}

//------------------------------------------------------------------------------------

Branch_ptr RecTree::DiseaseMutate(double eventT, long int endstatus, long int maxEvents, Branch_ptr active)
{
    Branch_ptr pBranch = Tree::DiseaseMutate(eventT, endstatus, maxEvents, active);

    //    pBranch->GetRangePtr()->SetMRange(pBranch->Child(0)->GetRangePtr());  // PRUNE?
    // A disease mutation does not change the active or newly active Links.
    return pBranch;
}

//------------------------------------------------------------------------------------

branchpair RecTree::RecombineActive(double eventT, long int maxEvents, FPartMap fparts,
                                    Branch_ptr pActive, long int recpoint, const rangeset & fcsites, bool lowSitesOnLeft)
{
    // "recpoint" is a recombination Littlelink (middle of target Biglink).

    if (NumberOfRecombinations() >= maxEvents)
    {
        rec_overrun e;
        throw e;
    }

    // Create left parent of the active branch, saving partition handling until end.
    // When done, "transmittedsites1" will be a RANGESET containing a single RANGEPAIR;
    // that is, it will represent a single contiguous interval of sites.
    bool newbranchisinactive(false);
    rangeset transmittedsites1;
    long int startleft;
    long int endleft;

    if (lowSitesOnLeft)
    {
        startleft = 0;                  // Transmitted sites are ZERO to first NOT transmitted (open upper end).
        endleft = recpoint + 1;
    }
    else
    {
        startleft = recpoint + 1;       // Transmitted sites are first above RECPOINT to (open) upper end.
        endleft = m_totalSites;
    }

    rangepair transmit1(startleft, endleft);
    transmittedsites1 = AddPairToRange(transmit1, transmittedsites1);

    RBranch_ptr pParentA = RBranch_ptr(new RBranch(pActive->GetRangePtr(), newbranchisinactive, transmittedsites1, fcsites));
    assert(pParentA);

    pParentA->m_eventTime  = eventT;    // Set the event time.
    pParentA->SetChild(0, pActive);
    pActive->SetParent(0, pParentA);

    // Create right parent of the active branch, saving partition handling until end.  Same as for left branch above.
    rangeset transmittedsites2;

    long int startright;
    long int endright;

    if (lowSitesOnLeft)
    {
        startright = recpoint + 1;      // Transmitted sites are first above RECPOINT to (open) upper end.
        endright = m_totalSites;
    }
    else
    {
        startright = 0;                 // Transmitted sites are ZERO to first NOT transmitted (open upper end).
        endright = recpoint + 1;
    }

    rangepair transmit2(startright, endright);
    transmittedsites2 = AddPairToRange(transmit2, transmittedsites2);

    RBranch_ptr pParentB = RBranch_ptr(new RBranch(pActive->GetRangePtr(), false, transmittedsites2, fcsites));
    assert(pParentB);

    pParentB->m_eventTime  = eventT;    // Set the event time.
    pParentB->SetChild(0, pActive);
    pActive->SetParent(1, pParentB);

    // Now deal with partitions.
    if (fparts.empty())
    {
        pParentA->CopyPartitionsFrom(pActive);
        pParentB->CopyPartitionsFrom(pActive);
    }
    else
    {
        pParentA->RecCopyPartitionsFrom(pActive, fparts, true);
        pParentB->RecCopyPartitionsFrom(pActive, fparts, false);
    }

    m_curTargetLinkweight -= pActive->GetRangePtr()->GetCurTargetLinkweight();
    m_curTargetLinkweight += pParentA->GetRangePtr()->GetCurTargetLinkweight();
    m_curTargetLinkweight += pParentB->GetRangePtr()->GetCurTargetLinkweight();

    // Now put both branches in place.
    m_timeList.Collate(pParentA, pParentB);

    return make_pair(pParentA, pParentB);
}

//------------------------------------------------------------------------------------

branchpair RecTree::RecombineInactive(double eventT, long int maxEvents, FPartMap fparts,
                                      Branch_ptr pBranch, long int recpoint, const rangeset & fcsites)
{
    // "recpoint" is a recombination Littlelink (middle of target Biglink).

    if (NumberOfRecombinations() >= maxEvents)
    {
        rec_overrun e;
        throw e;
    }

    // This is the branch already in the tree.
    bool inactive_is_low = pBranch->GetRangePtr()->AreLowSitesOnInactiveBranch(recpoint);

    // All this might eventually be one constructor call.
    rangepair transmit0;
    if (inactive_is_low)
    {
        transmit0.first = 0L;
        transmit0.second = recpoint + 1; // Transmitted sites are ZERO to first site NOT transmitted (open upper end).
    }
    else
    {
        transmit0.first = recpoint + 1;  // Transmitted sites are first site above "recpoint" to (open) upper end.
        transmit0.second = m_totalSites;
    }

    // When done, "transmittedsitesInactive" will be a RANGESET containing a single RANGEPAIR;
    // that is, it will represent a single contiguous interval of sites.
    rangeset transmittedsitesInactive;
    transmittedsitesInactive = AddPairToRange(transmit0, transmittedsitesInactive);

    RBranch_ptr pParentInactive = RBranch_ptr(new RBranch(pBranch->GetRangePtr(), true, transmittedsitesInactive, fcsites));
    pParentInactive->m_eventTime  = eventT;
    pParentInactive->CopyPartitionsFrom(pBranch);

    pParentInactive->SetChild(0, pBranch);
    pBranch->Parent(0)->ReplaceChild(pBranch, pParentInactive);
    pBranch->SetParent(0, pParentInactive);
    if (pBranch->Parent(1))
    {
        pBranch->Parent(1)->ReplaceChild(pBranch, pParentInactive);
        pBranch->SetParent(1, Branch::NONBRANCH);
    }

    // This is the new, active branch.
    if (!inactive_is_low)
    {
        transmit0.first = 0L;
        transmit0.second = recpoint + 1; // Transmitted sites are ZERO to first site NOT transmitted (open upper end).
    }
    else
    {
        transmit0.first = recpoint + 1;  // Transmitted sites are first site above "recpoint" to (open) upper end.
        transmit0.second = m_totalSites;
    }

    // When done, "transmittedsitesActive" will be a RANGESET containing a single RANGEPAIR;
    // that is, it will represent a single contiguous interval of sites.
    rangeset transmittedsitesActive;
    transmittedsitesActive = AddPairToRange(transmit0, transmittedsitesActive);
    assert(Intersection(transmittedsitesActive, pBranch->GetRangePtr()->GetOldTargetSites()).empty());

    RBranch_ptr pParentActive = RBranch_ptr(new RBranch(pBranch->GetRangePtr(), false, transmittedsitesActive, fcsites));
    pParentActive->m_eventTime = eventT;

    pParentActive->SetChild(0, pBranch);
    pBranch->SetParent(1, pParentActive);

    if (fparts.empty())
    {
        pParentActive->CopyPartitionsFrom(pBranch);
    }
    else
    {
        pParentActive->RecCopyPartitionsFrom(pBranch, fparts, !inactive_is_low);
    }

    // Now put both branches in place.
    m_timeList.Collate(pParentInactive, pParentActive);

    m_newTargetLinkweight -= pBranch->GetRangePtr()->GetNewTargetLinkweight();
    m_newTargetLinkweight += pParentInactive->GetRangePtr()->GetNewTargetLinkweight();
    m_curTargetLinkweight += pParentActive->GetRangePtr()->GetCurTargetLinkweight();

    return make_pair(pParentInactive, pParentActive);
}

//------------------------------------------------------------------------------------

rangevector RecTree::GetLocusSubtrees(rangepair span) const
{
    // Get Interval tree start sites (each is a site just to the right of a recombination breakpoint or is an endmarker).
    set<long int> startsites(GetIntervalTreeStartSites());

    // Push rangepairs representing each breakpoint into subtree vector.  The (pt + 1) avoids creating a rangepair
    // starting at the last site.  The strange iterator maneuver is because (pt + 1) is not allowed in g++.  We do
    // not risk an empty set; we know it contains at least 2 elements.
    rangevector subtrees;
    set<long int>::const_iterator pt = startsites.begin();
    set<long int>::const_iterator nextpt = pt;
    ++nextpt;
    long int begin = span.first;
    long int end = span.second;

    for ( ; nextpt != startsites.end(); ++pt, ++nextpt)
    {
        // No overlap so we don't add it.
        if (*nextpt <= begin || *pt >= end) continue;
        // Some overlap, but ends may need adjustment.
        long int first = *pt;
        long int last = *nextpt;
        if (first < begin) first = begin;
        if (last > end) last = end;
        subtrees.push_back(rangepair(first, last));
    }

    return subtrees;
} // RecTree::GetLocusSubtrees

//------------------------------------------------------------------------------------

void RecTree::SetMovingLocusVec(vector<Locus> * loc)
{
    m_pMovingLocusVec = loc;
    // We don't have to worry about the range--the moving loci move around within the range of the fixed loci.
} // RecTree::SetMovingLocusVec

//------------------------------------------------------------------------------------

void RecTree::SetMovingMapPosition(long int mloc, long int site)
{
    assert(mloc < static_cast<long int>(m_pMovingLocusVec->size()));
    (*m_pMovingLocusVec)[mloc].SetRegionalMapPosition(site);
}

//------------------------------------------------------------------------------------

TBranch_ptr RecTree::CreateTip(const TipData & tipdata, const vector<LocusCell> & cells,
                               const vector<LocusCell> & movingcells, const rangeset & diseasesites)
{
    TBranch_ptr pTip = m_timeList.CreateTip(tipdata, cells, movingcells, m_totalSites, diseasesites);
    return pTip;
}

//------------------------------------------------------------------------------------

TBranch_ptr RecTree::CreateTip(const TipData & tipdata, const vector<LocusCell> & cells,
                               const vector<LocusCell> & movingcells, const rangeset & diseasesites,
                               const vector<Locus> & loci)
{
    TBranch_ptr pTip = m_timeList.CreateTip(tipdata, cells, movingcells, m_totalSites, diseasesites, loci);
    return pTip;
}

//------------------------------------------------------------------------------------

bool RecTree::DoesThisLocusJump(long int mloc) const
{
    assert(mloc < static_cast<long int>(m_pMovingLocusVec->size()));
    return ((*m_pMovingLocusVec)[mloc].GetAnalysisType() == mloc_mapjump);
}

//------------------------------------------------------------------------------------

bool RecTree::AnyRelativeHaplotypes() const
{
    for (IndVec::const_iterator ind = m_individuals.begin(); ind != m_individuals.end(); ++ind)
    {
        if (ind->MultipleTraitHaplotypes()) return true;
    }
    return false;
}

//------------------------------------------------------------------------------------

void RecTree::CalculateDataLikes()
{
    m_overallDL = CalculateDataLikesForFixedLoci();
    //The base function accumulates a likelihood into m_overallDL.
    for (unsigned long int loc = 0; loc < m_pMovingLocusVec->size(); ++loc)
    {
        if ((*m_pMovingLocusVec)[loc].GetAnalysisType() == mloc_mapjump)
        {
            m_overallDL += CalculateDataLikesForMovingLocus(loc);
        }
    }
    m_timeList.ClearUpdateDLs();        // Reset the updating flags.
}

//------------------------------------------------------------------------------------

double RecTree::CalculateDataLikesForMovingLocus(long int loc)
{
    double likelihood;

    const Locus & locus = (*m_pMovingLocusVec)[loc];
    try                                 // Check for need to switch to normalization.
    {
        likelihood = locus.CalculateDataLikelihood(*this, true);
    }

    catch (datalikenorm_error & ex)     // Normalization is set by thrower.
    {
        m_timeList.SetAllUpdateDLs();   // All subsequent loci will recalculate the entire tree.
        RunReport & runreport = registry.GetRunReport();
        runreport.ReportChat("\n", 0);
        runreport.ReportChat("Subtree of likelihood 0.0 found:  Turning on normalization and re-calculating.");

        likelihood = locus.CalculateDataLikelihood(*this, true);
    }

    return likelihood;
} // RecTree::CalculateDataLikesForMovingLocus

//------------------------------------------------------------------------------------
// Called only when underlying data structures (trees, branches, ranges)
// are potentially recombinant (ie, contain RecRanges, not Ranges).

set<long int> RecTree::GetIntervalTreeStartSites() const
{
    // Create set of Interval tree start sites (each is a site just to the right
    // of a recombination breakpoint or is an endmarker).
    set<long int> startsites;
    startsites.insert(0);
    startsites.insert(m_totalSites);

    Branchconstiter brit;
    long int littlelink;
    for (brit = m_timeList.FirstBody(); brit != m_timeList.EndBranch(); brit = m_timeList.NextBody(brit))
    {
        // RBranch::GetRecpoint() returns Littlelink (Biglink midpoint) or "no-recombination" flag.
        littlelink = (*brit)->GetRecpoint();
        if (littlelink != FLAGLONG)     // FLAGLONG means there is no recombination here.
        {
            // Insert "littlelink + 1" because what we are inserting is the START SITE of an Interval,
            // that is, the first site AFTER the Littlelink which marks the recombination point.
            startsites.insert(littlelink + 1);
        }
    }

    return startsites;
} // RecTree::GetIntervalTreeStartSites

//------------------------------------------------------------------------------------

DoubleVec2d RecTree::GetMapSummary()
{
    DoubleVec2d retvec;
    DoubleVec1d zeroes(m_totalSites, 0.0);
    for (unsigned long int mloc = 0; mloc < m_pMovingLocusVec->size(); ++mloc)
    {
        DoubleVec1d mlikes = zeroes;
        long int currentsite;
        switch((*m_pMovingLocusVec)[mloc].GetAnalysisType())
        {
            case mloc_mapjump:
                //Find out where it is, make the likelihood at that value 1.
                currentsite = (*m_pMovingLocusVec)[mloc].GetRegionalMapPosition();
                mlikes[currentsite] = 1.0;
                break;
            case mloc_mapfloat:
                //Calculate the likelihoods over all subtrees, return vectors with it.
                //mlikes = CalculateDataLikesWithRandomHaplotypesForFloatingLocus(mloc);
                CalculateDataLikesForAllHaplotypesForFloatingLocus(mloc, mlikes);
                break;
            case mloc_data:
            case mloc_partition:
                assert(false);
                throw implementation_error("We seem to want to collect mapping data for a segment without that type"
                                           " of analysis.  This is our fault; e-mail us at lamarc@gs.washington.edu");
        }
        retvec.push_back(mlikes);
    }

    return retvec;
}

//------------------------------------------------------------------------------------

DoubleVec1d RecTree::CalculateDataLikesWithRandomHaplotypesForFloatingLocus(long int mloc)
{
    RandomizeMovingHaplotypes(mloc);
    return CalculateDataLikesForFloatingLocus(mloc);
}

//------------------------------------------------------------------------------------

void RecTree::CalculateDataLikesForAllHaplotypesForFloatingLocus(long int mloc, DoubleVec1d & mlikes)
{
    long int ind = 0;
    //We need to change the vector of mlikes from zeroes to EXPMINS.
    mlikes = SafeLog(mlikes);
    UpdateDataLikesForIndividualsFrom(ind, mloc, mlikes);
}

//------------------------------------------------------------------------------------

bool RecTree::UpdateDataLikesForIndividualsFrom(long int ind, long int mloc, DoubleVec1d & mlikes)
{
    if (static_cast<unsigned long int>(ind) == m_individuals.size()) return true;
    string lname = (*m_pMovingLocusVec)[mloc].GetName();
    //LS NOTE: If this ASSERTs, we are mapping something with more than one marker.
    // Might be OK, but should be checked.
    assert ((*m_pMovingLocusVec)[mloc].GetNmarkers() == 1);
    for (long int marker = 0; marker < (*m_pMovingLocusVec)[mloc].GetNmarkers(); ++marker)
    {
        bool newhaps = true;
        for (m_individuals[ind].ChooseFirstHaplotypeFor(lname, marker);
             newhaps;
             newhaps = m_individuals[ind].ChooseNextHaplotypeFor(lname, marker))
        {
            ReassignDLsFor(lname, marker, ind);
            if (UpdateDataLikesForIndividualsFrom(ind + 1, mloc, mlikes))
            {
                //We're on the last one--update the data likelihood.
                DoubleVec1d newlikes = CalculateDataLikesForFloatingLocus(mloc);
                //LS TEST:
                //cerr << ToString(newlikes, 5) << endl;
                mlikes = AddValsOfLogs(mlikes, newlikes);
            }
        }
    }
    return false;
}

//------------------------------------------------------------------------------------

DoubleVec1d RecTree::CalculateDataLikesForFloatingLocus(long int mloc)
{
    m_timeList.SetAllUpdateDLs();

    // We always need these on because there's only enough storage for a single subtree,
    // and the last subtree we used was at the other end of the range.
    DoubleVec1d datalikes(m_totalSites);
    rangeset allowedranges = (*m_pMovingLocusVec)[mloc].GetAllowedRange();

    // "startsites" is a set of Interval tree start sites (each is a site
    // just to the right of a recombination breakpoint or is an endmarker).
    set<long int> startsites = GetIntervalTreeStartSites();
    startsites = IgnoreDisallowedSubTrees(startsites, allowedranges);
    set<long int>::iterator left(startsites.begin()), right(startsites.begin());

    ++right;
    for ( ; right != startsites.end(); ++left, ++right )
    {
        (*m_pMovingLocusVec)[mloc].SetRegionalMapPosition(*left);
        double datalike = CalculateDataLikesForMovingLocus(mloc);
        for (long int siteindex = *left; siteindex < *right; ++siteindex)
        {
            datalikes[siteindex] = datalike;
        }
    }

    datalikes = ZeroDisallowedSites(datalikes, allowedranges);
    m_timeList.ClearUpdateDLs();

    //LS NOTE: We could theoretically not call ClearUpdateDLs if there was only one subtree,
    // but only if the *next* call to this function also had the exact same subtree, which
    // we can't enforce.  So, always call ClearUpdateDLs
    return datalikes;
}

//------------------------------------------------------------------------------------

set<long int> RecTree::IgnoreDisallowedSubTrees(set<long int> startsites, rangeset allowedranges)
{
    // "startsites" and "newstartsites" are sets of Interval tree start sites.
    // Each member is a site just to the right of a recombination breakpoint or is an endmarker).
    set<long int> newstartsites;
    newstartsites.insert(allowedranges.begin()->first);
    newstartsites.insert(m_totalSites); // To close out the final range.

    for (rangeset::iterator range = allowedranges.begin(); range != allowedranges.end(); ++range)
    {
        for (long int site = range->first; site < range->second; ++site)
        {
            if (startsites.find(site) != startsites.end())
            {
                newstartsites.insert(site);
            }
        }
    }
    return newstartsites;
}

//------------------------------------------------------------------------------------

DoubleVec1d RecTree::ZeroDisallowedSites(DoubleVec1d datalikes, rangeset allowedranges)
{
    DoubleVec1d newdatalikes(datalikes.size(), -DBL_BIG);
    for (rangeset::iterator range = allowedranges.begin(); range != allowedranges.end(); ++range)
    {
        assert(range->first >= 0);
        assert(static_cast<unsigned long int>(range->second) <= datalikes.size());
        for (long int site = range->first; site < range->second; ++site)
        {
            newdatalikes[site] = datalikes[site];
        }
    }
    return newdatalikes;
}

//------------------------------------------------------------------------------------

void RecTree::RandomizeMovingHaplotypes(long int mlocus)
{
    //This function loops over all individuals in m_individuals and randomizes the haplotypes.
    string lname = (*m_pMovingLocusVec)[mlocus].GetName();
    long int nmarkers = (*m_pMovingLocusVec)[mlocus].GetNmarkers();
    for (long int marker = 0; marker < nmarkers; ++marker)
    {
        for (unsigned long int ind = 0; ind < m_individuals.size(); ++ind)
        {
            if (m_individuals[ind].ChooseRandomHaplotypesFor(lname, marker))
            {
                //The chosen one is different from last time.
                ReassignDLsFor(lname, marker, ind);
            }
        }
    }
}

//------------------------------------------------------------------------------------

bool RecTree::SimulateDataIfNeeded()
{
    if (Tree::SimulateDataIfNeeded())
    {
        //LS DEBUG: Current version uses same data for all moving loci.  If we want to simulate data individually,
        // uncomment the following lines and replace all the subsequent loops over lnums to locus.whatever calls.
        //
        //  for (unsigned long int mloc = 0; mloc < m_pMovingLocusVec->size(); ++mloc)
        //  {
        //      Locus & locus = (*m_pMovingLocusVec)[mloc];
        if ((*m_pMovingLocusVec).size() > 0)
        {
            Locus & locus = (*m_pMovingLocusVec)[0];
            if (locus.GetShouldSimulate())
            {
                for (size_t lnum = 0; lnum < (*m_pMovingLocusVec).size(); ++lnum)
                {
                    (*m_pMovingLocusVec)[lnum].ClearVariability();
                    (*m_pMovingLocusVec)[lnum].SetNewMapPositionIfMoving();
                }

                // Check to see if this locus's site was already simulated.
                Locus * simlocus = NULL; //to prevent compiler warnings
                for (unsigned long int loc = 0; loc < m_pLocusVec->size(); ++loc)
                {
                    Locus & oldlocus = (*m_pLocusVec)[loc];
                    if (oldlocus.GetShouldSimulate())
                    {
                        if (oldlocus.SiteInLocus(locus.GetRegionalMapPosition()))
                        {
                            simlocus = & oldlocus;
                        }
                    }
                }
                if (simlocus != NULL)
                {
                    //If there was at least one site in the original that overlapped with the range on the moving
                    // locus, we take that chances as the chance that we hit the original at all, but we want
                    // to choose a variable site from that range.  This introduces an ascertainment bias that I'm
                    // not exactly sure how to compensate for, or if it needs to be compensated for.  But anyway.
                    long int newsite = simlocus->ChooseVariableSiteFrom(locus.GetAllowedRange());
                    if (newsite != FLAGLONG)
                    {
                        for (size_t lnum = 0; lnum < (*m_pMovingLocusVec).size(); ++lnum)
                        {
                            (*m_pMovingLocusVec)[lnum].SetRegionalMapPosition(newsite);
                            (*m_pMovingLocusVec)[lnum].SetTrueSite(newsite);
                            //LS TEST
                            //simlocus->PrintOnesAndZeroesForVariableSites();
                            (*m_pMovingLocusVec)[lnum].SetVariableRange(simlocus->CalculateVariableRange());
                        }
                        //LS DEBUG:  Not really for release.
                        //simlocus->CalculateDisEqFor(newsite);
                        //If there were no variable sites in the original, we keep the originally chosen site.
                        // Our trait isn't going to be variable, but them's the breaks.
                    }
                    for (size_t lnum = 0; lnum < (*m_pMovingLocusVec).size(); ++lnum)
                    {
                        (*m_pMovingLocusVec)[lnum].CopyDataFrom(*simlocus, *this);
                    }
                    if (locus.IsNighInvariant())
                    {
                        registry.GetRunReport().ReportNormal("All simulated data was nigh invariant for the"
                                                             " source segment, giving us nigh invariant data"
                                                             " for the simulated segment "
                                                             + locus.GetName() + " as well.");
                    }
                    //LS DEBUG SIM:  This would delete information again, for simulations where
                    // the data exists but you never sequenced it.
                    // simlocus->RandomizeHalf(*this);
                }
                else
                {
                    locus.SimulateData(*this, m_totalSites);
                    // Now copy this data into any other moving loci.
                    long int newsite = locus.GetRegionalMapPosition();
                    for (size_t lnum = 1; lnum < (*m_pMovingLocusVec).size(); ++lnum)
                    {
                        (*m_pMovingLocusVec)[lnum].SetRegionalMapPosition(newsite);
                        (*m_pMovingLocusVec)[lnum].SetTrueSite(newsite);
                        (*m_pMovingLocusVec)[lnum].CopyDataFrom(locus, *this);
                    }
                }
                for (size_t lnum = 0; lnum < (*m_pMovingLocusVec).size(); ++lnum)
                {
                    (*m_pMovingLocusVec)[lnum].MakePhenotypesFor(m_individuals);
                }
            }
        }
        //Redo the aliases, in case we randomized the data in the original locus.
        SetupAliases(*m_pLocusVec);
        return true;
    }
    return false;
}

//------------------------------------------------------------------------------------

long int RecTree::NumberOfRecombinations()
{
    return (m_timeList.HowMany(btypeRec) / 2);
}

//------------------------------------------------------------------------------------

void RecTree::SetCurTargetLinkweightFrom(const BranchBuffer & brbuffer)
{
    m_curTargetLinkweight = ZERO;

    vector<Branch_ptr> branches(brbuffer.ExtractConstBranches());
    vector<Branch_ptr>::const_iterator branch;

    for (branch = branches.begin(); branch != branches.end(); ++branch)
    {
        m_curTargetLinkweight += (*branch)->GetRangePtr()->GetCurTargetLinkweight();
    }
}

//------------------------------------------------------------------------------------
// Debugging function.

void RecTree::SetNewTargetLinkweightFrom(const BranchBuffer & brbuffer)
{
    m_newTargetLinkweight = ZERO;

    vector<Branch_ptr> branches(brbuffer.ExtractConstBranches());
    vector<Branch_ptr>::const_iterator branch;

    for (branch = branches.begin(); branch != branches.end(); ++branch)
    {
        m_newTargetLinkweight += (*branch)->GetRangePtr()->GetNewTargetLinkweight();
    }
}

//------------------------------------------------------------------------------------
// Debugging function.

void RecTree::PrintTipData(long int mloc, long int marker)
{
    cerr << endl << "Tip data:" << endl;
    for (Branchconstiter tip = m_timeList.FirstTip(); tip != m_timeList.FirstBody(); ++tip)
    {
        cerr << " " << (*m_pMovingLocusVec)[mloc].GetDataModel()->CellToData((*tip)->GetDLCell(mloc, marker, true), marker);
    }
    cerr << endl;
}

//------------------------------------------------------------------------------------
// Debugging function.

void RecTree::PrintRangeSetCount(const rangesetcount & rsc)
{
    for (RSCcIter rsci = rsc.begin(); rsci != rsc.end(); ++rsci)
    {
        cerr << (*rsci).first << ": " << ToString((*rsci).second) << endl;
    }
}

//------------------------------------------------------------------------------------
// Debugging function.

rangesetcount RecTree::RemoveEmpty(const rangesetcount & rsc)
{
    rangesetcount result;
    for (RSCcIter rsci = rsc.begin(); rsci != rsc.end(); ++rsci)
    {
        if (!(*rsci).second.empty())
        {
            result.insert(make_pair((*rsci).first, (*rsci).second));
        }
    }
    return result;
}

//____________________________________________________________________________________
