
#line 1 "../gen/tmpl/lib.c"
/*
  gsl_Fit.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_fit.h>

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



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

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

static VALUE cLinearResult;

#line 1 "tmpl/fit_linear.c"
static void
iter_fit_s_linear(na_loop_t *const lp)
{
    size_t   n;
    char    *p1,*p2;
    double  *p3,*p4,*p5,*p6,*p7,*p8;
    ssize_t  s1, s2;

    n = lp->args[0].shape[0];
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = (double*)GET_PTR(lp,2);
    p4 = (double*)GET_PTR(lp,3);
    p5 = (double*)GET_PTR(lp,4);
    p6 = (double*)GET_PTR(lp,5);
    p7 = (double*)GET_PTR(lp,6);
    p8 = (double*)GET_PTR(lp,7);

    gsl_fit_linear((double*)p1,s1/sizeof(double),
                   (double*)p2,s2/sizeof(double),
                   n,p3,p4,p5,p6,p7,p8);
}

/*
  @overload linear(x,y)
  @param  [DFloat]    x (input array)
  @param  [DFloat]    y (input array)
  @return [GSL::Fit::LinearResult] result Struct with members: c0, c1, cov00, cov01, cov11, sumsq.

  This function computes the best-fit linear regression coefficients
(c0,c1) of the model Y = c_0 + c_1 X for the dataset
(x, y), two vectors of length n with strides
xstride and ystride.  The errors on y are assumed unknown so 
the variance-covariance matrix for the
parameters (c0, c1) is estimated from the scatter of the
points around the best-fit line and returned via the parameters
(cov00, cov01, cov11).   
The sum of squares of the residuals from the best-fit line is returned
in sumsq.  Note: the correlation coefficient of the data can be computed using gsl_stats_correlation (Correlation), it does not depend on the fit.

*/
static VALUE
fit_s_linear(VALUE mod, VALUE v1, VALUE v2)
{
    VALUE r, result;
    ndfunc_arg_in_t ain[2] = {{cDF,1},{cDF,1}};
    ndfunc_arg_out_t aout[6] = {{cDF,0},{cDF,0},{cDF,0},{cDF,0},{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_fit_s_linear, NO_LOOP|NDF_EXTRACT,
                     2, 6, ain, aout };
    narray_t *x, *y;

    GetNArray(v1,x);
    GetNArray(v2,y);
    CHECK_GE_1D(x);
    CHECK_GE_1D(y);
    CHECK_SIZE_EQ(VEC_SIZE(x),VEC_SIZE(y),"x size does not match y size");

    r = na_ndloop(&ndf, 2, v1, v2);
    result = rb_class_new_instance(6, RARRAY_PTR(r), cLinearResult);
    RB_GC_GUARD(r);
    return result;
}

static VALUE cWlinearResult;

#line 1 "tmpl/fit_wlinear.c"
static void
iter_fit_s_wlinear(na_loop_t *const lp)
{
    size_t   n;
    char    *p1,*p2,*p3;
    double  *p4,*p5,*p6,*p7,*p8,*p9;
    ssize_t  s1, s2, s3;

    n = lp->args[0].shape[0];
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);
    p4 = (double*)GET_PTR(lp,3);
    p5 = (double*)GET_PTR(lp,4);
    p6 = (double*)GET_PTR(lp,5);
    p7 = (double*)GET_PTR(lp,6);
    p8 = (double*)GET_PTR(lp,7);
    p9 = (double*)GET_PTR(lp,8);

    gsl_fit_wlinear((double*)p1,s1/sizeof(double),
                   (double*)p2,s2/sizeof(double),
                   (double*)p3,s3/sizeof(double),
                   n,p4,p5,p6,p7,p8,p9);
}

/*
  @overload wlinear(x,w,y)
  @param  [DFloat]    x (input array)
  @param  [DFloat]    w (input array)
  @param  [DFloat]    y (input array)
  @return [GSL::Fit::WlinearResult] result Struct with members: c0, c1, cov00, cov01, cov11, chisq.

  This function computes the best-fit linear regression coefficients
(c0,c1) of the model Y = c_0 + c_1 X for the weighted
dataset (x, y), two vectors of length n with strides
xstride and ystride.  The vector w, of length n
and stride wstride, specifies the weight of each datapoint. The
weight is the reciprocal of the variance for each datapoint in y.

The covariance matrix for the parameters (c0, c1) is
computed using the weights and returned via the parameters
(cov00, cov01, cov11).  The weighted sum of squares
of the residuals from the best-fit line, \chi^2, is returned in
chisq.

*/
static VALUE
fit_s_wlinear(VALUE mod, VALUE v1, VALUE v2, VALUE v3)
{
    ndfunc_arg_in_t ain[3] = {{cDF,1},{cDF,1},{cDF,1}};
    ndfunc_arg_out_t aout[6] = {{cDF,0},{cDF,0},{cDF,0},{cDF,0},{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_fit_s_wlinear, STRIDE_LOOP_NIP|NDF_EXTRACT,
                     3, 6, ain, aout };
    narray_t *x, *y, *w;
    VALUE r, result;

    GetNArray(v1,x);
    GetNArray(v2,y);
    GetNArray(v3,w);
    CHECK_GE_1D(x);
    CHECK_GE_1D(y);
    CHECK_GE_1D(w);
    CHECK_SIZE_EQ(VEC_SIZE(x),VEC_SIZE(y),"y size does not match x size");
    CHECK_SIZE_EQ(VEC_SIZE(x),VEC_SIZE(w),"w size does not match x size");

    r = na_ndloop(&ndf, 3, v1, v2, v3);
    result = rb_class_new_instance(6, RARRAY_PTR(r), cWlinearResult);
    RB_GC_GUARD(r);
    return result;
}


#line 1 "tmpl/fit_linear_est.c"
static void
iter_fit_s_linear_est(na_loop_t *const lp)
{
    size_t   i;
    char    *p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8;
    ssize_t  s1, s2, s3, s4, s5, s6, s7, s8;
    double   x,c0,c1,cov00,cov01,cov11,y,ye;

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);
    INIT_PTR(lp, 3, p4, s4);
    INIT_PTR(lp, 4, p5, s5);
    INIT_PTR(lp, 5, p6, s6);
    INIT_PTR(lp, 6, p7, s7);
    INIT_PTR(lp, 7, p8, s8);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,c0);
        GET_DATA_STRIDE(p3,s3,double,c1);
        GET_DATA_STRIDE(p4,s4,double,cov00);
        GET_DATA_STRIDE(p5,s5,double,cov01);
        GET_DATA_STRIDE(p6,s6,double,cov11);
        gsl_fit_linear_est(x, c0, c1, cov00, cov01, cov11, &y, &ye);
        SET_DATA_STRIDE(p7,s7,double,y);
        SET_DATA_STRIDE(p8,s8,double,ye);
    }
}

/*
  @overload linear_est(x,linear_result)
  @param  [DFloat]    x
  @param  [(L|Wl)inearResult]  linear_result  Result of GSL::Fit.linear|wlinear
  @return [[DFloat,DFloat]] array of (y, y_err).

  This function uses the best-fit linear regression coefficients
c0, c1 and their covariance
cov00, cov01, cov11 to compute the fitted function
y and its standard deviation y_err for the model Y =
c_0 + c_1 X at the point x.

*/
static VALUE
fit_s_linear_est(VALUE mod, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[6] = {{cDF,0},{cDF,0},{cDF,0},{cDF,0},{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[2] = {{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_fit_s_linear_est, STRIDE_LOOP_NIP|NDF_EXTRACT,
                     6, 2, ain, aout };
    VALUE c0, c1, cov00, cov01, cov11;

    c0 = RSTRUCT_GET(v2,0);
    c1 = RSTRUCT_GET(v2,1);
    cov00 = RSTRUCT_GET(v2,2);
    cov01 = RSTRUCT_GET(v2,3);
    cov11 = RSTRUCT_GET(v2,4);
    return na_ndloop(&ndf, 6, v1, c0, c1, cov00, cov01, cov11);
}

static VALUE cMulResult;

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

    n = lp->args[0].shape[0];
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    p3 = (double*)GET_PTR(lp,2);
    p4 = (double*)GET_PTR(lp,3);
    p5 = (double*)GET_PTR(lp,4);

    gsl_fit_mul((double*)p1,s1/sizeof(double),
                   (double*)p2,s2/sizeof(double),
                   n,p3,p4,p5);
}

/*
  @overload mul(x,y)
  @param  [DFloat]    x (input array)
  @param  [DFloat]    y (input array)
  @return [GSL::Fit::MulResult] result Struct with members: c1, cov11, sumsq.

  This function computes the best-fit linear regression coefficient
c1 of the model Y = c_1 X for the datasets (x,
y), two vectors of length n with strides xstride and
ystride.  The errors on y are assumed unknown so the 
variance of the parameter c1 is estimated from
the scatter of the points around the best-fit line and returned via the
parameter cov11.  The sum of squares of the residuals from the
best-fit line is returned in sumsq.

*/
static VALUE
fit_s_mul(VALUE mod, VALUE v1, VALUE v2)
{
    VALUE r, result;
    ndfunc_arg_in_t ain[2] = {{cDF,1},{cDF,1}};
    ndfunc_arg_out_t aout[3] = {{cDF,0},{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_fit_s_mul, STRIDE_LOOP_NIP|NDF_EXTRACT,
                     2, 3, ain, aout };
    narray_t *x,*y;

    GetNArray(v1,x);
    GetNArray(v2,y);
    CHECK_GE_1D(x);
    CHECK_GE_1D(y);
    CHECK_SIZE_EQ(VEC_SIZE(x),VEC_SIZE(y),"x size does not match y size");

    r = na_ndloop(&ndf, 2, v1, v2);
    result = rb_class_new_instance(3, RARRAY_PTR(r), cMulResult);
    RB_GC_GUARD(r);
    return result;
}

static VALUE cWmulResult;

#line 1 "tmpl/fit_wmul.c"
static void
iter_fit_s_wmul(na_loop_t *const lp)
{
    size_t   n;
    char    *p1,*p2,*p3;
    double  *p4,*p5,*p6;
    ssize_t  s1, s2, s3;

    n = lp->args[0].shape[0];
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);
    p4 = (double*)GET_PTR(lp,3);
    p5 = (double*)GET_PTR(lp,4);
    p6 = (double*)GET_PTR(lp,5);

    gsl_fit_wmul((double*)p1,s1/sizeof(double),
                   (double*)p2,s2/sizeof(double),
                   (double*)p3,s3/sizeof(double),
                   n,p4,p5,p6);
}

/*
  @overload wmul(x,w,y)
  @param  [DFloat]    x (input array)
  @param  [DFloat]    w (input array)
  @param  [DFloat]    y (input array)
  @return [GSL::Fit::WmulResult] result Struct with members: c1, cov11, sumsq.

  This function computes the best-fit linear regression coefficient
c1 of the model Y = c_1 X for the weighted datasets
(x, y), two vectors of length n with strides
xstride and ystride.  The vector w, of length n
and stride wstride, specifies the weight of each datapoint. The
weight is the reciprocal of the variance for each datapoint in y.

The variance of the parameter c1 is computed using the weights
and returned via the parameter cov11.  The weighted sum of
squares of the residuals from the best-fit line, \chi^2, is
returned in chisq.

*/
static VALUE
fit_s_wmul(VALUE mod, VALUE v1, VALUE v2, VALUE v3)
{
    VALUE r, result;
    ndfunc_arg_in_t ain[3] = {{cDF,1},{cDF,1},{cDF,1}};
    ndfunc_arg_out_t aout[3] = {{cDF,0},{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_fit_s_wmul, STRIDE_LOOP_NIP|NDF_EXTRACT,
                     3, 3, ain, aout };
    narray_t *x,*y,*w;

    GetNArray(v1,x);
    GetNArray(v2,y);
    GetNArray(v3,w);
    CHECK_GE_1D(x);
    CHECK_GE_1D(y);
    CHECK_GE_1D(w);
    CHECK_SIZE_EQ(VEC_SIZE(x),VEC_SIZE(y),"y size does not match x size");
    CHECK_SIZE_EQ(VEC_SIZE(x),VEC_SIZE(w),"w size does not match x size");

    r = na_ndloop(&ndf, 3, v1, v2, v3);
    result = rb_class_new_instance(3, RARRAY_PTR(r), cWmulResult);
    RB_GC_GUARD(r);
    return result;
}


#line 1 "tmpl/fit_mul_est.c"
static void
iter_fit_s_mul_est(na_loop_t *const lp)
{
    size_t   i;
    char    *p1,*p2,*p3,*p4,*p5;
    ssize_t  s1, s2, s3, s4, s5;
    double   x,c1,cov11,y,ye;

    INIT_COUNTER(lp, i);
    INIT_PTR(lp, 0, p1, s1);
    INIT_PTR(lp, 1, p2, s2);
    INIT_PTR(lp, 2, p3, s3);
    INIT_PTR(lp, 3, p4, s4);
    INIT_PTR(lp, 4, p5, s5);

    for (; i--; ) {
        GET_DATA_STRIDE(p1,s1,double,x);
        GET_DATA_STRIDE(p2,s2,double,c1);
        GET_DATA_STRIDE(p3,s3,double,cov11);
        gsl_fit_mul_est(x, c1, cov11, &y, &ye);
        SET_DATA_STRIDE(p4,s4,double,y);
        SET_DATA_STRIDE(p5,s5,double,ye);
    }
}

/*
  @overload mul_est(x, mul_result)
  @param  [DFloat]    x
  @param  [(M|Wm)ulResult]  mul_result  Result of GSL::Fit.mul|wmul
  @return [[DFloat,DFloat]] array of [y,y_err]

  This function uses the best-fit linear regression coefficient c1
and its covariance cov11 to compute the fitted function
y and its standard deviation y_err for the model Y =
c_1 X at the point x.

*/
static VALUE
fit_s_mul_est(VALUE mod, VALUE v1, VALUE v2)
{
    ndfunc_arg_in_t ain[3] = {{cDF,0},{cDF,0},{cDF,0}};
    ndfunc_arg_out_t aout[2] = {{cDF,0},{cDF,0}};
    ndfunc_t ndf = { iter_fit_s_mul_est, STRIDE_LOOP_NIP|NDF_EXTRACT,
                     3, 2, ain, aout };
    VALUE c1, cov11;

    c1 = RSTRUCT_GET(v2,0);
    cov11 = RSTRUCT_GET(v2,1);
    return na_ndloop(&ndf, 3, v1, c1, cov11);
}


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

    


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

    /*
      Document-module: Numo::GSL::Fit
      
    */
    {
    
    mFit = rb_define_module_under(mG, "Fit");
    
    
    rb_define_module_function(mFit, "linear", fit_s_linear, 2);
    /*
      Document-class: Numo::GSL::Fit::LinearResult
      */
    cLinearResult = rb_struct_define_under(mFit,"LinearResult","c0","c1","cov00","cov01","cov11","sumsq",NULL);
    rb_define_module_function(mFit, "wlinear", fit_s_wlinear, 3);
    /*
      Document-class: Numo::GSL::Fit::WlinearResult
      */
    cWlinearResult = rb_struct_define_under(mFit,"WlinearResult","c0","c1","cov00","cov01","cov11","chisq",NULL);
    rb_define_module_function(mFit, "linear_est", fit_s_linear_est, 2);
    rb_define_module_function(mFit, "mul", fit_s_mul, 2);
    /*
      Document-class: Numo::GSL::Fit::MulResult
      */
    cMulResult = rb_struct_define_under(mFit,"MulResult","c1","cov11","sumsq",NULL);
    rb_define_module_function(mFit, "wmul", fit_s_wmul, 3);
    /*
      Document-class: Numo::GSL::Fit::WmulResult
      */
    cWmulResult = rb_struct_define_under(mFit,"WmulResult","c1","cov11","sumsq",NULL);
    rb_define_module_function(mFit, "mul_est", fit_s_mul_est, 2);
#line 12 "../gen/tmpl/init_module.c"
    }
#line 41 "../gen/tmpl/lib.c"
}
