
#line 1 "../gen/tmpl/lib.c"
/*
  gsl_SpMatrix.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_spmatrix.h>
#include <gsl/gsl_spblas.h>
#include <gsl/gsl_splinalg.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::SpMatrix
*/

static VALUE cSpMatrix;

static void
spmatrix_free(void *ptr)
{
    gsl_spmatrix_free(ptr);
}

static size_t
spmatrix_memsize(const void *ptr)
{
    return sizeof(gsl_spmatrix);
}

static const rb_data_type_t spmatrix_data_type = {
    "Numo::GSL::SpMatrix",
    {NULL, spmatrix_free, spmatrix_memsize,},
    0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};





#line 1 "tmpl/spmatrix_new.c"


#line 6 "tmpl/spmatrix_new.c"
/*
  @overload new(n1,n2,[nzmax,sptype])
  @param  [Integer]  n1
  @param  [Integer]  n2
  @param  [Ingeger]  nzmax
  @param  [Ingeger]  sptype   (default = GSL_SPMATRIX_TRIPLET)

  This function allocates a sparse matrix of size n1-by-n2 and
initializes it to all zeros. If the size of the matrix is not known at allocation
time, both n1 and n2 may be set to 1, and they will automatically
grow as elements are added to the matrix. The parameter nzmax specifies
the maximum number of non-zero elements which will be added to the matrix.
It does not need to be precisely known in advance, since storage space will 
automatically grow using gsl_spmatrix_realloc if nzmax is not
large enough. Accurate knowledge of this parameter reduces the number of
reallocation calls required. The parameter sptype specifies the
storage format of the sparse matrix. Possible values are
The allocated gsl_spmatrix structure is of size O(nzmax).
  */
static VALUE
spmatrix_s_new(int argc, VALUE *argv, VALUE klass)
{
    gsl_spmatrix *w;
    int narg;
    size_t sptype = GSL_SPMATRIX_TRIPLET;
    VALUE  n1, n2, v3, v4;

    narg = rb_scan_args(argc,argv,"22",&n1,&n2,&v3,&v4);
    switch(narg) {
    case 4:
        sptype = NUM2SIZET(v4);
    case 3:
        w = gsl_spmatrix_alloc_nzmax(NUM2SIZET(n1),NUM2SIZET(n2),NUM2SIZET(v3),sptype);
        break;
    case 2:
        w = gsl_spmatrix_alloc(NUM2SIZET(n1),NUM2SIZET(n2));
        break;
    default:
        rb_raise(rb_eArgError,"invalid number of argument: %d for 2..4",argc);
    }
    if (!w) {
        rb_raise(rb_eNoMemError,"fail to allocate struct");
    }
    return TypedData_Wrap_Struct(cSpMatrix, &spmatrix_data_type, (void*)w);
}


#line 1 "../gen/tmpl/c_self_f_sizet.c"
/*
  @overload realloc(m)
  @param  [Integer]   m
  @return [Numo::GSL::SpMatrix]   self

  This function reallocates the storage space for m to accomodate
nzmax non-zero elements. It is typically called internally by
gsl_spmatrix_set if the user wants to add more elements to the
sparse matrix than the previously specified nzmax.
*/
static VALUE
spmatrix_realloc(VALUE self, VALUE v1)
{
    gsl_spmatrix *w;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);

    
    gsl_spmatrix_realloc(NUM2SIZET(v1),w);
    
#line 20 "../gen/tmpl/c_self_f_sizet.c"
    return self;
}


#line 1 "../gen/tmpl/c_DFloat_f_SZ_x2.c"
static void
iter_spmatrix_get(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    size_t   x, y;
    double   z;
    gsl_spmatrix *w = (gsl_spmatrix*)(lp->opt_ptr);
    

    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,size_t,x);
        GET_DATA_STRIDE(p2,s2,size_t,y);
        z = gsl_spmatrix_get(w,x,y);
        SET_DATA_STRIDE(p3,s3,double,z);
    }
}

/*
  @overload get(i,j)
  @param  [UInt]      i
  @param  [UInt]      j
  @return [DFloat]    result

  This function returns element (i,j) of the matrix m.
The matrix may be in triplet or compressed format.
*/
static VALUE
spmatrix_get(VALUE self, VALUE v1, VALUE v2)
{
    gsl_spmatrix *w;
    ndfunc_arg_in_t ain[2] = {{cSZ,0},{cSZ,0}};
    ndfunc_arg_out_t aout[1] = {{cDF,0}};
    ndfunc_t ndf = {iter_spmatrix_get, STRIDE_LOOP|NDF_EXTRACT, 2,1, ain,aout};

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);

    return na_ndloop3(&ndf, w, 2, v1, v2);
}


#line 1 "../gen/tmpl/c_self_f_SZ_x2_DFloat.c"
static void
iter_spmatrix_set(na_loop_t *const lp)
{
    size_t   i;
    char    *p1, *p2, *p3;
    ssize_t  s1, s2, s3;
    size_t   x, y;
    double   z;
    gsl_spmatrix *w = (gsl_spmatrix*)(lp->opt_ptr);
    

    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,size_t,x);
        GET_DATA_STRIDE(p2,s2,size_t,y);
        GET_DATA_STRIDE(p3,s3,double,z);
        gsl_spmatrix_set(w,x,y,z);
    }
}

/*
  @overload set(i,j,j)
  @param  [UInt]      i
  @param  [UInt]      j
  @param  [DFloat]    x
  @return [DFloat]    self

  This function sets element (i,j) of the matrix m to
the value x. The matrix must be in triplet representation.
*/
static VALUE
spmatrix_set(VALUE self, VALUE v1, VALUE v2, VALUE v3)
{
    gsl_spmatrix *w;
    ndfunc_arg_in_t ain[3] = {{cSZ,0},{cSZ,0},{cDF,0}};
    ndfunc_t ndf = {iter_spmatrix_set, STRIDE_LOOP|NDF_EXTRACT, 3,0, ain,0};

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);

    na_ndloop3(&ndf, w, 3, v1, v2, v3);
    return self;
}


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

  This function sets (or resets) all the elements of the matrix m to zero.
*/
static VALUE
spmatrix_set_zero(VALUE self)
{
    gsl_spmatrix *w;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);
    gsl_spmatrix_set_zero(w);
    return self;
}


#line 1 "../gen/tmpl/c_self_f_other.c"
/*
  @overload memcpy(src)
  @param  [Numo::GSL::SpMatrix]  src other
  @return [Numo::GSL::SpMatrix]  self

  This function copies the elements of the sparse matrix src into
dest. The two matrices must have the same dimensions and be in the
same storage format.
*/
static VALUE
spmatrix_memcpy(VALUE self, VALUE other)
{
    gsl_spmatrix *w, *x;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);
    TypedData_Get_Struct(other, gsl_spmatrix, &spmatrix_data_type, x);
    gsl_spmatrix_memcpy(w,x);
    return self;
}


#line 1 "../gen/tmpl/c_self_f_other.c"
/*
  @overload transpose_memcpy(src)
  @param  [Numo::GSL::SpMatrix]  src other
  @return [Numo::GSL::SpMatrix]  self

  This function copies the transpose of the sparse matrix src into
dest. The dimensions of dest must match the transpose of the
matrix src. Also, both matrices must use the same sparse storage
format.
*/
static VALUE
spmatrix_transpose_memcpy(VALUE self, VALUE other)
{
    gsl_spmatrix *w, *x;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);
    TypedData_Get_Struct(other, gsl_spmatrix, &spmatrix_data_type, x);
    gsl_spmatrix_transpose_memcpy(w,x);
    return self;
}


#line 1 "tmpl/spmatrix_add.c"
/*
  @overload add(other)
  @param  [Numo::GSL::SpMatrix]  other
  @return [Numo::GSL::SpMatrix]  result = self + other

  This function computes the sum c = a + b. The three matrices must
have the same dimensions and be stored in compressed column format.
*/
static VALUE
spmatrix_add(VALUE self, VALUE other)
{
    gsl_spmatrix *a, *b, *c;
    VALUE result;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, a);
    TypedData_Get_Struct(other, gsl_spmatrix, &spmatrix_data_type, b);

    c = gsl_spmatrix_alloc_nzmax(a->size1, a->size2, a->nzmax+b->nzmax, a->sptype);
    result = TypedData_Wrap_Struct(cSpMatrix, &spmatrix_data_type, (void*)c);

    gsl_spmatrix_add(c,a,b);
    return result;
}


#line 1 "../gen/tmpl/c_self_f_double.c"
/*
  @overload scale(x)
  @param  [Float]     x
  @return [Numo::GSL::SpMatrix]   self

  This function scales all elements of the matrix m by the constant
factor x. The result m(i,j) \leftarrow x m(i,j) is stored in m.
*/
static VALUE
spmatrix_scale(VALUE self, VALUE v1)
{
    gsl_spmatrix *w;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);

    gsl_spmatrix_scale(w, NUM2DBL(v1));
    return self;
}


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

  This function returns the number of non-zero elements in m.
*/
static VALUE
spmatrix_nnz(VALUE self)
{
    gsl_spmatrix *w;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);

    return SIZET2NUM(gsl_spmatrix_nnz(w));
}


#line 1 "../gen/tmpl/c_self_f_other.c"
/*
  @overload equal(b)
  @param  [Numo::GSL::SpMatrix]  b other
  @return [Numo::GSL::SpMatrix]  self

  This function returns 1 if the matrices a and b are equal (by comparison of
element values) and 0 otherwise. The matrices a and b must be either
both triplet format or both compressed format for comparison.
*/
static VALUE
spmatrix_equal(VALUE self, VALUE other)
{
    gsl_spmatrix *w, *x;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);
    TypedData_Get_Struct(other, gsl_spmatrix, &spmatrix_data_type, x);
    gsl_spmatrix_equal(w,x);
    return self;
}


#line 1 "../gen/tmpl/c_double_x2_f_void.c"
/*
  @overload minmax()
  @return [Array]   array of [min_out,max_out]

  This function returns the minimum and maximum elements of the matrix
m, storing them in min_out and max_out, and searching
only the non-zero values.
*/
static VALUE
spmatrix_minmax(VALUE self)
{
    gsl_spmatrix *w;
    double d1, d2;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, w);

    gsl_spmatrix_minmax(w, &d1, &d2);
    return rb_assoc_new(DBL2NUM(d1),DBL2NUM(d2));
}


#line 1 "../gen/tmpl/c_other_f_void.c"
/*
  @overload compcol()
  @return [Numo::GSL::SpMatrix]

 This function creates a sparse matrix in compressed column format
from the input sparse matrix T which must be in triplet format.
A pointer to a newly allocated matrix is returned. The calling function
should free the newly allocated matrix when it is no longer needed.
 */
static VALUE
spmatrix_compcol(VALUE self)
{
    gsl_spmatrix *x, *w;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, x);

    w = gsl_spmatrix_compcol(x);
    if (!w) {
        rb_raise(rb_eNoMemError,"fail to allocate struct");
    }
    return TypedData_Wrap_Struct(cSpMatrix, &spmatrix_data_type, (void*)w);
}


#line 1 "tmpl/spmatrix_d2sp.c"

#line 4 "tmpl/spmatrix_d2sp.c"
/*
  @overload d2sp(nary)
  @param  [Numo::DFloat]          nary
  @return [Numo::GSL::SpMatrix]  result

  This function converts the dense matrix A into sparse triplet format
and stores the result in S.
*/
static VALUE
spmatrix_s_d2sp(VALUE klass, VALUE nary)
{
    gsl_spmatrix *s;
    gsl_matrix *m;
    narray_t *na;

    nary = cast_2d_contiguous(nary,cDF);
    GetNArray(nary,na);

    ALLOCA_GSL_MATRIX_FROM_NARRAY_R(nary,m);
    s = gsl_spmatrix_alloc(na->shape[0], na->shape[1]);

    gsl_spmatrix_d2sp(s, m);

    RB_GC_GUARD(nary);
    return TypedData_Wrap_Struct(cSpMatrix, &spmatrix_data_type, (void*)s);
}


#line 1 "tmpl/spmatrix_sp2d.c"
/*
  @overload sp2d
  @return [DFloat]  result

  This function converts the sparse matrix S into a dense matrix and
stores the result in A. S must be in triplet format.
*/
static VALUE
spmatrix_sp2d(VALUE self)
{
    gsl_spmatrix *s;
    gsl_matrix *m;
    size_t shape[2];
    VALUE result;

    TypedData_Get_Struct(self, gsl_spmatrix, &spmatrix_data_type, s);

    shape[0] = s->size1;
    shape[1] = s->size2;
    result = rb_narray_new(cDF, 2, shape);

    ALLOCA_GSL_MATRIX_FROM_NARRAY_W(result,m);

    gsl_spmatrix_sp2d(m,s);
    return result;
}


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

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




#line 1 "tmpl/spblas_dgemv.c"

#line 4 "tmpl/spblas_dgemv.c"
/*
  @overload dgemv(trans_a, alpha, a, x, beta, y)
  @param  [Integer]             trans_a = NO_TRANS | TRANS
  @param  [Float]               alpha
  @param  [Numo::GSL::SpMatrix] a (input sparse matrix)
  @param  [Numo::DFloat]        x (input vector)
  @param  [Float]               beta
  @param  [Numo::DFloat]        y (input|output vector)
  @return [Numo::DFloat]        result (or y)

  This function computes the matrix-vector product and sum
y \leftarrow \alpha op(A) x + \beta y, where
op(A) = A, A^T for TransA = CblasNoTrans,
CblasTrans. In-place computations are not supported, so
x and y must be distinct vectors.
The matrix A may be in triplet or compressed format.
*/
static VALUE
spblas_s_dgemv(VALUE mod, VALUE vTransA, VALUE valpha, VALUE va, VALUE vx, VALUE vbeta, VALUE vy)
{
    // y = alpha A x + beta y
    CBLAS_TRANSPOSE_t TransA;
    double alpha;
    gsl_spmatrix *A;
    gsl_vector *x;
    double beta;
    gsl_vector *y;

    TransA = NUM2INT(vTransA);
    alpha = NUM2DBL(valpha);
    beta = NUM2DBL(vbeta);
    TypedData_Get_Struct(va, gsl_spmatrix, &spmatrix_data_type, A);

    vx = cast_1d_contiguous(vx, cDF);
    ALLOCA_GSL_VECTOR_FROM_NARRAY_R(vx, x);
    vy = cast_1d_contiguous(vy, cDF);
    if (!TEST_INPLACE(vy)) {
        vy = na_copy(vy);
    }
    ALLOCA_GSL_VECTOR_FROM_NARRAY_RW(vy, y);

    gsl_spblas_dgemv(TransA, alpha, A, x, beta, y);
    RB_GC_GUARD(vx);
    return vy;
}


#line 1 "tmpl/spblas_dgemm.c"

#line 4 "tmpl/spblas_dgemm.c"
/*
  @overload dgemm(alpha, a, b)
  @param  [Float]               alpha
  @param  [Numo::GSL::SpMatrix] a (sparse matrix)
  @param  [Numo::GSL::SpMatrix] b (sparse matrix)
  @return [Numo::DFloat]        result C = A B

  This function computes the sparse matrix-matrix product
C = \alpha A B. The matrices must be in compressed format.
*/
static VALUE
spblas_s_dgemm(VALUE mod, VALUE valpha, VALUE va, VALUE vb)
{
    // C = A B
    double alpha;
    gsl_spmatrix *A;
    gsl_spmatrix *B;
    gsl_spmatrix *C;
    VALUE vc;

    alpha = NUM2DBL(valpha);
    TypedData_Get_Struct(va, gsl_spmatrix, &spmatrix_data_type, A);
    TypedData_Get_Struct(vb, gsl_spmatrix, &spmatrix_data_type, B);

    C = gsl_spmatrix_alloc_nzmax(A->size1,B->size2,A->nzmax+B->nzmax,A->sptype);
    vc = TypedData_Wrap_Struct(cSpMatrix, &spmatrix_data_type, C);

    gsl_spblas_dgemm(alpha, A, B, C);

    RB_GC_GUARD(va);
    RB_GC_GUARD(vb);
    return vc;
}


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

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


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

static VALUE cIterSolve;

static void
splinalg_itersolve_free(void *ptr)
{
    gsl_splinalg_itersolve_free(ptr);
}

static size_t
splinalg_itersolve_memsize(const void *ptr)
{
    return sizeof(gsl_splinalg_itersolve);
}

static const rb_data_type_t splinalg_itersolve_data_type = {
    "Numo::GSL::SpLinalg::IterSolve",
    {NULL, splinalg_itersolve_free, splinalg_itersolve_memsize,},
    0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};



#line 1 "tmpl/itersolve_new.c"

#line 6 "tmpl/itersolve_new.c"
/*
  :nodoc:
 */
static VALUE
splinalg_itersolve_s_new(VALUE self, const gsl_splinalg_itersolve_type *t, VALUE v1, VALUE v2)
{
    gsl_splinalg_itersolve *w;
    size_t n, m;

    n = NUM2SIZET(v1);
    m = NUM2SIZET(v2);
    w = gsl_splinalg_itersolve_alloc(t, n, m);
    if (!w) {
        rb_raise(rb_eNoMemError,"fail to allocate struct");
    }
    return TypedData_Wrap_Struct(cIterSolve, &splinalg_itersolve_data_type, (void*)w);
}


#line 1 "tmpl/itersolve_type_new.c"
/*
  @overload new(n, m)
  @param  [DFloat]  n
  @param  [DFloat]  m

  Generate an instance of Numo::GSL::SpLinalg::IterSolve::Gmres class,
  a subclass of Numo::GSL::SpLinalg::IterSolve class with gsl_splinalg_itersolve_gmres type.

  This function allocates a workspace for the iterative solution of
n-by-n sparse matrix systems. The iterative solver type
is specified by T. The argument m specifies the size
of the solution candidate subspace {\cal K}_m. The dimension
m may be set to 0 in which case a reasonable default value is used.

  */
static VALUE
splinalg_itersolve_gmres_s_new(VALUE self, VALUE v1, VALUE v2)
{
    return splinalg_itersolve_s_new(self, gsl_splinalg_itersolve_gmres, v1, v2);
}


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

  This function returns a string pointer to the name of the solver.
*/
static VALUE
splinalg_itersolve_name(VALUE self)
{
    gsl_splinalg_itersolve *w;

    TypedData_Get_Struct(self, gsl_splinalg_itersolve, &splinalg_itersolve_data_type, w);

    return rb_str_new_cstr(gsl_splinalg_itersolve_name(w));
}


#line 1 "tmpl/itersolve_iterate.c"

#line 4 "tmpl/itersolve_iterate.c"
/*
  @overload iterate(a, b, tol, x)
  @param  [Numo::GSL::SpMatrix] a (input sparse matrix)
  @param  [Numo::DFloat]        b (input vector)
  @param  [Float]               tol
  @param  [Numo::DFloat]        x (input|output vector)
  @return [Integer]             returns GSL::CONTINUE=-2 to signal that more iterations are required.

  This function performs one iteration of the iterative method for
the sparse linear system specfied by the matrix A, right hand
side vector b and solution vector x. On input, x
must be set to an initial guess for the solution. On output,
x is updated to give the current solution estimate. The
parameter tol specifies the relative tolerance between the residual
norm and norm of b in order to check for convergence.
When the following condition is satisfied:
|| A x - b || <= tol * || b ||
the method has converged, the function returns GSL_SUCCESS and
the final solution is provided in x. Otherwise, the function
returns GSL_CONTINUE to signal that more iterations are
required. Here, || \cdot || represents the Euclidean norm.
The input matrix A may be in triplet or compressed column
format.
*/
static VALUE
splinalg_itersolve_s_iterate(VALUE self, VALUE vA, VALUE vb, VALUE vtol, VALUE vx)
{
    gsl_spmatrix *A;
    gsl_vector *b, *x;
    double tol;
    gsl_splinalg_itersolve *w;
    narray_t *na;
    int status;

    TypedData_Get_Struct(self, gsl_splinalg_itersolve, &splinalg_itersolve_data_type, w);

    TypedData_Get_Struct(vA, gsl_spmatrix, &spmatrix_data_type, A);

    vb = cast_1d_contiguous(vb, cDF);
    ALLOCA_GSL_VECTOR_FROM_NARRAY_R(vb, b);
    tol = NUM2DBL(vtol);

    if (CLASS_OF(vx) != cDF) {
        rb_raise(rb_eTypeError, "x should be Numo::DFloat");
    }
    GetNArray(vx,na);
    if (NA_NDIM(na) != 1) {
        rb_raise(nary_eShapeError, "x should be 1-dimensional array");
    }
    if (!RTEST(na_check_contiguous(vx))) {
        rb_raise(nary_eOperationError, "x should be contiguous array");
    }
    ALLOCA_GSL_VECTOR_FROM_NARRAY_RW(vx, x);

    status = gsl_splinalg_itersolve_iterate(A, b, tol, x, w);
    RB_GC_GUARD(vb);
    return INT2FIX(status);
}


#line 1 "../gen/tmpl/c_double_f_void.c"
/*
  @overload normr
  @return [Float]

  This function returns the current residual norm
||r|| = ||A x - b||, which is updated after each call to
gsl_splinalg_itersolve_iterate.
*/
static VALUE
splinalg_itersolve_normr(VALUE self)
{
    gsl_splinalg_itersolve *w;

    TypedData_Get_Struct(self, gsl_splinalg_itersolve, &splinalg_itersolve_data_type, w);

    return DBL2NUM(gsl_splinalg_itersolve_normr(w));
}


#line 28 "../gen/tmpl/lib.c"
void
Init_spmatrix(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::SpMatrix
      
    */
    {
    cSpMatrix = rb_define_class_under(mG, "SpMatrix", rb_cObject);
    
    /*This flag specifies compressed column storage.*/
    rb_define_const(cSpMatrix,"CCS",INT2FIX(GSL_SPMATRIX_CCS));
    /*This flag specifies triplet storage. */
    rb_define_const(cSpMatrix,"TRIPLET",INT2FIX(GSL_SPMATRIX_TRIPLET));
    rb_undef_alloc_func(cSpMatrix);
    rb_define_singleton_method(cSpMatrix, "new", spmatrix_s_new, -1);
    rb_define_method(cSpMatrix, "realloc", spmatrix_realloc, 1);
    rb_define_method(cSpMatrix, "get", spmatrix_get, 2);
    rb_define_method(cSpMatrix, "set", spmatrix_set, 3);
    rb_define_method(cSpMatrix, "set_zero", spmatrix_set_zero, 0);
    rb_define_method(cSpMatrix, "memcpy", spmatrix_memcpy, 1);
    rb_define_method(cSpMatrix, "transpose_memcpy", spmatrix_transpose_memcpy, 1);
    rb_define_method(cSpMatrix, "add", spmatrix_add, 1);
    rb_define_method(cSpMatrix, "scale", spmatrix_scale, 1);
    rb_define_method(cSpMatrix, "nnz", spmatrix_nnz, 0);
    rb_define_method(cSpMatrix, "equal", spmatrix_equal, 1);
    rb_define_method(cSpMatrix, "minmax", spmatrix_minmax, 0);
    rb_define_method(cSpMatrix, "compcol", spmatrix_compcol, 0);
    rb_define_singleton_method(cSpMatrix, "d2sp", spmatrix_s_d2sp, 1);
    rb_define_method(cSpMatrix, "sp2d", spmatrix_sp2d, 0);
#line 10 "../gen/tmpl/init_class.c"
    }

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

    /*
      Document-module: Numo::GSL::SpBlas
      
    */
    {
    
    mSpBlas = rb_define_module_under(mG, "SpBlas");
    
    
    /**/
    rb_define_const(mSpBlas,"NOTRANS",INT2FIX(CblasNoTrans));
    /**/
    rb_define_const(mSpBlas,"TRANS",INT2FIX(CblasTrans));
    rb_define_module_function(mSpBlas, "dgemv", spblas_s_dgemv, 6);
    rb_define_module_function(mSpBlas, "dgemm", spblas_s_dgemm, 3);
#line 12 "../gen/tmpl/init_module.c"
    }

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

    /*
      Document-module: Numo::GSL::SpLinalg
      
    */
    {
    
    mSpLinalg = rb_define_module_under(mG, "SpLinalg");
    
    
    
#line 1 "../gen/tmpl/init_class.c"

    /*
      Document-class: Numo::GSL::SpLinalg::IterSolve
      
    */
    {
    cIterSolve = rb_define_class_under(mSpLinalg, "IterSolve", rb_cObject);
    
    rb_undef_alloc_func(cIterSolve);
    
    { VALUE cGmres = rb_define_class_under(cIterSolve, "Gmres", cIterSolve);
      rb_define_singleton_method(cGmres, "new", splinalg_itersolve_gmres_s_new, 2); }
    rb_define_method(cIterSolve, "name", splinalg_itersolve_name, 0);
    rb_define_singleton_method(cIterSolve, "iterate", splinalg_itersolve_s_iterate, 4);
    rb_define_method(cIterSolve, "normr", splinalg_itersolve_normr, 0);
#line 10 "../gen/tmpl/init_class.c"
    }

#line 12 "../gen/tmpl/init_module.c"
    }
#line 41 "../gen/tmpl/lib.c"
}
