/*
    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 <stdlib.h>
#include <math.h>
#include <float.h>
#include "statistics.h"
#include "DLTmath.h"
#include "rayleigh_dist.h"
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

/* The Rayleigh distribution has the form,

       p(x) dx = (x/a^2) exp(-(x^2/(2 a^2)) dx

       a > 0        scale parameter
       b > 0        shape parameter
       0 <= x < +inf

   http://en.wikipedia.org/wiki/Rayleigh_distribution
*/

double
rayleigh_dev(const double a, const double nullval, const gsl_rng *r2)
{
    return (gsl_ran_rayleigh (r2, a));
}


double
rayleigh_pdf(const double x, const double a, const double nullval)
{
    double          p, tmp;

    if (x <= 0.0)
    {
        return(0.0);
    }
    else
    {
        tmp = x / a;
        p = (tmp/a) * exp(-0.5 * tmp * tmp);
        return(p);
    }
}


double
rayleigh_lnpdf(const double x, const double a, const double nullval)
{
    double          p, tmp;

    tmp = x / a;
    p = log(tmp/a) - 0.5 * tmp * tmp;

    return(p);
}


double
rayleigh_cdf(const double x, const double a, const double nullval)
{
    return(1.0 - rayleigh_sdf(x, a, nullval));
}


double
rayleigh_sdf(const double x, const double a, const double nullval)
{
    if (x == 0.0)
        return(1.0);
    else
        return(exp(-0.5 * x * x / (a * a)));
}


double
rayleigh_int(const double x, const double y, const double a, const double nullval)
{
    return(rayleigh_sdf(x, a, nullval) - rayleigh_sdf(y, a, nullval));
}


/* From Cover and Thomas (1991) _Elements of Information Theory_ */
double
rayleigh_logL(const double a, const double nullval)
{
    return(0.5 * MY_EULER + log(a / sqrt(2.0)) + 1.0);
}


/* Maximum likelihood fit of data to a Weibull distribution
   Based on _Statistical Distributions_ 3rd ed.
   Evans, Hastings, and Peacock, p 193, 196.
   and on my own derivation of the Jacobian matrix (ugh!).
*/
double
rayleigh_fit(const double *x, const int nx, double *eta, double *nullp, double *prob)
{
    double           nd = (double) nx;
    double           sum;
    int              i;

    sum = 0.0;
    for (i = 0; i < nx; ++i)
        sum += x[i] * x[i];

    sum = sqrt(0.5 * sum / nd);

    *eta = sum;

    return(chi_sqr_adapt(x, nx, 0, prob, sum, 0.0, rayleigh_pdf, rayleigh_lnpdf, rayleigh_int));
}

