// $Id: bayescurve.h,v 1.12 2018/01/03 21:32:54 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: Lucian Smith, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


/*
  A bayes curve is a probability density function, aka a curve whose area
  under its curve is 1.0

  It's stored as a vector of doubles, with an offset and a bin width.

  Important functions include the creation of a new bayes curve from a vector
  of other bayes curves, and integration of ...
*/

#ifndef BAYESCURVE_H
#define BAYESCURVE_H

#include "vectorx.h"

typedef std::vector < std::pair < double, double> > DoublePairVec;

enum combine_type { ADD, MULTIPLY };

class BayesCurve
{
  public:
    //  Deleted since we never use, 4/4/06
    //  BayesCurve(unsigned long numpoints, double width,
    //             double minval, double maxval, double maxkernwidth);
    //  BayesCurve(const BayesCurve& bcurve); //We accept the default
    BayesCurve(); //Must use Initialize later.
    BayesCurve(const std::vector<BayesCurve> bcurve_vec, combine_type ctype);
    ~BayesCurve();

    void Initialize(unsigned long numpoints, double width, bool islog,
                    double minval, double maxval, double maxkernwidth);

    void AddKernel(double center, unsigned long num, double kernelwidth);
    //kernelwidth needs to be an argument instead of a member variable
    // because a possible implementation of kernel width is to have it be
    // adaptive, i.e. wider at the edges, and thinner in the middle.
    void Integrate(bool warnuser = true);
    double GetValAtPercentile(double percentile) const;
    double GetPercentileAtVal(double val) const;
    double GetLikeAtVal(double val) const;
    double GetLikeAtMax() const;
    double GetMax() const;

    DoublePairVec GetXYvec() const;
    double GetOffset() const {return m_offset;};
    double GetBinWidth() const {return m_binwidth;};
    bool IsLog() const {return m_islog;};

  private:
    double m_offset;
    double m_binwidth;
    unsigned long m_curr_numpoints;
    unsigned long m_target_numpoints;
    DoubleVec1d m_probabilities;
    DoubleVec1d m_integration;

    bool m_islog;

    void ClosestWidthsTo(const double val, double& low, double& high) const;

    //Three possible kernel functions; we're most likely to use the biweight.
    double BiweightKernel(double t) const;
    double EpanechnikovKernel(double t) const;
    double GaussianKernel(double t) const;
};

#endif  // BAYESCURVE_H

//____________________________________________________________________________________
