/*
    Theseus - maximum likelihood superpositioning of macromolecular structures

    Copyright (C) 2004-2015 Douglas L. Theobald

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the:

    Free Software Foundation, Inc.,
    59 Temple Place, Suite 330,
    Boston, MA  02111-1307  USA

    -/_|:|_|_\-
*/

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "statistics.h"
#include "DLTmath.h"
#include "exp_dist.h"


/* The exponential distribution has the form

   p(x) dx = exp(-x/mu) dx/mu

   0 < x > +infty
*/
double
exp_dev(const double mu, const double nullv, const gsl_rng *r2)
{
    return(-mu * log(gsl_rng_uniform(r2)));
}

/* 'nullval' is a dummy variable for compatibility w/ 2-parameter distributions */
double
exp_pdf(const double x, const double mu, const double nullval)
{
    if (x < 0.0)
        return (0.0);
    else
        return (exp(-x / mu) / mu);
}


double
exp_lnpdf(const double x, const double mu, const double nullval)
{
    return ((-x / mu) - log(mu));
}


double
exp_cdf(const double x, const double mu, const double nullval)
{
    if (x <= 0.0)
        return (0.0);
    else
        return (1.0 - exp_sdf(x, mu, nullval));
}


double
exp_sdf(const double x, const double mu, const double nullval)
{
    if (x <= 0.0)
        return (1.0);
    else
        return (exp(-x / mu));
}


double
exp_int(const double x, const double y, const double mu, const double nullval)
{
    if (x <= 0.0)
        return (exp_cdf(y, mu, nullval));
    else
        return (exp_sdf(x, mu, nullval) - exp_sdf(y, mu, nullval));
}


double
exp_logL(const double mu, const double c)
{
    return(-(log(mu) + 1));
}


/* method of moments fit of data to a exp distribution */
double
exp_fit(const double *x, const int n, double *mu, double *nullp, double *prob)
{
    double           nd = (double) n;
    double           b = 0.0;
    double           ave;
    int              i;

    /*  Based on _Statistical Distributions_ 3rd ed. Evans, Hastings, and Peacock, p 40. */
    ave = 0.0;
    for (i = 0; i < n; ++i)
    {
        if (x[i] < 0.0)
        {
            fprintf(stderr, "\n ERROR345: exponentially distributed data must be >= 0.0 ");
            return(-1.0);
        }
        else
        {
            ave += x[i];
        }
    }
    ave /= nd;

    *mu = ave;

    return(chi_sqr_adapt(x, n, 0, prob, ave, b, exp_pdf, exp_lnpdf, exp_int));
}


double
exp_histfit(double *x, double *freq, int n, double *mu, double *nullp, double *logL)
{
    double           norm;
    double           ave;
    int              i;

    norm = 0.0;
    for (i = 0; i < n; ++i)
        norm += freq[i];
SCREAME(norm);
    /*  Based on _Statistical Distributions_ 3rd ed. Evans, Hastings, and Peacock, p 40. */
    ave = 0.0;
    for (i = 0; i < n; ++i)
    {
        if (x[i] < 0.0)
        {
            fprintf(stderr, "\n ERROR345: exponentially distributed data must be >= 0.0 ");
            return(-1.0);
        }
        else
        {
            ave += (freq[i] * x[i]);
        }
    }
    ave /= norm;

    *mu = ave;

    return(chi_sqr_hist(x, freq, n, logL, *mu, *nullp, exp_pdf, exp_lnpdf, exp_int));
}
