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

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

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

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



#line 1 "../gen/tmpl/cast_1d_contiguous.c"
static VALUE
cast_1d_contiguous(VALUE v1, VALUE type)
{
    narray_t *na;

    v1 = rb_funcall(type, rb_intern("cast"), 1, v1);
    GetNArray(v1,na);
    if (NA_NDIM(na) != 1) {
        rb_raise(nary_eShapeError, "argument should be 1-dimensional array");
    }
    if (!RTEST(na_check_contiguous(v1))) {
        v1 = na_copy(v1);
    }
    return v1;
}


#line 1 "../gen/tmpl/cast_2d_contiguous.c"
static VALUE
cast_2d_contiguous(VALUE v1, VALUE type)
{
    narray_t *na;

    v1 = rb_funcall(type, rb_intern("cast"), 1, v1);
    GetNArray(v1,na);
    if (NA_NDIM(na) != 2) {
        rb_raise(nary_eShapeError, "argument should be 2-dimensional array");
    }
    if (!RTEST(na_check_contiguous(v1))) {
        v1 = na_copy(v1);
    }
    return v1;
}


#line 1 "../gen/tmpl/class.c"
/*
  class definition: Numo::GSL::InterpAccel
*/

static VALUE cInterpAccel;

static void
interp_accel_free(void *ptr)
{
    gsl_interp_accel_free(ptr);
}

static size_t
interp_accel_memsize(const void *ptr)
{
    return sizeof(gsl_interp_accel);
}

static const rb_data_type_t interp_accel_data_type = {
    "Numo::GSL::InterpAccel",
    {NULL, interp_accel_free, interp_accel_memsize,},
    0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};



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

#line 5 "../gen/tmpl/c_new_void.c"
/*
  @overload new

  allocate instance of InterpAccel class.

This function returns a pointer to an accelerator object, which is a
kind of iterator for interpolation lookups.  It tracks the state of
lookups, thus allowing for application of various acceleration
strategies. */
static VALUE
interp_accel_s_new(VALUE self)
{
    gsl_interp_accel *w;
    w = gsl_interp_accel_alloc();
    if (!w) {
        rb_raise(rb_eNoMemError,"fail to allocate struct");
    }
    return TypedData_Wrap_Struct(cInterpAccel, &interp_accel_data_type, (void*)w);
}


#line 1 "../gen/tmpl/c_self_f_void.c"
/*
  @overload reset

  This function reinitializes the accelerator object acc.  It
should be used when the cached information is no longer
applicable---for example, when switching to a new dataset.
*/
static VALUE
interp_accel_reset(VALUE self)
{
    gsl_interp_accel *w;

    TypedData_Get_Struct(self, gsl_interp_accel, &interp_accel_data_type, w);
    gsl_interp_accel_reset(w);
    return self;
}


#line 1 "../gen/tmpl/class.c"
/*
  class definition: Numo::GSL::Spline
*/

static VALUE cSpline;

static void
spline_free(void *ptr)
{
    gsl_spline_free(ptr);
}

static size_t
spline_memsize(const void *ptr)
{
    return sizeof(gsl_spline);
}

static const rb_data_type_t spline_data_type = {
    "Numo::GSL::Spline",
    {NULL, spline_free, spline_memsize,},
    0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};



#line 1 "tmpl/interp_new.c"

#line 6 "tmpl/interp_new.c"
/*
  :nodoc:
 */
static VALUE
spline_s_new(VALUE self, const gsl_interp_type *t, VALUE v1, VALUE v2)
{
    gsl_spline *w;
    double *p1, *p2;
    size_t n1, n2, sz;

    v1 = cast_1d_contiguous(v1, cDF);
    v2 = cast_1d_contiguous(v2, cDF);
    n1 = RNARRAY_SIZE(v1);
    n2 = RNARRAY_SIZE(v2);
    sz = (n1 < n2) ? n1 : n2;
    w  = gsl_spline_alloc(t, sz);
    p1 = (double*)na_get_pointer_for_read(v1);
    p2 = (double*)na_get_pointer_for_read(v2);
    gsl_spline_init(w, p1, p2, sz);
    RB_GC_GUARD(v1);
    RB_GC_GUARD(v2);

    return TypedData_Wrap_Struct(cSpline, &spline_data_type, (void*)w);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::Linear class,
  a subclass of Numo::GSL::Spline class with gsl_interp_linear type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_linear_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_linear, v1, v2);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::Polynomial class,
  a subclass of Numo::GSL::Spline class with gsl_interp_polynomial type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_polynomial_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_polynomial, v1, v2);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::Cspline class,
  a subclass of Numo::GSL::Spline class with gsl_interp_cspline type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_cspline_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_cspline, v1, v2);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::CsplinePeriodic class,
  a subclass of Numo::GSL::Spline class with gsl_interp_cspline_periodic type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_cspline_periodic_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_cspline_periodic, v1, v2);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::Akima class,
  a subclass of Numo::GSL::Spline class with gsl_interp_akima type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_akima_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_akima, v1, v2);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::AkimaPeriodic class,
  a subclass of Numo::GSL::Spline class with gsl_interp_akima_periodic type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_akima_periodic_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_akima_periodic, v1, v2);
}


#line 1 "tmpl/interp_type_new.c"
/*
  @overload new(xa[],ya[])
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline::Steffen class,
  a subclass of Numo::GSL::Spline class with gsl_interp_steffen type.

  This function initializes the interpolation object interp for the
data (xa,ya) where xa and ya are arrays of size
size.  The interpolation object (gsl_interp) does not save
the data arrays xa and ya and only stores the static state
computed from the data.  The xa data array is always assumed to be
strictly ordered, with increasing x values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline_steffen_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return spline_s_new(self, gsl_interp_steffen, v1, v2);
}


#line 1 "../gen/tmpl/c_str_f_void.c"
/*
  @overload name
  @return [String]

  This function returns the name of the interpolation type used by interp.
For example,

printf ("interp uses '%s' interpolation.\n", 
        gsl_interp_name (interp));

would print something like,

interp uses 'cspline' interpolation.
*/
static VALUE
spline_name(VALUE self)
{
    gsl_spline *w;

    TypedData_Get_Struct(self, gsl_spline, &spline_data_type, w);

    return rb_str_new_cstr(gsl_spline_name(w));
}


#line 1 "../gen/tmpl/c_uint_f_void.c"
/*
  @overload min_size()
  @return [Integer]

  These functions return the minimum number of points required by the
interpolation object interp or interpolation type T.  For
example, Akima spline interpolation requires a minimum of 5 points.
*/
static VALUE
spline_min_size(VALUE self)
{
    gsl_spline *w;

    TypedData_Get_Struct(self, gsl_spline, &spline_data_type, w);

    return UINT2NUM(gsl_spline_min_size(w));
}


#line 1 "tmpl/spline_eval.c"
static void
iter_spline_eval(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2;
    ssize_t  s1, s2;
    double   x, y;
    void   **opts;
    gsl_spline *w;
    gsl_interp_accel *a;

    opts = (void **)(lp->opt_ptr);
    w = (gsl_spline*)(opts[0]);
    a = (gsl_interp_accel*)(opts[1]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        y = gsl_spline_eval(w, x, a);
        SET_DATA_STRIDE(p2,s2,double,y);
    }
}

/*
  @overload eval(x)
  @param  [DFloat]    x
  @return [DFloat]    result

  These functions return the interpolated value of y for a given
point x, using the interpolation object interp, data
arrays xa and ya and the accelerator acc.  When
x is outside the range of xa, the error code
GSL_EDOM is returned with a value of GSL_NAN for
y.
*/
static VALUE
spline_eval(VALUE self, VALUE v1)
{
    ndfunc_arg_in_t ain[1] = {{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline_eval, STRIDE_LOOP|NDF_EXTRACT, 1,1, ain,aout};
    gsl_spline *w;
    gsl_interp_accel *a;
    void *opts[2];
    VALUE vac, v;

    TypedData_Get_Struct(self, gsl_spline, &spline_data_type, w);
    opts[0] = w;

    vac = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac, gsl_interp_accel, &interp_accel_data_type, a);
    opts[1] = a;

    v = na_ndloop3(&ndf, opts, 1, v1);
    RB_GC_GUARD(vac);
    return v;
}


#line 1 "tmpl/spline_eval.c"
static void
iter_spline_eval_deriv(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2;
    ssize_t  s1, s2;
    double   x, y;
    void   **opts;
    gsl_spline *w;
    gsl_interp_accel *a;

    opts = (void **)(lp->opt_ptr);
    w = (gsl_spline*)(opts[0]);
    a = (gsl_interp_accel*)(opts[1]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        y = gsl_spline_eval_deriv(w, x, a);
        SET_DATA_STRIDE(p2,s2,double,y);
    }
}

/*
  @overload eval_deriv(x)
  @param  [DFloat]    x
  @return [DFloat]    result

  These functions return the derivative d of an interpolated
function for a given point x, using the interpolation object
interp, data arrays xa and ya and the accelerator
acc. 
*/
static VALUE
spline_eval_deriv(VALUE self, VALUE v1)
{
    ndfunc_arg_in_t ain[1] = {{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline_eval_deriv, STRIDE_LOOP|NDF_EXTRACT, 1,1, ain,aout};
    gsl_spline *w;
    gsl_interp_accel *a;
    void *opts[2];
    VALUE vac, v;

    TypedData_Get_Struct(self, gsl_spline, &spline_data_type, w);
    opts[0] = w;

    vac = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac, gsl_interp_accel, &interp_accel_data_type, a);
    opts[1] = a;

    v = na_ndloop3(&ndf, opts, 1, v1);
    RB_GC_GUARD(vac);
    return v;
}


#line 1 "tmpl/spline_eval.c"
static void
iter_spline_eval_deriv2(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2;
    ssize_t  s1, s2;
    double   x, y;
    void   **opts;
    gsl_spline *w;
    gsl_interp_accel *a;

    opts = (void **)(lp->opt_ptr);
    w = (gsl_spline*)(opts[0]);
    a = (gsl_interp_accel*)(opts[1]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        y = gsl_spline_eval_deriv2(w, x, a);
        SET_DATA_STRIDE(p2,s2,double,y);
    }
}

/*
  @overload eval_deriv2(x)
  @param  [DFloat]    x
  @return [DFloat]    result

  These functions return the second derivative d2 of an interpolated
function for a given point x, using the interpolation object
interp, data arrays xa and ya and the accelerator
acc. 
*/
static VALUE
spline_eval_deriv2(VALUE self, VALUE v1)
{
    ndfunc_arg_in_t ain[1] = {{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline_eval_deriv2, STRIDE_LOOP|NDF_EXTRACT, 1,1, ain,aout};
    gsl_spline *w;
    gsl_interp_accel *a;
    void *opts[2];
    VALUE vac, v;

    TypedData_Get_Struct(self, gsl_spline, &spline_data_type, w);
    opts[0] = w;

    vac = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac, gsl_interp_accel, &interp_accel_data_type, a);
    opts[1] = a;

    v = na_ndloop3(&ndf, opts, 1, v1);
    RB_GC_GUARD(vac);
    return v;
}


#line 1 "tmpl/spline_integ.c"
static void
iter_spline_eval_integ(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline *w;
    gsl_interp_accel *a;

    opts = (void **)(lp->opt_ptr);
    w = (gsl_spline*)(opts[0]);
    a = (gsl_interp_accel*)(opts[1]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline_eval_integ(w, x, y, a);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval_integ(a,b)
  @param  [DFloat]    a
  @param  [DFloat]    b
  @return [DFloat]    result

  These functions return the numerical integral result of an
interpolated function over the range [a, b], using the
interpolation object interp, data arrays xa and ya and
the accelerator acc.
*/
static VALUE
spline_eval_integ(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline_eval_integ, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline *w;
    gsl_interp_accel *a;
    void *opts[2];
    VALUE vac, v;

    TypedData_Get_Struct(self, gsl_spline, &spline_data_type, w);
    opts[0] = w;
    vac = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac, gsl_interp_accel, &interp_accel_data_type, a);
    opts[1] = a;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac);
    return v;
}


#line 1 "../gen/tmpl/class.c"
/*
  class definition: Numo::GSL::Spline2D
*/

static VALUE cSpline2D;

static void
spline2d_free(void *ptr)
{
    gsl_spline2d_free(ptr);
}

static size_t
spline2d_memsize(const void *ptr)
{
    return sizeof(gsl_spline2d);
}

static const rb_data_type_t spline2d_data_type = {
    "Numo::GSL::Spline2D",
    {NULL, spline2d_free, spline2d_memsize,},
    0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};



#line 1 "tmpl/interp2d_new.c"

#line 6 "tmpl/interp2d_new.c"
/*
  :nodoc:
 */
static VALUE
spline2d_s_new(VALUE self, const gsl_interp2d_type *t, VALUE v1, VALUE v2, VALUE v3)
{
    double *p1, *p2, *p3;
    size_t nx, ny;
    narray_t *na;
    gsl_spline2d *w;

    v1 = cast_1d_contiguous(v1, cDF);
    v2 = cast_1d_contiguous(v2, cDF);
    v3 = cast_2d_contiguous(v3, cDF);
    nx = RNARRAY_SIZE(v1);
    ny = RNARRAY_SIZE(v2);
    GetNArray(v3,na);
    if (na->shape[1] != nx || na->shape[0] != ny) {
        rb_raise(nary_eShapeError,"za.shape should be [ya.size,xa.size]");
    }
    w  = gsl_spline2d_alloc(t, nx, ny);
    p1 = (double*)na_get_pointer_for_read(v1);
    p2 = (double*)na_get_pointer_for_read(v2);
    p3 = (double*)na_get_pointer_for_read(v3);
    gsl_spline2d_init(w, p1, p2, p3, nx, ny);
    RB_GC_GUARD(v1);
    RB_GC_GUARD(v2);
    RB_GC_GUARD(v3);

    return TypedData_Wrap_Struct(cSpline2D, &spline2d_data_type, (void*)w);
}


#line 1 "tmpl/interp2d_type_new.c"
/*
  @overload new(spline,xa[],ya[])
  @param  [DFloat]  spline
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline2D::Bilinear class,
  a subclass of Numo::GSL::Spline2D class with gsl_interp2d_bilinear type.

  This function initializes the interpolation object interp for the
data (xa,ya,za) where xa and ya are arrays of
the x and y grid points of size xsize and ysize
respectively, and za is an array of function values of size
xsize*ysize.  The interpolation object (gsl_interp2d) does
not save the data arrays xa, ya, and za and only stores the
static state computed from the data. The xa and ya data arrays
are always assumed to be strictly ordered, with increasing x,y values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline2d_bilinear_s_new(VALUE self, VALUE v1, VALUE v2, VALUE v3)
{
    return spline2d_s_new(self, gsl_interp2d_bilinear, v1, v2, v3);
}


#line 1 "tmpl/interp2d_type_new.c"
/*
  @overload new(spline,xa[],ya[])
  @param  [DFloat]  spline
  @param  [DFloat]  xa[]
  @param  [DFloat]  ya[]

  Generate an instance of Numo::GSL::Spline2D::Bicubic class,
  a subclass of Numo::GSL::Spline2D class with gsl_interp2d_bicubic type.

  This function initializes the interpolation object interp for the
data (xa,ya,za) where xa and ya are arrays of
the x and y grid points of size xsize and ysize
respectively, and za is an array of function values of size
xsize*ysize.  The interpolation object (gsl_interp2d) does
not save the data arrays xa, ya, and za and only stores the
static state computed from the data. The xa and ya data arrays
are always assumed to be strictly ordered, with increasing x,y values; 
the behavior for other arrangements is not defined.

  */
static VALUE
spline2d_bicubic_s_new(VALUE self, VALUE v1, VALUE v2, VALUE v3)
{
    return spline2d_s_new(self, gsl_interp2d_bicubic, v1, v2, v3);
}


#line 1 "../gen/tmpl/c_str_f_void.c"
/*
  @overload name
  @return [String]

  This function returns the name of the interpolation type used by interp.
For example,

printf ("interp uses '%s' interpolation.\n", 
        gsl_interp2d_name (interp));

would print something like,

interp uses 'bilinear' interpolation.
*/
static VALUE
spline2d_name(VALUE self)
{
    gsl_spline2d *w;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);

    return rb_str_new_cstr(gsl_spline2d_name(w));
}


#line 1 "../gen/tmpl/c_uint_f_void.c"
/*
  @overload min_size()
  @return [Integer]

  These functions return the minimum number of points required by the
interpolation object interp or interpolation type T.  For
example, bicubic interpolation requires a minimum of 4 points.
*/
static VALUE
spline2d_min_size(VALUE self)
{
    gsl_spline2d *w;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);

    return UINT2NUM(gsl_spline2d_min_size(w));
}


#line 1 "tmpl/spline2d_eval.c"
static void
iter_spline2d_eval(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;

    opts = (void **)(lp->opt_ptr);
    w  = (gsl_spline2d*)(opts[0]);
    a1 = (gsl_interp_accel*)(opts[1]);
    a2 = (gsl_interp_accel*)(opts[2]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline2d_eval(w, x, y, a1, a2);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval(x,y)
  @param  [DFloat]    x
  @param  [DFloat]    y
  @return [DFloat]    result

  These functions return the interpolated value of z for a given
point (x,y), using the interpolation object interp, data
arrays xa, ya, and za and the accelerators xacc
and yacc.  When x is outside the range of xa or y
is outside the range of ya, the error code
GSL_EDOM is returned.
*/
static VALUE
spline2d_eval(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline2d_eval, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;
    void *opts[3];
    VALUE vac1, vac2, v;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);
    opts[0] = w;
    vac1 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac1, gsl_interp_accel, &interp_accel_data_type, a1);
    opts[1] = a1;
    vac2 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac2, gsl_interp_accel, &interp_accel_data_type, a2);
    opts[2] = a2;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac1);
    RB_GC_GUARD(vac2);
    return v;
}


#line 1 "tmpl/spline2d_eval.c"
static void
iter_spline2d_eval_deriv_x(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;

    opts = (void **)(lp->opt_ptr);
    w  = (gsl_spline2d*)(opts[0]);
    a1 = (gsl_interp_accel*)(opts[1]);
    a2 = (gsl_interp_accel*)(opts[2]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline2d_eval_deriv_x(w, x, y, a1, a2);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval_deriv_x(x,y)
  @param  [DFloat]    x
  @param  [DFloat]    y
  @return [DFloat]    result

  These functions return the interpolated value d
= \partial z / \partial x for a given point (x,y),
using the interpolation object interp, data
arrays xa, ya, and za and the accelerators xacc
and yacc.  When x is outside the range of xa or y
is outside the range of ya, the error code
GSL_EDOM is returned.
*/
static VALUE
spline2d_eval_deriv_x(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline2d_eval_deriv_x, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;
    void *opts[3];
    VALUE vac1, vac2, v;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);
    opts[0] = w;
    vac1 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac1, gsl_interp_accel, &interp_accel_data_type, a1);
    opts[1] = a1;
    vac2 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac2, gsl_interp_accel, &interp_accel_data_type, a2);
    opts[2] = a2;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac1);
    RB_GC_GUARD(vac2);
    return v;
}


#line 1 "tmpl/spline2d_eval.c"
static void
iter_spline2d_eval_deriv_y(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;

    opts = (void **)(lp->opt_ptr);
    w  = (gsl_spline2d*)(opts[0]);
    a1 = (gsl_interp_accel*)(opts[1]);
    a2 = (gsl_interp_accel*)(opts[2]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline2d_eval_deriv_y(w, x, y, a1, a2);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval_deriv_y(x,y)
  @param  [DFloat]    x
  @param  [DFloat]    y
  @return [DFloat]    result

  These functions return the interpolated value d
= \partial z / \partial y for a given point (x,y),
using the interpolation object interp, data
arrays xa, ya, and za and the accelerators xacc
and yacc.  When x is outside the range of xa or y
is outside the range of ya, the error code
GSL_EDOM is returned.
*/
static VALUE
spline2d_eval_deriv_y(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline2d_eval_deriv_y, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;
    void *opts[3];
    VALUE vac1, vac2, v;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);
    opts[0] = w;
    vac1 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac1, gsl_interp_accel, &interp_accel_data_type, a1);
    opts[1] = a1;
    vac2 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac2, gsl_interp_accel, &interp_accel_data_type, a2);
    opts[2] = a2;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac1);
    RB_GC_GUARD(vac2);
    return v;
}


#line 1 "tmpl/spline2d_eval.c"
static void
iter_spline2d_eval_deriv_xx(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;

    opts = (void **)(lp->opt_ptr);
    w  = (gsl_spline2d*)(opts[0]);
    a1 = (gsl_interp_accel*)(opts[1]);
    a2 = (gsl_interp_accel*)(opts[2]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline2d_eval_deriv_xx(w, x, y, a1, a2);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval_deriv_xx(x,y)
  @param  [DFloat]    x
  @param  [DFloat]    y
  @return [DFloat]    result

  These functions return the interpolated value d
= \partial^2 z / \partial x^2 for a given point (x,y),
using the interpolation object interp, data
arrays xa, ya, and za and the accelerators xacc
and yacc.  When x is outside the range of xa or y
is outside the range of ya, the error code
GSL_EDOM is returned.
*/
static VALUE
spline2d_eval_deriv_xx(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline2d_eval_deriv_xx, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;
    void *opts[3];
    VALUE vac1, vac2, v;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);
    opts[0] = w;
    vac1 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac1, gsl_interp_accel, &interp_accel_data_type, a1);
    opts[1] = a1;
    vac2 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac2, gsl_interp_accel, &interp_accel_data_type, a2);
    opts[2] = a2;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac1);
    RB_GC_GUARD(vac2);
    return v;
}


#line 1 "tmpl/spline2d_eval.c"
static void
iter_spline2d_eval_deriv_yy(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;

    opts = (void **)(lp->opt_ptr);
    w  = (gsl_spline2d*)(opts[0]);
    a1 = (gsl_interp_accel*)(opts[1]);
    a2 = (gsl_interp_accel*)(opts[2]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline2d_eval_deriv_yy(w, x, y, a1, a2);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval_deriv_yy(x,y)
  @param  [DFloat]    x
  @param  [DFloat]    y
  @return [DFloat]    result

  These functions return the interpolated value d
= \partial^2 z / \partial y^2 for a given point (x,y),
using the interpolation object interp, data
arrays xa, ya, and za and the accelerators xacc
and yacc.  When x is outside the range of xa or y
is outside the range of ya, the error code
GSL_EDOM is returned.
*/
static VALUE
spline2d_eval_deriv_yy(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline2d_eval_deriv_yy, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;
    void *opts[3];
    VALUE vac1, vac2, v;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);
    opts[0] = w;
    vac1 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac1, gsl_interp_accel, &interp_accel_data_type, a1);
    opts[1] = a1;
    vac2 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac2, gsl_interp_accel, &interp_accel_data_type, a2);
    opts[2] = a2;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac1);
    RB_GC_GUARD(vac2);
    return v;
}


#line 1 "tmpl/spline2d_eval.c"
static void
iter_spline2d_eval_deriv_xy(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    double   x, y, z;
    void   **opts;
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;

    opts = (void **)(lp->opt_ptr);
    w  = (gsl_spline2d*)(opts[0]);
    a1 = (gsl_interp_accel*)(opts[1]);
    a2 = (gsl_interp_accel*)(opts[2]);

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,y);
        z = gsl_spline2d_eval_deriv_xy(w, x, y, a1, a2);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload eval_deriv_xy(x,y)
  @param  [DFloat]    x
  @param  [DFloat]    y
  @return [DFloat]    result

  These functions return the interpolated value d
= \partial^2 z / \partial x \partial y for a given point (x,y),
using the interpolation object interp, data
arrays xa, ya, and za and the accelerators xacc
and yacc.  When x is outside the range of xa or y
is outside the range of ya, the error code
GSL_EDOM is returned.
*/
static VALUE
spline2d_eval_deriv_xy(VALUE self, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[2] = {{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spline2d_eval_deriv_xy, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};
    gsl_spline2d *w;
    gsl_interp_accel *a1, *a2;
    void *opts[3];
    VALUE vac1, vac2, v;

    TypedData_Get_Struct(self, gsl_spline2d, &spline2d_data_type, w);
    opts[0] = w;
    vac1 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac1, gsl_interp_accel, &interp_accel_data_type, a1);
    opts[1] = a1;
    vac2 = interp_accel_s_new(cInterpAccel);
    TypedData_Get_Struct(vac2, gsl_interp_accel, &interp_accel_data_type, a2);
    opts[2] = a2;
    v = na_ndloop3(&ndf, opts, 2, v1, v2);
    RB_GC_GUARD(vac1);
    RB_GC_GUARD(vac2);
    return v;
}


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

    


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

    /*
      Document-class: Numo::GSL::InterpAccel
      
    */
    {
    cInterpAccel = rb_define_class_under(mG, "InterpAccel", rb_cObject);
    
    rb_undef_alloc_func(cInterpAccel);
    rb_define_singleton_method(cInterpAccel, "new", interp_accel_s_new, 0);
    rb_define_method(cInterpAccel, "reset", interp_accel_reset, 0);
#line 10 "../gen/tmpl/init_class.c"
    }

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

    /*
      Document-class: Numo::GSL::Spline
      
    */
    {
    cSpline = rb_define_class_under(mG, "Spline", rb_cObject);
    
    rb_undef_alloc_func(cSpline);
    
    { VALUE cLinear = rb_define_class_under(cSpline, "Linear", cSpline);
      rb_define_singleton_method(cLinear, "new", spline_linear_s_new, 2); }
    { VALUE cPolynomial = rb_define_class_under(cSpline, "Polynomial", cSpline);
      rb_define_singleton_method(cPolynomial, "new", spline_polynomial_s_new, 2); }
    { VALUE cCspline = rb_define_class_under(cSpline, "Cspline", cSpline);
      rb_define_singleton_method(cCspline, "new", spline_cspline_s_new, 2); }
    { VALUE cCsplinePeriodic = rb_define_class_under(cSpline, "CsplinePeriodic", cSpline);
      rb_define_singleton_method(cCsplinePeriodic, "new", spline_cspline_periodic_s_new, 2); }
    { VALUE cAkima = rb_define_class_under(cSpline, "Akima", cSpline);
      rb_define_singleton_method(cAkima, "new", spline_akima_s_new, 2); }
    { VALUE cAkimaPeriodic = rb_define_class_under(cSpline, "AkimaPeriodic", cSpline);
      rb_define_singleton_method(cAkimaPeriodic, "new", spline_akima_periodic_s_new, 2); }
    { VALUE cSteffen = rb_define_class_under(cSpline, "Steffen", cSpline);
      rb_define_singleton_method(cSteffen, "new", spline_steffen_s_new, 2); }
    rb_define_method(cSpline, "name", spline_name, 0);
    rb_define_method(cSpline, "min_size", spline_min_size, 0);
    rb_define_method(cSpline, "eval", spline_eval, 1);
    rb_define_method(cSpline, "eval_deriv", spline_eval_deriv, 1);
    rb_define_method(cSpline, "eval_deriv2", spline_eval_deriv2, 1);
    rb_define_method(cSpline, "eval_integ", spline_eval_integ, 2);
#line 10 "../gen/tmpl/init_class.c"
    }

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

    /*
      Document-class: Numo::GSL::Spline2D
      
    */
    {
    cSpline2D = rb_define_class_under(mG, "Spline2D", rb_cObject);
    
    rb_undef_alloc_func(cSpline2D);
    
    { VALUE cBilinear = rb_define_class_under(cSpline2D, "Bilinear", cSpline2D);
      rb_define_singleton_method(cBilinear, "new", spline2d_bilinear_s_new, 3); }
    { VALUE cBicubic = rb_define_class_under(cSpline2D, "Bicubic", cSpline2D);
      rb_define_singleton_method(cBicubic, "new", spline2d_bicubic_s_new, 3); }
    rb_define_method(cSpline2D, "name", spline2d_name, 0);
    rb_define_method(cSpline2D, "min_size", spline2d_min_size, 0);
    rb_define_method(cSpline2D, "eval", spline2d_eval, 2);
    rb_define_method(cSpline2D, "eval_deriv_x", spline2d_eval_deriv_x, 2);
    rb_define_method(cSpline2D, "eval_deriv_y", spline2d_eval_deriv_y, 2);
    rb_define_method(cSpline2D, "eval_deriv_xx", spline2d_eval_deriv_xx, 2);
    rb_define_method(cSpline2D, "eval_deriv_yy", spline2d_eval_deriv_yy, 2);
    rb_define_method(cSpline2D, "eval_deriv_xy", spline2d_eval_deriv_xy, 2);
#line 10 "../gen/tmpl/init_class.c"
    }
#line 41 "../gen/tmpl/lib.c"
}
