/**
 *
 * @file core_slauum.c
 *
 *  PLASMA core_blas kernel
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Julien Langou
 * @author Henricus Bouwmeester
 * @author Mathieu Faverge
 * @date 2010-11-15
 * @generated s Tue Jan  7 11:44:46 2014
 *
 **/
#include <lapacke.h>
#include "common.h"

/***************************************************************************//**
 *
 * @ingroup CORE_float
 *
 *  CORE_slauum - Computes the product U * U' or L' * L, where the triangular
 *  factor U or L is stored in the upper or lower triangular part of
 *  the array A.
 *
 *  If UPLO = 'U' or 'u' then the upper triangle of the result is stored,
 *  overwriting the factor U in A.
 *  If UPLO = 'L' or 'l' then the lower triangle of the result is stored,
 *  overwriting the factor L in A.
 *
 *******************************************************************************
 *
 * @param[in] uplo
 *          = PlasmaUpper: Upper triangle of A is stored;
 *          = PlasmaLower: Lower triangle of A is stored.
 *
 * @param[in] N
 *          The order of the triangular factor U or L.  N >= 0.
 *
 * @param[in,out] A
 *          On entry, the triangular factor U or L.
 *          On exit, if UPLO = 'U', the upper triangle of A is
 *          overwritten with the upper triangle of the product U * U';
 *          if UPLO = 'L', the lower triangle of A is overwritten with
 *          the lower triangle of the product L' * L.
 *
 * @param[in] LDA
 *          The leading dimension of the array A. LDA >= max(1,N).
 *
 ******************************************************************************/
#if defined(PLASMA_HAVE_WEAK)
#pragma weak CORE_slauum = PCORE_slauum
#define CORE_slauum PCORE_slauum
#endif
void CORE_slauum(PLASMA_enum uplo, int N, float *A, int LDA)
{
    LAPACKE_slauum_work(LAPACK_COL_MAJOR, lapack_const(uplo), N, A, LDA );
}


/****************************************************************************
 *                                                                          *
 * Copyright (C) 2005 ~ 2015 Neutrino International Inc.                    *
 *                                                                          *
 * Author : Brian Lin <lin.foxman@gmail.com>, Skype: wolfram_lin            *
 *                                                                          *
 * QtGSL acts as an interface between Qt and GNU GSL library.               *
 * Please keep QtGSL as simple as possible.                                 *
 *                                                                          *
 * Qt Version   : 5.4.1                                                     *
 * CIOS Version : 1.6.0                                                     *
 *                                                                          *
 ****************************************************************************/

#ifndef QT_GSL_H
#define QT_GSL_H

#include <QtCore>
#include <Essentials>

extern "C" {
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_const.h>
#include <gsl/gsl_const_cgs.h>
#include <gsl/gsl_const_cgsm.h>
#include <gsl/gsl_const_mks.h>
#include <gsl/gsl_const_mksa.h>
#include <gsl/gsl_const_num.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_cdf.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_qrng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_sum.h>
#include <gsl/gsl_poly.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_permute.h>
#include <gsl/gsl_permutation.h>
#include <gsl/gsl_combination.h>
#include <gsl/gsl_multiset.h>
#include <gsl/gsl_statistics.h>
#include <gsl/gsl_sort.h>
#include <gsl/gsl_sort_vector.h>
#include <gsl/gsl_heapsort.h>
#include <gsl/gsl_dht.h>
#include <gsl/gsl_histogram.h>
#include <gsl/gsl_histogram2d.h>
#include <gsl/gsl_fit.h>
#include <gsl/gsl_multifit.h>
#include <gsl/gsl_deriv.h>
#include <gsl/gsl_chebyshev.h>
#include <gsl/gsl_interp.h>
#include <gsl/gsl_spline.h>
#include <gsl/gsl_bspline.h>
#include <gsl/gsl_complex_math.h>
}

QT_BEGIN_NAMESPACE

#ifndef QT_STATIC
#  if defined(QT_BUILD_QTGSL_LIB)
#    define Q_GSL_EXPORT Q_DECL_EXPORT
#  else
#    define Q_GSL_EXPORT Q_DECL_IMPORT
#  endif
#else
#    define Q_GSL_EXPORT
#endif

class Q_GSL_EXPORT vcomplex
{ // GSL complex number
  public:

    double x ;
    double y ;

    explicit vcomplex      (void) ;
    explicit vcomplex      (double x,double y) ;
             vcomplex      (const vcomplex & complex) ;
    virtual ~vcomplex      (void) ;

    double real            (void) ;
    double imaginary       (void) ;
    double argument        (void) ;
    double magnitude       (void) ; // abs ,  |z|
    double squared         (void) ; // squared magnitude ,  |z|^2
    double logabs          (void) ; // log|z|

    vcomplex & operator  = (vcomplex & complex) ;
    vcomplex & operator += (vcomplex & complex) ;
    vcomplex & operator -= (vcomplex & complex) ;
    vcomplex & operator *= (vcomplex & complex) ;
    vcomplex & operator /= (vcomplex & complex) ;

    vcomplex & rectangular (double x,double y) ; // equal to operator =
    vcomplex & polar       (double r,double theta) ;
    vcomplex & conjugate   (void) ; // z^* = x - i y
    vcomplex & inverse     (void) ; // 1/z = (x - i y)/(x^2 + y^2)
    vcomplex & negative    (void) ; // -z = (-x) + i(-y)

    void sin               (vcomplex & value) ;
    void cos               (vcomplex & value) ;
    void tan               (vcomplex & value) ;
    void sec               (vcomplex & value) ;
    void csc               (vcomplex & value) ;
    void cot               (vcomplex & value) ;

    void arcsin            (vcomplex & value) ;
    void arccos            (vcomplex & value) ;
    void arctan            (vcomplex & value) ;
    void arcsec            (vcomplex & value) ;
    void arccsc            (vcomplex & value) ;
    void arccot            (vcomplex & value) ;

    void sinh              (vcomplex & value) ;
    void cosh              (vcomplex & value) ;
    void tanh              (vcomplex & value) ;
    void sech              (vcomplex & value) ;
    void csch              (vcomplex & value) ;
    void coth              (vcomplex & value) ;

    void arcsinh           (vcomplex & value) ;
    void arccosh           (vcomplex & value) ;
    void arctanh           (vcomplex & value) ;
    void arcsech           (vcomplex & value) ;
    void arccsch           (vcomplex & value) ;
    void arccoth           (vcomplex & value) ;

  protected:

  private:

};

typedef QList < vcomplex > vcomplexes ;

namespace N
{

class Q_GSL_EXPORT Random         ;
class Q_GSL_EXPORT Histogram      ;
class Q_GSL_EXPORT Chebyshev      ;
class Q_GSL_EXPORT Permutation    ;
class Q_GSL_EXPORT Combination    ;
class Q_GSL_EXPORT Multisets      ;
class Q_GSL_EXPORT MultiFit       ;
class Q_GSL_EXPORT BSplines       ;
class Q_GSL_EXPORT Interpolation  ;
class Q_GSL_EXPORT Vector         ;
class Q_GSL_EXPORT Matrix         ;
class Q_GSL_EXPORT LevinWithError ;
class Q_GSL_EXPORT Levin          ;

namespace Math
{

Q_GSL_EXPORT QList<int>       Differential                  (QList<int>       & discrete);
Q_GSL_EXPORT QList<long long> Differential                  (QList<long long> & discrete);
Q_GSL_EXPORT QList<float>     Differential                  (QList<float>     & discrete);
Q_GSL_EXPORT QList<double>    Differential                  (QList<double>    & discrete);
Q_GSL_EXPORT QList<double>    VectorMultiply                (QList<double>    & discrete,double v);
Q_GSL_EXPORT double           SquareSigma                   (QList<double>    & discrete);
Q_GSL_EXPORT double           VectorMin                     (QList<double>    & discrete);
Q_GSL_EXPORT double           VectorMax                     (QList<double>    & discrete);
Q_GSL_EXPORT QByteArray       VectorByteArray               (QList<double>    & discrete);
Q_GSL_EXPORT QList<double>    VectorFromByteArray           (QByteArray       & B);
Q_GSL_EXPORT double           Average                       (int total,double * values) ;
Q_GSL_EXPORT int              AddValues                     (int total,double * values,double value) ;
Q_GSL_EXPORT int              Multiply                      (int total,double * values,double value) ;
Q_GSL_EXPORT int              FaPb                          (int total,double * values,double a,double b) ; // F = a * ( x[i] + b )
Q_GSL_EXPORT int              FaXb                          (int total,double * values,double a,double b) ; // F = a * x[i] + b
Q_GSL_EXPORT int              Divide                        (int total,double * values,double value) ;
Q_GSL_EXPORT void             CutOff                        (int total,double * values,double minimum,double maximum) ;

Q_GSL_EXPORT int              toByteArray                   (const vcomplexes & complexes,QByteArray & body) ;
Q_GSL_EXPORT int              toComplexes                   (const QByteArray & body,vcomplexes & complexes) ;
Q_GSL_EXPORT int              toDouble                      (int items,char           * CHARS  ,double * DOUBLEs) ;
Q_GSL_EXPORT int              toDouble                      (int items,unsigned char  * UCHARS ,double * DOUBLEs) ;
Q_GSL_EXPORT int              toDouble                      (int items,short          * SHORTS ,double * DOUBLEs) ;
Q_GSL_EXPORT int              toDouble                      (int items,unsigned short * USHORTS,double * DOUBLEs) ;
Q_GSL_EXPORT int              toDouble                      (int items,int            * INTS   ,double * DOUBLEs) ;
Q_GSL_EXPORT int              toDouble                      (int items,unsigned int   * UINTS  ,double * DOUBLEs) ;
Q_GSL_EXPORT int              toDouble                      (int items,float          * FLOATS ,double * DOUBLEs) ;
Q_GSL_EXPORT int              Addition                      (int items,double * A,double * B           ) ; // A += B
Q_GSL_EXPORT int              Addition                      (int items,double * A,double * B,double * C) ; // A  = B + C
Q_GSL_EXPORT int              Subtract                      (int items,double * A,double * B           ) ; // A -= B
Q_GSL_EXPORT int              Subtract                      (int items,double * A,double * B,double * C) ; // A  = B - C
Q_GSL_EXPORT int              Multiply                      (int items,double * A,double * B           ) ; // A *= B
Q_GSL_EXPORT int              Multiply                      (int items,double * A,double * B,double * C) ; // A  = B * C
Q_GSL_EXPORT int              Divide                        (int items,double * A,double * B           ) ; // A /= B
Q_GSL_EXPORT int              Divide                        (int items,double * A,double * B,double * C) ; // A  = B / C

Q_GSL_EXPORT void             Sort                          (double * data,const size_t stride,size_t n) ;
Q_GSL_EXPORT void             Sort                          (float  * data,const size_t stride,size_t n) ;
Q_GSL_EXPORT void             Sort                          (int    * data,const size_t stride,size_t n) ;
Q_GSL_EXPORT void             SortIndex                     (size_t * p,const double * data,size_t stride,size_t n) ;
Q_GSL_EXPORT void             SortIndex                     (size_t * p,const float  * data,size_t stride,size_t n) ;
Q_GSL_EXPORT void             SortIndex                     (size_t * p,const int    * data,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortSmallest                  (double * dest,size_t k,const double * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortSmallest                  (float  * dest,size_t k,const float  * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortSmallest                  (int    * dest,size_t k,const int    * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortLargest                   (double * dest,size_t k,const double * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortLargest                   (float  * dest,size_t k,const float  * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortLargest                   (int    * dest,size_t k,const int    * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortSmallestIndex             (size_t * p,size_t k,const double * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortSmallestIndex             (size_t * p,size_t k,const float  * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortSmallestIndex             (size_t * p,size_t k,const int    * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortLargestIndex              (size_t * p,size_t k,const double * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortLargestIndex              (size_t * p,size_t k,const float  * src,size_t stride,size_t n) ;
Q_GSL_EXPORT int              SortLargestIndex              (size_t * p,size_t k,const int    * src,size_t stride,size_t n) ;

Q_GSL_EXPORT double           Mean                          (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           Variance                      (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           VarianceMean                  (const double data [],size_t stride,size_t n,double mean) ;
Q_GSL_EXPORT double           StandardDeviation             (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           StandardDeviationMean         (const double data [],size_t stride,size_t n,double mean) ;
Q_GSL_EXPORT double           TotalSumSquares               (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           TotalSumSquaresMean           (const double data [],size_t stride,size_t n,double mean) ;
Q_GSL_EXPORT double           VarianceFixedMean             (const double data [],size_t stride,size_t n,double mean) ;
Q_GSL_EXPORT double           StandardDeviationFixedMean    (const double data [],size_t stride,size_t n,double mean) ;
Q_GSL_EXPORT double           AbsoluteDeviation             (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           AbsoluteDeviationMean         (const double data [],size_t stride,size_t n,double mean) ;
Q_GSL_EXPORT double           Skew                          (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           SkewMeanSD                    (const double data [],size_t stride,size_t n,double mean,double sd) ;
Q_GSL_EXPORT double           Kurtosis                      (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           KurtosisMeanSD                (const double data [],size_t stride,size_t n,double mean,double sd) ;
Q_GSL_EXPORT double           Lag1AutoCorrelation           (const double data [],const size_t stride,const size_t n);
Q_GSL_EXPORT double           Lag1AutoCorrelationMean       (const double data [],const size_t stride,const size_t n,const double mean) ;
Q_GSL_EXPORT double           Covariance                    (const double data1[],const size_t stride1,const double data2[],const size_t stride2,const size_t n) ;
Q_GSL_EXPORT double           CovarianceMean                (const double data1[],const size_t stride1,const double data2[],const size_t stride2,const size_t n,const double mean1,const double mean2) ;
Q_GSL_EXPORT double           Correlation                   (const double data1[],const size_t stride1,const double data2[],const size_t stride2,const size_t n) ;
Q_GSL_EXPORT double           WeightedMean                  (const double w    [],size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedVariance              (const double w    [],size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedVarianceMean          (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,double wmean) ;
Q_GSL_EXPORT double           WeightedSd                    (const double w    [],size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedSdMean                (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,double wmean) ;
Q_GSL_EXPORT double           WeightedVarianceFixedMean     (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,const double mean) ;
Q_GSL_EXPORT double           WeightedSdFixedMean           (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,const double mean) ;
Q_GSL_EXPORT double           WeightedTss                   (const double w    [],const size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedTssMean               (const double w    [],const size_t wstride,const double data[],size_t stride,size_t n,double wmean) ;
Q_GSL_EXPORT double           WeightedAbsoluteDeviation     (const double w    [],size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedAbsoluteDeviationMean (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,double wmean) ;
Q_GSL_EXPORT double           WeightedSkew                  (const double w    [],size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedSkewMeanSd            (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,double wmean,double wsd) ;
Q_GSL_EXPORT double           WeightedKurtosis              (const double w    [],size_t wstride,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           WeightedKurtosisMeanSd        (const double w    [],size_t wstride,const double data[],size_t stride,size_t n,double wmean,double wsd) ;
Q_GSL_EXPORT double           MaxValue                      (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           MinValue                      (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT size_t           MaxIndex                      (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT size_t           MinIndex                      (const double data [],size_t stride,size_t n) ;
Q_GSL_EXPORT double           MedianFromSorted              (const double sorted_data[],size_t stride,size_t n) ;
Q_GSL_EXPORT double           QuantileFromSorted            (const double sorted_data[],size_t stride,size_t n,double f) ;
Q_GSL_EXPORT void             MinMax                        (double * min,double * max,const double data[],size_t stride,size_t n) ;
Q_GSL_EXPORT void             MinMaxIndex                   (size_t * min_index,size_t * max_index,const double data[],size_t stride,size_t n) ;

Q_GSL_EXPORT int              FitLinear                     (const double * x,const size_t xstride,const double * y,const size_t ystride,size_t n,double * c0,double * c1,double * cov00,double * cov01,double * cov11,double * sumsq) ;
Q_GSL_EXPORT int              FitMul                        (const double * x,const size_t xstride,const double * y,const size_t ystride,size_t n,double * c1,double * cov11,double * sumsq) ;
Q_GSL_EXPORT int              WeightedFitLinear             (const double * x,const size_t xstride,const double * w,const size_t wstride,const double * y,const size_t ystride,size_t n,double * c0,double * c1,double * cov00,double * cov01,double * cov11,double * chisq) ;
Q_GSL_EXPORT int              WeightedFitMul                (const double * x,const size_t xstride,const double * w,const size_t wstride,const double * y,const size_t ystride,size_t n,double * c1,double * cov11,double * sumsq) ;
Q_GSL_EXPORT int              FitLinearest                  (double x,double c0,double c1,double cov00,double cov01,double cov11,double * y,double * y_err) ;
Q_GSL_EXPORT int              FitMulest                     (double x,double c1,double cov11,double * y,double * y_err) ;

Q_GSL_EXPORT int              DerivativeCentral             (double x,double h,double * result,double * abserr,MathFunction function,void * params) ;
Q_GSL_EXPORT int              DerivativeForward             (double x,double h,double * result,double * abserr,MathFunction function,void * params) ;
Q_GSL_EXPORT int              DerivativeBackward            (double x,double h,double * result,double * abserr,MathFunction function,void * params) ;

Q_GSL_EXPORT void             IntegerMiddleArray            (int items,unsigned char * array,int gaps,void * funcdata) ;

}

namespace Polynomial
{

Q_GSL_EXPORT double   Eval        (const double c[]    ,const int len,const double   x) ;
Q_GSL_EXPORT vcomplex Eval        (const double c[]    ,const int len,const vcomplex z) ;
Q_GSL_EXPORT vcomplex Eval        (const vcomplexes & c,const int len,const vcomplex z) ;
Q_GSL_EXPORT int      Derivatives (const double c[],const size_t lenc,const double x,double res[],const size_t lenres) ;
Q_GSL_EXPORT int      ddInit      (double dd[],const double xa[],const double ya[],size_t size) ;
Q_GSL_EXPORT double   ddEval      (const double dd[],const double xa[],const size_t size,const double x) ;
Q_GSL_EXPORT int      ddTaylor    (double c[],double xp,const double dd[],const double xa[],size_t size,double w[]) ;
Q_GSL_EXPORT int      Quadratic   (double a,double b,double c,double * x0,double * x1) ;
Q_GSL_EXPORT int      Quadratic   (double a,double b,double c,vcomplex & z0,vcomplex & z1) ;
Q_GSL_EXPORT int      Cubic       (double a,double b,double c,double * x0,double * x1,double * x2) ;
Q_GSL_EXPORT int      Cubic       (double a,double b,double c,vcomplex & z0,vcomplex & z1,vcomplex & z2) ;

}

namespace Cpp
{

Q_GSL_EXPORT int SizeOf (Cpp::ValueTypes type) ;

}

/*****************************************************************************
 *                                                                           *
 *                                  Statistics                               *
 *                                                                           *
 *****************************************************************************/

class Q_GSL_EXPORT Random
{
  public:

    gsl_rng_type  * Type      ;
    gsl_rng       * Generator ;
    gsl_qrng_type * qType     ;
    gsl_qrng      * Quasi     ;

    explicit Random (unsigned long int seed = 0) ;
    explicit Random (gsl_rng_type  * type,unsigned long int seed = 0 ) ;
    explicit Random (gsl_qrng_type * type,unsigned int      dimension) ;
    virtual ~Random (void) ;

    static const gsl_rng_type ** All        (void) ;
    QString                      Name       (void) ;
    unsigned long int            Max        (void) ;
    unsigned long int            Min        (void) ;
    bool                         State      (QByteArray & state) ;

    bool                         Create     (gsl_rng_type * type,unsigned long int seed = 0 ) ;
    unsigned long int            Get        (void) ; // [min,max]
    unsigned long int            Get        (unsigned long int n) ; // [0,n-1]
    double                       Uniform    (void) ; // [0,1)
    double                       Positive   (void) ; // (0,1)

    bool                         Create     (gsl_qrng_type * type,unsigned int dimension) ;
    int                          QuasiGet   (double x[]) ;
    QString                      QuasiName  (void) ;
    bool                         QuasiState (QByteArray & state) ;
    void                         QuasiReset (void) ;

    Random &                     operator = (Random & source) ;

    double       Gaussian                   (double sigma) ;
    double       GaussianPDF                (double x,double sigma) ;
    double       GaussianZiggurat           (double sigma) ;
    double       GaussianRatioMethod        (double sigma) ;
    double       UnitGaussian               (void) ;
    double       UnitGaussianPDF            (double x) ;
    double       UnitGaussianRatioMethod    (void) ;
    double       CdfGaussianP               (double x,double sigma) ;
    double       CdfGaussianQ               (double x,double sigma) ;
    double       CdfGaussianPinv            (double P,double sigma) ;
    double       CdfGaussianQinv            (double Q,double sigma) ;
    double       CdfUnitGaussianP           (double x) ;
    double       CdfUnitGaussianQ           (double x) ;
    double       CdfUnitGaussianPinv        (double P) ;
    double       CdfUnitGaussianQinv        (double Q) ;
    double       GaussianTail               (double a,double sigma) ;
    double       GaussianTailPDF            (double x,double a,double sigma) ;
    double       UnitGaussianTail           (double a) ;
    double       UnitGaussianTailPDF        (double x, double a) ;
    bool         BivariateGaussian          (double   sigma_x ,
                                             double   sigma_y ,
                                             double   rho     ,
                                             double & x       ,
                                             double & y     ) ;
    double       BivariateGaussianPDF          (double x         ,
                                             double y         ,
                                             double sigma_x   ,
                                             double sigma_y   ,
                                             double rho     ) ;
    double       Exponential                (double mu) ;
    double       ExponentialPDF             (double x,double mu) ;
    double       CdfExponentialP            (double x,double mu) ;
    double       CdfExponentialQ            (double x,double mu) ;
    double       CdfExponentialPinv         (double P,double mu) ;
    double       CdfExponentialQinv         (double Q,double mu) ;
    double       Laplace                    (double a) ;
    double       LaplacePDF                 (double x,double a) ;
    double       CdfLaplaceP                (double x,double a) ;
    double       CdfLaplaceQ                (double x,double a) ;
    double       CdfLaplacePinv             (double P,double a) ;
    double       CdfLaplaceQinv             (double Q,double a) ;
    double       ExpPow                     (double a,double b) ;
    double       ExpPowPDF                  (double x,double a,double b) ;
    double       CdfExpPowP                 (double x,double a,double b) ;
    double       CdfExpPowQ                 (double x,double a,double b) ;
    double       Cauchy                     (double a) ;
    double       CauchyPDF                  (double x,double a) ;
    double       CdfCauchyP                 (double x,double a) ;
    double       CdfCauchyQ                 (double x,double a) ;
    double       CdfCauchyPinv              (double P,double a) ;
    double       CdfCauchyQinv              (double Q,double a) ;
    double       Rayleigh                   (double sigma) ;
    double       RayleighPDF                (double x,double sigma) ;
    double       CdfRayleighP               (double x,double sigma) ;
    double       CdfRayleighQ               (double x,double sigma) ;
    double       CdfRayleighPinv            (double P,double sigma) ;
    double       CdfRayleighQinv            (double Q,double sigma) ;
    double       RayleighTail               (double a,double sigma) ;
    double       RayleighTailPDF            (double x,double a, double sigma) ;
    double       Landau                     (void) ;
    double       LandauPDF                  (double x) ;
    double       Levy                       (double c,double alpha) ;
    double       LevySkew                   (double c,double alpha,double beta) ;
    double       Gamma                      (double a,double b) ;
    double       GammaKnuth                 (double a,double b) ;
    double       GammaKnuthPDF              (double x,double a,double b) ;
    double       CdfGammaP                  (double x,double a,double b) ;
    double       CdfGammaQ                  (double x,double a,double b) ;
    double       CdfGammaPinv               (double P,double a,double b) ;
    double       CdfGammaQinv               (double Q,double a,double b) ;
    double       Flat                       (double a,double b) ;
    double       FlatPDF                    (double x,double a,double b) ;
    double       CdfFlatP                   (double x,double a,double b) ;
    double       CdfFlatQ                   (double x,double a,double b) ;
    double       CdfFlatPinv                (double P,double a,double b) ;
    double       CdfFlatQinv                (double Q,double a,double b) ;
    double       LogNormal                  (double zeta,double sigma) ;
    double       LogNormalPDF               (double x,double zeta,double sigma) ;
    double       CdfLogNormalP              (double x,double zeta,double sigma) ;
    double       CdfLogNormalQ              (double x,double zeta,double sigma) ;
    double       CdfLogNormalPinv           (double P,double zeta,double sigma) ;
    double       CdfLogNormalQinv           (double Q,double zeta,double sigma) ;
    double       ChiSquared                 (double nu) ;
    double       ChiSquaredPDF              (double x,double nu) ;
    double       CdfChiSquaredP             (double x,double nu) ;
    double       CdfChiSquaredQ             (double x,double nu) ;
    double       CdfChiSquaredPinv          (double P,double nu) ;
    double       CdfChiSquaredQinv          (double Q,double nu) ;
    double       Fdist                      (double a,double b) ;
    double       FdistPDF                   (double x,double a,double b) ;
    double       CdfFdistP                  (double x,double a,double b) ;
    double       CdfFdistQ                  (double x,double a,double b) ;
    double       CdfFdistPinv               (double P,double a,double b) ;
    double       CdfFdistQinv               (double Q,double a,double b) ;
    double       Tdist                      (double a) ;
    double       TdistPDF                   (double x,double a) ;
    double       CdfTdistP                  (double x,double a) ;
    double       CdfTdistQ                  (double x,double a) ;
    double       CdfTdistPinv               (double P,double a) ;
    double       CdfTdistQinv               (double Q,double a) ;
    double       Beta                       (double a,double b) ;
    double       BetaPDF                    (double x,double a,double b) ;
    double       CdfBetaP                   (double x,double a,double b) ;
    double       CdfBetaQ                   (double x,double a,double b) ;
    double       CdfBetaPinv                (double P,double a,double b) ;
    double       CdfBetaQinv                (double Q,double a,double b) ;
    double       Logistic                   (double a) ;
    double       LogisticPDF                (double x,double a) ;
    double       CdfLogisticP               (double x,double a) ;
    double       CdfLogisticQ               (double x,double a) ;
    double       CdfLogisticPinv            (double P,double a) ;
    double       CdfLogisticQinv            (double Q,double a) ;
    double       Pareto                     (double a,double b) ;
    double       ParetoPDF                  (double x,double a,double b) ;
    double       CdfParetoP                 (double x,double a,double b) ;
    double       CdfParetoQ                 (double x,double a,double b) ;
    double       CdfParetoPinv              (double P,double a,double b) ;
    double       CdfParetoQinv              (double Q,double a,double b) ;
    double       Weibull                    (double a,double b) ;
    double       WeibullPDF                 (double x,double a,double b) ;
    double       CdfWeibullP                (double x,double a,double b) ;
    double       CdfWeibullQ                (double x,double a,double b) ;
    double       CdfWeibullPinv             (double P,double a,double b) ;
    double       CdfWeibullQinv             (double Q,double a,double b) ;
    double       Gumbell                    (double a,double b) ;
    double       GumbellPDF                 (double x,double a,double b) ;
    double       CdfGumbellP                (double x,double a,double b) ;
    double       CdfGumbellQ                (double x,double a,double b) ;
    double       CdfGumbellPinv             (double P,double a,double b) ;
    double       CdfGumbellQinv             (double Q,double a,double b) ;
    double       Gumbell2                   (double a,double b) ;
    double       Gumbell2PDF                (double x,double a,double b) ;
    double       CdfGumbell2P               (double x,double a,double b) ;
    double       CdfGumbell2Q               (double x,double a,double b) ;
    double       CdfGumbell2Pinv            (double P,double a,double b) ;
    double       CdfGumbell2Qinv            (double Q,double a,double b) ;
    unsigned int Poisson                    (double mu) ;
    double       PoissonPDF                 (unsigned int k,double mu) ;
    double       CdfPoissonP                (unsigned int k,double mu) ;
    double       CdfPoissonQ                (unsigned int k,double mu) ;
    unsigned int Bernoulli                  (double p) ;
    double       BernoulliPDF               (unsigned int k,double p) ;
    unsigned int Binomial                   (double p,unsigned int n) ;
    double       BinomialPDF                (unsigned int k,double p,unsigned int n) ;
    double       CdfBinomialP               (unsigned int k,double p,unsigned int n) ;
    double       CdfBinomialQ               (unsigned int k,double p,unsigned int n) ;
    void         Multinomial                (size_t       K     ,
                                             unsigned int N     ,
                                             const double p[]   ,
                                             unsigned int n[] ) ;
    double       MultinomialPDF             (size_t             K     ,
                                             const double       p[]   ,
                                             const unsigned int n[] ) ;
    double       MultinomialLnPDF           (size_t             K     ,
                                             const double       p[]   ,
                                             const unsigned int n[] ) ;
    unsigned int NegativeBinomial           (double p,double n) ;
    double       NegativeBinomialPDF        (unsigned int k,double p,double n) ;
    double       CdfNegativeBinomialP       (unsigned int k,double p,double n) ;
    double       CdfNegativeBinomialQ       (unsigned int k,double p,double n) ;
    unsigned int Pascal                     (double p,unsigned int n) ;
    double       PascalPDF                  (unsigned int k,double p,unsigned int n) ;
    double       CdfPascalP                 (unsigned int k,double p,unsigned int n) ;
    double       CdfPascalQ                 (unsigned int k,double p,unsigned int n) ;
    unsigned int Geometric                  (double p) ;
    double       GeometricPDF               (unsigned int k,double p) ;
    double       CdfGeometricP              (unsigned int k,double p) ;
    double       CdfGeometricQ              (unsigned int k,double p) ;
    unsigned int Hypergeometric             (unsigned int n1          ,
                                             unsigned int n2          ,
                                             unsigned int t         ) ;
    double       HypergeometricPDF          (unsigned int k           ,
                                             unsigned int n1          ,
                                             unsigned int n2          ,
                                             unsigned int t         ) ;
    double       CdfHypergeometricP         (unsigned int k           ,
                                             unsigned int n1          ,
                                             unsigned int n2          ,
                                             unsigned int t         ) ;
    double       CdfHypergeometricQ         (unsigned int k           ,
                                             unsigned int n1          ,
                                             unsigned int n2          ,
                                             unsigned int t         ) ;
    unsigned int Logarithmic                (double p) ;
    double       LogarithmicPDF             (unsigned int k, double p) ;
    void         Dirichlet                  (int K,const double alpha[],double theta[]) ;
    double       DirichletPDF               (int K,const double alpha[],const double theta[]) ;
    double       DirichletLnPDF             (int K,const double alpha[],const double theta[]) ;
    void         SphericalDir2D             (double & x,double & y) ;
    void         SphericalDir2DTrigMethod   (double & x,double & y) ;
    void         SphericalDir3D             (double & x,double & y,double & z) ;
    void         SphericalDirN              (int n, double * x) ;
    gsl_ran_discrete_t * PrepareDiscrete    (int K,const double * P) ;
    size_t               Discrete           (const gsl_ran_discrete_t * g) ;
    double               DiscretePDF        (size_t k,const gsl_ran_discrete_t * g) ;
    void                 DiscreteFree       (gsl_ran_discrete_t * g) ;
    void         Shuffle                    (void * base,size_t n,size_t size) ;
    void         Choose                     (void * dest,size_t k,void * src,size_t n,size_t size) ;
    void         Sample                     (void * dest,size_t k,void * src,size_t n,size_t size) ;

};

class Q_GSL_EXPORT Histogram
{
  public:

    gsl_histogram       * histo      ;
    gsl_histogram_pdf   * histoPdf   ;
    gsl_histogram2d     * histo2d    ;
    gsl_histogram2d_pdf * histo2dPdf ;

    explicit Histogram        (void) ;
    explicit Histogram        (int n) ;
             Histogram        (const Histogram & histogram) ;
    virtual ~Histogram        (void) ;

    bool   allocate           (int n) ;
    int    setRanges          (const double range[],int size) ;
    int    uniformRanges      (double xmin, double xmax) ;
    int    increment          (double x) ;
    int    accumulate         (double x,double weight) ;
    double get                (int i) ;
    int    getRange           (int i,double * lower,double * upper) ;
    double Max                (void) ;
    double Min                (void) ;
    int    bins               (void) ;
    void   reset              (void) ;
    int    find               (double x,size_t * i) ;
    double maxValue           (void) ;
    double minValue           (void) ;
    double mean               (void) ;
    double sigma              (void) ;
    double sum                (void) ;
    int    maxBin             (void) ;
    int    minBin             (void) ;
    int    scale              (double scale) ;
    int    shift              (double offset) ;
    bool   equalBins          (Histogram & histogram) ;
    int    add                (Histogram & histogram) ;
    int    sub                (Histogram & histogram) ;
    int    mul                (Histogram & histogram) ;
    int    div                (Histogram & histogram) ;

    bool   allocatePdf        (int n) ;
    double sample             (double r) ;

    bool   allocate2d         (int nx,int ny) ;
    int    setRanges2d        (const double xrange[],int xsize,const double yrange[],int ysize) ;
    int    uniformRanges2d    (double xmin,double xmax,double ymin,double ymax) ;
    int    increment2d        (double x,double y) ;
    int    accumulate2d       (double x,double y,double weight) ;
    double get2d              (int i,int j) ;
    int    getXrange2d        (int i,double * xlower,double * xupper) ;
    int    getYrange2d        (int j,double * ylower,double * yupper) ;
    double xmax2d             (void) ;
    double xmin2d             (void) ;
    int    nx2d               (void) ;
    int    ny2d               (void) ;
    double ymax2d             (void) ;
    double ymin2d             (void) ;
    void   reset2d            (void) ;
    int    find2d             (double x,double y,size_t * i,size_t * j) ;
    double maxValue2d         (void) ;
    double minValue2d         (void) ;
    void   maxBin2d           (size_t * i,size_t * j) ;
    void   minBin2d           (size_t * i,size_t * j) ;
    double xmean2d            (void) ;
    double ymean2d            (void) ;
    double xsigma2d           (void) ;
    double ysigma2d           (void) ;
    double cov2d              (void) ;
    double sum2d              (void) ;
    int    scale2d            (double scale) ;
    int    shift2d            (double offset);
    bool   equalBins2d        (Histogram & histogram) ;
    int    add2d              (Histogram & histogram) ;
    int    sub2d              (Histogram & histogram) ;
    int    mul2d              (Histogram & histogram) ;
    int    div2d              (Histogram & histogram) ;

    bool   allocatePdf2d      (int nx,int ny) ;
    int    sample2d           (double r1,double r2,double * x,double * y) ;

  protected:

  private:

};

class Q_GSL_EXPORT Chebyshev
{
  public:

    gsl_cheb_series * chebyshev ;
    gsl_function    * function  ;

    explicit Chebyshev    (void) ;
    explicit Chebyshev    (int n) ;
             Chebyshev    (const Chebyshev & cheb) ;
    virtual ~Chebyshev    (void) ;

    bool     Allocate     (int n) ;
    int      Initialize   (const double   a         ,
                           const double   b         ,
                           MathFunction   equation  ,
                           void         * params  ) ;

    size_t   Order        (void) ;
    size_t   Size         (void) ;
    double * Coefficients (void) ;
    double   Eval         (double x) ;
    double   EvalN        (size_t         order    ,
                           double         x      ) ;
    int      EvalAbsErr   (const double   x        ,
                           double       * result   ,
                           double       * abserr ) ;
    int      EvalNAbserr  (const size_t   order    ,
                           const double   x        ,
                           double       * result   ,
                           double       * abserr ) ;

    int      Derivative   (Chebyshev & cheb) ;
    int      Integral     (Chebyshev & cheb) ;

  protected:

  private:

};

/*****************************************************************************
 *                                                                           *
 *                        Permutation and Combination                        *
 *                                                                           *
 *****************************************************************************/

class Q_GSL_EXPORT Permutation : public QByteArray
{
  public:

    explicit Permutation          (void) ;
    explicit Permutation          (int size) ;
    explicit Permutation          (QString m) ;
             Permutation          (const Permutation & permutation) ;
    virtual ~Permutation          (void) ;

    int           isValid         (void) ; // gsl_permutation_valid
    int           toCUIDs         (CUIDs & Cuids) ;
    QString       toString        (void) ;
    int           toByteArray     (QByteArray & blob) ;
    int           setElements     (int size) ;
    int           elements        (void) const ;
    size_t *      array           (void) const ;
    Permutation & operator =      (const Permutation & permutation) ;
    Permutation & assign          (const Permutation & permutation) ;
    Permutation & toIdentity      (void) ; // gsl_permutation_init
    Permutation & Reverse         (void) ; // gsl_permutation_reverse
    void          swap            (int a,int b) ; // gsl_permutation_swap
    void          setValue        (int index,int   value) ;
    void          setValue        (int index,char  value) ;
    void          setValue        (int index,QChar value) ;
    void          setValue        (QString m) ;
    int           operator []     (int index) ; // gsl_permutation_get
    int           next            (void) ; // gsl_permutation_next
    int           previous        (void) ; // gsl_permutation_prev
    int           inverse         (Permutation & inv) ; // gsl_permutation_inverse(inv,this)
    int           toCanonical     (Permutation & canonical); //gsl_permutation_linear_to_canonical(canonical,this)
    int           toLinear        (Permutation & linear); //gsl_permutation_canonical_to_linear(linear,this)
    int           inversions      (void) ; // gsl_permutation_inversions
    int           linearCycles    (void) ; // gsl_permutation_linear_cycles
    int           canonicalCycles (void) ; // gsl_permutation_canonical_cycles
    static int    permute         (const size_t * p,double * data,size_t stride,size_t n) ; // gsl_permute
    static int    inverse         (const size_t * p,double * data,size_t stride,size_t n) ; // gsl_permute_inverse

    // gsl_permute_vector
    // gsl_permute_vector_inverse
    // gsl_permutation_mul

  protected:

  private:

};

class Q_GSL_EXPORT Combination : public QByteArray
{
  public:

    explicit Combination      (void) ;
    explicit Combination      (int n,int k) ;
             Combination      (const Combination & combination) ;
    virtual ~Combination      (void) ;

    int           isValid     (void) ; // gsl_combination_valid
    int           toCUIDs     (CUIDs & Cuids) ;
    int           toByteArray (QByteArray & blob) ;
    int           setElements (int n,int k) ;
    int           setChosen   (int k) ;
    int           elements    (void) const ;
    int           chosen      (void) const ;
    size_t *      array       (void) const ;
    Combination & operator =  (const Combination & combination) ;
    Combination & assign      (const Combination & combination) ;
    Combination & toFirst     (void) ; // gsl_combination_init_first
    Combination & toLast      (void) ; // gsl_combination_init_last
    void          setValue    (int index,int   value) ;
    void          setValue    (int index,char  value) ;
    void          setValue    (int index,QChar value) ;
    int           operator [] (int index) ; // gsl_combination_get
    int           next        (void) ; // gsl_combination_next
    int           previous    (void) ; // gsl_combination_prev

  protected:

  private:

};

class Q_GSL_EXPORT Multisets : public QByteArray
{
  public:

    explicit Multisets      (void) ;
    explicit Multisets      (int n,int k) ;
             Multisets      (const Multisets & multisets) ;
    virtual ~Multisets      (void) ;

    int         isValid     (void) ; // gsl_combination_valid
    int         toCUIDs     (CUIDs & Cuids) ;
    int         toByteArray (QByteArray & blob) ;
    int         setElements (int n,int k) ;
    int         setChosen   (int k) ;
    int         elements    (void) const ;
    int         chosen      (void) const ;
    size_t    * array       (void) const ;
    Multisets & operator =  (const Multisets & multisets) ;
    Multisets & assign      (const Multisets & multisets) ;
    Multisets & toFirst     (void) ; // gsl_combination_init_first
    Multisets & toLast      (void) ; // gsl_combination_init_last
    void        setValue    (int index,int   value) ;
    void        setValue    (int index,char  value) ;
    void        setValue    (int index,QChar value) ;
    int         operator [] (int index) ; // gsl_combination_get
    int         next        (void) ; // gsl_combination_next
    int         previous    (void) ; // gsl_combination_prev

  protected:

  private:

};

/*****************************************************************************
 *                                                                           *
 *                               Linear algebra                              *
 *                                                                           *
 *****************************************************************************/

class Q_GSL_EXPORT MultiFit
{
  public:

    gsl_multifit_linear_workspace * work ;

    explicit MultiFit      (void) ;
    explicit MultiFit      (int n,int p) ;
             MultiFit      (const MultiFit & fit) ;
    virtual ~MultiFit      (void) ;

    bool Allocate          (int n,int p) ;

    int Linear             (const gsl_matrix * X       ,
                            const gsl_vector * y       ,
                                  gsl_vector * c       ,
                                  gsl_matrix * cov     ,
                            double           * chisq ) ;
    int WeightedLinear     (const gsl_matrix * X       ,
                            const gsl_vector * w       ,
                            const gsl_vector * y       ,
                                  gsl_vector * c       ,
                                  gsl_matrix * cov     ,
                            double           * chisq ) ;
    int svdLinear          (const gsl_matrix * X     ) ;
    int svdWeightedLinear  (const gsl_matrix * X       ,
                            const gsl_vector * w       ,
                            const gsl_vector * y       ,
                            double             tol     ,
                            size_t           * rank    ,
                                  gsl_vector * c       ,
                                  gsl_matrix * cov     ,
                            double           * chisq ) ;
    int usvdWeightedLinear (const gsl_matrix * X       ,
                            const gsl_vector * w       ,
                            const gsl_vector * y       ,
                            double             tol     ,
                            size_t           * rank    ,
                                  gsl_vector * c       ,
                                  gsl_matrix * cov     ,
                            double           * chisq ) ;

    int Linearest          (const gsl_vector * x       ,
                            const gsl_vector * c       ,
                            const gsl_matrix * cov     ,
                            double           * y       ,
                            double           * y_err ) ;
    int Residuals          (const gsl_matrix * X       ,
                            const gsl_vector * y       ,
                            const gsl_vector * c       ,
                                  gsl_vector * r     ) ;

  protected:

  private:

};

class Q_GSL_EXPORT BSplines
{
  public:

    gsl_bspline_workspace * work ;

    explicit BSplines            (void) ;
    explicit BSplines            (int k,int nbreak) ;
             BSplines            (const BSplines & bsplines) ;
    virtual ~BSplines            (void) ;

    bool   Allocate              (int k,int nbreak) ;

    int    Knots                 (const gsl_vector * breakpts) ;
    int    uniformKnots          (const double a,const double b) ;
    int    Eval                  (const double x,gsl_vector * B) ;
    int    EvalNonZero           (const double   x       ,
                                  gsl_vector   * Bk      ,
                                  size_t       * istart  ,
                                  size_t       * iend  ) ;
    int    Coefficients          (void) ;
    double GrevilleAbscissa      (int i) ;

    int    DerivativeEval        (const double   x       ,
                                  const int      nderiv  ,
                                  gsl_matrix   * dB    ) ;
    int    DerivativeEvalNonZero (const double   x       ,
                                  const int      nderiv  ,
                                  gsl_matrix   * dB      ,
                                  size_t       * istart  ,
                                  size_t       * iend  ) ;

  protected:

  private:

};

class Q_GSL_EXPORT Interpolation
{
  public:

    gsl_interp       * work   ;
    gsl_interp_accel * accel  ;
    gsl_spline       * spline ;

    explicit Interpolation              (void) ;
    explicit Interpolation              (const gsl_interp_type * T,int size) ;
             Interpolation              (const Interpolation & interpolation) ;
    virtual ~Interpolation              (void) ;

    bool         Allocate               (const gsl_interp_type * T,int size) ;
    bool         AllocateAccel          (void) ;
    bool         AllocateSpline         (const gsl_interp_type * T,int size) ;

    int          Initialize             (const double xa[]   ,
                                         const double ya[]   ,
                                         int          size ) ;
    int          InitializeSpline       (const double xa[]   ,
                                         const double ya[]   ,
                                         int          size ) ;

    QString      Name                   (void) ;
    QString      SplineName             (void) ;
    unsigned int MinSize                (void) ;
    unsigned int MinSize                (const gsl_interp_type * T) ;
    unsigned int SplineMinSize          (void) ;

    int          BSearch                (const double x_array[]  ,
                                               double x          ,
                                               int    index_lo   ,
                                               int    index_hi ) ;
    int          Find                   (const double x_array[]  ,
                                               int    size       ,
                                               double x        ) ;
    int          Reset                  (void) ;

    double       Eval                   (const double   xa[]  ,
                                         const double   ya[]  ,
                                               double   x   ) ;
    int          EvalE                  (const double   xa[]  ,
                                         const double   ya[]  ,
                                               double   x     ,
                                               double * y   ) ;
    double       EvalDerivative         (const double xa[]    ,
                                         const double ya[]    ,
                                               double x     ) ;
    double       EvalDerivative2        (const double xa[]    ,
                                         const double ya[]    ,
                                               double x     ) ;
    double       EvalIntegral           (const double xa[]    ,
                                         const double ya[]    ,
                                               double a       ,
                                               double b     ) ;
    double       SplineEval             (double x) ;
    double       SplineEvalDerivative   (double x) ;
    double       SplineEvalDerivative2  (double x) ;
    double       SplineEvalIntegral     (double a,double b) ;
    int          EvalDerivativeE        (const double   xa[] ,
                                         const double   ya[] ,
                                               double   x    ,
                                               double * d  ) ;
    int          EvalDerivative2E       (const double   xa[] ,
                                         const double   ya[] ,
                                               double   x    ,
                                               double * d2 ) ;
    int          EvalIntegralE          (const double   xa[]     ,
                                         const double   ya[]     ,
                                               double   a        ,
                                               double   b        ,
                                               double * result ) ;
    int          SplineEvalE            (double x,double * y) ;
    int          SplineEvalDerivativeE  (double x,double * d) ;
    int          SplineEvalDerivative2E (double x,double * d2) ;
    int          SplineEvalIntegralE    (double a,double b,double * result) ;

  protected:

  private:

};

class Q_GSL_EXPORT Vector : public QByteArray
{
  public:

    explicit Vector              (void) ;
    explicit Vector              (Cpp::ValueTypes type,int items) ;
             Vector              (const Vector & vector) ;
    virtual ~Vector              (void) ;

    Cpp::ValueTypes Type         (void);
    int             BytesPerCell (void) ;

    Vector & operator =          (const Vector & vector) ;

    bool     subVector           (Vector & vector,int offset,int items) ; // get sub-vector
    bool     setVector           (int offset,Vector & vector) ;

    void     reset               (void);
    void     set                 (Cpp::ValueTypes type,int items) ;

    void *   array               (void);

    int      count               (void) ;
    void     setZero             (void) ;
    void     setAll              (double x) ;
    void     setBasis            (int index) ;
    bool     swap                (int i,int j) ;
    bool     reverse             (void) ;
    int      take                (int pos,int items) ;
    int      append              (int items,const char * source) ;
    int      append              (int items,int gap,const char * source) ;
    int      insert              (int pos,int items,const char * source) ;
    int      insert              (int pos,int items,int gap,const char * source) ;

    Vector & operator +=         (Vector & vector) ;
    Vector & operator -=         (Vector & vector) ;
    Vector & operator *=         (Vector & vector) ;
    Vector & operator /=         (Vector & vector) ;

    Vector & operator +=         (double x) ;
    Vector & operator -=         (double x) ;
    Vector & operator *=         (double x) ;

    QString  toCpp               (void) ;
    QString  toCpp               (QString variableName) ;

    // P(x) = c[0] + c[1] x + c[2] x^2 + ... + c[len-1] x^{len-1}
    double   polynomial          (double x) ;
    bool     polynomial          (vcomplex & x,vcomplex & result) ;
    int      derivatives         (double x,int length,double * results) ;

  protected:

  private:

};

class Q_GSL_EXPORT Matrix : public QByteArray
{
  public:

    explicit Matrix        (void);
    explicit Matrix        (Cpp::ValueTypes type,int rows,int columns) ;
             Matrix        (const Matrix & matrix) ;
    virtual ~Matrix        (void);

    Cpp::ValueTypes Type   (void);

    Matrix & operator  =   (const Matrix & matrix) ;

    Matrix & operator +=   (const Matrix & matrix) ;
    Matrix & operator +=   (int value) ;
    Matrix & operator +=   (double value) ;
    Matrix & operator -=   (const Matrix & matrix) ;
    Matrix & operator -=   (int value) ;
    Matrix & operator -=   (double value) ;
    Matrix & operator *=   (int value) ;
    Matrix & operator *=   (double value) ;
    Matrix & operator /=   (int value) ;
    Matrix & operator /=   (double value) ;

    void   reset           (void);
    void   assign          (const Matrix & matrix) ;
    void   set             (Cpp::ValueTypes type,int rows,int columns);
    void   zerofill        (void);

    int    Rows            (void);
    int    Columns         (void);
    int    at              (int row,int column) ;

    void * array           (void);

    bool   swapRows        (int i,int j) ;
    bool   swapColumns     (int i,int j) ;

    bool   transpose       (void) ;
    bool   transpose       (const Matrix & T) ;
    bool   inverse         (Matrix & T) ;

    static double sum      (double * v,int items) ;
    static void   dispatch (int shift,int column,int items,double * R,double * S) ;
    static double multiple (int length,double * a,double * b) ;
    static double multiple (int length,double * R,double * a,double * b) ;

    QString toCpp          (void) ;
    QString toCpp          (QString variableName) ;

    void    vertical       (double * R,double * V) ;

  protected:

  private:

};

/*****************************************************************************
 *                                                                           *
 *               Fourier, Wavelet, and other series transformation           *
 *                                                                           *
 *****************************************************************************/

class Q_GSL_EXPORT LevinWithError
{
  public:

    gsl_sum_levin_u_workspace * work ;

    explicit LevinWithError (void) ;
    explicit LevinWithError (int n) ;
             LevinWithError (const LevinWithError & levin) ;
    virtual ~LevinWithError (void) ;

    bool Allocate           (int n) ;
    int  Acceleration       (const double * array       ,
                             const size_t   n           ,
                             double       * sum_accel   ,
                             double       * abserr    ) ;
    int  MinMax             (const double * array       ,
                             const size_t   n           ,
                             const size_t   min_terms   ,
                             const size_t   max_terms   ,
                             double       * sum_accel   ,
                             double       * abserr    ) ;
    int  Step               (const double   term        ,
                             const size_t   n           ,
                             const size_t   nmax        ,
                             double       * sum_accel ) ;

  protected:

  private:

};

class Q_GSL_EXPORT Levin
{
  public:

    gsl_sum_levin_utrunc_workspace * work ;

    explicit Levin    (void) ;
    explicit Levin    (int n) ;
             Levin    (const Levin & levin) ;
    virtual ~Levin    (void) ;

    bool Allocate     (int n) ;
    int  Acceleration (const double * array          ,
                       const size_t   n              ,
                       double       * sum_accel      ,
                       double       * abserr_trunc ) ;
    int  MinMax       (const double * array          ,
                       const size_t   n              ,
                       const size_t   min_terms      ,
                       const size_t   max_terms      ,
                       double       * sum_accel      ,
                       double       * abserr_trunc ) ;
    int  Step         (const double   term           ,
                       const size_t   n              ,
                       double       * sum_accel    ) ;

  protected:

  private:

};

}

Q_DECLARE_METATYPE(vcomplex)
Q_DECLARE_METATYPE(vcomplexes)
Q_DECLARE_METATYPE(N::Random)
Q_DECLARE_METATYPE(N::Histogram)
Q_DECLARE_METATYPE(N::Chebyshev)
Q_DECLARE_METATYPE(N::Permutation)
Q_DECLARE_METATYPE(N::Combination)
Q_DECLARE_METATYPE(N::Multisets)
Q_DECLARE_METATYPE(N::MultiFit)
Q_DECLARE_METATYPE(N::BSplines)
Q_DECLARE_METATYPE(N::Interpolation)
Q_DECLARE_METATYPE(N::Vector)
Q_DECLARE_METATYPE(N::Matrix)
Q_DECLARE_METATYPE(N::LevinWithError)
Q_DECLARE_METATYPE(N::Levin)

QT_END_NAMESPACE

#endif


#ifndef SPARSE_AUC_AUC_OPT_METHODS_H
#define SPARSE_AUC_AUC_OPT_METHODS_H

#include <time.h>
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <limits.h>
// These are the third part library needed.
#include <cblas.h>
#include "fast_pcst.h"
#include "loss.h"

#define PI 3.14159265358979323846
#define sign(x) (x > 0) - (x < 0)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define swap(a, b) { register double temp=(a);(a)=(b);(b)=temp; }
#define is_posi(x) ( x > 0.0 ? 1.0 : 0.0)
#define is_nega(x) ( x < 0.0 ? 1.0 : 0.0)

typedef struct {
    double *wt;
    double *wt_prev;
    double *aucs;
    double *rts;
    int auc_len; // how many auc evaluated.
    int total_iterations; // total iterations
    int total_epochs; // total epochs executed.
} AlgoResults;

typedef struct {
    int num_passes;
    int verbose;
    int step_len;
    int record_aucs;
    double stop_eps;
} GlobalParas;

AlgoResults *make_algo_results(int data_p, int total_num_eval);

bool free_algo_results(AlgoResults *re);

typedef struct {
    Array *re_nodes;
    Array *re_edges;
    double *prizes;
    double *costs;
    int num_pcst;
    double run_time;
    int num_iter;
} GraphStat;

typedef struct {
    const double *x_tr_vals;
    const int *x_tr_inds;
    const int *x_tr_poss;
    const int *x_tr_lens;
    const double *y_tr;
    bool is_sparse;
    int n;
    int p;
    // this is only for the graph operator.
    bool is_graph;
    int m; // number of edges.
    EdgePair *edges;
    double *weights;
    int g;
    double *proj_prizes;
    GraphStat *graph_stat;
} Data;

GraphStat *make_graph_stat(int p, int m);

bool free_graph_stat(GraphStat *graph_stat);

typedef struct {
    double val;
    int index;
} data_pair;

bool head_tail_binsearch(
        const EdgePair *edges, const double *costs, const double *prizes,
        int n, int m, int target_num_clusters, int root, int sparsity_low,
        int sparsity_high, int max_num_iter, PruningMethod pruning,
        int verbose, GraphStat *stat);

/**
 * SOLAM: Stochastic Online AUC Maximization
 * ---
 * BibTEX:
 * @inproceedings{ying2016stochastic,
 * title={Stochastic online AUC maximization},
 * author={Ying, Yiming and Wen, Longyin and Lyu, Siwei},
 * booktitle={Advances in neural information processing systems},
 * pages={451--459},
 * year={2016}
 * }
 * @param data
 * @param paras
 * @param re
 * @param para_xi
 * @param para_r
 * @author --- (Email: ---)
 * @return
 */
bool _algo_solam(Data *data,
                 GlobalParas *paras,
                 AlgoResults *re,
                 double para_xi,
                 double para_r);

/**
 * This function implements the algorithm proposed in the following paper.
 * Stochastic Proximal Algorithms for AUC Maximization.
 * ---
 * @inproceedings{natole2018stochastic,
 * title={Stochastic proximal algorithms for AUC maximization},
 * author={Natole, Michael and Ying, Yiming and Lyu, Siwei},
 * booktitle={International Conference on Machine Learning},
 * pages={3707--3716},
 * year={2018}}
 * ---
 * Do not use the function directly. Instead, call it by Python Wrapper.
 * @param data
 * @param paras
 * @param re
 * @param para_xi
 * @param para_l1_reg
 * @param para_l2_reg
 * @author --- (Email: ---)
 */
void _algo_spam(Data *data,
                GlobalParas *paras,
                AlgoResults *re,
                double para_xi,
                double para_l1_reg,
                double para_l2_reg);

/**
 * Stochastic Hard Thresholding for AUC maximization.
 * @param data
 * @param paras
 * @param re
 * @param para_s
 * @param para_b
 * @param para_c
 * @param para_l2_reg
 */
void _algo_sht_auc(Data *data,
                   GlobalParas *paras,
                   AlgoResults *re,
                   int version,
                   int operator_id,
                   int para_s,
                   int para_b,
                   double para_c,
                   double para_l2_reg);

void _algo_sto_iht(Data *data,
                   GlobalParas *paras,
                   AlgoResults *re,
                   int para_s,
                   int para_b,
                   double para_xi,
                   double para_l2_reg);

/**
 *
 * @param data
 * @param paras
 * @param re
 * @param para_s
 * @param para_tau
 * @param para_zeta
 * @param para_step_init
 * @param para_l2
 */
void _algo_hsg_ht(Data *data,
                  GlobalParas *paras,
                  AlgoResults *re,
                  int para_s,
                  double para_tau,
                  double para_zeta,
                  double para_step_init,
                  double para_l2);

int _hard_thresholding(double *arr, int n, int k);

/**
 *
 * @param data
 * @param paras
 * @param re
 * @param para_tau
 * @param para_eta
 * @param para_lambda
 */
void _algo_opauc(Data *data,
                 GlobalParas *paras,
                 AlgoResults *re,
                 int para_tau,
                 double para_eta,
                 double para_lambda);

/**
 * This function implements the algorithm, FSAUC, proposed in the following paper:
 * ---
 * @inproceedings{liu2018fast,
 * title={Fast stochastic AUC maximization with O (1/n)-convergence rate},
 * author={Liu, Mingrui and Zhang, Xiaoxuan and Chen, Zaiyi and Wang, Xiaoyu and Yang, Tianbao},
 * booktitle={International Conference on Machine Learning},
 * pages={3195--3203},
 * year={2018}}
 * ---
 * @param data
 * @param paras
 * @param re
 * @param para_r
 * @param para_g
 */
void _algo_fsauc(Data *data,
                 GlobalParas *paras,
                 AlgoResults *re,
                 double para_r,
                 double para_g);

#endif //SPARSE_AUC_AUC_OPT_METHODS_H


/* multifit/lmniel.c
 *
 * Copyright (C) 2014 Patrick Alken
 *
 * 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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_multifit_nlin.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_blas.h>

#define SCALE 0

/*
 * This module contains an implementation of the Levenberg-Marquardt
 * algorithm for nonlinear optimization problems. This implementation
 * closely follows the following works:
 *
 * [1] H. B. Nielsen, K. Madsen, Introduction to Optimization and
 *     Data Fitting, Informatics and Mathematical Modeling,
 *     Technical University of Denmark (DTU), 2010.
 */

typedef struct
{
  gsl_matrix *A;             /* J^T J */
  gsl_matrix *A_copy;        /* copy of J^T J */
  gsl_matrix *J;             /* Jacobian J(x) */
  gsl_vector *diag;          /* D = diag(J^T J) */
  gsl_vector *rhs;           /* rhs vector = -g = -J^T f */
  gsl_vector *x_trial;       /* trial parameter vector */
  gsl_vector *f_trial;       /* trial function vector */
  gsl_vector *work;          /* workspace length p */
  long nu;                   /* nu */
  double mu;                 /* LM damping parameter mu */
  double tau;                /* initial scale factor for mu */
} lmniel_state_t;

#include "lmmisc.c"

#define LM_ONE_THIRD         (0.333333333333333)

static int lmniel_alloc (void *vstate, const size_t n, const size_t p);
static void lmniel_free(void *vstate);
static int lmniel_set(void *vstate, const gsl_vector * swts,
                      gsl_multifit_function_fdf *fdf,
                      gsl_vector *x, gsl_vector *f, gsl_vector *dx);
static int lmniel_iterate(void *vstate, const gsl_vector *swts,
                          gsl_multifit_function_fdf *fdf,
                          gsl_vector *x, gsl_vector *f, gsl_vector *dx);

static int
lmniel_alloc (void *vstate, const size_t n, const size_t p)
{
  lmniel_state_t *state = (lmniel_state_t *) vstate;

  state->A = gsl_matrix_alloc(p, p);
  if (state->A == NULL)
    {
      GSL_ERROR ("failed to allocate space for A", GSL_ENOMEM);
    }

  state->J = gsl_matrix_alloc(n, p);
  if (state->J == NULL)
    {
      GSL_ERROR ("failed to allocate space for J", GSL_ENOMEM);
    }

  state->diag = gsl_vector_alloc(p);
  if (state->diag == NULL)
    {
      GSL_ERROR ("failed to allocate space for diag", GSL_ENOMEM);
    }

  state->rhs = gsl_vector_alloc(p);
  if (state->rhs == NULL)
    {
      GSL_ERROR ("failed to allocate space for rhs", GSL_ENOMEM);
    }

  state->work = gsl_vector_alloc(p);
  if (state->work == NULL)
    {
      GSL_ERROR ("failed to allocate space for work", GSL_ENOMEM);
    }

  state->A_copy = gsl_matrix_alloc(p, p);
  if (state->A_copy == NULL)
    {
      GSL_ERROR ("failed to allocate space for A_copy", GSL_ENOMEM);
    }

  state->x_trial = gsl_vector_alloc(p);
  if (state->x_trial == NULL)
    {
      GSL_ERROR ("failed to allocate space for x_trial", GSL_ENOMEM);
    }

  state->f_trial = gsl_vector_alloc(n);
  if (state->f_trial == NULL)
    {
      GSL_ERROR ("failed to allocate space for f_trial", GSL_ENOMEM);
    }

  state->tau = 1.0e-3;

  return GSL_SUCCESS;
} /* lmniel_alloc() */

static void
lmniel_free(void *vstate)
{
  lmniel_state_t *state = (lmniel_state_t *) vstate;

  if (state->A)
    gsl_matrix_free(state->A);

  if (state->J)
    gsl_matrix_free(state->J);

  if (state->diag)
    gsl_vector_free(state->diag);

  if (state->rhs)
    gsl_vector_free(state->rhs);

  if (state->work)
    gsl_vector_free(state->work);

  if (state->A_copy)
    gsl_matrix_free(state->A_copy);

  if (state->x_trial)
    gsl_vector_free(state->x_trial);

  if (state->f_trial)
    gsl_vector_free(state->f_trial);
} /* lmniel_free() */

static int
lmniel_set(void *vstate, const gsl_vector *swts,
           gsl_multifit_function_fdf *fdf, gsl_vector *x,
           gsl_vector *f, gsl_vector *dx)
{
  int status;
  lmniel_state_t *state = (lmniel_state_t *) vstate;
  const size_t p = x->size;
  size_t i;

  /* initialize counters for function and Jacobian evaluations */
  fdf->nevalf = 0;
  fdf->nevaldf = 0;

  /* evaluate function and Jacobian at x and apply weight transform */
  status = gsl_multifit_eval_wf(fdf, x, swts, f);
  if (status)
   return status;

  if (fdf->df)
    status = gsl_multifit_eval_wdf(fdf, x, swts, state->J);
  else
    status = gsl_multifit_fdfsolver_dif_df(x, swts, fdf, f, state->J);
  if (status)
    return status;

  /* compute rhs = -J^T f */
  gsl_blas_dgemv(CblasTrans, -1.0, state->J, f, 0.0, state->rhs);

#if SCALE
  gsl_vector_set_zero(state->diag);
#else
  gsl_vector_set_all(state->diag, 1.0);
#endif

  /* set default parameters */
  state->nu = 2;

#if SCALE
  state->mu = state->tau;
#else
  /* compute mu_0 = tau * max(diag(J^T J)) */
  state->mu = -1.0;
  for (i = 0; i < p; ++i)
    {
      gsl_vector_view c = gsl_matrix_column(state->J, i);
      double result; /* (J^T J)_{ii} */

      gsl_blas_ddot(&c.vector, &c.vector, &result);
      state->mu = GSL_MAX(state->mu, result);
    }

  state->mu *= state->tau;
#endif

  return GSL_SUCCESS;
} /* lmniel_set() */

/*
lmniel_iterate()
  This function performs 1 iteration of the LM algorithm 6.18
from [1]. The algorithm is slightly modified to loop until we
find an acceptable step dx, in order to guarantee that each
function call contains a new input vector x.

Args: vstate - lm workspace
      swts   - data weights (NULL if unweighted)
      fdf    - function and Jacobian pointers
      x      - on input, current parameter vector
               on output, new parameter vector x + dx
      f      - on input, f(x)
               on output, f(x + dx)
      dx     - (output only) parameter step vector

Notes:
1) On input, the following must be initialized in state:
nu, mu, rhs, J

2) On output, the following are updated with the current iterates:
nu, mu, rhs, J

rhs needs to be set on each output, so that lmniel_gradient supplies
the correct g = J^T f
*/

static int
lmniel_iterate(void *vstate, const gsl_vector *swts,
               gsl_multifit_function_fdf *fdf, gsl_vector *x,
               gsl_vector *f, gsl_vector *dx)
{
  int status;
  lmniel_state_t *state = (lmniel_state_t *) vstate;
  gsl_matrix *J = state->J;                   /* Jacobian J(x) */
  gsl_matrix *A = state->A;                   /* J^T J */
  gsl_vector *rhs = state->rhs;               /* -g = -J^T f */
  gsl_vector *x_trial = state->x_trial;       /* trial x + dx */
  gsl_vector *f_trial = state->f_trial;       /* trial f(x + dx) */
  gsl_vector *diag = state->diag;             /* diag(D) */
  double dF;                                  /* F(x) - F(x + dx) */
  double dL;                                  /* L(0) - L(dx) */
  int foundstep = 0;                          /* found step dx */

  /* compute A = J^T J */
  status = gsl_blas_dsyrk(CblasLower, CblasTrans, 1.0, J, 0.0, A);
  if (status)
    return status;

  /* copy lower triangle to upper */
  gsl_matrix_transpose_tricpy('L', 0, A, A);

#if SCALE
  lmniel_update_diag(J, diag);
#endif

  /* loop until we find an acceptable step dx */
  while (!foundstep)
    {
      /* solve (A + mu*I) dx = g */
      status = lmniel_calc_dx(state->mu, A, rhs, dx, state);
      if (status)
        return status;

      /* compute x_trial = x + dx */
      lmniel_trial_step(x, dx, x_trial);

      /* compute f(x + dx) */
      status = gsl_multifit_eval_wf(fdf, x_trial, swts, f_trial);
      if (status)
       return status;

      /* compute dF = F(x) - F(x + dx) */
      dF = lmniel_calc_dF(f, f_trial);

      /* compute dL = L(0) - L(dx) = dx^T (mu*dx - g) */
      dL = lmniel_calc_dL(state->mu, diag, dx, rhs);

      /* check that rho = dF/dL > 0 */
      if ((dL > 0.0) && (dF >= 0.0))
        {
          /* reduction in error, step acceptable */

          double tmp;

          /* update LM parameter mu */
          tmp = 2.0 * (dF / dL) - 1.0;
          tmp = 1.0 - tmp*tmp*tmp;
          state->mu *= GSL_MAX(LM_ONE_THIRD, tmp);
          state->nu = 2;

          /* compute J <- J(x + dx) */
          if (fdf->df)
            status = gsl_multifit_eval_wdf(fdf, x_trial, swts, J);
          else
            status = gsl_multifit_fdfsolver_dif_df(x_trial, swts, fdf, f_trial, J);
          if (status)
            return status;

          /* update x <- x + dx */
          gsl_vector_memcpy(x, x_trial);

          /* update f <- f(x + dx) */
          gsl_vector_memcpy(f, f_trial);

          /* compute new rhs = -J^T f */
          gsl_blas_dgemv(CblasTrans, -1.0, J, f, 0.0, rhs);

          foundstep = 1;
        }
      else
        {
          long nu2;

          /* step did not reduce error, reject step */
          state->mu *= (double) state->nu;
          nu2 = state->nu << 1; /* 2*nu */
          if (nu2 <= state->nu)
            {
              gsl_vector_view d = gsl_matrix_diagonal(A);

              /*
               * nu has wrapped around / overflown, reset mu and nu
               * to original values and break to force another iteration
               */
              /*GSL_ERROR("nu parameter has overflown", GSL_EOVRFLW);*/
              state->nu = 2;
              state->mu = state->tau * gsl_vector_max(&d.vector);
              break;
            }
          state->nu = nu2;
        }
    } /* while (!foundstep) */

  return GSL_SUCCESS;
} /* lmniel_iterate() */

static int
lmniel_gradient(void *vstate, gsl_vector * g)
{
  lmniel_state_t *state = (lmniel_state_t *) vstate;
  gsl_vector_memcpy(g, state->rhs);
  gsl_vector_scale(g, -1.0);
  return GSL_SUCCESS;
}

static int
lmniel_jac(void *vstate, gsl_matrix * J)
{
  lmniel_state_t *state = (lmniel_state_t *) vstate;
  int s = gsl_matrix_memcpy(J, state->J);

  return s;
}

static const gsl_multifit_fdfsolver_type lmniel_type =
{
  "lmniel",
  sizeof(lmniel_state_t),
  &lmniel_alloc,
  &lmniel_set,
  &lmniel_iterate,
  &lmniel_gradient,
  &lmniel_jac,
  &lmniel_free
};

const gsl_multifit_fdfsolver_type *gsl_multifit_fdfsolver_lmniel = &lmniel_type;


#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <dc1394/dc1394.h>
#include <math.h>
#include <fitsio.h>
#include <gsl/gsl_statistics.h>
#include <xpa.h>
#include <sys/time.h>
#include <string.h>
#include <inttypes.h>

#define NXPA 10

typedef struct _Box {
    double  x;
    double  y;
    double  fwhm;
    double  cenx;
    double  ceny;
    double  counts;
    double  background;
    double  noise;
    double  sigmaxythresh;
    double  sigmaxy;
    double  sigmafwhmthresh;
    double  sigmafwhm;
    int     r;
} Box;

typedef struct _Back {
    double x;
    double y;
    double background;
    double sigma;
    int r;
    int width;
} Back;

Box box[3];
Back back;
long nelements, naxes[2], fpixel;
int boxsize = 30;
double pixel_scale = 1.22;

double stardist(int i, int j) {
    return( sqrt( (box[i].cenx-box[j].cenx)*(box[i].cenx-box[j].cenx) +
		  (box[i].ceny-box[j].ceny)*(box[i].ceny-box[j].ceny) ) );
}

/* this routine uses a. tokovinin's modified equation given in
   2002, PASP, 114, 1156
*/
double seeing(double var, double d, double r) {
    double lambda;
    double b, K, seeing;

    lambda = 0.65e-6;
    b = r/d;

    /* pixel scale in "/pixel, convert to rad */
    var = var*pow(pixel_scale/206265.0,2);

    K = 0.364*(1.0 - 0.532*pow(b, -1/3) - 0.024*pow(b, -7/3));

    seeing = 206265.0*0.98*pow(d/lambda, 0.2)*pow(var/K, 0.6);

    return seeing;
}

/* this routine uses the classic DIMM equation */
double old_seeing(double var, double d, double r) {
    double lambda;
    double r0;

    lambda = 0.65e-6;

    /* pixel scale in "/pixel, convert to rad */
    var = var*pow(pixel_scale/206265.0,2);

    r0 = pow(2.0*(lambda*lambda)*(
		 ( 0.1790*pow(d, (-1.0/3.0)) -
		   0.0968*pow(r, (-1.0/3.0)) )/var
		 ), 0.6);

    return 206265.0*0.98*lambda/r0;
}

/* measure the background in an annulus around the spot pattern */
int background(char *image, int imwidth, int imheight) {

    int i, j, backpix;
    int low_y, up_y, low_x, up_x;
    double dist, sum, sumsq;

    backpix = 0;
    sum = 0.0;
    sumsq = 0.0;

    low_y = back.y - back.r - back.width;
    up_y  = back.y + back.r + back.width;
    low_x = back.x - back.r - back.width;
    up_x  = back.x + back.r + back.width;
    if (low_y < 0) {
	low_y = 0;
    }
    if (up_y >= imheight) {
	up_y = imheight;
    }
    if (low_x < 0) {
	low_x = 0;
    }
    if (up_x >= imwidth) {
	up_x = imwidth;
    }

    for (i=low_y; i<up_y; i++) {
	for (j=low_x; j<up_x; j++) {
	    dist = sqrt(pow(back.x-j, 2) + pow(back.y-i, 2));
	    if (dist >= back.r && dist <= back.r+back.width) {
		sum += image[i*naxes[0]+j];
		backpix++;
	    }
	}
    }

    back.background = sum/backpix;
    //back.background = 0.0;

    for (i=low_y; i<up_y; i++) {
	for (j=low_x; j<up_x; j++) {
	    dist = sqrt(pow(back.x-j, 2) + pow(back.y-i, 2));
	    if (dist >= back.r && dist <= back.r+back.width) {
		sumsq += (image[i*naxes[0]+j]-back.background)*
		    (image[i*naxes[0]+j]-back.background);
	    }
	}
    }

    back.sigma = sqrt(sumsq/backpix);
    //back.sigma = 1.0;

    return 1;

}

/* measure centroid using center-of-mass algorithm */
int centroid(char *image, int imwidth, int imheight, int num) {

    int i, j;
    double  sum    = 0.0;
    double  sumx   = 0.0;
    double  sumxx  = 0.0;
    double  sumy   = 0.0;
    double  sumyy  = 0.0;
    double  val = 0.0;
    double  gain = 0.5;
    double  rmom;
    double  dist;
    double nsigma = 5.0;
    int low_y, up_y, low_x, up_x;
    int sourcepix = 0;

    low_y = box[num].y - box[num].r;
    up_y  = box[num].y + box[num].r;
    low_x = box[num].x - box[num].r;
    up_x  = box[num].x + box[num].r;
    if (low_y < 0) {
	low_y = 0;
    }
    if (up_y >= imheight) {
	up_y = imheight;
    }
    if (low_x < 0) {
	low_x = 0;
    }
    if (up_x >= imwidth) {
	up_x = imwidth;
    }

    for (i=low_y; i<up_y; i++) {
	for (j=low_x; j<up_x; j++) {

	    dist = sqrt(pow(box[num].x-j, 2) + pow(box[num].y-i, 2));
	    if (dist <= box[num].r) {
		val = image[i*naxes[0]+j] - back.background;
		if (val >= nsigma*back.sigma) {
		    sum   += val;
		    sumx  += val*j;
		    sumxx += val*j*j;
		    sumy  += val*i;
		    sumyy += val*i*i;
		    sourcepix++;
		}
	    }

	}
    }

    if ( sum <= 0.0 ) {
	box[num].sigmaxy = -1.0;
	box[num].sigmafwhm = -1.0;
	//box[num].x = imwidth/2.0;
	//box[num].y = imheight/2.0;
	box[num].fwhm = -1.0;
    } else {
	rmom = ( sumxx - sumx * sumx / sum + sumyy - sumy * sumy / sum ) / sum;

	if ( rmom <= 0 ) {
	    box[num].fwhm = -1.0;
	} else {
	    box[num].fwhm = sqrt(rmom)  * 2.354 / sqrt(2.0);
	}

	box[num].counts = sum;
	box[num].cenx   = sumx / sum;
	box[num].ceny   = sumy / sum;
	box[num].x += gain*(box[num].cenx - box[num].x);
	box[num].y += gain*(box[num].ceny - box[num].y);
	box[num].sigmaxy= box[num].noise * sourcepix / box[num].counts / sqrt(6.0);
	box[num].sigmafwhm = box[num].noise * pow(sourcepix,1.5) / 10.
	    / box[num].fwhm / box[num].counts
	    * 2.354 * 2.354 / 2.0;
    }

    return 1;

}

int grab_frame(dc1394camera_t *cam, char *buf, int nbytes) {
    dc1394video_frame_t *frame=NULL;
    dc1394error_t err;

    err = dc1394_capture_dequeue(cam, DC1394_CAPTURE_POLICY_WAIT, &frame);
    if (err != DC1394_SUCCESS) {
	dc1394_log_error("Unable to capture.");
	dc1394_capture_stop(cam);
	dc1394_camera_free(cam);
	exit(1);
    }

    memcpy(buf, frame->image, nbytes);
    dc1394_capture_enqueue(cam, frame);
    return 1;
}

int add_gaussian(char *buffer, float cenx, float ceny, float a, float sigma) {
    float gauss, rsq;
    int i, j, low_x, up_x, low_y, up_y, size;

    size = 30;
    low_x = (int)(cenx-size);
    up_x = (int)(cenx+size);
    low_y = (int)(ceny-size);
    up_y = (int)(ceny+size);

    for (i=low_y; i<up_y; i++) {
	for (j=low_x; j<up_x; j++) {
	    rsq = (cenx - j)*(cenx - j) + (ceny - i)*(ceny - i);
	    gauss = a*expf(-1.0*rsq/(sigma*sigma));
	    if (gauss > 255)
		gauss = 255;
	    buffer[i*naxes[0]+j] += (char)gauss;
	}
    }

    return 1;
}

int main() {

    dc1394camera_t *camera;
    char *buffer, *buffer2, *average;
    fitsfile *fptr;
    int i, j, f, status, nimages, anynul, nboxes, test;
    char fitsfile[256], xpastr[256];
    char *froot, *timestr;
    FILE *init, *out;
    float xx = 0.0, yy = 0.0, xsum = 0.0, ysum = 0.0;
    double dist[2000], sig[2000], dist_l[2000], sig_l[2000];
    double mean, var, var_l, avesig;
    double seeing_short, seeing_long, seeing_ave;
    struct timeval start_time, end_time;
    time_t start_sec, end_sec;
    suseconds_t start_usec, end_usec;
    float elapsed_time, fps;

    dc1394_t * dc;
    dc1394camera_list_t * list;
    dc1394error_t err;

    unsigned int min_bytes, max_bytes, max_height, max_width;
    unsigned int actual_bytes, winleft, wintop;
    uint64_t total_bytes = 0;
    char *names[NXPA];
    char *messages[NXPA];

    double d = 0.060;
    double r = 0.130;

    XPA xpa;
    xpa = XPAOpen(NULL);

    stderr = freopen("measure_seeing.log", "w", stderr);

    status = 0;
    anynul = 0;
    naxes[0] = 320;
    naxes[1] = 240;
    fpixel = 1;

    nelements = naxes[0]*naxes[1];

    dc = dc1394_new();
    if (!dc)
	return 1;
    err = dc1394_camera_enumerate(dc, &list);
    DC1394_ERR_RTN(err, "Failed to enumerate cameras.");

    if (list->num == 0) {
	dc1394_log_error("No cameras found.");
	return 1;
    }

    camera = dc1394_camera_new(dc, list->ids[0].guid);
    if (!camera) {
	dc1394_log_error("Failed to initialize camera with guid %"PRIx64".",
			 list->ids[0].guid);
	return 1;
    }
    dc1394_camera_free_list(list);

    printf("Using camera with GUID %"PRIx64"\n", camera->guid);

    // need to use legacy firewire400 mode for now.  800 not quite reliable.
    dc1394_video_set_iso_speed(camera, DC1394_ISO_SPEED_400);

    // configure camera for format7
    err = dc1394_video_set_mode(camera, DC1394_VIDEO_MODE_FORMAT7_1);
    DC1394_ERR_CLN_RTN(err, dc1394_camera_free(camera), "Can't choose format7_0");
    printf("I: video mode is format7_0\n");

    err = dc1394_format7_get_max_image_size(camera, DC1394_VIDEO_MODE_FORMAT7_1,
					    &max_width, &max_height);
    DC1394_ERR_CLN_RTN(err,dc1394_camera_free (camera),"cannot get max image size for format7_0");
    printf ("I: max image size is: height = %d, width = %d\n", max_height, max_width);
    printf ("I: current image size is: height = %ld, width = %ld\n", naxes[1], naxes[0]);

    //winleft = (max_width - naxes[0])/2;
    //wintop = (max_height - naxes[1])/2;
    winleft = 0;
    wintop = 0;

    err = dc1394_format7_set_roi(camera,
				 DC1394_VIDEO_MODE_FORMAT7_1,
				 DC1394_COLOR_CODING_MONO8,
				 DC1394_USE_MAX_AVAIL,
				 winleft, wintop, // left, top
				 naxes[0], naxes[1]);
    DC1394_ERR_CLN_RTN(err, dc1394_camera_free(camera), "Can't set ROI.");
    printf("I: ROI is (%d, %d) - (%ld, %ld)\n",
	   winleft, wintop, winleft+naxes[0], wintop+naxes[1]);

    err = dc1394_format7_get_total_bytes(camera, DC1394_VIDEO_MODE_FORMAT7_1, &total_bytes);
    DC1394_ERR_CLN_RTN(err, dc1394_camera_free(camera), "Can't get total bytes.");
    printf("I: total bytes per frame are %"PRIu64"\n", total_bytes);

    err = dc1394_capture_setup(camera, 16, DC1394_CAPTURE_FLAGS_DEFAULT);
    DC1394_ERR_CLN_RTN(err, dc1394_camera_free(camera), "Error capturing.");

    // start the camera up
    err = dc1394_video_set_transmission(camera, DC1394_ON);
    if (err != DC1394_SUCCESS) {
	dc1394_log_error("Unable to start camera iso transmission.");
	dc1394_capture_stop(camera);
	dc1394_camera_free(camera);
	exit(1);
    }

    out = fopen("seeing.dat", "a");
    init = fopen("init_cen_all", "r");
    i = 0;
    while (fscanf(init, "%f %f\n", &xx, &yy) != EOF) {
	box[i].x = xx;
	box[i].cenx = xx;
	box[i].y = yy;
	box[i].ceny = yy;
	box[i].r = boxsize/2.0;
	i++;
    }
    nboxes = i;
    fclose(init);

    back.r = 80;
    back.width = 10;

    /* allocate the buffers */
    if (!(buffer = malloc(nelements*sizeof(char)))) {
	printf("Couldn't Allocate Image Buffer\n");
	exit(-1);
    }
    if (!(buffer2 = malloc(nelements*sizeof(char)))) {
	printf("Couldn't Allocate 2nd Image Buffer\n");
	exit(-1);
    }
    if (!(average = malloc(nelements*sizeof(char)))) {
	printf("Couldn't Allocate Average Image Buffer\n");
	exit(-1);
    }

    nimages = 2000;
    froot = "seeing.fits";

    gettimeofday(&start_time, NULL);

    for (f=0; f<nimages; f++) {
	/* first do a single exposure */
	grab_frame(camera, buffer, nelements*sizeof(char));
	// add_gaussian(buffer, 175.0, 130.0, 50.0, 3.0);
	// add_gaussian(buffer, 155.0, 115.0, 50.0, 3.0);

	// find center of star images and calculate background
	xsum = 0.0;
	ysum = 0.0;
	for (i=0; i<nboxes; i++) {
	    xsum += box[i].cenx;
	    ysum += box[i].ceny;
	}
	back.x = xsum/nboxes;
	back.y = ysum/nboxes;
	background(buffer, naxes[0], naxes[1]);

	for (i=0; i<nboxes; i++) {
	    box[i].noise = back.sigma;
	    box[i].r = boxsize/2.0;
	    //centroid(buffer, i);
	    //box[i].r = boxsize/3.0;
	    //centroid(buffer, i);
	    //box[i].r = boxsize/4.0;
	    centroid(buffer, naxes[0], naxes[1], i);
	}

	dist[f] = stardist(0, 1);
	sig[f] = box[0].sigmaxy*box[0].sigmaxy + box[1].sigmaxy*box[1].sigmaxy;

	/* now average two exposures */
	grab_frame(camera, buffer, nelements*sizeof(char));
	grab_frame(camera, buffer2, nelements*sizeof(char));

	for (j=0; j<nelements; j++) {
	    test = buffer[j]+buffer2[j];
	    if (test <= 254) {
		average[j] = buffer[j]+buffer2[j];
	    } else {
		average[j] = 254;
	    }
	}
	// add_gaussian(average, 175.0, 130.0, 50.0, 3.0);
	// add_gaussian(average, 155.0, 115.0, 50.0, 3.0);

	xsum = 0.0;
	ysum = 0.0;
	for (i=0; i<nboxes; i++) {
	    xsum += box[i].cenx;
	    ysum += box[i].ceny;
	}
	back.x = xsum/nboxes;
	back.y = ysum/nboxes;
	background(average, naxes[0], naxes[1]);

	for (i=0; i<nboxes; i++) {
	    box[i].noise = back.sigma;
	    box[i].r = boxsize/2.0;
	    //centroid(average, i);
	    //box[i].r = boxsize/3.0;
	    //centroid(average, i);
	    //box[i].r = boxsize/4.0;
	    centroid(average, naxes[0], naxes[1], i);
	}

	dist_l[f] = stardist(0, 1);
	sig_l[f] = box[0].sigmaxy*box[0].sigmaxy + box[1].sigmaxy*box[1].sigmaxy;

	if (f % 40 == 0) {
	    status = XPASet(xpa, "ds9", "array [xdim=320,ydim=240,bitpix=8]", "ack=false",
			    average, nelements, names, messages, NXPA);
	    sprintf(xpastr, "image; box %f %f %d %d 0.0",
		    box[0].x, box[0].y, boxsize, boxsize);
	    status = XPASet(xpa, "ds9", "regions", "ack=false",
			    xpastr, strlen(xpastr), names, messages, NXPA);
	    sprintf(xpastr, "image; box %f %f %d %d 0.0",
		    box[1].x, box[1].y, boxsize, boxsize);
	    status = XPASet(xpa, "ds9", "regions", "ack=false",
			    xpastr, strlen(xpastr), names, messages, NXPA);
	}

    }

    gettimeofday(&end_time, NULL);
    printf("End capture.\n");

    /*-----------------------------------------------------------------------
     *  stop data transmission
     *-----------------------------------------------------------------------*/
    start_sec = start_time.tv_sec;
    start_usec = start_time.tv_usec;
    end_sec = end_time.tv_sec;
    end_usec = end_time.tv_usec;

    elapsed_time = (float)((end_sec + 1.0e-6*end_usec) - (start_sec + 1.0e-6*start_usec));
    fps = 3*nimages/elapsed_time;
    printf("Elapsed time = %g seconds.\n", elapsed_time);
    printf("Framerate = %g fps.\n", fps);

    err=dc1394_video_set_transmission(camera,DC1394_OFF);
    DC1394_ERR_RTN(err,"couldn't stop the camera?");

    /*
    sprintf(fitsfile, "!%s", froot);
    fits_create_file(&fptr, fitsfile, &status);
    fits_create_img(fptr, BYTE_IMG, 2, naxes, &status);
    fits_write_img(fptr, TBYTE, fpixel, nelements, buffer, &status);
    fits_close_file(fptr, &status);
    fits_report_error(stderr, status);
    */

    /* analyze short exposure */
    printf("\t SHORT EXPOSURE\n");
    mean = gsl_stats_mean(dist, 1, nimages);
    avesig = gsl_stats_mean(sig, 1, nimages);
    printf("mean = %f, avesig = %f\n", mean, avesig);

    printf("\n");

    var = gsl_stats_variance_m(dist, 1, nimages, mean);
    var = var - avesig;
    seeing_short = seeing(var, d, r);
    printf("sigma = %f, seeing = %f\n", sqrt(var), seeing_short);

    /* analyze long exposure */
    printf("\t LONG EXPOSURE\n");
    mean = gsl_stats_mean(dist_l, 1, nimages);
    avesig = gsl_stats_mean(sig_l, 1, nimages);
    printf("mean_l = %f, avesig_l = %f\n", mean, avesig);

    printf("\n");

    var_l = gsl_stats_variance_m(dist_l, 1, nimages, mean);
    var_l = var_l - avesig;
    seeing_long = seeing(var_l, d, r);
    printf("sigma_l = %f, seeing_l = %f\n", sqrt(var_l), seeing_long);

    seeing_ave = pow(seeing_short, 1.75)*pow(seeing_long,-0.75);
    printf("Exposure corrected seeing = %4.2f\"\n\n", seeing_ave);

    timestr = ctime(&end_sec);
    fprintf(out, "%s %f %f %f %f %f\n", timestr, var, var_l, seeing_short, seeing_long, seeing_ave);

    init = fopen("init_cen_all", "w");
    for (i=0; i<nboxes; i++) {
	fprintf(init, "%f %f\n", box[i].cenx, box[i].ceny);
    }
    fclose(init);

    fclose(out);

    return (status);
}