/*
  randist.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_common.h"
#include "rb_gsl_rng.h"
#include <gsl/gsl_randist.h>
#include <gsl/gsl_cdf.h>

static VALUE rb_gsl_eval_pdf_cdf(VALUE xx, double (*f)(double));
static VALUE rb_gsl_eval_pdf_cdf2(VALUE xx, VALUE aa, double (*f)(double, double));
static VALUE rb_gsl_eval_pdf_cdf3(VALUE xx, VALUE aa, VALUE bb, 
			      double (*f)(double, double, double));
static VALUE rb_gsl_eval_pdf_cdf2_uint(VALUE xx, VALUE aa, 
				       double (*f)(unsigned int, double));
static VALUE rb_gsl_ran_gaussian(int argc, VALUE *argv, VALUE obj)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);    
  if (argc == 0) {
    return rb_float_new(gsl_ran_ugaussian(r));
  } else {
    return rb_float_new(gsl_ran_gaussian(r, NUM2DBL(argv[0])));
  }
}

static VALUE rb_gsl_ran_gaussian_ratio_method(int argc, VALUE *argv, VALUE obj)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);    
  if (argc == 0) {
    return rb_float_new(gsl_ran_ugaussian_ratio_method(r));
  } else {
    return rb_float_new(gsl_ran_gaussian_ratio_method(r, NUM2DBL(argv[0])));
  }
}

static VALUE rb_gsl_ran_gaussian_pdf(int argc, VALUE *argv, VALUE obj)
{
  if (argc == 1) {
    return rb_gsl_eval_pdf_cdf(argv[0], gsl_ran_ugaussian_pdf);
  } else if (argc == 2) {
    return rb_gsl_eval_pdf_cdf2(argv[0], argv[1], gsl_ran_gaussian_pdf);
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)");
  }
}

static VALUE rb_gsl_ran_gaussian_tail(int argc, VALUE *argv, VALUE obj)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);    
  if (argc == 1) {
    return rb_float_new(gsl_ran_ugaussian_tail(r, NUM2DBL(argv[0])));
  } else if (argc == 2) {
    return rb_float_new(gsl_ran_gaussian_tail(r, NUM2DBL(argv[0]), NUM2DBL(argv[1])));
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)");
  }
}

static VALUE rb_gsl_ran_gaussian_tail_pdf(int argc, VALUE *argv, VALUE obj)
{
  if (argc == 2) {
    return rb_gsl_eval_pdf_cdf2(argv[0], argv[1], gsl_ran_ugaussian_tail_pdf);
  } else if (argc == 3) {
    return rb_gsl_eval_pdf_cdf3(argv[0], argv[1], argv[2], gsl_ran_gaussian_tail_pdf);
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (2 or 3)");
  }
}

static VALUE rb_gsl_ran_bivariate_gaussian(VALUE obj, VALUE sx, VALUE sy, VALUE rr)
{
  gsl_rng *r = NULL;	
  double sigmax, sigmay, rho, x, y;
  Need_Float(sx); Need_Float(sy); Need_Float(rr);
  Data_Get_Struct(obj, gsl_rng, r);  
  sigmax = NUM2DBL(sx);
  sigmay = NUM2DBL(sy);
  rho = NUM2DBL(rr);
  gsl_ran_bivariate_gaussian(r, sigmax, sigmay, rho, &x, &y);
  return rb_ary_new3(2, rb_float_new(x), rb_float_new(y));
}

static VALUE rb_gsl_ran_bivariate_gaussian_pdf(VALUE obj, VALUE x, VALUE y, VALUE sx, VALUE sy, VALUE rr)
{
  Need_Float(x); Need_Float(y);
  Need_Float(sx); Need_Float(sy); Need_Float(rr);
  return rb_float_new(gsl_ran_bivariate_gaussian_pdf(NUM2DBL(x), NUM2DBL(y), NUM2DBL(sx), NUM2DBL(sy), NUM2DBL(rr)));
}

static VALUE rb_gsl_ran_exponential(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_exponential(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_exponential_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_ran_exponential_pdf);
}

static VALUE rb_gsl_ran_laplace(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_laplace(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_laplace_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_ran_laplace_pdf);
}

static VALUE rb_gsl_ran_exppow(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a); Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_exppow(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_exppow_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a); Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_exppow_pdf);
}

static VALUE rb_gsl_ran_cauchy(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_cauchy(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_cauchy_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_ran_cauchy_pdf);
}

static VALUE rb_gsl_ran_rayleigh(VALUE obj, VALUE a)
{
  gsl_rng *r = NULL;	
  Need_Float(a);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_rayleigh(r, NUM2DBL(a)));
}

static VALUE rb_gsl_ran_rayleigh_pdf(VALUE obj, VALUE x, VALUE a)
{
  Need_Float(a);
  return rb_gsl_eval_pdf_cdf2(x, a, gsl_ran_rayleigh_pdf);
}

static VALUE rb_gsl_ran_rayleigh_tail(VALUE obj, VALUE a, VALUE s)
{
  gsl_rng *r = NULL;	
  Need_Float(a);  Need_Float(s);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_rayleigh_tail(r, NUM2DBL(a), NUM2DBL(s)));
}

static VALUE rb_gsl_ran_rayleigh_tail_pdf(VALUE obj, VALUE x, VALUE a, VALUE s)
{
  Need_Float(a);  Need_Float(s);
  return rb_gsl_eval_pdf_cdf3(x, a, s, gsl_ran_rayleigh_tail_pdf);
}

static VALUE rb_gsl_ran_landau(VALUE obj)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_landau(r));
}

static VALUE rb_gsl_ran_landau_pdf(VALUE obj, VALUE x)
{
  return rb_gsl_eval_pdf_cdf(x, gsl_ran_landau_pdf);
}

static VALUE rb_gsl_ran_levy(VALUE obj, VALUE c, VALUE a)
{
  gsl_rng *r = NULL;	
  Need_Float(c);   Need_Float(a);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_levy(r, NUM2DBL(c), NUM2DBL(a)));
}

static VALUE rb_gsl_ran_levy_skew(VALUE obj, VALUE c, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(c);   Need_Float(a); Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_levy_skew(r, NUM2DBL(c), NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_gamma(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a); Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_gamma(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_gamma_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a); Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_gamma_pdf);
}

static VALUE rb_gsl_ran_flat(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a); Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_flat(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_flat_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a); Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_flat_pdf);
}

static VALUE rb_gsl_ran_lognormal(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a); Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_lognormal(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_lognormal_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a); Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_lognormal_pdf);
}

static VALUE rb_gsl_ran_chisq(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_chisq(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_chisq_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_ran_chisq_pdf);
}

static VALUE rb_gsl_ran_fdist(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a); Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_fdist(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_fdist_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a); Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_fdist_pdf);
}

static VALUE rb_gsl_ran_tdist(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_tdist(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_tdist_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_ran_tdist_pdf);
}

static VALUE rb_gsl_ran_beta(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a);  Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_beta(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_beta_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a);  Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_beta_pdf);
}

static VALUE rb_gsl_ran_logistic(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_logistic(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_logistic_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_ran_logistic_pdf);
}

static VALUE rb_gsl_ran_pareto(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a);  Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_pareto(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_pareto_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a);  Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_pareto_pdf);
}

static VALUE rb_gsl_ran_weibull(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a);  Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_weibull(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_weibull_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a);  Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_weibull_pdf);
}

static VALUE rb_gsl_ran_gumbel1(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a);  Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_gumbel1(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_gumbel1_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a);  Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_gumbel1_pdf);
}

static VALUE rb_gsl_ran_gumbel2(VALUE obj, VALUE a, VALUE b)
{
  gsl_rng *r = NULL;	
  Need_Float(a);  Need_Float(b);
  Data_Get_Struct(obj, gsl_rng, r);  
  return rb_float_new(gsl_ran_gumbel2(r, NUM2DBL(a), NUM2DBL(b)));
}

static VALUE rb_gsl_ran_gumbel2_pdf(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  Need_Float(a);  Need_Float(b);
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_ran_gumbel2_pdf);
}

static VALUE rb_gsl_ran_poisson(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_poisson(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_poisson_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2_uint(x, mu, gsl_ran_poisson_pdf);
}

static VALUE rb_gsl_ran_bernoulli(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Need_Float(mu);
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_bernoulli(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_bernoulli_pdf(VALUE obj, VALUE x, VALUE mu)
{
  Need_Float(mu);
  return rb_gsl_eval_pdf_cdf2_uint(x, mu, gsl_ran_bernoulli_pdf);
}

static VALUE rb_gsl_ran_binomial(VALUE obj, VALUE p, VALUE n)
{
  gsl_rng *r = NULL;	
  Need_Float(p);
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_binomial(r, NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_binomial_tpe(VALUE obj, VALUE p, VALUE n)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_binomial_tpe(r, NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_binomial_pdf(VALUE obj, VALUE x, VALUE p, VALUE n)
{
  return rb_float_new(gsl_ran_binomial_pdf(NUM2UINT(x), NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_negative_binomial(VALUE obj, VALUE p, VALUE n)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_negative_binomial(r, NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_negative_binomial_pdf(VALUE obj, VALUE x, VALUE p, VALUE n)
{
  return rb_float_new(gsl_ran_negative_binomial_pdf(NUM2UINT(x), NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_pascal(VALUE obj, VALUE p, VALUE n)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_pascal(r, NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_pascal_pdf(VALUE obj, VALUE x, VALUE p, VALUE n)
{
  return rb_float_new(gsl_ran_pascal_pdf(NUM2UINT(x), NUM2DBL(p), NUM2UINT(n)));
}

static VALUE rb_gsl_ran_geometric(VALUE obj, VALUE p)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_geometric(r, NUM2DBL(p)));
}

static VALUE rb_gsl_ran_geometric_pdf(VALUE obj, VALUE x, VALUE p)
{
  return rb_gsl_eval_pdf_cdf2_uint(x, p, gsl_ran_geometric_pdf);
}

static VALUE rb_gsl_ran_hypergeometric(VALUE obj, VALUE n1, VALUE n2, VALUE t)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_hypergeometric(r, NUM2UINT(n1),  NUM2UINT(n2),  NUM2UINT(t)));
}

static VALUE rb_gsl_ran_hypergeometric_pdf(VALUE obj, VALUE k, VALUE n1, VALUE n2, VALUE t)
{
  return rb_float_new(gsl_ran_hypergeometric_pdf(NUM2UINT(k), NUM2UINT(n1),  NUM2UINT(n2),  NUM2UINT(t)));
}

static VALUE rb_gsl_ran_logarithmic(VALUE obj, VALUE mu)
{
  gsl_rng *r = NULL;	
  Data_Get_Struct(obj, gsl_rng, r);  
  return UINT2NUM(gsl_ran_logarithmic(r, NUM2DBL(mu)));
}

static VALUE rb_gsl_ran_logarithmic_pdf(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2_uint(x, mu, gsl_ran_logarithmic_pdf);
}

static VALUE rb_gsl_ran_dir_2d(VALUE obj)
{
  gsl_rng *r = NULL;	
  double x, y;
  Data_Get_Struct(obj, gsl_rng, r);  
  gsl_ran_dir_2d(r, &x, &y);
  return rb_ary_new3(2, rb_float_new(x), rb_float_new(y));
}

static VALUE rb_gsl_ran_dir_2d_trig_method(VALUE obj)
{
  gsl_rng *r = NULL;	
  double x, y;
  Data_Get_Struct(obj, gsl_rng, r);  
  gsl_ran_dir_2d_trig_method(r, &x, &y);
  return rb_ary_new3(2, rb_float_new(x), rb_float_new(y));
}

static VALUE rb_gsl_ran_dir_3d(VALUE obj)
{
  gsl_rng *r = NULL;	
  double x, y, z;
  Data_Get_Struct(obj, gsl_rng, r);  
  gsl_ran_dir_3d(r, &x, &y, &z);
  return rb_ary_new3(3, rb_float_new(x), rb_float_new(y), rb_float_new(z));
}

static VALUE rb_gsl_ran_dir_nd(VALUE obj, VALUE nn, VALUE vv)
{
  gsl_rng *r = NULL;	
  gsl_vector *v = NULL;

  Data_Get_Struct(obj, gsl_rng, r);  
  if (!rb_obj_is_kind_of(vv, cgsl_vector)) {
      rb_raise(rb_eArgError, "wrong type argument (GSL_Vector required)");
  }
  Data_Get_Struct(vv, gsl_vector, v);  
  gsl_ran_dir_nd(r, FIX2INT(nn), v->data);
  return Qnil;
}

static VALUE rb_gsl_ran_shuffle(VALUE obj, VALUE vv)
{
  gsl_rng *r = NULL;	
  gsl_vector *v = NULL;
  gsl_permutation *p = NULL;
  Data_Get_Struct(obj, gsl_rng, r);  
  if (rb_obj_is_kind_of(vv, cgsl_vector)) { 
    Data_Get_Struct(vv, gsl_vector, v);  
    gsl_ran_shuffle(r, v->data, v->size, sizeof(double));
  } else if (rb_obj_is_kind_of(vv, cgsl_permutation)) { 
    Data_Get_Struct(vv, gsl_permutation, p);  
    gsl_ran_shuffle(r, p->data, p->size, sizeof(size_t));
  } else {
    rb_raise(rb_eTypeError, "wrong argument type");
  }
  return Qnil;
}

static VALUE rb_gsl_ran_choose(VALUE obj, VALUE vv, VALUE kk)
{
  gsl_rng *r = NULL;	
  gsl_vector *v = NULL, *v2 = NULL;
  size_t k, n;
  Data_Get_Struct(obj, gsl_rng, r);  
  Data_Get_Struct(vv, gsl_vector, v);  
  n = v->size;
  k = FIX2INT(kk);
  if (k > n) rb_raise(rb_eArgError, "the argument 1 must be less than or equal to the size of the vector.");
  v2 = gsl_vector_alloc(k);
  gsl_ran_choose(r, v2->data, k, v->data, n, sizeof(double));
  return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, v2);;
}

static VALUE rb_gsl_ran_sample(VALUE obj, VALUE vv, VALUE kk)
{
  gsl_rng *r = NULL;	
  gsl_vector *v = NULL, *v2 = NULL;
  size_t k, n;
  Data_Get_Struct(obj, gsl_rng, r);  
  Data_Get_Struct(vv, gsl_vector, v);  
  n = v->size;
  k = FIX2INT(kk);
  v2 = gsl_vector_alloc(k);
  gsl_ran_sample(r, v2->data, k, v->data, n, sizeof(double));
  return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, v2);;
}

static VALUE rb_gsl_cdf_gaussian_P(int argc, VALUE *argv, VALUE obj)
{
  if (argc == 1) {
    return rb_gsl_eval_pdf_cdf(argv[0], gsl_cdf_ugaussian_P);
  } else if (argc == 2) {
    return rb_gsl_eval_pdf_cdf2(argv[0], argv[1], gsl_cdf_gaussian_P);
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
  }
}
static VALUE rb_gsl_cdf_gaussian_Q(int argc, VALUE *argv, VALUE obj)
{
  if (argc == 1) {
    return rb_gsl_eval_pdf_cdf(argv[0], gsl_cdf_ugaussian_Q);
  } else if (argc == 2) {
    return rb_gsl_eval_pdf_cdf2(argv[0], argv[1], gsl_cdf_gaussian_Q);
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
  }
}

static VALUE rb_gsl_cdf_gaussian_Pinv(int argc, VALUE *argv, VALUE obj)
{
  if (argc == 1) {
    return rb_gsl_eval_pdf_cdf(argv[0], gsl_cdf_ugaussian_Pinv);
  } else if (argc == 2) {
    return rb_gsl_eval_pdf_cdf2(argv[0], argv[1], gsl_cdf_gaussian_Pinv);
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
  }
}

static VALUE rb_gsl_cdf_gaussian_Qinv(int argc, VALUE *argv, VALUE obj)
{
  if (argc == 1) {
    return rb_gsl_eval_pdf_cdf(argv[0], gsl_cdf_ugaussian_Qinv);
  } else if (argc == 2) {
    return rb_gsl_eval_pdf_cdf2(argv[0], argv[1], gsl_cdf_gaussian_Qinv);
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc);
  }
}

static VALUE rb_gsl_cdf_exponential_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_exponential_P);
}  

static VALUE rb_gsl_cdf_exponential_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_exponential_Q);
}  

static VALUE rb_gsl_cdf_exponential_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_exponential_Pinv);
}  

static VALUE rb_gsl_cdf_exponential_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_exponential_Qinv);
}  

static VALUE rb_gsl_cdf_laplace_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_laplace_P);
}  

static VALUE rb_gsl_cdf_laplace_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_laplace_Q);
}  

static VALUE rb_gsl_cdf_laplace_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_laplace_Pinv);
}  

static VALUE rb_gsl_cdf_laplace_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_laplace_Qinv);
}  

static VALUE rb_gsl_cdf_cauchy_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_cauchy_P);
}  

static VALUE rb_gsl_cdf_cauchy_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_cauchy_Q);
}  

static VALUE rb_gsl_cdf_cauchy_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_cauchy_Pinv);
}  

static VALUE rb_gsl_cdf_cauchy_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_cauchy_Qinv);
}  

static VALUE rb_gsl_cdf_rayleigh_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_rayleigh_P);
}  

static VALUE rb_gsl_cdf_rayleigh_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_rayleigh_Q);
}  

static VALUE rb_gsl_cdf_rayleigh_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_rayleigh_Pinv);
}  

static VALUE rb_gsl_cdf_rayleigh_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_rayleigh_Qinv);
}  

static VALUE rb_gsl_cdf_gamma_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gamma_P);
}  

static VALUE rb_gsl_cdf_gamma_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_gamma_Q);
}  

static VALUE rb_gsl_cdf_gamma_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_gamma_Pinv);
}  

static VALUE rb_gsl_cdf_gamma_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_gamma_Qinv);
}  

static VALUE rb_gsl_cdf_flat_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_flat_P);
}  

static VALUE rb_gsl_cdf_flat_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_flat_Q);
}  

static VALUE rb_gsl_cdf_flat_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_flat_Pinv);
}  

static VALUE rb_gsl_cdf_flat_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_flat_Qinv);
}  

static VALUE rb_gsl_cdf_lognormal_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_lognormal_P);
}  

static VALUE rb_gsl_cdf_lognormal_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_lognormal_Q);
}  

static VALUE rb_gsl_cdf_lognormal_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_lognormal_Pinv);
}  

static VALUE rb_gsl_cdf_lognormal_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b,  gsl_cdf_lognormal_Qinv);
}  

static VALUE rb_gsl_cdf_chisq_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_chisq_P);
}  

static VALUE rb_gsl_cdf_chisq_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_chisq_Q);
}  

static VALUE rb_gsl_cdf_chisq_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_chisq_Pinv);
}  

static VALUE rb_gsl_cdf_chisq_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_chisq_Qinv);
}  

static VALUE rb_gsl_cdf_fdist_P(VALUE obj, VALUE x, VALUE nu1, VALUE nu2)
{
  return rb_gsl_eval_pdf_cdf3(x, nu1, nu2, gsl_cdf_fdist_P);
}  

static VALUE rb_gsl_cdf_fdist_Q(VALUE obj, VALUE x, VALUE nu1, VALUE nu2)
{
  return rb_gsl_eval_pdf_cdf3(x, nu1, nu2, gsl_cdf_fdist_Q);
}  

static VALUE rb_gsl_cdf_tdist_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_tdist_P);
}  

static VALUE rb_gsl_cdf_tdist_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_tdist_Q);
}  

static VALUE rb_gsl_cdf_tdist_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_tdist_Pinv);
}  

static VALUE rb_gsl_cdf_tdist_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_tdist_Qinv);
}  

static VALUE rb_gsl_cdf_beta_P(VALUE obj, VALUE x, VALUE nu1, VALUE nu2)
{
  return rb_gsl_eval_pdf_cdf3(x, nu1, nu2, gsl_cdf_beta_P);
}  

static VALUE rb_gsl_cdf_beta_Q(VALUE obj, VALUE x, VALUE nu1, VALUE nu2)
{
  return rb_gsl_eval_pdf_cdf3(x, nu1, nu2, gsl_cdf_beta_Q);
}  

static VALUE rb_gsl_cdf_logistic_P(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_logistic_P);
}  

static VALUE rb_gsl_cdf_logistic_Q(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_logistic_Q);
}  

static VALUE rb_gsl_cdf_logistic_Pinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_logistic_Pinv);
}  

static VALUE rb_gsl_cdf_logistic_Qinv(VALUE obj, VALUE x, VALUE mu)
{
  return rb_gsl_eval_pdf_cdf2(x, mu, gsl_cdf_logistic_Qinv);
}  

static VALUE rb_gsl_cdf_pareto_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_pareto_P);
}  

static VALUE rb_gsl_cdf_pareto_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_pareto_Q);
}  

static VALUE rb_gsl_cdf_pareto_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_pareto_Pinv);
}  

static VALUE rb_gsl_cdf_pareto_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_pareto_Qinv);
}  

static VALUE rb_gsl_cdf_weibull_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_weibull_P);
}  

static VALUE rb_gsl_cdf_weibull_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_weibull_Q);
}  

static VALUE rb_gsl_cdf_weibull_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_weibull_Pinv);
}  

static VALUE rb_gsl_cdf_weibull_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_weibull_Qinv);
}  

static VALUE rb_gsl_cdf_gumbel1_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel1_P);
}  

static VALUE rb_gsl_cdf_gumbel1_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel1_Q);
}  

static VALUE rb_gsl_cdf_gumbel1_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel1_Pinv);
}  

static VALUE rb_gsl_cdf_gumbel1_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel1_Qinv);
}  

static VALUE rb_gsl_cdf_gumbel2_P(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel2_P);
}  

static VALUE rb_gsl_cdf_gumbel2_Q(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel2_Q);
}  

static VALUE rb_gsl_cdf_gumbel2_Pinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel2_Pinv);
}  

static VALUE rb_gsl_cdf_gumbel2_Qinv(VALUE obj, VALUE x, VALUE a, VALUE b)
{
  return rb_gsl_eval_pdf_cdf3(x, a, b, gsl_cdf_gumbel2_Qinv);
}  

#ifdef GSL_1_3_LATER
static VALUE rb_gsl_ran_dirichlet(int argc, VALUE *argv, VALUE obj)
{
  gsl_rng *r = NULL;	
  gsl_vector *v = NULL, *v2 = NULL;
  Data_Get_Struct(obj, gsl_rng, r);    
  if (argc == 1) {
    Data_Get_Struct(argv[0], gsl_vector, v);    
    v2 = gsl_vector_alloc(v->size);
    gsl_ran_dirichlet(r, v->size, v->data, v2->data);
    return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, v2);
  } else if (argc == 2) {
    Data_Get_Struct(argv[0], gsl_vector, v);    
    Data_Get_Struct(argv[1], gsl_vector, v2);    
    gsl_ran_dirichlet(r, v->size, v->data, v2->data);
    return obj;
  } else {
    rb_raise(rb_eArgError, "wrong number of arguments (1 or 2 GSL_Vectors)");
  }
}

static VALUE rb_gsl_ran_dirichlet_pdf(VALUE obj, VALUE a, VALUE t)
{
  gsl_vector *alpha = NULL, *theta = NULL;
  Data_Get_Struct(a, gsl_vector, alpha);    
  Data_Get_Struct(t, gsl_vector, theta);    
  return rb_float_new(gsl_ran_dirichlet_pdf(alpha->size, alpha->data, theta->data));
}
static VALUE rb_gsl_ran_dirichlet_lnpdf(VALUE obj, VALUE a, VALUE t)
{
  gsl_vector *alpha = NULL, *theta = NULL;
  Data_Get_Struct(a, gsl_vector, alpha);    
  Data_Get_Struct(t, gsl_vector, theta);    
  return rb_float_new(gsl_ran_dirichlet_lnpdf(alpha->size, alpha->data, theta->data));
}
#endif

static VALUE rb_gsl_ran_discrete_new(VALUE klass, VALUE vv)
{
  gsl_vector *v = NULL;
  gsl_ran_discrete_t *g = NULL;
  Data_Get_Struct(vv, gsl_vector, v);
  g = gsl_ran_discrete_preproc(v->size, v->data);
  return Data_Wrap_Struct(klass, 0, gsl_ran_discrete_free, g);
}

static VALUE rb_gsl_ran_discrete(VALUE obj, VALUE gg)
{
  gsl_rng *r = NULL;
  gsl_ran_discrete_t *g = NULL;
  Data_Get_Struct(obj, gsl_rng, r);
  Data_Get_Struct(gg, gsl_ran_discrete_t, g);
  return INT2FIX(gsl_ran_discrete(r, g));
}

static VALUE rb_gsl_ran_discrete_pdf(VALUE obj, VALUE k, VALUE gg)
{
  gsl_ran_discrete_t *g = NULL;
  Data_Get_Struct(gg, gsl_ran_discrete_t, g);
  return rb_float_new(gsl_ran_discrete_pdf(FIX2INT(k), g));
}

/*****/
static VALUE rb_gsl_eval_pdf_cdf(VALUE xx, double (*f)(double))
{
  VALUE x, ary;
  gsl_vector *v = NULL, *vnew = NULL;
  gsl_matrix *m = NULL, *mnew = NULL;
  int i, j, n;
  if (CLASS_OF(xx) == rb_cRange) xx = rb_gsl_range2ary(xx);
  switch(TYPE(xx)) {
  case T_FIXNUM:
  case T_BIGNUM:
  case T_FLOAT:
    return rb_float_new((*f)(NUM2DBL(xx)));
    break;
  case T_ARRAY:
    n = RARRAY(xx)->len;
    ary = rb_ary_new2(n);
    for (i = 0; i < n; i++) {
      x = rb_ary_entry(xx, i);
      Need_Float(x);
      rb_ary_store(ary, i, rb_float_new((*f)(NUM2DBL(x))));
    }
    return ary;
    break;
  default:
    if (VECTOR_P(xx)) {
      Data_Get_Struct(xx, gsl_vector, v);
      vnew = gsl_vector_alloc(v->size);
      for (i = 0; i < v->size; i++) {
	gsl_vector_set(vnew, i, (*f)(gsl_vector_get(v, i)));
      }
      return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, vnew);
    } else if (MATRIX_P(xx)) {
      Data_Get_Struct(xx, gsl_matrix, m);
      mnew = gsl_matrix_alloc(m->size1, m->size2);
      for (i = 0; i < m->size1; i++) {
	for (j = 0; j < m->size2; j++) {
	  gsl_matrix_set(mnew, i, j, (*f)(gsl_matrix_get(m, i, j)));
	}
      }
      return Data_Wrap_Struct(cgsl_matrix, 0, gsl_matrix_free, mnew);
    } else {
      rb_raise(rb_eTypeError, "wrong argument type");
    }
    break;
  }
  /* never reach here */
  return Qnil;
}

static VALUE rb_gsl_eval_pdf_cdf2(VALUE xx, VALUE aa, 
			      double (*f)(double, double))
{
  VALUE x, ary;
  double a;
  gsl_vector *v = NULL, *vnew = NULL;
  gsl_matrix *m = NULL, *mnew = NULL;
  int i, j, n;
  Need_Float(aa);
  a = NUM2DBL(aa);
  if (CLASS_OF(xx) == rb_cRange) xx = rb_gsl_range2ary(xx);
  switch(TYPE(xx)) {
  case T_FIXNUM:
  case T_BIGNUM:
  case T_FLOAT:
    return rb_float_new((*f)(NUM2DBL(xx), a));
    break;
  case T_ARRAY:
    n = RARRAY(xx)->len;
    ary = rb_ary_new2(n);
    for (i = 0; i < n; i++) {
      x = rb_ary_entry(xx, i);
      Need_Float(x);
      rb_ary_store(ary, i, rb_float_new((*f)(NUM2DBL(x), a)));
    }
    return ary;
    break;
  default:
    if (VECTOR_P(xx)) {
      Data_Get_Struct(xx, gsl_vector, v);
      vnew = gsl_vector_alloc(v->size);
      for (i = 0; i < v->size; i++) {
	gsl_vector_set(vnew, i, (*f)(gsl_vector_get(v, i), a));
      }
      return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, vnew);
    } else if (MATRIX_P(xx)) {
      Data_Get_Struct(xx, gsl_matrix, m);
      mnew = gsl_matrix_alloc(m->size1, m->size2);
      for (i = 0; i < m->size1; i++) {
	for (j = 0; j < m->size2; j++) {
	  gsl_matrix_set(mnew, i, j, (*f)(gsl_matrix_get(m, i, j), a));
	}
      }
      return Data_Wrap_Struct(cgsl_matrix, 0, gsl_matrix_free, mnew);
    } else {
      rb_raise(rb_eTypeError, "wrong argument type");
    }
    break;
  }
  /* never reach here */
  return Qnil;
}

static VALUE rb_gsl_eval_pdf_cdf3(VALUE xx, VALUE aa, VALUE bb, 
			      double (*f)(double, double, double))
{
  VALUE x, ary;
  double a, b;
  gsl_vector *v = NULL, *vnew = NULL;
  gsl_matrix *m = NULL, *mnew = NULL;
  int i, j, n;
  Need_Float(aa);  Need_Float(bb);
  a = NUM2DBL(aa); b = NUM2DBL(bb);
  if (CLASS_OF(xx) == rb_cRange) xx = rb_gsl_range2ary(xx);
  switch(TYPE(xx)) {
  case T_FIXNUM:
  case T_BIGNUM:
  case T_FLOAT:
    return rb_float_new((*f)(NUM2DBL(xx), a, b));
    break;
  case T_ARRAY:
    n = RARRAY(xx)->len;
    ary = rb_ary_new2(n);
    for (i = 0; i < n; i++) {
      x = rb_ary_entry(xx, i);
      Need_Float(x);
      rb_ary_store(ary, i, rb_float_new((*f)(NUM2DBL(x), a, b)));
    }
    return ary;
    break;
  default:
    if (VECTOR_P(xx)) {
      Data_Get_Struct(xx, gsl_vector, v);
      vnew = gsl_vector_alloc(v->size);
      for (i = 0; i < v->size; i++) {
	gsl_vector_set(vnew, i, (*f)(gsl_vector_get(v, i), a, b));
      }
      return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, vnew);
    } else if (MATRIX_P(xx)) {
      Data_Get_Struct(xx, gsl_matrix, m);
      mnew = gsl_matrix_alloc(m->size1, m->size2);
      for (i = 0; i < m->size1; i++) {
	for (j = 0; j < m->size2; j++) {
	  gsl_matrix_set(mnew, i, j, (*f)(gsl_matrix_get(m, i, j), a, b));
	}
      }
      return Data_Wrap_Struct(cgsl_matrix, 0, gsl_matrix_free, mnew);
    } else {
      rb_raise(rb_eTypeError, "wrong argument type");
    }
    break;
  }
  /* never reach here */
  return Qnil;
}

static VALUE rb_gsl_eval_pdf_cdf2_uint(VALUE xx, VALUE aa, 
				       double (*f)(unsigned int, double))
{
  VALUE x, ary;
  double a;
  gsl_vector *v = NULL, *vnew = NULL;
  gsl_matrix *m = NULL, *mnew = NULL;
  int i, j, n;
  Need_Float(aa);
  a = NUM2DBL(aa);
  if (CLASS_OF(xx) == rb_cRange) xx = rb_gsl_range2ary(xx);
  switch(TYPE(xx)) {
  case T_FIXNUM:
  case T_BIGNUM:
  case T_FLOAT:
    return rb_float_new((*f)(NUM2DBL(xx), a));
    break;
  case T_ARRAY:
    n = RARRAY(xx)->len;
    ary = rb_ary_new2(n);
    for (i = 0; i < n; i++) {
      x = rb_ary_entry(xx, i);
      rb_ary_store(ary, i, rb_float_new((*f)(NUM2UINT(x), a)));
    }
    return ary;
    break;
  default:
    if (VECTOR_P(xx)) {
      Data_Get_Struct(xx, gsl_vector, v);
      vnew = gsl_vector_alloc(v->size);
      for (i = 0; i < v->size; i++) {
	gsl_vector_set(vnew, i, (*f)(gsl_vector_get(v, i), a));
      }
      return Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, vnew);
    } else if (MATRIX_P(xx)) {
      Data_Get_Struct(xx, gsl_matrix, m);
      mnew = gsl_matrix_alloc(m->size1, m->size2);
      for (i = 0; i < m->size1; i++) {
	for (j = 0; j < m->size2; j++) {
	  gsl_matrix_set(mnew, i, j, (*f)(gsl_matrix_get(m, i, j), a));
	}
      }
      return Data_Wrap_Struct(cgsl_matrix, 0, gsl_matrix_free, mnew);
    } else {
      rb_raise(rb_eTypeError, "wrong argument type");
    }
    break;
  }
  /* never reach here */
  return Qnil;
}

void Init_gsl_ran()
{
  VALUE mgsl_ran;
  VALUE mgsl_cdf;
  VALUE cgsl_ran_discrete;

  mgsl_ran = rb_define_module_under(mgsl, "Ran");
  mgsl_cdf = rb_define_module_under(mgsl, "Cdf");
  
  rb_define_method(cgsl_rng, "gaussian", rb_gsl_ran_gaussian, -1);
  rb_define_alias(cgsl_rng, "ugaussian", "gaussian");
  rb_define_method(cgsl_rng, "gaussian_ratio_method", rb_gsl_ran_gaussian_ratio_method, -1);
  rb_define_alias(cgsl_rng, "ugaussian_ratio_method", "gaussian_ratio_method");
  rb_define_module_function(mgsl_ran,  "gaussian_pdf", rb_gsl_ran_gaussian_pdf, -1);
  rb_define_module_function(mgsl_ran,  "ugaussian_pdf", rb_gsl_ran_gaussian_pdf, -1);

  rb_define_method(cgsl_rng, "gaussian_tail", rb_gsl_ran_gaussian_tail, -1);
  rb_define_alias(cgsl_rng, "ugaussian_tail", "gaussian_tail");
  rb_define_module_function(mgsl_ran,  "gaussian_tail_pdf", rb_gsl_ran_gaussian_tail_pdf, -1);
  rb_define_module_function(mgsl_ran,  "ugaussian_tail_pdf", rb_gsl_ran_gaussian_tail_pdf, -1);

  rb_define_method(cgsl_rng, "bivariate_gaussian", rb_gsl_ran_bivariate_gaussian, 3);
  rb_define_module_function(mgsl_ran,  "bivariate_gaussian_pdf", rb_gsl_ran_bivariate_gaussian_pdf, 5);

  rb_define_method(cgsl_rng, "exponential", rb_gsl_ran_exponential, 1);
  rb_define_module_function(mgsl_ran,  "exponential_pdf", rb_gsl_ran_exponential_pdf, 2);
  rb_define_method(cgsl_rng, "laplace", rb_gsl_ran_laplace, 1);
  rb_define_module_function(mgsl_ran,  "laplace_pdf", rb_gsl_ran_laplace_pdf, 2);
  rb_define_method(cgsl_rng, "exppow", rb_gsl_ran_exppow, 2);
  rb_define_module_function(mgsl_ran,  "exppow_pdf", rb_gsl_ran_exppow_pdf, 3);
  rb_define_method(cgsl_rng, "cauchy", rb_gsl_ran_cauchy, 1);
  rb_define_module_function(mgsl_ran,  "cauchy_pdf", rb_gsl_ran_cauchy_pdf, 2);
  rb_define_method(cgsl_rng, "rayleigh", rb_gsl_ran_rayleigh, 1);
  rb_define_module_function(mgsl_ran,  "rayleigh_pdf", rb_gsl_ran_rayleigh_pdf, 2);
 rb_define_method(cgsl_rng, "rayleigh_tail", rb_gsl_ran_rayleigh_tail, 2);
  rb_define_module_function(mgsl_ran,  "rayleigh_tail_pdf", rb_gsl_ran_rayleigh_tail_pdf, 3);

  rb_define_method(cgsl_rng, "landau", rb_gsl_ran_landau, 0);
  rb_define_module_function(mgsl_ran,  "landau_pdf", rb_gsl_ran_landau_pdf, 1);

  rb_define_method(cgsl_rng, "levy", rb_gsl_ran_levy, 2);
  rb_define_method(cgsl_rng, "levy_skew", rb_gsl_ran_levy_skew, 3);

  rb_define_method(cgsl_rng, "gamma", rb_gsl_ran_gamma, 2);
  rb_define_module_function(mgsl_ran,  "gamma_pdf", rb_gsl_ran_gamma_pdf, 3);
  rb_define_method(cgsl_rng, "flat", rb_gsl_ran_flat, 2);
  rb_define_module_function(mgsl_ran,  "flat_pdf", rb_gsl_ran_flat_pdf, 3);
  rb_define_method(cgsl_rng, "lognormal", rb_gsl_ran_lognormal, 2);
  rb_define_module_function(mgsl_ran,  "lognormal_pdf", rb_gsl_ran_lognormal_pdf, 3);
  rb_define_method(cgsl_rng, "chisq", rb_gsl_ran_chisq, 1);
  rb_define_module_function(mgsl_ran,  "chisq_pdf", rb_gsl_ran_chisq_pdf, 2);

  rb_define_method(cgsl_rng, "fdist", rb_gsl_ran_fdist, 2);
  rb_define_module_function(mgsl_ran,  "fdist_pdf", rb_gsl_ran_fdist_pdf, 3);

 rb_define_method(cgsl_rng, "tdist", rb_gsl_ran_tdist, 1);
  rb_define_module_function(mgsl_ran,  "tdist_pdf", rb_gsl_ran_tdist_pdf, 2);

  rb_define_method(cgsl_rng, "beta", rb_gsl_ran_beta, 2);
  rb_define_module_function(mgsl_ran,  "beta_pdf", rb_gsl_ran_beta_pdf, 3);

  rb_define_method(cgsl_rng, "logistic", rb_gsl_ran_logistic, 1);
  rb_define_module_function(mgsl_ran,  "logistic_pdf", rb_gsl_ran_logistic_pdf, 2);

  rb_define_method(cgsl_rng, "pareto", rb_gsl_ran_pareto, 2);
  rb_define_module_function(mgsl_ran,  "pareto_pdf", rb_gsl_ran_pareto_pdf, 3);

  rb_define_method(cgsl_rng, "weibull", rb_gsl_ran_weibull, 2);
  rb_define_module_function(mgsl_ran,  "weibull_pdf", rb_gsl_ran_weibull_pdf, 3);
  rb_define_method(cgsl_rng, "gumbel1", rb_gsl_ran_gumbel1, 2);
  rb_define_module_function(mgsl_ran,  "gumbel1_pdf", rb_gsl_ran_gumbel1_pdf, 3);
  rb_define_method(cgsl_rng, "gumbel2", rb_gsl_ran_gumbel2, 2);
  rb_define_module_function(mgsl_ran,  "gumbel2_pdf", rb_gsl_ran_gumbel2_pdf, 3);

  rb_define_method(cgsl_rng, "poisson", rb_gsl_ran_poisson, 1);
  rb_define_module_function(mgsl_ran,  "poisson_pdf", rb_gsl_ran_poisson_pdf, 2);
  rb_define_method(cgsl_rng, "bernoulli", rb_gsl_ran_bernoulli, 1);
  rb_define_module_function(mgsl_ran,  "bernoulli_pdf", rb_gsl_ran_bernoulli_pdf, 2);
  rb_define_method(cgsl_rng, "binomial", rb_gsl_ran_binomial, 2);
  rb_define_method(cgsl_rng, "binomial_tpe", rb_gsl_ran_binomial_tpe, 2);
  rb_define_module_function(mgsl_ran,  "binomial_pdf", rb_gsl_ran_binomial_pdf, 3);
  rb_define_method(cgsl_rng, "negative_binomial", rb_gsl_ran_negative_binomial, 2);
  rb_define_module_function(mgsl_ran,  "negative_binomial_pdf", rb_gsl_ran_negative_binomial_pdf, 3);
  rb_define_method(cgsl_rng, "pascal", rb_gsl_ran_pascal, 2);
  rb_define_module_function(mgsl_ran,  "pascal_pdf", rb_gsl_ran_pascal_pdf, 3);

  rb_define_method(cgsl_rng, "geometric", rb_gsl_ran_geometric, 1);
  rb_define_module_function(mgsl_ran,  "geometric_pdf", rb_gsl_ran_geometric_pdf, 2);
  rb_define_method(cgsl_rng, "hypergeometric", rb_gsl_ran_hypergeometric, 3);
  rb_define_module_function(mgsl_ran,  "hypergeometric_pdf", rb_gsl_ran_hypergeometric_pdf, 4);

 rb_define_method(cgsl_rng, "logarithmic", rb_gsl_ran_logarithmic, 1);
  rb_define_module_function(mgsl_ran,  "logarithmic_pdf", rb_gsl_ran_logarithmic_pdf, 2);

  rb_define_method(cgsl_rng, "dir_2d", rb_gsl_ran_dir_2d, 0);
  rb_define_method(cgsl_rng, "dir_2d_trig_method", rb_gsl_ran_dir_2d_trig_method, 0);
  rb_define_method(cgsl_rng, "dir_3d", rb_gsl_ran_dir_3d, 0);
  rb_define_method(cgsl_rng, "dir_nd", rb_gsl_ran_dir_nd, 2);

  rb_define_method(cgsl_rng, "shuffle", rb_gsl_ran_shuffle, 1);
  rb_define_method(cgsl_rng, "choose", rb_gsl_ran_choose, 2);
  rb_define_method(cgsl_rng, "sample", rb_gsl_ran_sample, 2);

  /***** Cumulative distribution functions *****/
  rb_define_module_function(mgsl, "cdf_gaussian_P", rb_gsl_cdf_gaussian_P, -1);
  rb_define_module_function(mgsl, "cdf_ugaussian_P", rb_gsl_cdf_gaussian_P, -1);
  rb_define_module_function(mgsl, "cdf_gaussian_Q", rb_gsl_cdf_gaussian_Q, -1);
  rb_define_module_function(mgsl, "cdf_ugaussian_Q", rb_gsl_cdf_gaussian_Q, -1);
  rb_define_module_function(mgsl, "cdf_gaussian_Pinv", rb_gsl_cdf_gaussian_Pinv, -1);
  rb_define_module_function(mgsl, "cdf_ugaussian_Pinv", rb_gsl_cdf_gaussian_Pinv, -1);
  rb_define_module_function(mgsl, "cdf_gaussian_Qinv", rb_gsl_cdf_gaussian_Qinv, -1);
  rb_define_module_function(mgsl, "cdf_ugaussian_Qinv", rb_gsl_cdf_gaussian_Qinv, -1);

  rb_define_module_function(mgsl, "cdf_exponential_P", rb_gsl_cdf_exponential_P, 2);
 rb_define_module_function(mgsl, "cdf_exponential_Q", rb_gsl_cdf_exponential_Q, 2);
  rb_define_module_function(mgsl, "cdf_exponential_Pinv", rb_gsl_cdf_exponential_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_exponential_Qinv", rb_gsl_cdf_exponential_Qinv, 2);

 rb_define_module_function(mgsl, "cdf_laplace_P", rb_gsl_cdf_laplace_P, 2);
 rb_define_module_function(mgsl, "cdf_laplace_Q", rb_gsl_cdf_laplace_Q, 2);
  rb_define_module_function(mgsl, "cdf_laplace_Pinv", rb_gsl_cdf_laplace_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_laplace_Qinv", rb_gsl_cdf_laplace_Qinv, 2);

  rb_define_module_function(mgsl, "cdf_cauchy_P", rb_gsl_cdf_cauchy_P, 2);
  rb_define_module_function(mgsl, "cdf_cauchy_Q", rb_gsl_cdf_cauchy_Q, 2);
  rb_define_module_function(mgsl, "cdf_cauchy_Pinv", rb_gsl_cdf_cauchy_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_cauchy_Qinv", rb_gsl_cdf_cauchy_Qinv, 2);

  rb_define_module_function(mgsl, "cdf_rayleigh_P", rb_gsl_cdf_rayleigh_P, 2);
  rb_define_module_function(mgsl, "cdf_rayleigh_Q", rb_gsl_cdf_rayleigh_Q, 2);
  rb_define_module_function(mgsl, "cdf_rayleigh_Pinv", rb_gsl_cdf_rayleigh_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_rayleigh_Qinv", rb_gsl_cdf_rayleigh_Qinv, 2);

  rb_define_module_function(mgsl, "cdf_gamma_P", rb_gsl_cdf_gamma_P, 3);
  rb_define_module_function(mgsl, "cdf_gamma_Q", rb_gsl_cdf_gamma_Q, 3);
  rb_define_module_function(mgsl, "cdf_gamma_Pinv", rb_gsl_cdf_gamma_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_gamma_Qinv", rb_gsl_cdf_gamma_Qinv, 3);

  rb_define_module_function(mgsl, "cdf_flat_P", rb_gsl_cdf_flat_P, 3);
  rb_define_module_function(mgsl, "cdf_flat_Q", rb_gsl_cdf_flat_Q, 3);
  rb_define_module_function(mgsl, "cdf_flat_Pinv", rb_gsl_cdf_flat_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_flat_Qinv", rb_gsl_cdf_flat_Qinv, 3);

  rb_define_module_function(mgsl, "cdf_lognormal_P", rb_gsl_cdf_lognormal_P, 3);
  rb_define_module_function(mgsl, "cdf_lognormal_Q", rb_gsl_cdf_lognormal_Q, 3);
  rb_define_module_function(mgsl, "cdf_lognormal_Pinv", rb_gsl_cdf_lognormal_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_lognormal_Qinv", rb_gsl_cdf_lognormal_Qinv, 3);

  rb_define_module_function(mgsl, "cdf_chisq_P", rb_gsl_cdf_chisq_P, 2);
  rb_define_module_function(mgsl, "cdf_chisq_Q", rb_gsl_cdf_chisq_Q, 2);
  rb_define_module_function(mgsl, "cdf_chisq_Pinv", rb_gsl_cdf_chisq_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_chisq_Qinv", rb_gsl_cdf_chisq_Qinv, 2);
  
  rb_define_module_function(mgsl, "cdf_fdist_P", rb_gsl_cdf_fdist_P, 3);
  rb_define_module_function(mgsl, "cdf_fdist_Q", rb_gsl_cdf_fdist_Q, 3);

  rb_define_module_function(mgsl, "cdf_tdist_P", rb_gsl_cdf_tdist_P, 2);
  rb_define_module_function(mgsl, "cdf_tdist_Q", rb_gsl_cdf_tdist_Q, 2);
  rb_define_module_function(mgsl, "cdf_tdist_Pinv", rb_gsl_cdf_tdist_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_tdist_Qinv", rb_gsl_cdf_tdist_Qinv, 2);
  
  rb_define_module_function(mgsl, "cdf_beta_P", rb_gsl_cdf_beta_P, 3);
  rb_define_module_function(mgsl, "cdf_beta_Q", rb_gsl_cdf_beta_Q, 3);

  rb_define_module_function(mgsl, "cdf_logistic_P", rb_gsl_cdf_logistic_P, 2);
  rb_define_module_function(mgsl, "cdf_logistic_Q", rb_gsl_cdf_logistic_Q, 2);
  rb_define_module_function(mgsl, "cdf_logistic_Pinv", rb_gsl_cdf_logistic_Pinv, 2);
  rb_define_module_function(mgsl, "cdf_logistic_Qinv", rb_gsl_cdf_logistic_Qinv, 2);
  
  rb_define_module_function(mgsl, "cdf_pareto_P", rb_gsl_cdf_pareto_P, 3);
  rb_define_module_function(mgsl, "cdf_pareto_Q", rb_gsl_cdf_pareto_Q, 3);
  rb_define_module_function(mgsl, "cdf_pareto_Pinv", rb_gsl_cdf_pareto_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_pareto_Qinv", rb_gsl_cdf_pareto_Qinv, 3);

  rb_define_module_function(mgsl, "cdf_weibull_P", rb_gsl_cdf_weibull_P, 3);
  rb_define_module_function(mgsl, "cdf_weibull_Q", rb_gsl_cdf_weibull_Q, 3);
  rb_define_module_function(mgsl, "cdf_weibull_Pinv", rb_gsl_cdf_weibull_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_weibull_Qinv", rb_gsl_cdf_weibull_Qinv, 3);

  rb_define_module_function(mgsl, "cdf_gumbel1_P", rb_gsl_cdf_gumbel1_P, 3);
  rb_define_module_function(mgsl, "cdf_gumbel1_Q", rb_gsl_cdf_gumbel1_Q, 3);
  rb_define_module_function(mgsl, "cdf_gumbel1_Pinv", rb_gsl_cdf_gumbel1_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_gumbel1_Qinv", rb_gsl_cdf_gumbel1_Qinv, 3);

  rb_define_module_function(mgsl, "cdf_gumbel2_P", rb_gsl_cdf_gumbel2_P, 3);
  rb_define_module_function(mgsl, "cdf_gumbel2_Q", rb_gsl_cdf_gumbel2_Q, 3);
  rb_define_module_function(mgsl, "cdf_gumbel2_Pinv", rb_gsl_cdf_gumbel2_Pinv, 3);
  rb_define_module_function(mgsl, "cdf_gumbel2_Qinv", rb_gsl_cdf_gumbel2_Qinv, 3);

  /*****/

  rb_define_module_function(mgsl_cdf, "gaussian_P", rb_gsl_cdf_gaussian_P, -1);
  rb_define_module_function(mgsl_cdf, "gaussian_Q", rb_gsl_cdf_gaussian_Q, -1);
  rb_define_module_function(mgsl_cdf, "gaussian_Pinv", rb_gsl_cdf_gaussian_Pinv, -1);
  rb_define_module_function(mgsl_cdf, "gaussian_Qinv", rb_gsl_cdf_gaussian_Qinv, -1);
  rb_define_module_function(mgsl_cdf, "ugaussian_P", rb_gsl_cdf_gaussian_P, -1);
  rb_define_module_function(mgsl_cdf, "ugaussian_Q", rb_gsl_cdf_gaussian_Q, -1);
  rb_define_module_function(mgsl_cdf, "ugaussian_Pinv", rb_gsl_cdf_gaussian_Pinv, -1);
  rb_define_module_function(mgsl_cdf, "ugaussian_Qinv", rb_gsl_cdf_gaussian_Qinv, -1);

  rb_define_module_function(mgsl_cdf, "exponential_P", rb_gsl_cdf_exponential_P, 2);
 rb_define_module_function(mgsl_cdf, "exponential_Q", rb_gsl_cdf_exponential_Q, 2);
  rb_define_module_function(mgsl_cdf, "exponential_Pinv", rb_gsl_cdf_exponential_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "exponential_Qinv", rb_gsl_cdf_exponential_Qinv, 2);

 rb_define_module_function(mgsl_cdf, "laplace_P", rb_gsl_cdf_laplace_P, 2);
 rb_define_module_function(mgsl_cdf, "laplace_Q", rb_gsl_cdf_laplace_Q, 2);
  rb_define_module_function(mgsl_cdf, "laplace_Pinv", rb_gsl_cdf_laplace_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "laplace_Qinv", rb_gsl_cdf_laplace_Qinv, 2);

  rb_define_module_function(mgsl_cdf, "cauchy_P", rb_gsl_cdf_cauchy_P, 2);
  rb_define_module_function(mgsl_cdf, "cauchy_Q", rb_gsl_cdf_cauchy_Q, 2);
  rb_define_module_function(mgsl_cdf, "cauchy_Pinv", rb_gsl_cdf_cauchy_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "cauchy_Qinv", rb_gsl_cdf_cauchy_Qinv, 2);

  rb_define_module_function(mgsl_cdf, "rayleigh_P", rb_gsl_cdf_rayleigh_P, 2);
  rb_define_module_function(mgsl_cdf, "rayleigh_Q", rb_gsl_cdf_rayleigh_Q, 2);
  rb_define_module_function(mgsl_cdf, "rayleigh_Pinv", rb_gsl_cdf_rayleigh_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "rayleigh_Qinv", rb_gsl_cdf_rayleigh_Qinv, 2);

  rb_define_module_function(mgsl_cdf, "gamma_P", rb_gsl_cdf_gamma_P, 3);
  rb_define_module_function(mgsl_cdf, "gamma_Q", rb_gsl_cdf_gamma_Q, 3);
  rb_define_module_function(mgsl_cdf, "gamma_Pinv", rb_gsl_cdf_gamma_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "gamma_Qinv", rb_gsl_cdf_gamma_Qinv, 3);

  rb_define_module_function(mgsl_cdf, "flat_P", rb_gsl_cdf_flat_P, 3);
  rb_define_module_function(mgsl_cdf, "flat_Q", rb_gsl_cdf_flat_Q, 3);
  rb_define_module_function(mgsl_cdf, "flat_Pinv", rb_gsl_cdf_flat_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "flat_Qinv", rb_gsl_cdf_flat_Qinv, 3);

  rb_define_module_function(mgsl_cdf, "lognormal_P", rb_gsl_cdf_lognormal_P, 3);
  rb_define_module_function(mgsl_cdf, "lognormal_Q", rb_gsl_cdf_lognormal_Q, 3);
  rb_define_module_function(mgsl_cdf, "lognormal_Pinv", rb_gsl_cdf_lognormal_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "lognormal_Qinv", rb_gsl_cdf_lognormal_Qinv, 3);

  rb_define_module_function(mgsl_cdf, "chisq_P", rb_gsl_cdf_chisq_P, 2);
  rb_define_module_function(mgsl_cdf, "chisq_Q", rb_gsl_cdf_chisq_Q, 2);
  rb_define_module_function(mgsl_cdf, "chisq_Pinv", rb_gsl_cdf_chisq_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "chisq_Qinv", rb_gsl_cdf_chisq_Qinv, 2);
  
  rb_define_module_function(mgsl_cdf, "fdist_P", rb_gsl_cdf_fdist_P, 3);
  rb_define_module_function(mgsl_cdf, "fdist_Q", rb_gsl_cdf_fdist_Q, 3);

  rb_define_module_function(mgsl_cdf, "tdist_P", rb_gsl_cdf_tdist_P, 2);
  rb_define_module_function(mgsl_cdf, "tdist_Q", rb_gsl_cdf_tdist_Q, 2);
  rb_define_module_function(mgsl_cdf, "tdist_Pinv", rb_gsl_cdf_tdist_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "tdist_Qinv", rb_gsl_cdf_tdist_Qinv, 2);
  
  rb_define_module_function(mgsl_cdf, "beta_P", rb_gsl_cdf_beta_P, 3);
  rb_define_module_function(mgsl_cdf, "beta_Q", rb_gsl_cdf_beta_Q, 3);

  rb_define_module_function(mgsl_cdf, "logistic_P", rb_gsl_cdf_logistic_P, 2);
  rb_define_module_function(mgsl_cdf, "logistic_Q", rb_gsl_cdf_logistic_Q, 2);
  rb_define_module_function(mgsl_cdf, "logistic_Pinv", rb_gsl_cdf_logistic_Pinv, 2);
  rb_define_module_function(mgsl_cdf, "logistic_Qinv", rb_gsl_cdf_logistic_Qinv, 2);
  
  rb_define_module_function(mgsl_cdf, "pareto_P", rb_gsl_cdf_pareto_P, 3);
  rb_define_module_function(mgsl_cdf, "pareto_Q", rb_gsl_cdf_pareto_Q, 3);
  rb_define_module_function(mgsl_cdf, "pareto_Pinv", rb_gsl_cdf_pareto_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "pareto_Qinv", rb_gsl_cdf_pareto_Qinv, 3);

  rb_define_module_function(mgsl_cdf, "weibull_P", rb_gsl_cdf_weibull_P, 3);
  rb_define_module_function(mgsl_cdf, "weibull_Q", rb_gsl_cdf_weibull_Q, 3);
  rb_define_module_function(mgsl_cdf, "weibull_Pinv", rb_gsl_cdf_weibull_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "weibull_Qinv", rb_gsl_cdf_weibull_Qinv, 3);

  rb_define_module_function(mgsl_cdf, "gumbel1_P", rb_gsl_cdf_gumbel1_P, 3);
  rb_define_module_function(mgsl_cdf, "gumbel1_Q", rb_gsl_cdf_gumbel1_Q, 3);
  rb_define_module_function(mgsl_cdf, "gumbel1_Pinv", rb_gsl_cdf_gumbel1_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "gumbel1_Qinv", rb_gsl_cdf_gumbel1_Qinv, 3);

  rb_define_module_function(mgsl_cdf, "gumbel2_P", rb_gsl_cdf_gumbel2_P, 3);
  rb_define_module_function(mgsl_cdf, "gumbel2_Q", rb_gsl_cdf_gumbel2_Q, 3);
  rb_define_module_function(mgsl_cdf, "gumbel2_Pinv", rb_gsl_cdf_gumbel2_Pinv, 3);
  rb_define_module_function(mgsl_cdf, "gumbel2_Qinv", rb_gsl_cdf_gumbel2_Qinv, 3);

  /*****/

  cgsl_ran_discrete = rb_define_class_under(mgsl_ran, "Discrete", rb_cObject);
  rb_define_singleton_method(cgsl_ran_discrete, "new", rb_gsl_ran_discrete_new, 1);
  rb_define_singleton_method(cgsl_ran_discrete, "preproc", rb_gsl_ran_discrete_new, 1);
  rb_define_method(cgsl_rng, "discrete", rb_gsl_ran_discrete, 1);
  rb_define_module_function(mgsl_ran,  "discrete_pdf", rb_gsl_ran_discrete_pdf, 2);

#ifdef GSL_1_3_LATER
  rb_define_method(cgsl_rng, "dirichlet", rb_gsl_ran_dirichlet, -1);
  rb_define_module_function(mgsl_ran,  "dirichlet_pdf", rb_gsl_ran_dirichlet_pdf, 2);
  rb_define_module_function(mgsl_ran,  "dirichlet_lnpdf", rb_gsl_ran_dirichlet_lnpdf, 2);
#endif

}
