// $Id: dlcalc.h,v 1.45 2018/01/03 21:32:57 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 */


#ifndef DLCALCULATOR_H
#define DLCALCULATOR_H

#include <cmath>
#include <vector>

#include "vectorx.h"
#include "constants.h"
#include "rangex.h"
#include "dlcell.h"
#include "branch.h"

/*********************************************************************
 DLCalculator manages the calculation of data likelihoods on
 a given locus specified at constructor time.  Call
 the member function Calculate() to perform the actual calculation.
 Calculate() makes use of DataModel member functions
 ComputeExponentials(), ComputeSiteDLs() and ComputeTreeDL(),
 and returns the likelihood.

 The class is polymorphic on data type (not data model).

 We assume that we start with a correct tree with all update flags set
 appropriately.  We end with a tree with correct likelihoods.  This
 class does NOT reset the update flags after updating the likelihood,
 as the flags may be needed by subsequent calculations.

 This file also holds the small helper class ChildInfo used to
 simplify data likelihood calculation code.

 Written by Jon Yamato, revised by Jim Sloan, revised by Jon Yamato
 2002/01/28 added microsatellite support -- Mary Kuhner
            moved markerweights to base class
 2002/07/08 added k-allele model -- Mary
 2002/07/21 refactoring to remove duplicate code -- Mary
 2004/07/13 added trait-locus code -- Mary
 2005/03/01 moved aliases to tree -- Mary
 2005/09/22 deleted markerweights entirely.

**********************************************************************/

// The following are used in the .cpp code:
// #include "datapack.h" for access to
//    datamodel, GetDataLength(), GetNTips()
// #include "dlmodel.h" for access to
//    Finalize(), ComputeExponentials(), ComputeSiteDLs(),
//    ComputeTreeDLs()
// #include "tree.h" for access to
//    timelist, SetDLValue()
// #include "timelist.h" for access to
//    BeginBranch(), GetBranch(), BeginBody(), InRange()

class Locus;
class Tree;
class DataModel;
class NucModel;
class ChildInfo;
class TimeList;

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

class DLCalculator
{
  private:
    DLCalculator();                               // undefined
    DLCalculator& operator=(const DLCalculator&); // undefined

  protected:
    DataModel& m_datamodel;
    LongVec1d m_markerpos;

    DLCalculator(const DLCalculator& src);        // internal use

    rangepair SitePairToMarkerPair(rangepair sites);
    ChildInfo GetChildInfo(Branch_ptr branch, long locus, long childindex,
                           long cellindex, long posn, bool moving) const;
    ChildInfo NullChildInfo() const;

  public:
    DLCalculator(const Locus& locus);
    virtual ~DLCalculator()            {};
    virtual DLCalculator* Clone() const = 0;
    virtual double Calculate(Tree& tree, const Locus& locus, bool moving) = 0;
    virtual void SimulateData(Tree& tree, Locus& locus);
    virtual void CopyDataFrom(Locus& destloc, Locus& origloc, Tree& tree);
    virtual void Randomize(Locus& destloc, rangeset rset, Tree& tree);
    virtual void MarkPanelBranches(Tree& tree, const Locus& locus);
    virtual LongVec1d RecalculateAliases(const Tree&, const Locus&) const
    { LongVec1d empty; return empty; };

};

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

class NucCalculator : public DLCalculator
{
  private:
    LongVec1d CalculateAliasesFromData(const std::vector<DoubleVec2d>& data) const;
    LongVec1d SetupAliases(const Locus& locus) const;

  protected:
    typedef double** SiteDL;

    NucCalculator(const NucCalculator& src);    // internal use
    virtual void CalculateSite(Cell_ptr child1, Cell_ptr child2,
                               Cell_ptr newcell, long pos, long alias);
    void Breakalias(LongVec1d& aliases, const rangevector& subtrees);

  public:
    NucCalculator(const Locus& locus);
    virtual ~NucCalculator() {};
    virtual LongVec1d RecalculateAliases(const Tree& tree, const Locus& locus) const;

};

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

class DNACalculator : public NucCalculator
{
  private:

  protected:
    DNACalculator(const DNACalculator& src) : NucCalculator(src) {};

  public:
    DNACalculator(const Locus& locus) : NucCalculator(locus) {};
    virtual ~DNACalculator() {};
    virtual DLCalculator* Clone() const;
    virtual double Calculate(Tree& tree, const Locus& locus, bool moving);
};

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

class SNPCalculator : public NucCalculator
{
  private:
    NucModel* m_invarmodel;

    void CalculateInvarSite(Cell_ptr child1, Cell_ptr child2, Cell_ptr newcell, long pos);
    void MaskPanelTips(TimeList& timeList, long loci, long first, long last, long i);

  protected:
    SNPCalculator(const SNPCalculator& src);

    // no-panel pathway
    double CalcNoPanel(Tree& tree, long loc, std::pair<long,long> sitespan, LongVec1d aliases);
    double SumNoPanel(Cell_ptr varcell, Cell_ptr invarcell, std::pair<long,long> sitespan);

    // panel pathway
    Branch_ptr CalcPanel(Tree& tree, long loc, std::pair<long,long> sitespan, LongVec1d aliases);
    Branch_ptr CalcPanelInvariants(Tree& tree, long loc, std::pair<long,long> sitespan);
    double SumPanel(Cell_ptr varcell, std::pair<long,long> sitespan, Cell_ptr sumcell);

  public:
    SNPCalculator(const Locus& locus);
    virtual ~SNPCalculator();
    virtual DLCalculator* Clone() const;
    virtual double Calculate(Tree& tree, const Locus& locus, bool moving);
    virtual void SimulateData(Tree& tree, Locus& locus);

};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// This subclass is suitable for any type of allelic data, such as
// microsats, electrophoretic alleles or the k-allele data type.
// It used to have subclasses, but they weren't needed.

class AlleleCalculator : public DLCalculator
{
  protected:
    AlleleCalculator(const AlleleCalculator& src);  // internal use

  public:
    AlleleCalculator(const Locus& locus);
    virtual ~AlleleCalculator() {};
    virtual DLCalculator* Clone() const { return new AlleleCalculator(*this); };
    virtual double Calculate(Tree& tree, const Locus& locus, bool moving);

};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// This tiny class saves some information for use by data likelihood
// calculations.  It is similar to std::pair.

class ChildInfo
{
  public:
    Cell_ptr m_cell;
    double m_length;

    ChildInfo(Cell_ptr cell, double len) : m_cell(cell), m_length(len) {};
    ChildInfo() : m_length(0) {};
};

#endif // DLCALCULATOR_H

//____________________________________________________________________________________
