/*
  stats.c
  Ruby/GSL: Ruby extension library for GSL (GNU Scientific Library)
    (C) Copyright 2001-2004 by Yoshiki Tsunesada

  Ruby/GSL is free software: you can redistribute it and/or modify it
  under the terms of the GNU General Public License.
  This library is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY.
*/

#include "rb_gsl_array.h"
#include "rb_gsl_statistics.h"

static double* get_vector_stats2(int argc, VALUE *argv, VALUE obj, size_t *stride, 
				 size_t *size)
{
  double *v = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    v = get_vector_ptr(argv[0], stride, size);
    break;
  default:
    v = get_vector_ptr(obj, stride, size);
    break;
  }
  return v;
}

static VALUE rb_gsl_stats_mean(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  return rb_float_new(gsl_stats_mean(data, stride, size));
}

static VALUE rb_gsl_stats_variance(int argc, VALUE *argv, VALUE obj)
{
  double *data = NULL;
  size_t stride, size;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  return rb_float_new(gsl_stats_variance(data, stride, size));
}

static VALUE rb_gsl_stats_variance_m(int argc, VALUE *argv, VALUE obj)
{
  double variance, mean, *data = NULL;
  size_t stride, size;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    mean = NUM2DBL(argv[1]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    mean = NUM2DBL(argv[0]);
    break;
  }
  variance = gsl_stats_variance_m(data, stride, size, mean);
  return rb_float_new(variance);
}

static VALUE rb_gsl_stats_sd(int argc, VALUE *argv, VALUE obj)
{
  double sd, *data = NULL;
  size_t stride, size;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  sd = gsl_stats_sd(data, stride, size);
  return rb_float_new(sd);
}

static VALUE rb_gsl_stats_sd_m(int argc, VALUE *argv, VALUE obj)
{
  double sd, mean, *data = NULL;
  size_t stride, size;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    mean = NUM2DBL(argv[1]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    mean = NUM2DBL(argv[0]);
    break;
  }
  sd = gsl_stats_sd_m(data, stride, size, mean);
  return rb_float_new(sd);
}

static VALUE rb_gsl_stats_variance_with_fixed_mean(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double variance_with_fixed_mean, m, *data = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[1]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    m = NUM2DBL(argv[0]);
    break;
  }
  variance_with_fixed_mean = gsl_stats_variance_with_fixed_mean(data, stride, size, m);
  return rb_float_new(variance_with_fixed_mean);
}

static VALUE rb_gsl_stats_sd_with_fixed_mean(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double sd_with_fixed_mean, m, *data = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[1]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    m = NUM2DBL(argv[0]);
    break;
  }
  sd_with_fixed_mean = gsl_stats_sd_with_fixed_mean(data, stride, size, m);
  return rb_float_new(sd_with_fixed_mean);
}

static VALUE rb_gsl_stats_absdev(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double absdev, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  absdev = gsl_stats_absdev(data, stride, size);
  return rb_float_new(absdev);
}

static VALUE rb_gsl_stats_absdev_m(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double absdev, m, *data = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[1]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    m = NUM2DBL(argv[0]);
    break;
  }
  absdev = gsl_stats_absdev_m(data, stride, size, m);
  return rb_float_new(absdev);
}

static VALUE rb_gsl_stats_skew(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double skew, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  skew = gsl_stats_skew(data, stride, size);
  return rb_float_new(skew);
}

static VALUE rb_gsl_stats_skew_m_sd(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double skew, m, sd, *data = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[1]);
    sd = NUM2DBL(argv[2]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    m = NUM2DBL(argv[0]);
    sd = NUM2DBL(argv[1]);
    break;
  }
  skew = gsl_stats_skew_m_sd(data, stride, size, m, sd);
  return rb_float_new(skew);
}

static VALUE rb_gsl_stats_kurtosis(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double kurtosis, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  kurtosis = gsl_stats_kurtosis(data, stride, size);
  return rb_float_new(kurtosis);
}

static VALUE rb_gsl_stats_kurtosis_m_sd(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double kurtosis, m, sd, *data = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[1]);
    sd = NUM2DBL(argv[2]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[0]);
    sd = NUM2DBL(argv[1]);
    break;
  }
  kurtosis = gsl_stats_kurtosis_m_sd(data, stride, size, m, sd);
  return rb_float_new(kurtosis);
}

static VALUE rb_gsl_stats_lag1_autocorrelation(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double autocorrelation, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  autocorrelation = gsl_stats_lag1_autocorrelation(data, stride, size);
  return rb_float_new(autocorrelation);
}

static VALUE rb_gsl_stats_lag1_autocorrelation_m(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double autocorrelation, m, *data = NULL;
  switch (TYPE(obj)) {
  case T_MODULE:
  case T_CLASS:
  case T_OBJECT:
    if (argc != 2) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 2)", argc);
    data = get_vector_ptr(argv[0], &stride, &size);
    m = NUM2DBL(argv[1]);
    break;
  default:
    if (argc != 1) rb_raise(rb_eArgError, 
			    "wrong number of arguments (%d for 1)", argc);
    data = get_vector_ptr(obj, &stride, &size);
    m = NUM2DBL(argv[0]);
    break;
  }
  autocorrelation = gsl_stats_lag1_autocorrelation_m(data, stride, size, m);
  return rb_float_new(autocorrelation);
}

static VALUE rb_gsl_stats_wmean(VALUE obj, VALUE ww)
{
  gsl_vector *v, *w;
  double mean;
  v = get_cvector(obj);
  w = get_cvector(ww);
  mean = gsl_stats_wmean(w->data, 1, v->data, 1, v->size);
  return rb_float_new(mean);
}

static VALUE rb_gsl_stats_wvariance(VALUE obj, VALUE ww)
{
  gsl_vector *v, *w;
  double variance;
  v = get_cvector(obj);
  w = get_cvector(ww);
  variance = gsl_stats_wvariance(w->data, 1, v->data, 1, v->size);
  return rb_float_new(variance);
}

static VALUE rb_gsl_stats_wvariance_m(VALUE obj, VALUE ww, VALUE wm)
{
  gsl_vector *v, *w;
  double variance;
  v = get_cvector(obj);
  w = get_cvector(ww);
  variance = gsl_stats_wvariance_m(w->data, 1, v->data, 1, v->size, NUM2DBL(wm));
  return rb_float_new(variance);
}

static VALUE rb_gsl_stats_wsd(VALUE obj, VALUE ww)
{
  gsl_vector *v, *w;
  double sd;
  v = get_cvector(obj);
  w = get_cvector(ww);
  sd = gsl_stats_wsd(w->data, 1, v->data, 1, v->size);
  return rb_float_new(sd);
}

static VALUE rb_gsl_stats_wsd_m(VALUE obj, VALUE ww, VALUE wm)
{
  gsl_vector *v, *w;
  double sd;
  v = get_cvector(obj);
  w = get_cvector(ww);
  sd = gsl_stats_wsd_m(w->data, 1, v->data, 1, v->size, NUM2DBL(wm));
  return rb_float_new(sd);
}

static VALUE rb_gsl_stats_wvariance_with_fixed_mean(VALUE obj, VALUE ww, VALUE wm)
{
  gsl_vector *v, *w;
  double variance;
  v = get_cvector(obj);
  w = get_cvector(ww);
  variance = gsl_stats_wvariance_with_fixed_mean(w->data, 1, v->data, 1, v->size,
						 NUM2DBL(wm));
  return rb_float_new(variance);
}

static VALUE rb_gsl_stats_wsd_with_fixed_mean(VALUE obj, VALUE ww, VALUE wm)
{
  gsl_vector *v, *w;
  double sd;
  v = get_cvector(obj);
  w = get_cvector(ww);
  sd = gsl_stats_wsd_with_fixed_mean(w->data, 1, v->data, 1, v->size,
				     NUM2DBL(wm));
  return rb_float_new(sd);
}

static VALUE rb_gsl_stats_wabsdev(VALUE obj, VALUE ww)
{
  gsl_vector *v, *w;
  double absdev;
  v = get_cvector(obj);
  w = get_cvector(ww);
  absdev = gsl_stats_wabsdev(w->data, 1, v->data, 1, v->size);
  return rb_float_new(absdev);
}

static VALUE rb_gsl_stats_wabsdev_m(VALUE obj, VALUE ww, VALUE wm)
{
  gsl_vector *v, *w;
  double absdev_m;
  v = get_cvector(obj);
  w = get_cvector(ww);
  absdev_m = gsl_stats_wabsdev_m(w->data, 1, v->data, 1, v->size, NUM2DBL(wm));
  return rb_float_new(absdev_m);
}

static VALUE rb_gsl_stats_wskew(VALUE obj, VALUE ww)
{
  gsl_vector *v, *w;
  double skew;
  v = get_cvector(obj);
  w = get_cvector(ww);
  skew = gsl_stats_wskew(w->data, 1, v->data, 1, v->size);
  return rb_float_new(skew);
}

static VALUE rb_gsl_stats_wskew_m_sd(VALUE obj, VALUE ww, VALUE wm, VALUE wsd)
{
  gsl_vector *v, *w;
  double skew_m;
  v = get_cvector(obj);
  w = get_cvector(ww);
  skew_m = gsl_stats_wskew_m_sd(w->data, 1, v->data, 1, v->size, NUM2DBL(wm),
				NUM2DBL(wsd));
  return rb_float_new(skew_m);
}

static VALUE rb_gsl_stats_wkurtosis(VALUE obj, VALUE ww)
{
  gsl_vector *v, *w;
  double kurtosis;
  v = get_cvector(obj);
  w = get_cvector(ww);
  kurtosis = gsl_stats_wkurtosis(w->data, 1, v->data, 1, v->size);
  return rb_float_new(kurtosis);
}

static VALUE rb_gsl_stats_wkurtosis_m_sd(VALUE obj, VALUE ww, VALUE wm, VALUE wsd)
{
  gsl_vector *v, *w;
  double kurtosis_m;
  v = get_cvector(obj);
  w = get_cvector(ww);
  kurtosis_m = gsl_stats_wkurtosis_m_sd(w->data, 1, v->data, 1, v->size, NUM2DBL(wm),
					NUM2DBL(wsd));
  return rb_float_new(kurtosis_m);
}

static VALUE rb_gsl_stats_max(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double max, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  max = gsl_stats_max(data, stride, size);
  return rb_float_new(max);
}

static VALUE rb_gsl_stats_min(int argc, VALUE *argv, VALUE obj)
{
  double min, *data = NULL;
  size_t stride, size;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  min = gsl_stats_min(data, stride, size);
  return rb_float_new(min);
}

static VALUE rb_gsl_stats_minmax(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double min, max, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  gsl_stats_minmax(&min, &max, data, stride, size);
  return rb_ary_new3(2, rb_float_new(min), rb_float_new(max));
}

static VALUE rb_gsl_stats_max_index(int argc, VALUE *argv, VALUE obj)
{
  double *data = NULL;
  size_t index, stride, size;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  index = gsl_stats_max_index(data, stride, size);
  return INT2FIX(index);
}

static VALUE rb_gsl_stats_min_index(int argc, VALUE *argv, VALUE obj)
{
  double *data = NULL;
  size_t index, stride, size;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  index = gsl_stats_min_index(data, stride, size);
  return INT2FIX(index);
}

static VALUE rb_gsl_stats_minmax_index(int argc, VALUE *argv, VALUE obj)
{
  double *data = NULL;
  size_t imin, imax, stride, size;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  gsl_stats_minmax_index(&imin, &imax, data, stride, size);
  return rb_ary_new3(2, INT2FIX(imin), INT2FIX(imax));
}

static VALUE rb_gsl_stats_median_from_sorted_data(int argc, VALUE *argv, VALUE obj)
{
  size_t stride, size;
  double median, *data = NULL;
  data = get_vector_stats2(argc, argv, obj, &stride, &size);
  median = gsl_stats_median_from_sorted_data(data, stride, size);
  return rb_float_new(median);
}

static VALUE rb_gsl_stats_quantile_from_sorted_data(VALUE obj, VALUE f)
{
  size_t stride, size;
  double quantile, *data = NULL;
  data = get_vector_ptr(obj, &stride, &size);
  quantile = gsl_stats_quantile_from_sorted_data(data, stride, size, NUM2DBL(f));
  return rb_float_new(quantile);
}

static VALUE rb_gsl_stats_covariance2(VALUE obj, VALUE vv1, VALUE vv2)
{
  double *data1, *data2;
  size_t stride1, stride2, size;
  data1 = get_vector_ptr(vv1, &stride1, &size);
  data2 = get_vector_ptr(vv2, &stride2, &size);
  return rb_float_new(gsl_stats_covariance(data1, stride2, data2,
					   stride2, size));
}

static VALUE rb_gsl_stats_covariance_m2(VALUE obj, VALUE vv1, VALUE vv2,
					VALUE m1, VALUE m2)
{
  double *data1, *data2;
  size_t stride1, stride2, size;
  data1 = get_vector_ptr(vv1, &stride1, &size);
  data2 = get_vector_ptr(vv2, &stride2, &size);
  return rb_float_new(gsl_stats_covariance_m(data1, stride2, data2,
					   stride2, size, NUM2DBL(m1), NUM2DBL(m2)));
}

static VALUE rb_gsl_stats_wmean2(VALUE obj, VALUE ww, VALUE dd)
{
  double wmean, *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  wmean = gsl_stats_wmean(dataw, stridew, data, strided, size);
  return rb_float_new(wmean);
}

static VALUE rb_gsl_stats_wvariance2(VALUE obj, VALUE ww, VALUE dd)
{
  double wvariance, *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  wvariance = gsl_stats_wvariance(dataw, stridew, data, strided, size);
  return rb_float_new(wvariance);
}

static VALUE rb_gsl_stats_wvariance_m2(VALUE obj, VALUE ww, VALUE dd, VALUE mm)
{
  double *dataw = NULL, *data = NULL;
  double wvariance, m;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  wvariance = gsl_stats_wvariance_m(dataw, stridew, data, strided, size, m);
  return rb_float_new(wvariance);
}

static VALUE rb_gsl_stats_wsd2(VALUE obj, VALUE ww, VALUE dd)
{
  double wsd, *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  wsd = gsl_stats_wsd(dataw, stridew, data, strided, size);
  return rb_float_new(wsd);
}

static VALUE rb_gsl_stats_wsd_m2(VALUE obj, VALUE ww, VALUE dd, VALUE mm)
{
  double *dataw = NULL, *data = NULL;
  double wsd, m;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  wsd = gsl_stats_wsd_m(dataw, stridew, data, strided, size, m);
  return rb_float_new(wsd);
}

static VALUE rb_gsl_stats_wvariance_with_fixed_mean2(VALUE obj, VALUE ww, VALUE dd, 
						     VALUE mm)
{
  double wvariance, m;
  double *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  wvariance = gsl_stats_wvariance_with_fixed_mean(dataw, stridew, 
						  data, strided, size, m);

  return rb_float_new(wvariance);
}

static VALUE rb_gsl_stats_wsd_with_fixed_mean2(VALUE obj, VALUE ww, VALUE dd, 
						     VALUE mm)
{
  double wsd, m;
  double *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  wsd = gsl_stats_wsd_with_fixed_mean(dataw, stridew, data, strided, size, m);
  return rb_float_new(wsd);
}


static VALUE rb_gsl_stats_wabsdev2(VALUE obj, VALUE ww, VALUE dd)
{
  double wabsdev, *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  wabsdev = gsl_stats_wabsdev(dataw, stridew, data, strided, size);
  return rb_float_new(wabsdev);
}

static VALUE rb_gsl_stats_wabsdev_m2(VALUE obj, VALUE ww, VALUE dd, VALUE mm)
{
  double *dataw = NULL, *data = NULL;
  double wabsdev, m;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  wabsdev = gsl_stats_wabsdev_m(dataw, stridew, data, strided, size, m);
  return rb_float_new(wabsdev);
}
static VALUE rb_gsl_stats_wskew2(VALUE obj, VALUE ww, VALUE dd)
{
  double wskew, *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  wskew = gsl_stats_wskew(dataw, stridew, data, strided, size);
  return rb_float_new(wskew);
}

static VALUE rb_gsl_stats_wskew_m2(VALUE obj, VALUE ww, VALUE dd, VALUE mm, VALUE ss)
{
  double *dataw = NULL, *data = NULL;
  double wskew, m, sd;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  sd = NUM2DBL(ss);
  wskew = gsl_stats_wskew_m_sd(dataw, stridew, data, strided, size, m, sd);
  return rb_float_new(wskew);
}

static VALUE rb_gsl_stats_wkurtosis2(VALUE obj, VALUE ww, VALUE dd)
{
  double wkurtosis, *dataw = NULL, *data = NULL;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  wkurtosis = gsl_stats_wkurtosis(dataw, stridew, data, strided, size);
  return rb_float_new(wkurtosis);
}

static VALUE rb_gsl_stats_wkurtosis_m2(VALUE obj, VALUE ww, VALUE dd, VALUE mm, VALUE ss)
{
  double *dataw = NULL, *data = NULL;
  double wkurtosis, m, sd;
  size_t stridew, strided, size;
  dataw = get_vector_ptr(ww, &stridew, &size);
  data = get_vector_ptr(dd, &strided, &size);
  m = NUM2DBL(mm);
  sd = NUM2DBL(ss);
  wkurtosis = gsl_stats_wkurtosis_m_sd(dataw, stridew, data, strided, size, m, sd);
  return rb_float_new(wkurtosis);
}

void Init_gsl_stats()
{
  VALUE mgsl_stats;

  mgsl_stats = rb_define_module_under(mgsl, "Stats");

  rb_define_singleton_method(mgsl_stats, "mean", rb_gsl_stats_mean, -1);
  rb_define_method(cgsl_vector, "stats_mean", rb_gsl_stats_mean, -1);
  rb_define_alias(cgsl_vector, "mean", "stats_mean");

  rb_define_singleton_method(mgsl_stats, "variance", rb_gsl_stats_variance, -1);
  rb_define_method(cgsl_vector, "stats_variance", rb_gsl_stats_variance, -1);
  rb_define_alias(cgsl_vector, "variance", "stats_variance");

  rb_define_singleton_method(mgsl_stats, "variance_m", rb_gsl_stats_variance_m, -1);
  rb_define_method(cgsl_vector, "stats_variance_m", rb_gsl_stats_variance_m, -1);
  rb_define_alias(cgsl_vector, "variance_m", "stats_variance_m");

  rb_define_singleton_method(mgsl_stats, "sd", rb_gsl_stats_sd, -1);
  rb_define_method(cgsl_vector, "stats_sd", rb_gsl_stats_sd, -1);
  rb_define_alias(cgsl_vector, "sd", "stats_sd");
  rb_define_alias(cgsl_vector, "sigma", "stats_sd");

  rb_define_singleton_method(mgsl_stats, "sd_m", rb_gsl_stats_sd_m, -1);
  rb_define_method(cgsl_vector, "stats_sd_m", rb_gsl_stats_sd_m, -1);
  rb_define_alias(cgsl_vector, "sd_m", "stats_sd_m");

  rb_define_singleton_method(mgsl_stats, "variance_with_fixed_mean", 
			     rb_gsl_stats_variance_with_fixed_mean, -1);
  rb_define_method(cgsl_vector, "stats_variance_with_fixed_mean", 
		   rb_gsl_stats_variance_with_fixed_mean, -1);
  rb_define_alias(cgsl_vector, "variance_with_fixed_mean", 
		  "stats_variance_with_fixed_mean");

  rb_define_singleton_method(mgsl_stats, "sd_with_fixed_mean", 
			     rb_gsl_stats_sd_with_fixed_mean, -1);
  rb_define_method(cgsl_vector, "stats_sd_with_fixed_mean", 
		   rb_gsl_stats_sd_with_fixed_mean, -1);
  rb_define_alias(cgsl_vector, "sd_with_fixed_mean", 
		  "sd_with_fixed_mean");

  rb_define_singleton_method(mgsl_stats, "absdev", rb_gsl_stats_absdev, -1);
  rb_define_method(cgsl_vector, "stats_absdev", rb_gsl_stats_absdev, -1);
  rb_define_alias(cgsl_vector, "absdev", "stats_absdev");

  rb_define_singleton_method(mgsl_stats, "absdev_m", rb_gsl_stats_absdev_m, -1);
  rb_define_method(cgsl_vector, "stats_absdev_m", rb_gsl_stats_absdev_m, -1);
  rb_define_alias(cgsl_vector, "absdev_m", "stats_absdev_m");

  rb_define_singleton_method(mgsl_stats, "skew", rb_gsl_stats_skew, -1);
  rb_define_method(cgsl_vector, "stats_skew", rb_gsl_stats_skew, -1);
  rb_define_alias(cgsl_vector, "skew", "stats_skew");  

  rb_define_singleton_method(mgsl_stats, "skew_m_sd", rb_gsl_stats_skew_m_sd, -1);
  rb_define_method(cgsl_vector, "stats_skew_m_sd", rb_gsl_stats_skew_m_sd, -1);
  rb_define_alias(cgsl_vector, "skew_m_sd", "stats_skew_m_sd");  

  rb_define_singleton_method(mgsl_stats, "kurtosis", rb_gsl_stats_kurtosis, -1);
  rb_define_method(cgsl_vector, "stats_kurtosis", rb_gsl_stats_kurtosis, -1);
  rb_define_alias(cgsl_vector, "kurtosis", "stats_kurtosis");  

  rb_define_singleton_method(mgsl_stats, "kurtosis_m_sd", 
			     rb_gsl_stats_kurtosis_m_sd, -1);
  rb_define_method(cgsl_vector, "stats_kurtosis_m_sd", rb_gsl_stats_kurtosis_m_sd, -1);
  rb_define_alias(cgsl_vector, "kurtosis_m_sd", "stats_kurtosis_m_sd");  

  rb_define_singleton_method(mgsl_stats, "lag1_autocorrelation", 
			     rb_gsl_stats_lag1_autocorrelation, -1);
  rb_define_method(cgsl_vector, "stats_lag1_autocorrelation", rb_gsl_stats_lag1_autocorrelation, -1);
  rb_define_alias(cgsl_vector, "lag1_autocorrelation", "stats_lag1_autocorrelation");  

  rb_define_singleton_method(mgsl_stats, "lag1_autocorrelation_m", 
			     rb_gsl_stats_lag1_autocorrelation_m, -1);
  rb_define_method(cgsl_vector, "stats_lag1_autocorrelation_m", 
		   rb_gsl_stats_lag1_autocorrelation_m, -1);
  rb_define_alias(cgsl_vector, "lag1_autocorrelation_m", "stats_lag1_autocorrelation_m"); 

  rb_define_singleton_method(mgsl_stats, "covariance", rb_gsl_stats_covariance2, 2);
  rb_define_singleton_method(mgsl_stats, "covariance_m", rb_gsl_stats_covariance_m2, 4);
  /*  rb_define_method(cgsl_vector, "stats_covariance", rb_gsl_stats_covariance, 1);
  rb_define_alias(cgsl_vector, "covariance", "stats_covariance");  
  rb_define_method(cgsl_vector, "stats_covariance_m", rb_gsl_stats_covariance_m, 3);
  rb_define_alias(cgsl_vector, "covariance_m", "stats_covariance_m");  
  */
  /*****/
  
  rb_define_singleton_method(mgsl_stats, "wmean", rb_gsl_stats_wmean2, 2);
  rb_define_singleton_method(mgsl_stats, "wvariance", rb_gsl_stats_wvariance2, 2);
  rb_define_singleton_method(mgsl_stats, "wvariance_m", rb_gsl_stats_wvariance_m2, 3);
  rb_define_singleton_method(mgsl_stats, "wsd", rb_gsl_stats_wsd2, 2);
  rb_define_singleton_method(mgsl_stats, "wsd_m", rb_gsl_stats_wsd_m2, 3);
  rb_define_singleton_method(mgsl_stats, "wvariance_with_fixed_mean", 
			     rb_gsl_stats_wvariance_with_fixed_mean2, 3);
  rb_define_singleton_method(mgsl_stats, "wsd_with_fixed_mean", 
			     rb_gsl_stats_wsd_with_fixed_mean2, 3);
  rb_define_singleton_method(mgsl_stats, "wabsdev", rb_gsl_stats_wabsdev2, 2);
  rb_define_singleton_method(mgsl_stats, "wabsdev_m", rb_gsl_stats_wabsdev_m2, 3);
  rb_define_singleton_method(mgsl_stats, "wskew", rb_gsl_stats_wskew2, 2);
  rb_define_singleton_method(mgsl_stats, "wskew_m_sd", rb_gsl_stats_wskew_m2, 4);
  rb_define_singleton_method(mgsl_stats, "wkurtosis", rb_gsl_stats_wkurtosis2, 2);
  rb_define_singleton_method(mgsl_stats, "wkurtosis_m_sd", rb_gsl_stats_wkurtosis_m2, 4);

  /*****/

  rb_define_method(cgsl_vector, "stats_wmean", rb_gsl_stats_wmean, 1);
  rb_define_alias(cgsl_vector, "wmean", "stats_wmean");
  rb_define_method(cgsl_vector, "stats_wvariance", rb_gsl_stats_wvariance, 1);
  rb_define_alias(cgsl_vector, "wvariance", "stats_wvariance");
  rb_define_method(cgsl_vector, "stats_wvariance_m", rb_gsl_stats_wvariance_m, 2);
  rb_define_alias(cgsl_vector, "wvariance_m", "stats_wvariance_m");
  rb_define_method(cgsl_vector, "stats_wsd", rb_gsl_stats_wsd, 1);
  rb_define_alias(cgsl_vector, "wsd", "stats_wsd");
  rb_define_method(cgsl_vector, "stats_wsd_m", rb_gsl_stats_wsd_m, 2);
  rb_define_alias(cgsl_vector, "wsd_m", "stats_wsd_m");
  rb_define_method(cgsl_vector, "stats_wvariance_with_fixed_mean", rb_gsl_stats_wvariance_with_fixed_mean, 2);
  rb_define_alias(cgsl_vector, "wvariance_with_fixed_mean", "stats_wvariance_with_fixed_mean");
  rb_define_method(cgsl_vector, "stats_wsd_with_fixed_mean", rb_gsl_stats_wsd_with_fixed_mean, 2);
  rb_define_alias(cgsl_vector, "wsd_with_fixed_mean", "stats_wsd_with_fixed_mean");
  rb_define_method(cgsl_vector, "stats_wabsdev", rb_gsl_stats_wabsdev, 1);
  rb_define_alias(cgsl_vector, "wabsdev", "stats_wabsdev");
  rb_define_method(cgsl_vector, "stats_wabsdev_m", rb_gsl_stats_wabsdev_m, 2);
  rb_define_alias(cgsl_vector, "wabsdev_m", "stats_wabsdev_m");
  rb_define_method(cgsl_vector, "stats_wskew", rb_gsl_stats_wskew, 1);
  rb_define_alias(cgsl_vector, "wskew", "stats_wskew");
  rb_define_method(cgsl_vector, "stats_wskew_m_sd", rb_gsl_stats_wskew_m_sd, 2);
  rb_define_alias(cgsl_vector, "wskew_m_sd", "stats_wskew_m_sd");
  rb_define_method(cgsl_vector, "stats_wkurtosis", rb_gsl_stats_wkurtosis, 1);
  rb_define_alias(cgsl_vector, "wkurtosis", "stats_wkurtosis");
  rb_define_method(cgsl_vector, "stats_wkurtosis_m_sd", rb_gsl_stats_wkurtosis_m_sd, 2);
  rb_define_alias(cgsl_vector, "wkurtosis_m_sd", "stats_wkurtosis_m_sd");

  /*****/
  rb_define_singleton_method(mgsl_stats, "max", rb_gsl_stats_max, -1);
  rb_define_singleton_method(mgsl_stats, "min", rb_gsl_stats_min, -1);
  rb_define_singleton_method(mgsl_stats, "minmax", rb_gsl_stats_minmax, -1);
  rb_define_singleton_method(mgsl_stats, "max_index", rb_gsl_stats_max_index, -1);
  rb_define_singleton_method(mgsl_stats, "min_index", rb_gsl_stats_min_index, -1);
  rb_define_singleton_method(mgsl_stats, "minmax_index", rb_gsl_stats_minmax_index, -1);

  rb_define_method(cgsl_vector, "stats_max", rb_gsl_stats_max, -1);
  rb_define_alias(cgsl_vector, "max", "stats_max");
  rb_define_method(cgsl_vector, "stats_min", rb_gsl_stats_min, -1);
  rb_define_alias(cgsl_vector, "min", "stats_min");
  rb_define_method(cgsl_vector, "stats_minmax", rb_gsl_stats_minmax, -1);
  rb_define_alias(cgsl_vector, "minmax", "stats_minmax");
  rb_define_method(cgsl_vector, "stats_max_index", rb_gsl_stats_max_index, -1);
  rb_define_alias(cgsl_vector, "max_index", "stats_max_index");
  rb_define_method(cgsl_vector, "stats_min_index", rb_gsl_stats_min_index, -1);
  rb_define_alias(cgsl_vector, "min_index", "stats_min_index");
  rb_define_method(cgsl_vector, "stats_minmax_index", rb_gsl_stats_minmax_index, -1);
  rb_define_alias(cgsl_vector, "minmax_index", "stats_minmax_index");

  rb_define_singleton_method(mgsl_stats, "median_from_sorted_data", rb_gsl_stats_median_from_sorted_data, -1);
  rb_define_method(cgsl_vector, "stats_median_from_sorted_data", rb_gsl_stats_median_from_sorted_data, -1);
  rb_define_alias(cgsl_vector, "median_from_sorted_data", "stats_median_from_sorted_data");
  rb_define_alias(cgsl_vector, "median", "stats_median_from_sorted_data");

  rb_define_method(cgsl_vector, "stats_quantile_from_sorted_data", rb_gsl_stats_quantile_from_sorted_data, 1);
  rb_define_alias(cgsl_vector, "quantile_from_sorted_data", "stats_quantile_from_sorted_data");
  rb_define_alias(cgsl_vector, "quantile", "stats_quantile_from_sorted_data");

}
