/* !!!!!!!!! Editing !!!!!!!!!!! lapack.c LAPACK wrapper for Ruby/Numo (C) Copyright 2017 by Masahiro TANAKA This program is free software. NO WARRANTY. */ #include #include #include "numo/narray.h" #include "numo/template.h" // from ruby/ext/fiddle/fiddle.h #if defined(HAVE_DLFCN_H) # include # /* some stranger systems may not define all of these */ #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #else # if defined(_WIN32) # include # define dlopen(name,flag) ((void*)LoadLibrary(name)) # define dlerror() strerror(rb_w32_map_errno(GetLastError())) # define dlsym(handle,name) ((void*)GetProcAddress((handle),(name))) # define RTLD_LAZY -1 # define RTLD_NOW -1 # define RTLD_GLOBAL -1 # endif #endif #define lapack_complex_float scomplex #define lapack_complex_double dcomplex #include "lapacke.h" #include "lapacke_t.h" static void *lapack_handle = 0; static char *lapack_prefix = 0; VALUE numo_lapacke_option_value(VALUE value, VALUE default_value) { switch(TYPE(value)) { case T_NIL: case T_UNDEF: return default_value; } return value; } int numo_lapacke_option_order(VALUE order) { int opt; char *ptr; switch(TYPE(order)) { case T_NIL: case T_UNDEF: case T_FALSE: return LAPACK_ROW_MAJOR; case T_TRUE: return LAPACK_COL_MAJOR; case T_FIXNUM: opt = FIX2INT(order); if (opt == LAPACK_ROW_MAJOR || opt == LAPACK_COL_MAJOR) { return opt; } break; case T_SYMBOL: order = rb_sym2str(order); case T_STRING: ptr = RSTRING_PTR(order); if (RSTRING_LEN(order) > 0) { switch(ptr[0]){ case 'R': case 'r': return LAPACK_ROW_MAJOR; case 'C': case 'c': return LAPACK_COL_MAJOR; } } break; } rb_raise(rb_eArgError,"invalid value for LAPACKE_ORDER"); return 0; } char numo_lapacke_option_job(VALUE job, char true_char, char false_char) { char *ptr, c; switch(TYPE(job)) { case T_NIL: case T_UNDEF: case T_TRUE: return true_char; case T_FALSE: return false_char; case T_SYMBOL: job = rb_sym2str(job); case T_STRING: ptr = RSTRING_PTR(job); if (RSTRING_LEN(job) > 0) { c = ptr[0]; if (c >= 'a' && c <= 'z') { c -= 'a'-'A'; } return c; } break; } rb_raise(rb_eArgError,"invalid value for JOB option"); return 0; } char numo_lapacke_option_range(VALUE job, char true_char, char false_char) { char *ptr, c; switch(TYPE(job)) { case T_NIL: case T_UNDEF: case T_TRUE: return true_char; case T_FALSE: return false_char; case T_SYMBOL: job = rb_sym2str(job); case T_STRING: ptr = RSTRING_PTR(job); if (RSTRING_LEN(job) > 0) { c = ptr[0]; if (c >= 'a' && c <= 'z') { c -= 'a'-'A'; } return c; } break; } rb_raise(rb_eArgError,"invalid value for JOB option"); return 0; } char numo_lapacke_option_trans(VALUE trans) { int opt; char *ptr; switch(TYPE(trans)) { case T_NIL: case T_UNDEF: case T_FALSE: return 'N'; case T_TRUE: return 'T'; case T_FIXNUM: opt = FIX2INT(trans); if (opt >= 'N' && opt <= 'C') { return opt; } break; case T_SYMBOL: trans = rb_sym2str(trans); case T_STRING: ptr = RSTRING_PTR(trans); if (RSTRING_LEN(trans) > 0) { switch(ptr[0]){ case 'N': case 'n': return 'N'; case 'T': case 't': return 'T'; case 'C': case 'c': return 'C'; } } break; } rb_raise(rb_eArgError,"invalid value for LAPACKE_TRANSPOSE"); return 0; } char numo_lapacke_option_uplo(VALUE uplo) { int opt; char *ptr; switch(TYPE(uplo)) { case T_NIL: case T_UNDEF: case T_TRUE: return 'U'; case T_FALSE: return 'L'; case T_FIXNUM: opt = FIX2INT(uplo); switch(opt){ case 'U': case 'L': return opt; } break; case T_SYMBOL: uplo = rb_sym2str(uplo); case T_STRING: ptr = RSTRING_PTR(uplo); if (RSTRING_LEN(uplo) > 0) { switch(ptr[0]){ case 'U': case 'u': return 'U'; case 'L': case 'l': return 'L'; } } break; } rb_raise(rb_eArgError,"invalid value for LAPACKE_UPLO"); return 0; } char numo_lapacke_option_diag(VALUE diag) { int opt; char *ptr; switch(TYPE(diag)) { case T_NIL: case T_FALSE: case T_UNDEF: return 'N'; case T_TRUE: return 'U'; case T_FIXNUM: opt = FIX2INT(diag); switch(opt){ case 'N': case 'U': return opt; } break; case T_SYMBOL: diag = rb_sym2str(diag); case T_STRING: ptr = RSTRING_PTR(diag); if (RSTRING_LEN(diag) > 0) { switch(ptr[0]){ case 'N': case 'n': return 'N'; case 'U': case 'u': return 'U'; } } break; } rb_raise(rb_eArgError,"invalid value for LAPACKE_DIAG"); return 0; } char numo_lapacke_option_side(VALUE side) { int opt; char *ptr; switch(TYPE(side)) { case T_NIL: case T_UNDEF: case T_FALSE: return 'L'; case T_TRUE: return 'R'; case T_FIXNUM: opt = FIX2INT(side); switch(opt){ case 'L': case 'R': return opt; } break; case T_SYMBOL: side = rb_sym2str(side); case T_STRING: ptr = RSTRING_PTR(side); if (RSTRING_LEN(side) > 0) { switch(ptr[0]){ case 'L': case 'l': return 'L'; case 'R': case 'r': return 'R'; } } break; } rb_raise(rb_eArgError,"invalid value for LAPACKE_SIDE"); return 0; } void numo_lapacke_check_func(void **func, const char *name) { char *s, *error; if (*func==0) { if (lapack_handle==0) { rb_raise(rb_eRuntimeError,"LAPACK library is not loaded"); } if (lapack_prefix==0) { rb_raise(rb_eRuntimeError,"LAPACKE prefix is not set"); } s = alloca(strlen(lapack_prefix)+strlen(name)+1); strcpy(s,lapack_prefix); strcat(s,name); #if defined(HAVE_DLFCN_H) dlerror(); #endif *func = dlsym(lapack_handle, s); #if defined(HAVE_DLFCN_H) if ((error = dlerror()) != 0) { func = 0; } #endif if ( !func ) { rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", s); } } } /* module definition: Numo::Linalg */ static VALUE mLinalg; /* module definition: Numo::Linalg::Lapack */ static VALUE mLapack; static VALUE lapack_s_dlopen(int argc, VALUE *argv, VALUE mod) { int i, f; VALUE lib, flag; char *error; void *handle; i = rb_scan_args(argc, argv, "11", &lib, &flag); if (i==2) { f = NUM2INT(flag); } else { f = RTLD_LAZY; } #if defined(HAVE_DLFCN_H) dlerror(); #endif handle = dlopen(StringValueCStr(lib), f); #if defined(HAVE_DLFCN_H) if ( !handle && (error = dlerror()) ) { rb_raise(rb_eRuntimeError, "%s", error); } #else if ( !handle ) { error = dlerror(); rb_raise(rb_eRuntimeError, "%s", error); } #endif lapack_handle = handle; return Qnil; } static VALUE lapack_s_prefix_set(VALUE mod, VALUE prefix) { long len; if (TYPE(prefix) != T_STRING) { rb_raise(rb_eTypeError,"argument must be string"); } if (lapack_prefix) { free(lapack_prefix); } len = RSTRING_LEN(prefix); lapack_prefix = malloc(len+1); strcpy(lapack_prefix, StringValueCStr(prefix)); return prefix; } void Init_numo_linalg_lapack_s(); void Init_numo_linalg_lapack_d(); void Init_numo_linalg_lapack_c(); void Init_numo_linalg_lapack_z(); void Init_lapack(void) { VALUE mN; mN = rb_define_module("Numo"); /* Document-module: Numo::Linalg */ mLinalg = rb_define_module_under(mN, "Linalg"); mLapack = rb_define_module_under(mLinalg, "Lapack"); rb_define_module_function(mLapack, "dlopen", lapack_s_dlopen, -1); rb_define_module_function(mLapack, "prefix=", lapack_s_prefix_set, 1); lapack_prefix = malloc(strlen("LAPACKE_")+1); // default prefix strcpy(lapack_prefix,"LAPACKE_"); Init_numo_linalg_lapack_s(); Init_numo_linalg_lapack_d(); Init_numo_linalg_lapack_c(); Init_numo_linalg_lapack_z(); }