
#line 1 "../gen/tmpl/lib.c"
/*
  gsl_Stats.c
  Ruby/Numo::GSL - GSL wrapper for Ruby/Numo::NArray

  created on: 2017-03-11
  Copyright (C) 2017 Masahiro Tanaka
*/

#include <ruby.h>
#include <assert.h>
#include "numo/narray.h"
#include "numo/template.h"
#include "../numo_gsl.h"
#line 15 "../gen/tmpl/lib.c"
#include <gsl/gsl_statistics.h>

#line 18 "../gen/tmpl/lib.c"
static VALUE mG;



#line 1 "../gen/tmpl/module.c"
/*
  module definition: Numo::GSL::Stats
*/

#line 6 "../gen/tmpl/module.c"
static VALUE mStats;


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_mean(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_mean((double*)p1,s1/sizeof(double),n);
}

/*
  This function returns the arithmetic mean of data, a dataset of
length n with stride stride.  The arithmetic mean, or
sample mean, is denoted by \Hat\mu and defined as,

\Hat\mu = (1/N) \sum x_i

where x_i are the elements of the dataset data.  For
samples drawn from a gaussian distribution the variance of
\Hat\mu is \sigma^2 / N.
  @overload mean(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_mean(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_mean, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_variance(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_variance((double*)p1,s1/sizeof(double),n);
}

/*
  This function returns the estimated, or sample, variance of
data, a dataset of length n with stride stride.  The
estimated variance is denoted by \Hat\sigma^2 and is defined by,

\Hat\sigma^2 = (1/(N-1)) \sum (x_i - \Hat\mu)^2

where x_i are the elements of the dataset data.  Note that
the normalization factor of 1/(N-1) results from the derivation
of \Hat\sigma^2 as an unbiased estimator of the population
variance \sigma^2.  For samples drawn from a Gaussian distribution
the variance of \Hat\sigma^2 itself is 2 \sigma^4 / N.

This function computes the mean via a call to gsl_stats_mean.  If
you have already computed the mean then you can pass it directly to
gsl_stats_variance_m.
  @overload variance(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_variance(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_variance, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_variance_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_variance_m((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  This function returns the sample variance of data relative to the
given value of mean.  The function is computed with \Hat\mu
replaced by the value of mean that you supply,

\Hat\sigma^2 = (1/(N-1)) \sum (x_i - mean)^2
  @overload variance_m(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_variance_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_variance_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_sd(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_sd((double*)p1,s1/sizeof(double),n);
}

/*
  The standard deviation is defined as the square root of the variance.
These functions return the square root of the corresponding variance
functions above.
  @overload sd(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_sd(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_sd, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_sd_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_sd_m((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  The standard deviation is defined as the square root of the variance.
These functions return the square root of the corresponding variance
functions above.
  @overload sd_m(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_sd_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_sd_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_tss(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_tss((double*)p1,s1/sizeof(double),n);
}

/*
  These functions return the total sum of squares (TSS) of data about
the mean.  For gsl_stats_tss_m the user-supplied value of
mean is used, and for gsl_stats_tss it is computed using
gsl_stats_mean.

TSS =  \sum (x_i - mean)^2
  @overload tss(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_tss(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_tss, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_tss_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_tss_m((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  These functions return the total sum of squares (TSS) of data about
the mean.  For gsl_stats_tss_m the user-supplied value of
mean is used, and for gsl_stats_tss it is computed using
gsl_stats_mean.

TSS =  \sum (x_i - mean)^2
  @overload tss_m(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_tss_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_tss_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_variance_with_fixed_mean(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_variance_with_fixed_mean((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  This function computes an unbiased estimate of the variance of
data when the population mean mean of the underlying
distribution is known a priori.  In this case the estimator for
the variance uses the factor 1/N and the sample mean
\Hat\mu is replaced by the known population mean \mu,

\Hat\sigma^2 = (1/N) \sum (x_i - \mu)^2
  @overload variance_with_fixed_mean(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_variance_with_fixed_mean(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_variance_with_fixed_mean, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_sd_with_fixed_mean(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_sd_with_fixed_mean((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  This function calculates the standard deviation of data for a
fixed population mean mean.  The result is the square root of the
corresponding variance function.
  @overload sd_with_fixed_mean(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_sd_with_fixed_mean(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_sd_with_fixed_mean, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_absdev(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_absdev((double*)p1,s1/sizeof(double),n);
}

/*
  This function computes the absolute deviation from the mean of
data, a dataset of length n with stride stride.  The
absolute deviation from the mean is defined as,

absdev  = (1/N) \sum |x_i - \Hat\mu|

where x_i are the elements of the dataset data.  The
absolute deviation from the mean provides a more robust measure of the
width of a distribution than the variance.  This function computes the
mean of data via a call to gsl_stats_mean.
  @overload absdev(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_absdev(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_absdev, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_absdev_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_absdev_m((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  This function computes the absolute deviation of the dataset data
relative to the given value of mean,

absdev  = (1/N) \sum |x_i - mean|

This function is useful if you have already computed the mean of
data (and want to avoid recomputing it), or wish to calculate the
absolute deviation relative to another value (such as zero, or the
median).
  @overload absdev_m(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_absdev_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_absdev_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_skew(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_skew((double*)p1,s1/sizeof(double),n);
}

/*
  This function computes the skewness of data, a dataset of length
n with stride stride.  The skewness is defined as,

skew = (1/N) \sum ((x_i - \Hat\mu)/\Hat\sigma)^3

where x_i are the elements of the dataset data.  The skewness
measures the asymmetry of the tails of a distribution.

The function computes the mean and estimated standard deviation of
data via calls to gsl_stats_mean and gsl_stats_sd.
  @overload skew(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_skew(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_skew, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a2p.c"
static void
iter_stats_s_skew_m_sd(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_skew_m_sd((double*)p1,s1/sizeof(double),n,opt[0],opt[1]);
}

/*
  This function computes the skewness of the dataset data using the
given values of the mean mean and standard deviation sd,

skew = (1/N) \sum ((x_i - mean)/sd)^3

These functions are useful if you have already computed the mean and
standard deviation of data and want to avoid recomputing them.
  @overload skew_m_sd(data[],mean,sd, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @param [Float] sd
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_skew_m_sd(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[2];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_skew_m_sd, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);
    opt[1] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_kurtosis(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_kurtosis((double*)p1,s1/sizeof(double),n);
}

/*
  This function computes the kurtosis of data, a dataset of length
n with stride stride.  The kurtosis is defined as,

kurtosis = ((1/N) \sum ((x_i - \Hat\mu)/\Hat\sigma)^4)  - 3

The kurtosis measures how sharply peaked a distribution is, relative to
its width.  The kurtosis is normalized to zero for a Gaussian
distribution.
  @overload kurtosis(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_kurtosis(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_kurtosis, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a2p.c"
static void
iter_stats_s_kurtosis_m_sd(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_kurtosis_m_sd((double*)p1,s1/sizeof(double),n,opt[0],opt[1]);
}

/*
  This function computes the kurtosis of the dataset data using the
given values of the mean mean and standard deviation sd,

kurtosis = ((1/N) \sum ((x_i - mean)/sd)^4) - 3

This function is useful if you have already computed the mean and
standard deviation of data and want to avoid recomputing them.
  @overload kurtosis_m_sd(data[],mean,sd, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @param [Float] sd
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_kurtosis_m_sd(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[2];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_kurtosis_m_sd, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);
    opt[1] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_lag1_autocorrelation(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_lag1_autocorrelation((double*)p1,s1/sizeof(double),n);
}

/*
  This function computes the lag-1 autocorrelation of the dataset data.

a_1 = [\sum_[i = 1]^[n] (x_[i] - \Hat\mu) (x_[i-1] - \Hat\mu)
       \over
       \sum_[i = 1]^[n] (x_[i] - \Hat\mu) (x_[i] - \Hat\mu)]
  @overload lag1_autocorrelation(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_lag1_autocorrelation(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_lag1_autocorrelation, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_lag1_autocorrelation_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_lag1_autocorrelation_m((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  This function computes the lag-1 autocorrelation of the dataset
data using the given value of the mean mean.

  @overload lag1_autocorrelation_m(data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_lag1_autocorrelation_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_lag1_autocorrelation_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_covariance(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_covariance((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function computes the covariance of the datasets data1 and
data2 which must both be of the same length n.

covar = (1/(n - 1)) \sum_[i = 1]^[n] (x_i - \Hat x) (y_i - \Hat y)
  @overload covariance(data1[],data2[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data1[]
  @param [Numo::DFloat] data2[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_covariance(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_covariance, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a2p.c"
static void
iter_stats_s_covariance_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_covariance_m((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0],opt[1]);
}

/*
  This function computes the covariance of the datasets data1 and
data2 using the given values of the means, mean1 and
mean2.  This is useful if you have already computed the means of
data1 and data2 and want to avoid recomputing them.
  @overload covariance_m(data1[],data2[],mean1,mean2, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data1[]
  @param [Numo::DFloat] data2[]
  @param [Float] mean1
  @param [Float] mean2
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_covariance_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[2];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_covariance_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<4) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=4)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);
    opt[1] = NUM2DBL(argv[3]);

    reduce = nary_reduce_dimension(argc-4, argv+4, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_correlation(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_correlation((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function efficiently computes the Pearson correlation coefficient
between the datasets data1 and data2 which must both be of
the same length n.
r = cov(x, y) / (\Hat\sigma_x \Hat\sigma_y)
  = [1/(n-1) \sum (x_i - \Hat x) (y_i - \Hat y)
     \over
     \sqrt[1/(n-1) \sum (x_i - \Hat x)^2] \sqrt[1/(n-1) \sum (y_i - \Hat y)^2]
    ]
  @overload correlation(data1[],data2[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data1[]
  @param [Numo::DFloat] data2[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_correlation(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_correlation, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_spearman.c"
static void
iter_stats_s_spearman(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_spearman((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt);
}

/*
  This function computes the Spearman rank correlation coefficient between
the datasets data1 and data2 which must both be of the same
length n. Additional workspace of size 2*n is required in
work. The Spearman rank correlation between vectors x and
y is equivalent to the Pearson correlation between the ranked
vectors x_R and y_R, where ranks are defined to be the
average of the positions of an element in the ascending order of the values.
  @overload spearman(data1[],data2[],work[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data1[]
  @param [Numo::DFloat] data2[]
  @param [Numo::DFloat] work[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_spearman(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce, v, buf = 0;
    narray_t *na;
    double *opt;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_spearman, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    GetNArray(argv[0],na);
    opt = ALLOCV_N(double,buf,na->size*2); // todo: get loop size
    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    v = na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
    ALLOCV_END(buf);
    return v;
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wmean(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wmean((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function returns the weighted mean of the dataset data with
stride stride and length n, using the set of weights w
with stride wstride and length n.  The weighted mean is defined as,

\Hat\mu = (\sum w_i x_i) / (\sum w_i)
  @overload wmean(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wmean(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wmean, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wvariance(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wvariance((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function returns the estimated variance of the dataset data
with stride stride and length n, using the set of weights
w with stride wstride and length n.  The estimated
variance of a weighted dataset is calculated as,

\Hat\sigma^2 = ((\sum w_i)/((\sum w_i)^2 - \sum (w_i^2))) 
                \sum w_i (x_i - \Hat\mu)^2

Note that this expression reduces to an unweighted variance with the
familiar 1/(N-1) factor when there are N equal non-zero
weights.
  @overload wvariance(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wvariance(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wvariance, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a1p.c"
static void
iter_stats_s_wvariance_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wvariance_m((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0]);
}

/*
  This function returns the estimated variance of the weighted dataset
data using the given weighted mean wmean.
  @overload wvariance_m(w[],data[],wmean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] wmean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wvariance_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wvariance_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wsd(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wsd((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  The standard deviation is defined as the square root of the variance.
This function returns the square root of the corresponding variance
function gsl_stats_wvariance above.
  @overload wsd(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wsd(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wsd, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a1p.c"
static void
iter_stats_s_wsd_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wsd_m((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0]);
}

/*
  This function returns the square root of the corresponding variance
function gsl_stats_wvariance_m above.
  @overload wsd_m(w[],data[],wmean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] wmean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wsd_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wsd_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a1p.c"
static void
iter_stats_s_wvariance_with_fixed_mean(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wvariance_with_fixed_mean((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0]);
}

/*
  This function computes an unbiased estimate of the variance of the weighted
dataset data when the population mean mean of the underlying
distribution is known a priori.  In this case the estimator for
the variance replaces the sample mean \Hat\mu by the known
population mean \mu,

\Hat\sigma^2 = (\sum w_i (x_i - \mu)^2) / (\sum w_i)
  @overload wvariance_with_fixed_mean(w[],data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wvariance_with_fixed_mean(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wvariance_with_fixed_mean, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a1p.c"
static void
iter_stats_s_wsd_with_fixed_mean(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wsd_with_fixed_mean((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0]);
}

/*
  The standard deviation is defined as the square root of the variance.
This function returns the square root of the corresponding variance
function above.
  @overload wsd_with_fixed_mean(w[],data[],mean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] mean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wsd_with_fixed_mean(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wsd_with_fixed_mean, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wtss(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wtss((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  These functions return the weighted total sum of squares (TSS) of
data about the weighted mean.  For gsl_stats_wtss_m the
user-supplied value of wmean is used, and for gsl_stats_wtss
it is computed using gsl_stats_wmean.

TSS =  \sum w_i (x_i - wmean)^2
  @overload wtss(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wtss(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wtss, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a1p.c"
static void
iter_stats_s_wtss_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wtss_m((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0]);
}

/*
  These functions return the weighted total sum of squares (TSS) of
data about the weighted mean.  For gsl_stats_wtss_m the
user-supplied value of wmean is used, and for gsl_stats_wtss
it is computed using gsl_stats_wmean.

TSS =  \sum w_i (x_i - wmean)^2
  @overload wtss_m(w[],data[],wmean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] wmean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wtss_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wtss_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wabsdev(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wabsdev((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function computes the weighted absolute deviation from the weighted
mean of data.  The absolute deviation from the mean is defined as,

absdev = (\sum w_i |x_i - \Hat\mu|) / (\sum w_i)
  @overload wabsdev(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wabsdev(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wabsdev, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a1p.c"
static void
iter_stats_s_wabsdev_m(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wabsdev_m((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0]);
}

/*
  This function computes the absolute deviation of the weighted dataset
data about the given weighted mean wmean.
  @overload wabsdev_m(w[],data[],wmean, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] wmean
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wabsdev_m(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wabsdev_m, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<3) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=3)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);

    reduce = nary_reduce_dimension(argc-3, argv+3, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wskew(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wskew((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function computes the weighted skewness of the dataset data.

skew = (\sum w_i ((x_i - \Hat x)/\Hat \sigma)^3) / (\sum w_i)
  @overload wskew(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wskew(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wskew, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a2p.c"
static void
iter_stats_s_wskew_m_sd(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wskew_m_sd((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0],opt[1]);
}

/*
  This function computes the weighted skewness of the dataset data
using the given values of the weighted mean and weighted standard
deviation, wmean and wsd.
  @overload wskew_m_sd(w[],data[],wmean,wsd, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] wmean
  @param [Float] wsd
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wskew_m_sd(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[2];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wskew_m_sd, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<4) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=4)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);
    opt[1] = NUM2DBL(argv[3]);

    reduce = nary_reduce_dimension(argc-4, argv+4, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a0p.c"
static void
iter_stats_s_wkurtosis(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wkurtosis((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n);
}

/*
  This function computes the weighted kurtosis of the dataset data.

kurtosis = ((\sum w_i ((x_i - \Hat x)/\Hat \sigma)^4) / (\sum w_i)) - 3
  @overload wkurtosis(w[],data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wkurtosis(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wkurtosis, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    reduce = nary_reduce_dimension(argc-2, argv+2, 2, argv, &ndf, 0);
    return na_ndloop(&ndf, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_2a2p.c"
static void
iter_stats_s_wkurtosis_m_sd(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    *(double*)p3 = gsl_stats_wkurtosis_m_sd((double*)p1,s1/sizeof(double),
                                 (double*)p2,s2/sizeof(double),n,opt[0],opt[1]);
}

/*
  This function computes the weighted kurtosis of the dataset data
using the given values of the weighted mean and weighted standard
deviation, wmean and wsd.
  @overload wkurtosis_m_sd(w[],data[],wmean,wsd, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] w[]
  @param [Numo::DFloat] data[]
  @param [Float] wmean
  @param [Float] wsd
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_wkurtosis_m_sd(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[2];
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_wkurtosis_m_sd, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3, 1, ain, aout };

    if (argc<4) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=4)",argc);
    }

    opt[0] = NUM2DBL(argv[2]);
    opt[1] = NUM2DBL(argv[3]);

    reduce = nary_reduce_dimension(argc-4, argv+4, 2, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 3, argv[0], argv[1], reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_max(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_max((double*)p1,s1/sizeof(double),n);
}

/*
  This function returns the maximum value in data, a dataset of
length n with stride stride.  The maximum value is defined
as the value of the element x_i which satisfies $x_i \ge x_j$
x_i >= x_j for all j.

If you want instead to find the element with the largest absolute
magnitude you will need to apply fabs or abs to your data
before calling this function.
  @overload max(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_max(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_max, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_min(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_min((double*)p1,s1/sizeof(double),n);
}

/*
  This function returns the minimum value in data, a dataset of
length n with stride stride.  The minimum value is defined
as the value of the element x_i which satisfies $x_i \le x_j$
x_i <= x_j for all j.

If you want instead to find the element with the smallest absolute
magnitude you will need to apply fabs or abs to your data
before calling this function.
  @overload min(data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_min(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_min, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_minmax.c"
static void
iter_stats_s_minmax(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2, *p3;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;
    p3 = lp->args[2].ptr + lp->args[2].iter[0].pos;

    gsl_stats_minmax((double*)p2,(double*)p3,(double*)p1,s1/sizeof(double),n);
}

/*
  This function finds both the minimum and maximum values min,
max in data in a single pass.
  @overload minmax(data[], axis:nil, keepdims:falsek)
  
  @param [Numo::DFloat] data[]
  @return [[Numo::DFloat, Numo::DFloat]]  array of [min, max]
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_minmax(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[2] = {{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_minmax, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 2, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, argv[0], reduce);
}


#line 1 "tmpl/stats_1a0p_index.c"
#line 2 "tmpl/stats_1a0p_index.c"
#define idx_t int64_t
static void
iter_stats_s_max_index_index64(na_loop_t *const lp)
{
    size_t   n, idx;
    char    *d_ptr, *i_ptr, *o_ptr;
    ssize_t  d_step, i_step;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, d_ptr, d_step);

    idx = gsl_stats_max_index((double*)d_ptr,d_step/sizeof(double),n);

    INIT_PTR(lp, 1, i_ptr, i_step);
    o_ptr = NDL_PTR(lp,2);
    *(idx_t*)o_ptr = *(idx_t*)(i_ptr + i_step * idx);
}
#undef idx_t
#line 2 "tmpl/stats_1a0p_index.c"
#define idx_t int32_t
static void
iter_stats_s_max_index_index32(na_loop_t *const lp)
{
    size_t   n, idx;
    char    *d_ptr, *i_ptr, *o_ptr;
    ssize_t  d_step, i_step;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, d_ptr, d_step);

    idx = gsl_stats_max_index((double*)d_ptr,d_step/sizeof(double),n);

    INIT_PTR(lp, 1, i_ptr, i_step);
    o_ptr = NDL_PTR(lp,2);
    *(idx_t*)o_ptr = *(idx_t*)(i_ptr + i_step * idx);
}
#undef idx_t

#line 22 "tmpl/stats_1a0p_index.c"
/*
 This function returns the index of the maximum value in data, a
dataset of length n with stride stride.  The maximum value is
defined as the value of the element x_i which satisfies 
$x_i \ge x_j$
x_i >= x_j for all j.  When there are several equal maximum
elements then the first one is chosen.
  @overload max_index() => Integer
  @overload max_index(axis:nil, keepdims:false) => Integer or Numo::Int32/64
  
  @param [Numo::DFloat] data[]
  @return [Numo::UInt64]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_max_index(int argc, VALUE *argv, VALUE mod)
{
    narray_t *na;
    VALUE idx, reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{Qnil,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{0,0,0}};
    ndfunc_t ndf = {0, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT, 3,1, ain,aout};

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    GetNArray(argv[0],na);
    if (na->ndim==0) {
        return INT2FIX(0);
    }
    if (na->size > (~(u_int32_t)0)) {
        aout[0].type = numo_cInt64;
        idx = rb_narray_new(numo_cInt64, na->ndim, na->shape);
        ndf.func = iter_stats_s_max_index_index64;
    } else {
        aout[0].type = numo_cInt32;
        idx = rb_narray_new(numo_cInt32, na->ndim, na->shape);
        ndf.func = iter_stats_s_max_index_index32;
    }
    rb_funcall(idx, rb_intern("seq"), 0);

    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);

    return na_ndloop(&ndf, 3, argv[0], idx, reduce);
}


#line 1 "tmpl/stats_1a0p_index.c"
#line 2 "tmpl/stats_1a0p_index.c"
#define idx_t int64_t
static void
iter_stats_s_min_index_index64(na_loop_t *const lp)
{
    size_t   n, idx;
    char    *d_ptr, *i_ptr, *o_ptr;
    ssize_t  d_step, i_step;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, d_ptr, d_step);

    idx = gsl_stats_min_index((double*)d_ptr,d_step/sizeof(double),n);

    INIT_PTR(lp, 1, i_ptr, i_step);
    o_ptr = NDL_PTR(lp,2);
    *(idx_t*)o_ptr = *(idx_t*)(i_ptr + i_step * idx);
}
#undef idx_t
#line 2 "tmpl/stats_1a0p_index.c"
#define idx_t int32_t
static void
iter_stats_s_min_index_index32(na_loop_t *const lp)
{
    size_t   n, idx;
    char    *d_ptr, *i_ptr, *o_ptr;
    ssize_t  d_step, i_step;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, d_ptr, d_step);

    idx = gsl_stats_min_index((double*)d_ptr,d_step/sizeof(double),n);

    INIT_PTR(lp, 1, i_ptr, i_step);
    o_ptr = NDL_PTR(lp,2);
    *(idx_t*)o_ptr = *(idx_t*)(i_ptr + i_step * idx);
}
#undef idx_t

#line 22 "tmpl/stats_1a0p_index.c"
/*
 This function returns the index of the minimum value in data, a
dataset of length n with stride stride.  The minimum value
is defined as the value of the element x_i which satisfies
$x_i \ge x_j$
x_i >= x_j for all j.  When there are several equal
minimum elements then the first one is chosen.
  @overload min_index() => Integer
  @overload min_index(axis:nil, keepdims:false) => Integer or Numo::Int32/64
  
  @param [Numo::DFloat] data[]
  @return [Numo::UInt64]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_min_index(int argc, VALUE *argv, VALUE mod)
{
    narray_t *na;
    VALUE idx, reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{Qnil,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{0,0,0}};
    ndfunc_t ndf = {0, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT, 3,1, ain,aout};

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    GetNArray(argv[0],na);
    if (na->ndim==0) {
        return INT2FIX(0);
    }
    if (na->size > (~(u_int32_t)0)) {
        aout[0].type = numo_cInt64;
        idx = rb_narray_new(numo_cInt64, na->ndim, na->shape);
        ndf.func = iter_stats_s_min_index_index64;
    } else {
        aout[0].type = numo_cInt32;
        idx = rb_narray_new(numo_cInt32, na->ndim, na->shape);
        ndf.func = iter_stats_s_min_index_index32;
    }
    rb_funcall(idx, rb_intern("seq"), 0);

    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);

    return na_ndloop(&ndf, 3, argv[0], idx, reduce);
}


#line 1 "tmpl/stats_minmax_index.c"
#line 2 "tmpl/stats_minmax_index.c"
#define idx_t int64_t
static void
iter_stats_s_minmax_index_index64(na_loop_t *const lp)
{
    size_t   n;
    size_t   min_idx, max_idx;
    char    *d_ptr, *i_ptr;
    ssize_t  d_step, i_step;
    char    *min_ptr, *max_ptr;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, d_ptr, d_step);

    gsl_stats_minmax_index(&min_idx,&max_idx,(double*)d_ptr,d_step/sizeof(double),n);

    INIT_PTR(lp, 1, i_ptr, i_step);
    min_ptr = NDL_PTR(lp,2);
    max_ptr = NDL_PTR(lp,3);
    *(idx_t*)min_ptr = *(idx_t*)(i_ptr + i_step * min_idx);
    *(idx_t*)max_ptr = *(idx_t*)(i_ptr + i_step * max_idx);
}
#undef idx_t
#line 2 "tmpl/stats_minmax_index.c"
#define idx_t int32_t
static void
iter_stats_s_minmax_index_index32(na_loop_t *const lp)
{
    size_t   n;
    size_t   min_idx, max_idx;
    char    *d_ptr, *i_ptr;
    ssize_t  d_step, i_step;
    char    *min_ptr, *max_ptr;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, d_ptr, d_step);

    gsl_stats_minmax_index(&min_idx,&max_idx,(double*)d_ptr,d_step/sizeof(double),n);

    INIT_PTR(lp, 1, i_ptr, i_step);
    min_ptr = NDL_PTR(lp,2);
    max_ptr = NDL_PTR(lp,3);
    *(idx_t*)min_ptr = *(idx_t*)(i_ptr + i_step * min_idx);
    *(idx_t*)max_ptr = *(idx_t*)(i_ptr + i_step * max_idx);
}
#undef idx_t

#line 26 "tmpl/stats_minmax_index.c"
/*
 This function returns the indexes min_index, max_index of
the minimum and maximum values in data in a single pass.
  @overload minmax_index() => [Integer, Integer]
  @overload minmax_index(axis:nil, keepdims:false) => 2-element array of Integer or Numo::Int32/64
  
  @param [Numo::DFloat] data[]
  @return [[Numo::UInt64, Numo::UInt64]]  array of [min_index, max_index]
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_minmax_index(int argc, VALUE *argv, VALUE mod)
{
    narray_t *na;
    VALUE idx, reduce;
    ndfunc_arg_in_t ain[3] = {{cDF,0},{Qnil,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[2] = {{0,0,0},{0,0,0}};
    ndfunc_t ndf = { 0, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     3,2, ain,aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    GetNArray(argv[0],na);
    if (na->ndim==0) {
        return INT2FIX(0);
    }
    if (na->size > (~(u_int32_t)0)) {
        aout[0].type = numo_cInt64;
        aout[1].type = numo_cInt64;
        idx = rb_narray_new(numo_cInt64, na->ndim, na->shape);
        ndf.func = iter_stats_s_minmax_index_index64;
    } else {
        aout[0].type = numo_cInt32;
        aout[1].type = numo_cInt32;
        idx = rb_narray_new(numo_cInt32, na->ndim, na->shape);
        ndf.func = iter_stats_s_minmax_index_index32;
    }
    rb_funcall(idx, rb_intern("seq"), 0);

    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);

    return na_ndloop(&ndf, 3, argv[0], idx, reduce);
}


#line 1 "tmpl/stats_1a0p.c"
static void
iter_stats_s_median_from_sorted_data(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_median_from_sorted_data((double*)p1,s1/sizeof(double),n);
}

/*
  This function returns the median value of sorted_data, a dataset
of length n with stride stride.  The elements of the array
must be in ascending numerical order.  There are no checks to see
whether the data are sorted, so the function gsl_sort should
always be used first.

When the dataset has an odd number of elements the median is the value
of element (n-1)/2.  When the dataset has an even number of
elements the median is the mean of the two nearest middle values,
elements (n-1)/2 and n/2.  Since the algorithm for
computing the median involves interpolation this function always returns
a floating-point number, even for integer data types.
  @overload median_from_sorted_data(sorted_data[], axis:nil, keepdims:false)
  
  @param [Numo::DFloat] sorted_data[]
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in the result array as dimensions with size one.
*/
static VALUE
stats_s_median_from_sorted_data(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_median_from_sorted_data, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<1) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=1)",argc);
    }
    reduce = nary_reduce_dimension(argc-1, argv+1, 1, argv, &ndf, 0);
    return na_ndloop(&ndf, 2, *argv, reduce);
}


#line 1 "tmpl/stats_1a1p.c"
static void
iter_stats_s_quantile_from_sorted_data(na_loop_t *const lp)
{
    size_t   n;
    char    *p1, *p2;
    ssize_t  s1;
    double  *opt = (double*)(lp->opt_ptr);

    INIT_COUNTER(lp, n);
    INIT_PTR(lp, 0, p1, s1);
    p2 = lp->args[1].ptr + lp->args[1].iter[0].pos;

    *(double*)p2 = gsl_stats_quantile_from_sorted_data((double*)p1,s1/sizeof(double),n,opt[0]);
}

/*
  This function returns a quantile value of sorted_data, a
double-precision array of length n with stride stride.  The
elements of the array must be in ascending numerical order.  The
quantile is determined by the f, a fraction between 0 and 1.  For
example, to compute the value of the 75th percentile f should have
the value 0.75.

There are no checks to see whether the data are sorted, so the function
gsl_sort should always be used first.

The quantile is found by interpolation, using the formula

quantile = (1 - \delta) x_i + \delta x_[i+1]

where i is floor((n - 1)f) and \delta is
(n-1)f - i.

Thus the minimum value of the array (data[0*stride]) is given by
f equal to zero, the maximum value (data[(n-1)*stride]) is
given by f equal to one and the median value is given by f
equal to 0.5.  Since the algorithm for computing quantiles involves
interpolation this function always returns a floating-point number, even
for integer data types.
  @overload quantile_from_sorted_data(sorted_data[],f, axis:nil, keepdims:false)
  
  @param [Numo::DFloat] sorted_data[]
  @param [Float] f
  @return [Numo::DFloat]  return
  @param [Numeric,Array,Range] axis (keyword) Axes along which the operation is performed.
  @param [TrueClass] keepdims (keyword) If true, the reduced axes are left in th*/
static VALUE
stats_s_quantile_from_sorted_data(int argc, VALUE *argv, VALUE mod)
{
    VALUE reduce;
    double opt[1];
    ndfunc_arg_in_t ain[2] = {{cDF,0},{sym_reduce,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = { iter_stats_s_quantile_from_sorted_data, STRIDE_LOOP_NIP|NDF_FLAT_REDUCE|NDF_EXTRACT,
                     2, 1, ain, aout };

    if (argc<2) {
        rb_raise(rb_eArgError,"wrong number of argument (%d for >=2)",argc);
    }

    opt[0] = NUM2DBL(argv[1]);

    reduce = nary_reduce_dimension(argc-2, argv+2, 1, argv, &ndf, 0);
    return na_ndloop3(&ndf, opt, 2, argv[0], reduce);
}


#line 28 "../gen/tmpl/lib.c"
void
Init_stats(void)
{
    VALUE mN;
    mN = rb_define_module("Numo");
    mG = rb_define_module_under(mN, "GSL");

    


#line 1 "../gen/tmpl/init_module.c"

    /*
      Document-module: Numo::GSL::Stats
      
    */
    {
    
    mStats = rb_define_module_under(mG, "Stats");
    
    
    rb_define_module_function(mStats, "mean", stats_s_mean, -1);
    rb_define_module_function(mStats, "variance", stats_s_variance, -1);
    rb_define_module_function(mStats, "variance_m", stats_s_variance_m, -1);
    rb_define_module_function(mStats, "sd", stats_s_sd, -1);
    rb_define_module_function(mStats, "sd_m", stats_s_sd_m, -1);
    rb_define_module_function(mStats, "tss", stats_s_tss, -1);
    rb_define_module_function(mStats, "tss_m", stats_s_tss_m, -1);
    rb_define_module_function(mStats, "variance_with_fixed_mean", stats_s_variance_with_fixed_mean, -1);
    rb_define_module_function(mStats, "sd_with_fixed_mean", stats_s_sd_with_fixed_mean, -1);
    rb_define_module_function(mStats, "absdev", stats_s_absdev, -1);
    rb_define_module_function(mStats, "absdev_m", stats_s_absdev_m, -1);
    rb_define_module_function(mStats, "skew", stats_s_skew, -1);
    rb_define_module_function(mStats, "skew_m_sd", stats_s_skew_m_sd, -1);
    rb_define_module_function(mStats, "kurtosis", stats_s_kurtosis, -1);
    rb_define_module_function(mStats, "kurtosis_m_sd", stats_s_kurtosis_m_sd, -1);
    rb_define_module_function(mStats, "lag1_autocorrelation", stats_s_lag1_autocorrelation, -1);
    rb_define_module_function(mStats, "lag1_autocorrelation_m", stats_s_lag1_autocorrelation_m, -1);
    rb_define_module_function(mStats, "covariance", stats_s_covariance, -1);
    rb_define_module_function(mStats, "covariance_m", stats_s_covariance_m, -1);
    rb_define_module_function(mStats, "correlation", stats_s_correlation, -1);
    rb_define_module_function(mStats, "spearman", stats_s_spearman, -1);
    rb_define_module_function(mStats, "wmean", stats_s_wmean, -1);
    rb_define_module_function(mStats, "wvariance", stats_s_wvariance, -1);
    rb_define_module_function(mStats, "wvariance_m", stats_s_wvariance_m, -1);
    rb_define_module_function(mStats, "wsd", stats_s_wsd, -1);
    rb_define_module_function(mStats, "wsd_m", stats_s_wsd_m, -1);
    rb_define_module_function(mStats, "wvariance_with_fixed_mean", stats_s_wvariance_with_fixed_mean, -1);
    rb_define_module_function(mStats, "wsd_with_fixed_mean", stats_s_wsd_with_fixed_mean, -1);
    rb_define_module_function(mStats, "wtss", stats_s_wtss, -1);
    rb_define_module_function(mStats, "wtss_m", stats_s_wtss_m, -1);
    rb_define_module_function(mStats, "wabsdev", stats_s_wabsdev, -1);
    rb_define_module_function(mStats, "wabsdev_m", stats_s_wabsdev_m, -1);
    rb_define_module_function(mStats, "wskew", stats_s_wskew, -1);
    rb_define_module_function(mStats, "wskew_m_sd", stats_s_wskew_m_sd, -1);
    rb_define_module_function(mStats, "wkurtosis", stats_s_wkurtosis, -1);
    rb_define_module_function(mStats, "wkurtosis_m_sd", stats_s_wkurtosis_m_sd, -1);
    rb_define_module_function(mStats, "max", stats_s_max, -1);
    rb_define_module_function(mStats, "min", stats_s_min, -1);
    rb_define_module_function(mStats, "minmax", stats_s_minmax, -1);
    rb_define_module_function(mStats, "max_index", stats_s_max_index, -1);
    rb_define_module_function(mStats, "min_index", stats_s_min_index, -1);
    rb_define_module_function(mStats, "minmax_index", stats_s_minmax_index, -1);
    rb_define_module_function(mStats, "median_from_sorted_data", stats_s_median_from_sorted_data, -1);
    rb_define_module_function(mStats, "quantile_from_sorted_data", stats_s_quantile_from_sorted_data, -1);
#line 12 "../gen/tmpl/init_module.c"
    }
#line 41 "../gen/tmpl/lib.c"
}
