// $Id: dlcell.h,v 1.38 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 */


/******************************************************************
 This file defines the branch data-likelihood storage object.  It maintains the data
 likelihoods internally as a bare array for speed reasons (ability to use memcpy).

 The DLCell constructors and Clone make fully functional *empty* DLCells suitable
 for use on internal branches.  Copy() can be used to make a filled-up DLCell,
 or you can Initialize() it with a sequence.

 The base DLCell class maintains a private internal store of allocated arrays, as a speed-up.
 This store should be cleared at the beginning of every region (by calling ClearStore()) or
 it will turn into a major memory leak.  The freestore-management code assumes that all of
 the data-likelihood arrays are three-dimensional contiguous allocation using new[].  If you
 write one that isn't, derive from Cell, not from DLCell!

 The file also contains the simple helper class 'triplet', analogous to std::pair.

 NB:  It would be more efficient to do MSCells in some other way, but it would mean writing
 a lot of new code, so I didn't.  If Microsats are too space-intensive to use, review this code.

 Written by Jim Sloan, revised by Mary Kuhner
    added datalikelihood branchwise-normalization -- Jon 2001/03/09
    added NullCell -- Mary 2002/05/03
    deleted SNPCell (replaced with a pair of DNACells) -- Mary 2002/05/28
    put SNPCell back, much simplified -- Mary 2002/06/11
    added KCell -- Mary 2002/07/08
    collapsed the AlleleCell subclasses -- Mary 2002/07/22

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

#ifndef DLCELL_H
#define DLCELL_H

#include <cassert>                      // May be needed for inline definitions.
#include <iostream>
#include <stdlib.h>
#include <string>

#include "constants.h"
#include "types.h"
#include "vectorx.h"

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

// This struct is similar to std::pair<long>

struct triplet
{
  public:
    long first;
    long second;
    long third;

    triplet();
    triplet(long f, long s, long t);
    bool operator<(const triplet& rhs) const;

    // We accept default destructor, copy constructor and operator=
};

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

class Cell
{
  protected:
    Cell() {};

  public:
    virtual          ~Cell() {};
    virtual Cell*    Clone()         const                = 0;
    virtual Cell*    Copy()          const                = 0;

    // Initialize from data.
    virtual void     Initialize(const StringVec1d& sequence, const DataModel_ptr trans) = 0;
#if 1
    virtual void     CopyInitialize(const Cell& src)         = 0;
#endif
    virtual void     EmptyCell()                             = 0;

    // Retrieve individual marker DLs.
    virtual void     SetSiteDLs(long posn, double** siteDLs)   = 0;
    virtual void     AddToSiteDLs(long posn, double** siteDLs) = 0;
    virtual double** GetSiteDLs(long posn) const               = 0;

    virtual double** GetNextMarker(double** marker)          = 0;

    // Manage the normalization coefficients.
    virtual double   Normalize(double** siteDLs)             = 0;
    virtual void     SetNorms(double val, long pos)          = 0;
    virtual double   GetNorms(long pos) const                = 0;

    virtual void SumMarkers(long startpos, long endpos, bool normalize) = 0;

    // Swap two markers..
    virtual void     SwapDLs(Cell_ptr other, long pos)          = 0;

    // Compare DLCell contents.
    virtual bool     IsSameAs(const Cell_ptr othercell, long pos) const = 0;
    virtual long     DiffersFrom(Cell_ptr othercell) const = 0;

    // Simulation functions.
    virtual void     SetAllCategoriesTo(DoubleVec1d& state, long posn) = 0;
    virtual DoubleVec1d GetStateFor(long posn, long cat) const = 0;
    virtual void     SetStateTo(long posn, long cat, DoubleVec1d state) = 0;
    virtual void     AddTo(const Cell_ptr othercell) = 0;
    virtual void     SubtractFrom(const Cell_ptr othercell) = 0;
    virtual void     MultiplyBy(double mult) = 0;
    virtual void     MultiplyBy(const Cell_ptr othercell) = 0;

    // For output.
    virtual LongVec1d GetOnes(long marker) const = 0;

    // Debugging functions.
    virtual string   DLsToString(long start, long end) const = 0;
    virtual long     GetNMarkers() = 0;
    virtual long     GetNCats() = 0;
    virtual long     GetNBins() = 0;

}; // Cell

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

class DLCell : public Cell
{
  private:
    DLCell(const DLCell&);               // undefined
    DLCell&    operator=(const DLCell&); // undefined

  protected:
    triplet     m_identifier;           // used to manage free store
    long        m_nmarkers;             // number of markers
    long        m_ncats;                // number of rate categories
    long        m_nbins;                // number of allelic states
    DoubleVec1d m_norms;                // normalization coefficients
    cellarray   m_DLs;                  // array of data likelihoods: position X category X bin

    // Error checking (debugging).
    bool       IsValidPosition(long pos) const;

  public:

    DLCell(long markers, long cats, long bins);
    virtual          ~DLCell();
    virtual Cell*    Copy()          const;
    cellarray  MakeArray();             // NB:  must not be virtual--it's called by base class constructor!
    void EmptyCell();

    virtual void     CopyInitialize(const Cell& src); // Initialize from data.

    // Retrieve individual marker DLs.
    virtual void     SetSiteDLs(long posn, double** siteDLs);
    virtual void     AddToSiteDLs(long posn, double** siteDLs);
    virtual double** GetSiteDLs(long posn) const {assert(IsValidPosition(posn)); return m_DLs[posn];};
    virtual double** GetNextMarker(double** marker) {return marker + m_ncats;};

    // Manage the normalization coefficients.
    double   Normalize(double** siteDLs);
    void     SetNorms(double val, long pos)  {assert(IsValidPosition(pos)); m_norms[pos] = val; };
    double   GetNorms(long pos) const        {assert(IsValidPosition(pos)); return m_norms[pos]; };

    // This function accumulates all the values from startpos, up to but not including endpos, *INTO* endpos.  Careful!
    void     SumMarkers(long startpos, long endpos, bool normalize);

    // Swap two markers.
    virtual void     SwapDLs(Cell_ptr other, long pos);

    // Clear the free store.
    // This is called by control code when a new region is begun, so that
    // the old cellarrays, which are no longer useful, can be discarded.
    static  void     ClearStore();

    // Compare DLCell contents.
    virtual bool     IsSameAs(const Cell_ptr othercell, long pos) const;

    // DiffersFrom returns the first position that IsSameAs() thinks
    // the 2 cells differ at, FLAGLONG if no position is found.
    virtual long     DiffersFrom(Cell_ptr othercell) const;

    // Simulation functions.
    virtual void     SetAllCategoriesTo(DoubleVec1d& state, long posn);
    virtual DoubleVec1d GetStateFor(long posn, long cat) const;
    virtual void     SetStateTo(long posn, long cat, DoubleVec1d state);
    virtual void     AddTo(const Cell_ptr othercell);
    virtual void     SubtractFrom(const Cell_ptr othercell);
    virtual void     MultiplyBy(double mult);
    virtual void     MultiplyBy(const Cell_ptr othercell);

    // For output.
    virtual LongVec1d GetOnes(long marker) const;

    // Debugging functions.
    virtual string   DLsToString(long start, long end) const;
    virtual long     GetNMarkers() {return m_nmarkers;};
    virtual long     GetNCats() {return m_ncats;};
    virtual long     GetNBins() {return m_nbins;};

}; // DLCell

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

// NullCell is a Cell that does nothing, useful in simplifying certain algorithms
// in DLCalculator.  They are not currently used in the Tree.

class NullCell : public Cell
{
  public:
    NullCell();
    virtual          ~NullCell() {};
    virtual Cell*    Clone() const { return new NullCell; };
    virtual Cell*    Copy() const { return new NullCell; };
    virtual void     Initialize(const StringVec1d&, const DataModel_ptr trans);
#if 1
    virtual void     CopyInitialize(const Cell&) { assert(false); }; // no! it's Null!
#endif
    virtual void     EmptyCell() {};
    virtual void     SetSiteDLs(long, double**) { assert(false); };  // no! it's Null!
    virtual void     AddToSiteDLs(long, double**) {};
    virtual double** GetSiteDLs(long) const    { return NULL; };
    virtual double   Normalize(double**) {return 0; };
    virtual void     SetNorms(double, long) {};
    virtual double   GetNorms(long) const {return 0; };
    virtual void     SumMarkers(long, long, bool) { assert(false); };
    virtual double** GetNextMarker(double**) { assert(false); return NULL; };
    virtual void     SwapDLs(Cell_ptr, long) { assert(false); };

    virtual bool     IsSameAs(const Cell_ptr, long) const
    { assert(false); return false; };   // no! it's Null!

    virtual long     DiffersFrom(Cell_ptr) const { assert(false); return 0; };

    // Simulation functions.
    virtual void     SetAllCategoriesTo(DoubleVec1d&, long) {};
    virtual DoubleVec1d GetStateFor(long posn, long cat) const;
    virtual void     SetStateTo(long, long, DoubleVec1d) {};
    virtual void     AddTo(const Cell_ptr) {};
    virtual void     SubtractFrom(const Cell_ptr) {};
    virtual void     MultiplyBy(double) {};
    virtual void     MultiplyBy(const Cell_ptr) {};

    // For output.
    virtual LongVec1d GetOnes(long) const { return LongVec1d();};

    // Debugging functions.
    virtual string   DLsToString(long, long) const { return string(""); };
    virtual long     GetNMarkers() {return 0;};
    virtual long     GetNCats() {return 0;};
    virtual long     GetNBins() {return 0;};
}; // NullCell

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

class NucCell : public DLCell
{
  public:
    NucCell(long markers, long cats);
    virtual          ~NucCell()          {};
    virtual void     Initialize(const StringVec1d& sequence, const DataModel_ptr trans);

}; // NucCell

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

class DNACell : public NucCell
{
  public:
    DNACell(long markers, long cats);
    virtual         ~DNACell()            {};
    virtual Cell* Clone()    const;
};

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

class SNPCell : public NucCell
{
  public:
    SNPCell(long markers, long cats);
    virtual           ~SNPCell();
    virtual  Cell*    Clone() const;
    virtual  void     Initialize(const StringVec1d&, const DataModel_ptr trans);

}; // SNPCell

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

class AlleleCell : public DLCell
{
  public:
    AlleleCell(long markers, long cats, long bins);
    virtual          ~AlleleCell()               {};
    virtual  Cell*   Clone() const;
    virtual void     Initialize(const StringVec1d& sequence, const DataModel_ptr trans);

}; // AlleleCell

#endif // DLCELL_H

//____________________________________________________________________________________
