#ifdef HAVE_JACOBI_H
#include "include/rb_gsl.h"
#include "jacobi.h"

static VALUE jac_eval3_e(VALUE x, VALUE a, VALUE b,
                         int (*f)(double, double, double, gsl_sf_result*))
{
  gsl_sf_result *result;
  VALUE obj;
  obj = Data_Make_Struct(cgsl_sf_result, gsl_sf_result, 0, free, result);
  (*f)(NUM2DBL(x), NUM2DBL(a), NUM2DBL(b), result);
  return obj;
}

static VALUE jac_eval3(VALUE xx, VALUE aa, VALUE bb, double (*f)(double, double, double))
{
  gsl_vector *x, *y;
  double a, b;
  size_t i, len;
  VALUE ary;
  a = NUM2DBL(aa);
  b = NUM2DBL(bb);
  if (VECTOR_P(xx)) {
    Data_Get_Struct(xx, gsl_vector, x);
    y = gsl_vector_alloc(x->size);
    for (i = 0; i < x->size; i++) {
      gsl_vector_set(y, i, (*f)(gsl_vector_get(x, i), a, b));
    }
    return Data_Wrap_Struct(VECTOR_ROW_COL(CLASS_OF(xx)), 0, gsl_vector_free, y);
  } else if (TYPE(xx) == T_ARRAY) {
    //    len = RARRAY(xx)->len;
    len = RARRAY_LEN(xx);
    ary = rb_ary_new2(len);
    for (i = 0; i < len; i++) {
      rb_ary_store(ary, i, rb_float_new((*f)(NUM2DBL(rb_ary_entry(xx, i)), a, b)));
    }
    return ary;
#ifdef HAVE_NARRAY_H
  } else if (NA_IsNArray(xx)) {
    double *ptr1, *ptr2;
    struct NARRAY *na;
    GetNArray(xx, na);
    len = na->total;
    ptr1 = (double*) na->ptr;
    ary = na_make_object(NA_DFLOAT, na->rank, na->shape, CLASS_OF(xx));
    ptr2 = NA_PTR_TYPE(ary, double*);
    for (i = 0; i < len; i++) {
      ptr2[i] = (*f)(ptr1[i], a, b);
    }
    return ary;
#endif
  } else {
    return rb_float_new((*f)(NUM2DBL(xx), a, b));
  }
}

static VALUE rb_jac_jacobi_eval(int argc, VALUE *argv,
                                double (*f)(double, int, double, double),
                                int (*f2)(int, const double*, int, double*, double, double, double*))
{
  gsl_vector *x, *ws, *y;
  double a, b;
  VALUE ary;
  size_t len, i;
  int n, flag = 0;
  if (argc < 4) rb_raise(rb_eArgError, "Too few arguments (%d for >= 4)", argc);
  if (VECTOR_P(argv[0])) {
    Data_Get_Struct(argv[0], gsl_vector, x);
    y = gsl_vector_alloc(x->size);
    ary = Data_Wrap_Struct(VECTOR_ROW_COL(CLASS_OF(x)), 0, gsl_vector_free, y);
    switch (argc) {
    case 4:
      ws = gsl_vector_alloc(2*x->size);
      flag = 1;
      break;
    case 5:
      CHECK_VECTOR(argv[4]);
      Data_Get_Struct(argv[4], gsl_vector, ws);
      break;
    default:
      rb_raise(rb_eArgError, "Too many arguments (%d for 4 or 5)", argc);
    }
    (*f2)(x->size, x->data, FIX2INT(argv[1]), y->data, NUM2DBL(argv[2]), NUM2DBL(argv[3]),
          ws->data);
    if (flag == 1) gsl_vector_free(ws);
    return ary;
  } else if (TYPE(argv[0]) == T_ARRAY) {
    n = FIX2INT(argv[1]);
    a = NUM2DBL(argv[2]);
    b = NUM2DBL(argv[3]);
    //    len = RARRAY(argv[0])->len;
    len = RARRAY_LEN(argv[0]);
    ary = rb_ary_new2(len);
    for (i = 0; i < len; i++) {
      rb_ary_store(ary, i, rb_float_new((*f)(NUM2DBL(rb_ary_entry(argv[0], i)), n, a, b)));
    }
    return ary;
#ifdef HAVE_NARRAY_H
  } else if (NA_IsNArray(argv[0])) {
    double *ptr1, *ptr2;
    struct NARRAY *na;
    GetNArray(argv[0], na);
    len = na->total;
    ptr1 = (double*) na->ptr;
    ary = na_make_object(NA_DFLOAT, na->rank, na->shape, CLASS_OF(argv[0]));
    ptr2 = NA_PTR_TYPE(ary, double*);
    n = FIX2INT(argv[1]);
    a = NUM2DBL(argv[2]);
    b = NUM2DBL(argv[3]);
    ws = gsl_vector_alloc(len);
    (*f2)(len, ptr1, n, ptr2, a, b, ws->data);
    gsl_vector_free(ws);
    return ary;
#endif
  } else {
    return rb_float_new((*f)(NUM2DBL(argv[0]), FIX2INT(argv[1]), NUM2DBL(argv[2]), NUM2DBL(argv[3])));
  }
}
static VALUE rb_jac_jacobi_P0_e(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3_e(x, a, b, jac_jacobi_P0_e);
}

static VALUE rb_jac_jacobi_P0(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3(x, a, b, jac_jacobi_P0);
}

static VALUE rb_jac_jacobi_P1_e(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3_e(x, a, b, jac_jacobi_P1_e);
}

static VALUE rb_jac_jacobi_P1(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3(x, a, b, jac_jacobi_P1);
}


static VALUE rb_jac_jacobi(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_jacobi_eval(argc, argv, jac_jacobi, jac_jacobi_array);
}

static VALUE rb_jac_djacobi_P0_e(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3_e(x, a, b, jac_djacobi_P0_e);
}

static VALUE rb_jac_djacobi_P0(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3(x, a, b, jac_djacobi_P0);
}

static VALUE rb_jac_djacobi_P1_e(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3_e(x, a, b, jac_djacobi_P1_e);
}

static VALUE rb_jac_djacobi_P1(VALUE module, VALUE x, VALUE a, VALUE b)
{
  return jac_eval3(x, a, b, jac_djacobi_P1);
}

static VALUE rb_jac_djacobi(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_jacobi_eval(argc, argv, jac_djacobi, jac_djacobi_array);
}

static VALUE rb_jac_zeros_eval(int argc, VALUE *argv, VALUE module,
                               int (*f)(double*, int, double, double))
{
  gsl_vector *x;
  int m, status;
  double a, b;
  VALUE xx;
  switch (argc) {
  case 3:
    if (FIXNUM_P(argv[0])) {
      m = FIX2INT(argv[0]);
      a = NUM2DBL(argv[1]);
      b = NUM2DBL(argv[2]);
      x = gsl_vector_alloc(m);
      xx = Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, x);
    } else if (VECTOR_P(argv[0])) {
      Data_Get_Struct(argv[0], gsl_vector, x);
      m = x->size;
      a = NUM2DBL(argv[1]);
      b = NUM2DBL(argv[2]);
      xx = argv[0];
    } else {
      rb_raise(rb_eTypeError, "Wrong argument type %s (Fixnum or GSL::Vector expected)",
               rb_class2name(CLASS_OF(argv[0])));
    }
    break;
  case 4:
    CHECK_VECTOR(argv[0]);
    Data_Get_Struct(argv[0], gsl_vector, x);
    m = FIX2INT(argv[1]);
    a = NUM2DBL(argv[2]);
    b = NUM2DBL(argv[3]);
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments (%d for 3 or 4)", argc);
  }
  status = (*f)(x->data, m, a, b);
  if (status != GSL_SUCCESS)
    rb_raise(rb_eRuntimeError, "Something wrong. (error code %d)", status);
  return xx;
}

static VALUE rb_jac_jacobi_zeros(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_zeros_eval(argc, argv, module, jac_jacobi_zeros);
}

static void jac_define_const(VALUE module)
{
  rb_define_const(module, "GJ", INT2FIX(JAC_GJ));
  rb_define_const(module, "GLJ", INT2FIX(JAC_GLJ));
  rb_define_const(module, "GRJM", INT2FIX(JAC_GRJM));
  rb_define_const(module, "GRJP", INT2FIX(JAC_GRJP));
}

static VALUE rb_jac_quadrature_alloc(VALUE klass, VALUE vQ)
{
  jac_quadrature *q;

  q = jac_quadrature_alloc(FIX2INT(vQ));

  return Data_Wrap_Struct(klass, 0, jac_quadrature_free, q);
}

static VALUE rb_jac_quadrature_Q(VALUE obj)
{
  jac_quadrature *q;
  Data_Get_Struct(obj, jac_quadrature, q);
  return INT2FIX(q->Q);
}

static VALUE rb_jac_quadrature_type(VALUE obj)
{
  jac_quadrature *q;
  Data_Get_Struct(obj, jac_quadrature, q);
  return INT2FIX((int) q->type);
}

static VALUE rb_jac_quadrature_alpha(VALUE obj)
{
  jac_quadrature *q;
  Data_Get_Struct(obj, jac_quadrature, q);
  return NUM2DBL(q->alpha);
}

static VALUE rb_jac_quadrature_beta(VALUE obj)
{
  jac_quadrature *q;
  Data_Get_Struct(obj, jac_quadrature, q);
  return NUM2DBL(q->beta);
}

static VALUE rb_jac_quadrature_x(VALUE obj)
{
  jac_quadrature *q;
  gsl_vector_view *v;
  Data_Get_Struct(obj, jac_quadrature, q);
  v = gsl_vector_view_alloc();
  v->vector.data = q->x;
  v->vector.size = q->Q;
  v->vector.stride = 1;
  return Data_Wrap_Struct(cgsl_vector_view, 0, gsl_vector_view_free, v);
}

static VALUE rb_jac_quadrature_w(VALUE obj)
{
  jac_quadrature *q;
  gsl_vector_view *v;
  Data_Get_Struct(obj, jac_quadrature, q);
  v = gsl_vector_view_alloc();
  v->vector.data = q->w;
  v->vector.size = q->Q;
  v->vector.stride = 1;
  return Data_Wrap_Struct(cgsl_vector_view, 0, gsl_vector_view_free, v);
}

static VALUE rb_jac_quadrature_D(VALUE obj)
{
  jac_quadrature *q;
  gsl_vector_view *v;
  Data_Get_Struct(obj, jac_quadrature, q);
  v = gsl_vector_view_alloc();
  v->vector.data = q->D;
  v->vector.size = q->Q;
  v->vector.stride = 1;
  return Data_Wrap_Struct(cgsl_vector_view, 0, gsl_vector_view_free, v);
}

static VALUE rb_jac_quadrature_xp(VALUE obj)
{
  jac_quadrature *q;
  gsl_vector_view *v;
  Data_Get_Struct(obj, jac_quadrature, q);
  v = gsl_vector_view_alloc();
  v->vector.data = q->w;
  v->vector.size = q->np;
  v->vector.stride = 1;
  return Data_Wrap_Struct(cgsl_vector_view, 0, gsl_vector_view_free, v);
}

static VALUE rb_jac_interpmat_alloc(int argc, VALUE *argv, VALUE obj)
{
  int err;
  jac_quadrature *q;
  gsl_vector *xp;
  int np;
  Data_Get_Struct(obj, jac_quadrature, q);
  switch (argc) {
  case 1:
    CHECK_VECTOR(argv[0]);
    Data_Get_Struct(argv[0], gsl_vector, xp);
    np = xp->size;
    break;
  case 2:
    CHECK_VECTOR(argv[1]);
    Data_Get_Struct(argv[1], gsl_vector, xp);
    np = FIX2INT(argv[0]);
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments (%d for 1 or 2)", argc);
  }
  err = jac_interpmat_alloc(q, np, xp->data);
  return FIX2INT(err);
}

static VALUE rb_jac_interpmat_free(VALUE obj)
{
  jac_quadrature *q;
  Data_Get_Struct(obj, jac_quadrature, q);
  jac_interpmat_free(q);
  return Qtrue;
}

static VALUE rb_jac_quadrature_zwd(int argc, VALUE *argv, VALUE obj)
{
  jac_quadrature *q;
  gsl_vector *ws;
  int flag = 0, type, status;
  double a, b;
  Data_Get_Struct(obj, jac_quadrature, q);
  switch (argc) {
  case 3:
    type = FIX2INT(argv[0]);
    a = NUM2DBL(argv[1]);
    b = NUM2DBL(argv[2]);
    ws = gsl_vector_alloc(q->Q);
    flag = 1;
    break;
  case 4:
    type = FIX2INT(argv[0]);
    a = NUM2DBL(argv[1]);
    b = NUM2DBL(argv[2]);
    Data_Get_Struct(argv[3], gsl_vector, ws);
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments (%d for 3 or 4)", argc);
  }
  status = jac_quadrature_zwd(q, type, a, b, ws->data);
  if (flag == 1) gsl_vector_free(ws);
  return INT2FIX(status);
}

static VALUE rb_jac_integrate(VALUE obj, VALUE ff)
{
  jac_quadrature *q;
  gsl_vector *f;
  CHECK_VECTOR(ff);
  Data_Get_Struct(obj, jac_quadrature, q);
  Data_Get_Struct(ff, gsl_vector, f);
  return rb_float_new(jac_integrate(q, f->data));
}

static VALUE rb_jac_interpolate(int argc, VALUE *argv, VALUE obj)
{
  jac_quadrature *q;
  gsl_vector *f, *fout;
  VALUE vfout;
  switch (argc) {
  case 1:
    CHECK_VECTOR(argv[0]);
    Data_Get_Struct(argv[0], gsl_vector, f);
    fout = gsl_vector_alloc(f->size);
    vfout = Data_Wrap_Struct(VECTOR_ROW_COL(CLASS_OF(argv[0])), 0, gsl_vector_free, fout);
    break;
  case 2:
    CHECK_VECTOR(argv[0]);
    Data_Get_Struct(argv[0], gsl_vector, f);
    CHECK_VECTOR(argv[1]);
    Data_Get_Struct(argv[1], gsl_vector, fout);
    vfout = argv[1];
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments (%d for 1 or 2)", argc);
  }
  Data_Get_Struct(obj, jac_quadrature, q);
  jac_interpolate(q, f->data, fout->data);
  return vfout;
}

static VALUE rb_jac_differentiate(int argc, VALUE *argv, VALUE obj)
{
  jac_quadrature *q;
  gsl_vector *f, *fout;
  VALUE vfout;
  switch (argc) {
  case 1:
    CHECK_VECTOR(argv[0]);
    Data_Get_Struct(argv[0], gsl_vector, f);
    fout = gsl_vector_alloc(f->size);
    vfout = Data_Wrap_Struct(VECTOR_ROW_COL(CLASS_OF(argv[0])), 0, gsl_vector_free, fout);
    break;
  case 2:
    CHECK_VECTOR(argv[0]);
    Data_Get_Struct(argv[0], gsl_vector, f);
    CHECK_VECTOR(argv[1]);
    Data_Get_Struct(argv[1], gsl_vector, fout);
    vfout = argv[1];
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments (%d for 1 or 2)", argc);
  }
  Data_Get_Struct(obj, jac_quadrature, q);
  jac_differentiate(q, f->data, fout->data);
  return vfout;
}

/*****/
static VALUE rb_jac_qeval(int argc, VALUE *argv,
                          int (*f)(double*, double*, const int, double, double, double*))
{
  gsl_vector *z, *D, *ws;
  int Q;
  int flag = 0, status;
  double alpha, beta;
  VALUE vD;
  if (argc < 3) rb_raise(rb_eArgError, "Too few arguments (%d for >= 3)", argc);
  CHECK_VECTOR(argv[0]);
  Data_Get_Struct(argv[0], gsl_vector, z);
  argc -= 1;
  argv += 1;
  if (VECTOR_P(argv[argc-1])) {
    Data_Get_Struct(argv[argc-1], gsl_vector, ws);
    argc -= 1;
  } else {
    ws = gsl_vector_alloc(z->size);
    flag = 1;
  }
  switch (argc) {
  case 2:
    Q = z->size;
    D = gsl_vector_alloc(Q*Q);
    alpha = NUM2DBL(argv[0]);
    beta = NUM2DBL(argv[1]);
    vD = Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, D);
    break;
  case 4:
    Data_Get_Struct(argv[0], gsl_vector, D);
    vD = argv[0];
    Q = FIX2INT(argv[1]);
    alpha = NUM2DBL(argv[2]);
    beta = NUM2DBL(argv[3]);
    break;
  case 3:
    if (VECTOR_P(argv[0])) {
      Q = z->size;
      Data_Get_Struct(argv[0], gsl_vector, D);
      vD = argv[0];
    } else {
      Q = FIX2INT(argv[0]);
      D = gsl_vector_alloc(Q*Q);
      vD = Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, D);
    }
    alpha = NUM2DBL(argv[1]);
    beta = NUM2DBL(argv[2]);
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments.");
  }
  status = (*f)(z->data, D->data, Q, alpha, beta, ws->data);
  if (flag == 1) gsl_vector_free(ws);
  if (status != GSL_SUCCESS) rb_raise(rb_eRuntimeError, "Something wrong.");
  return vD;
}

static VALUE rb_jac_diffmat_gj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_diffmat_gj);
}

static VALUE rb_jac_diffmat_glj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_diffmat_glj);
}

static VALUE rb_jac_diffmat_grjm(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_diffmat_grjm);
}

static VALUE rb_jac_diffmat_grjp(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_diffmat_grjp);
}

static VALUE rb_jac_weights_gj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_weights_gj);
}

static VALUE rb_jac_weights_glj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_weights_glj);
}

static VALUE rb_jac_weights_grjm(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_weights_grjm);
}

static VALUE rb_jac_weights_grjp(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_qeval(argc, argv, jac_weights_grjp);
}

static VALUE rb_jac_zeros_gj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_zeros_eval(argc, argv, module, jac_zeros_gj);
}
static VALUE rb_jac_zeros_glj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_zeros_eval(argc, argv, module, jac_zeros_glj);
}
static VALUE rb_jac_zeros_grjm(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_zeros_eval(argc, argv, module, jac_zeros_grjm);
}
static VALUE rb_jac_zeros_grjp(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_zeros_eval(argc, argv, module, jac_zeros_grjp);
}

static VALUE rb_jac_lagrange_eval(int argc, VALUE *argv,
                                  double (*f)(int, double, int, double*, double, double))
{
  gsl_vector *z;
  int i, Q;
  double alpha, beta, zz;

  switch (argc) {
  case 5:
    i = FIX2INT(argv[0]);
    zz = NUM2DBL(argv[1]);
    CHECK_VECTOR(argv[2]);
    Data_Get_Struct(argv[2], gsl_vector, z);
    Q = z->size;
    alpha = NUM2DBL(argv[3]);
    beta = NUM2DBL(argv[4]);
    break;
  case 6:
    i = FIX2INT(argv[0]);
    zz = NUM2DBL(argv[1]);
    Q = FIX2INT(argv[2]);
    CHECK_VECTOR(argv[3]);
    Data_Get_Struct(argv[3], gsl_vector, z);
    alpha = NUM2DBL(argv[4]);
    beta = NUM2DBL(argv[5]);
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments (%d for 5 or 6)", argc);
  }
  return rb_float_new((*f)(i, zz, Q, z->data, alpha, beta));
}

static VALUE rb_jac_lagrange_gj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_lagrange_eval(argc, argv, jac_lagrange_gj);
}
static VALUE rb_jac_lagrange_glj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_lagrange_eval(argc, argv, jac_lagrange_glj);
}
static VALUE rb_jac_lagrange_grjm(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_lagrange_eval(argc, argv, jac_lagrange_grjm);
}

static VALUE rb_jac_lagrange_grjp(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_lagrange_eval(argc, argv, jac_lagrange_grjp);
}

static VALUE rb_jac_interpmat_eval(int argc, VALUE *argv,
                                   int (*f)(double*, double*, int, double*, int, double, double))
{
  gsl_vector *imat, *zp, *z;
  double alpha, beta;
  int np, Q, status;
  VALUE vimat;

  if (argc < 3) rb_raise(rb_eArgError, "Too few arguments (%d for >= 3)", argc);
  CHECK_VECTOR(argv[0]);
  if (VECTOR_P(argv[1])) {
    Data_Get_Struct(argv[0], gsl_vector, imat);
    Data_Get_Struct(argv[1], gsl_vector, zp);
    vimat = argv[0];
    if (FIXNUM_P(argv[2])) np = FIX2INT(argv[2]);
    argc -= 3;
    argv += 3;
  } else {
    Data_Get_Struct(argv[0], gsl_vector, zp);
    if (FIXNUM_P(argv[1])) np = FIX2INT(argv[1]);
    else np = zp->size;
    imat = gsl_vector_alloc(np);
    vimat = Data_Wrap_Struct(cgsl_vector, 0, gsl_vector_free, imat);
    argc -= 2;
    argv += 2;
  }
  CHECK_VECTOR(argv[0]);
  Data_Get_Struct(argv[0], gsl_vector, z);
  argc -= 1;
  argv += 1;
  switch (argc) {
  case 3:
    Q = FIX2INT(argv[0]);
    alpha = NUM2DBL(argv[1]);
    beta = NUM2DBL(argv[2]);
    break;
  case 2:
    Q = z->size;
    alpha = NUM2DBL(argv[0]);
    beta = NUM2DBL(argv[1]);
    break;
  default:
    rb_raise(rb_eArgError, "Wrong number of arguments.");
  }
  (*f)(imat->data, zp->data, np, z->data, Q, alpha, beta);
  if (status != GSL_SUCCESS) rb_raise(rb_eRuntimeError, "Some error.");
  return vimat;
}

static VALUE rb_jac_interpmat_gj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_interpmat_eval(argc, argv, jac_interpmat_gj);
}

static VALUE rb_jac_interpmat_glj(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_interpmat_eval(argc, argv, jac_interpmat_glj);
}
static VALUE rb_jac_interpmat_grjm(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_interpmat_eval(argc, argv, jac_interpmat_grjm);
}
static VALUE rb_jac_interpmat_grjp(int argc, VALUE *argv, VALUE module)
{
  return rb_jac_interpmat_eval(argc, argv, jac_interpmat_grjp);
}
void Init_jacobi(VALUE module)
{
  VALUE mjac, cjacq;

  mjac = rb_define_module("Jac");
  jac_define_const(mjac);
  cjacq = rb_define_class_under(mjac, "Quadrature", cGSL_Object);

  rb_define_module_function(mjac, "jacobi_P0_e", rb_jac_jacobi_P0_e, 3);
  rb_define_module_function(mjac, "jacobi_P0", rb_jac_jacobi_P0, 3);
  rb_define_module_function(mjac, "jacobi_P1_e", rb_jac_jacobi_P1_e, 3);
  rb_define_module_function(mjac, "jacobi_P1", rb_jac_jacobi_P1, 3);
  rb_define_module_function(mjac, "jacobi", rb_jac_jacobi, -1);
  rb_define_module_function(mjac, "djacobi_P0_e", rb_jac_djacobi_P0_e, 3);
  rb_define_module_function(mjac, "djacobi_P0", rb_jac_djacobi_P0, 3);
  rb_define_module_function(mjac, "djacobi_P1_e", rb_jac_djacobi_P1_e, 3);
  rb_define_module_function(mjac, "djacobi_P1", rb_jac_djacobi_P1, 3);
  rb_define_module_function(mjac, "djacobi", rb_jac_djacobi, 4);

  rb_define_module_function(mjac, "jacobi_zeros", rb_jac_jacobi_zeros, -1);

  /*****/
  rb_define_singleton_method(cjacq, "alloc", rb_jac_quadrature_alloc, 1);
  rb_define_method(cjacq, "Q", rb_jac_quadrature_Q, 0);
  rb_define_method(cjacq, "type", rb_jac_quadrature_type, 0);
  rb_define_method(cjacq, "alpha", rb_jac_quadrature_alpha, 0);
  rb_define_method(cjacq, "beta", rb_jac_quadrature_beta, 0);
  rb_define_method(cjacq, "x", rb_jac_quadrature_x, 0);
  rb_define_method(cjacq, "w", rb_jac_quadrature_w, 0);
  rb_define_method(cjacq, "D", rb_jac_quadrature_D, 0);
  rb_define_method(cjacq, "xp", rb_jac_quadrature_xp, 0);
  rb_define_method(cjacq, "interpmat_alloc", rb_jac_interpmat_alloc, -1);
  rb_define_method(cjacq, "interpmat_free", rb_jac_interpmat_free, 0);
  rb_define_method(cjacq, "zwd", rb_jac_quadrature_zwd, -1);
  rb_define_method(cjacq, "integrate", rb_jac_integrate, 1);
  rb_define_method(cjacq, "interpolate", rb_jac_interpolate, -1);
  rb_define_method(cjacq, "differentiate", rb_jac_differentiate, -1);
  /*****/
  rb_define_module_function(mjac, "diffmat_gj", rb_jac_diffmat_gj, -1);
  rb_define_module_function(mjac, "diffmat_glj", rb_jac_diffmat_glj, -1);
  rb_define_module_function(mjac, "diffmat_grjm", rb_jac_diffmat_grjm, -1);
  rb_define_module_function(mjac, "diffmat_grjp", rb_jac_diffmat_grjp, -1);

  rb_define_module_function(mjac, "weights_gj", rb_jac_weights_gj, -1);
  rb_define_module_function(mjac, "weights_glj", rb_jac_weights_glj, -1);
  rb_define_module_function(mjac, "weights_grjm", rb_jac_weights_grjm, -1);
  rb_define_module_function(mjac, "weights_grjp", rb_jac_weights_grjp, -1);

  rb_define_module_function(mjac, "zeros_gj", rb_jac_zeros_gj, -1);
  rb_define_module_function(mjac, "zeros_glj", rb_jac_zeros_glj, -1);
  rb_define_module_function(mjac, "zeros_grjm", rb_jac_zeros_grjm, -1);
  rb_define_module_function(mjac, "zeros_grjp", rb_jac_zeros_grjp, -1);

  rb_define_module_function(mjac, "lagrange_gj", rb_jac_lagrange_gj, -1);
  rb_define_module_function(mjac, "lagrange_glj", rb_jac_lagrange_glj, -1);
  rb_define_module_function(mjac, "lagrange_grjm", rb_jac_lagrange_grjm, -1);
  rb_define_module_function(mjac, "lagrange_grjp", rb_jac_lagrange_grjp, -1);

  rb_define_module_function(mjac, "interpmat_gj", rb_jac_interpmat_gj, -1);
  rb_define_module_function(mjac, "interpmat_glj", rb_jac_interpmat_glj, -1);
  rb_define_module_function(mjac, "interpmat_grjm", rb_jac_interpmat_grjm, -1);
  rb_define_module_function(mjac, "interpmat_grjp", rb_jac_interpmat_grjp, -1);

}

#endif

