/* narray.c Numerical Array Extention for Ruby (C) Copyright 1999-2003 by Masahiro TANAKA This program is free software. You can distribute/modify this program under the same terms as Ruby itself. NO WARRANTY. */ int isascii(int c){ c = c & 0x000000ff; if (0 <= c && c <= 127){ return 1; } else { return 0; } } int __isascii(int c){ c = c & 0x000000ff; if (0 <= c && c <= 127){ return 1; } else { return 0; } } #include #include #include "narray.h" #include "narray_local.h" #if RUBY_VERSION_CODE < 150 #define NARRAY_GC #endif /* global variables within this module */ VALUE cNArray, cNArrayScalar, cComplex; ID na_id_beg, na_id_end, na_id_exclude_end; ID na_id_minus, na_id_abs, na_id_power; ID na_id_compare, na_id_and, na_id_or; ID na_id_class_dim; ID na_id_add, na_id_sbt, na_id_mul, na_id_div, na_id_mod; ID na_id_real, na_id_imag; ID na_id_coerce_rev; ID na_id_new; static ID na_id_to_i, na_id_usec, na_id_now; const int na_sizeof[NA_NTYPES+1] = { 0, sizeof(u_int8_t), sizeof(int16_t), sizeof(int32_t), sizeof(float), sizeof(double), sizeof(scomplex), sizeof(dcomplex), sizeof(VALUE), 0 }; const char *na_typestring[] = { "none", "byte", /* 1 */ "sint", /* 2 */ "int", /* 3 */ "sfloat", /* 4 */ "float", /* 5 */ "scomplex", /* 6 */ "complex", /* 7 */ "object", /* 8 */ "ntypes" /* 9 */ }; #ifdef NARRAY_GC static int mem_count = 0; static int na_gc_freq = 2500000; /* Frequency of Garbage Collection */ #endif void Init_fftw(void); void Init_nmath(void); void Init_na_funcs(void); void Init_na_linalg(void); void Init_na_random(void); #ifdef DEBUG void na_xfree(void *ptr) { if (!ptr) abort(); free(ptr); } #endif /* mark items */ static void na_mark_obj(struct NARRAY *ary) { int i; VALUE *ptr; ptr = (VALUE*) ary->ptr; for (i=ary->total; i>0; i--) rb_gc_mark(*ptr++); } static void na_mark_ref(struct NARRAY *ary) { struct NARRAY *a2; rb_gc_mark( ary->ref ); GetNArray(ary->ref,a2); if (a2->type == NA_ROBJ) na_mark_obj(a2); } static void na_free(struct NARRAY* ary) { if ( ary->total > 0 ) { if (ary->ref == Qnil || ary->ref == Qtrue) { /* non reference */ xfree(ary->ptr); } xfree(ary->shape); #ifdef DEBUG ary->shape = NULL; ary->ptr = NULL; #endif } xfree(ary); } /* allocation of NARRAY */ struct NARRAY* na_alloc_struct(int type, int rank, int *shape) { int total=1; int i, memsz; struct NARRAY *ary; for (i=0; irank = ary->total = 0; ary->shape = NULL; ary->ptr = NULL; ary->type = type; } else { memsz = na_sizeof[type] * total; /* Garbage Collection */ #ifdef NARRAY_GC mem_count += memsz; if ( mem_count > na_gc_freq ) { rb_gc(); mem_count=0; } #endif ary = ALLOC(struct NARRAY); ary->shape = ALLOC_N(int, rank); ary->ptr = ALLOC_N(char, memsz); ary->rank = rank; ary->total = total; ary->type = type; for (i=0; ishape[i] = shape[i]; } ary->ref = Qtrue; return ary; } static void na_check_class_narray(VALUE v) { if (TYPE(v) != T_CLASS) { rb_raise(rb_eRuntimeError, "class required"); } while (v) { if (v == cNArray || RCLASS(v)->m_tbl == RCLASS(cNArray)->m_tbl) return; v = RCLASS(v)->super; } rb_raise(rb_eRuntimeError, "need NArray or its subclass"); } static VALUE na_wrap_struct_class(struct NARRAY *ary, VALUE klass) { VALUE v; int class_dim; /* Extract element */ if (ary->rank==0 && ary->total==1) { SetFuncs[NA_ROBJ][ary->type](1,&v,0,ary->ptr,0); na_free(ary); return v; } /* check NArray >= klass */ na_check_class_narray(klass); /* Check dimension */ class_dim = NUM2INT(rb_const_get(klass, na_id_class_dim)); if (ary->rank < class_dim) rb_raise(rb_eTypeError, "array.dim(=%i) < CLASS_DIMENSION(=%i)", ary->rank, class_dim); if (ary->ref == Qnil) rb_raise(rb_eRuntimeError, "already wrapped object"); /* Turn on WRAPPED flag */ if (ary->ref == Qtrue) { ary->ref = Qnil; if (NA_IsROBJ(ary)) return Data_Wrap_Struct(klass, na_mark_obj, na_free, ary); else return Data_Wrap_Struct(klass, 0, na_free, ary); } /* reference to another NArray*/ return Data_Wrap_Struct(klass, na_mark_ref, na_free, ary); } static VALUE na_wrap_struct(struct NARRAY *ary, VALUE obj) { return na_wrap_struct_class(ary,CLASS_OF(obj)); } VALUE na_make_object(int type, int rank, int *shape, VALUE klass) { struct NARRAY *na; na = na_alloc_struct(type, rank, shape); if (type==NA_ROBJ) { rb_mem_clear((VALUE*)(na->ptr), na->total); } return na_wrap_struct_class(na, klass); } /* restriction: Integer, Float, Complex === obj */ VALUE na_make_scalar(VALUE obj, int type) { static int shape=1; VALUE v; struct NARRAY *ary; v = na_make_object(type,1,&shape,cNArrayScalar); GetNArray(v,ary); SetFuncs[ary->type][NA_ROBJ](1, ary->ptr,0, &obj,0); return v; } VALUE na_make_empty(int type, VALUE klass) { struct NARRAY *na; na = na_alloc_struct(type, 0, NULL); return na_wrap_struct_class(na, klass); } /* allocate reference to NArray */ struct NARRAY* na_ref_alloc_struct(VALUE obj) { int i; struct NARRAY *orig, *ary; GetNArray(obj,orig); if (orig->rank<=0) rb_raise(rb_eRuntimeError, "cannot create NArrayRefer of Empty NArray"); ary = ALLOC(struct NARRAY); ary->shape = ALLOC_N(int, orig->rank); ary->ptr = orig->ptr; ary->rank = orig->rank; ary->total = orig->total; ary->type = orig->type; for (i=0; irank; i++) ary->shape[i] = orig->shape[i]; ary->ref = obj; return ary; } /* method: self.refer */ static VALUE na_refer(VALUE self) { return na_wrap_struct(na_ref_alloc_struct(self), self); } /* singleton method: NArray.refer( other ) */ static VALUE na_s_refer(VALUE klass, VALUE self) { return na_wrap_struct_class(na_ref_alloc_struct(self), klass); } /* method: self.original */ static VALUE na_original(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); return ary->ref; } /* void na_touch_object(VALUE val, ...) { return; } */ void na_clear_data(struct NARRAY *ary) { if (NA_IsROBJ(ary)) rb_mem_clear((VALUE*)(ary->ptr), ary->total); else MEMZERO(ary->ptr, char, na_sizeof[ary->type]*ary->total); } /* local function for new array creation */ static VALUE na_new2(int argc, VALUE *argv, int type, VALUE klass) { int i, *shape; struct NARRAY *ary; VALUE v; if (argc == 0) rb_raise(rb_eArgError, "Argument required"); shape = ALLOCA_N(int,argc); for (i=0; itype != NA_ROBJ) na_clear_data(ary); /* rb_obj_call_init(v, 0, 0); */ return v; } /* Convert type arguments -> typecode */ int na_get_typecode(VALUE v) { struct NARRAY *na; int i; if (v==rb_cFloat) return NA_DFLOAT; if (v==rb_cInteger) return NA_LINT; if (v==cComplex) return NA_DCOMPLEX; if (v==rb_cObject) return NA_ROBJ; if (FIXNUM_P(v)) { i = NUM2INT(v); if (i<=NA_NONE || i>=NA_NTYPES) rb_raise(rb_eArgError, "Wrong type code"); return i; } if (NA_IsNArray(v)) { GetNArray(v,na); return na->type; } if (TYPE(v)==T_STRING) { for (i=1; iptr, na_typestring[i], RSTRING(v)->len) ) return i; } } rb_raise(rb_eArgError, "Unrecognized NArray type"); return 0; } /* class method: new(type, size1,size2,...,sizeN) */ static VALUE na_s_new(int argc, VALUE *argv, VALUE klass) { if (argc == 0) rb_raise(rb_eArgError, "Argument required"); return na_new2(argc-1, argv+1, na_get_typecode(argv[0]), klass); } /* class method: byte(size1,size2,...,sizeN) */ static VALUE na_s_new_byte(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_BYTE, klass); } /* class method: sint(size1,size2,...,sizeN) */ static VALUE na_s_new_sint(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_SINT, klass); } /* class method: int(size1,size2,...,sizeN) */ static VALUE na_s_new_int(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_LINT, klass); } /* class method: sfloat(size1,size2,...,sizeN) */ static VALUE na_s_new_sfloat(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_SFLOAT, klass); } /* class method: float(size1,size2,...,sizeN) */ static VALUE na_s_new_float(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_DFLOAT, klass); } /* class method: scomplex(size1,size2,...,sizeN) */ static VALUE na_s_new_scomplex(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_SCOMPLEX, klass); } /* class method: complex(size1,size2,...,sizeN) */ static VALUE na_s_new_complex(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_DCOMPLEX, klass); } /* class method: object(size1,size2,...,sizeN) */ static VALUE na_s_new_object(int argc, VALUE *argv, VALUE klass) { return na_new2(argc, argv, NA_ROBJ, klass); } /* method: dup() */ VALUE na_clone(VALUE self) { struct NARRAY *org, *cpy; GetNArray(self,org); cpy = na_alloc_struct(org->type,org->rank,org->shape); memcpy(cpy->ptr, org->ptr, na_sizeof[org->type] * org->total); return na_wrap_struct(cpy,self); } /* local function */ void na_copy_nary(struct NARRAY *dst, struct NARRAY *src) { if (dst->total != src->total) rb_raise(rb_eRuntimeError, "src and dst array sizes mismatch"); if (dst->type == src->type) memcpy(dst->ptr, src->ptr, src->total*na_sizeof[src->type]); else { SetFuncs[dst->type][src->type]( src->total, dst->ptr, na_sizeof[dst->type], src->ptr, na_sizeof[src->type] ); } } /* method: to_type(type) */ static VALUE na_to_type(VALUE self, VALUE vtype) { struct NARRAY *a1, *a2; VALUE v; GetNArray(self,a1); v = na_make_object(na_get_typecode(vtype), a1->rank, a1->shape, CLASS_OF(self)); GetNArray(v,a2); na_copy_nary(a2,a1); return v; } /* method: to_f() */ static VALUE na_to_float(VALUE self) { struct NARRAY *a1, *a2; VALUE v; GetNArray(self,a1); v = na_make_object(na_upcast[NA_SFLOAT][a1->type], a1->rank, a1->shape, CLASS_OF(self)); GetNArray(v,a2); na_copy_nary(a2,a1); return v; } /* method: to_i() */ static VALUE na_to_integer(VALUE self) { int type; struct NARRAY *a1, *a2; VALUE v; GetNArray(self,a1); if (!NA_IsINTEGER(a1)) type = NA_LINT; else type = a1->type; v = na_make_object(type, a1->rank, a1->shape, CLASS_OF(self)); GetNArray(v,a2); na_copy_nary(a2,a1); return v; } /* method: shape() -- returns an array of shape of each rank */ static VALUE na_shape(VALUE self) { struct NARRAY *ary; VALUE *shape; int i; GetNArray(self,ary); shape = ALLOCA_N(VALUE,ary->rank); for (i = 0; i < ary->rank; i++) shape[i] = INT2FIX(ary->shape[i]); return rb_ary_new4(ary->rank,shape); } /* method: rank() -- returns the rank of the array */ static VALUE na_rank(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); return INT2FIX(ary->rank); } /* method: size() -- returns the total number of elements */ static VALUE na_size(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); return INT2FIX(ary->total); } /* method: typecode -- returns the type of the array */ static VALUE na_typecode(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); return INT2FIX(ary->type); } /* method: element_size -- returns the element size of the array type */ static VALUE na_element_size(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); return INT2FIX(na_sizeof[ary->type]); } /* method: empty? -- returns true if empty array */ static VALUE na_is_empty(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); if (ary->total==0) return Qtrue; return Qfalse; } /* Binary copy of String => NArray */ static VALUE na_str_to_na(int argc, VALUE *argv, VALUE str) { struct NARRAY *ary; VALUE v; int i, type, len=1, str_len, *shape, rank=argc-1; if (argc < 1) rb_raise(rb_eArgError, "Type and Size Arguments required"); type = na_get_typecode(argv[0]); str_len = RSTRING(str)->len; if (argc == 1) { rank = 1; shape = ALLOCA_N(int,rank); if ( str_len % na_sizeof[type] != 0 ) rb_raise(rb_eArgError, "string size mismatch"); shape[0] = str_len / na_sizeof[type]; } else { shape = ALLOCA_N(int,rank); for (i=0; iptr, RSTRING(str)->ptr, ary->total*na_sizeof[type] ); return v; } /* method: to_s -- convert the data contents to a binary string */ static VALUE na_to_s(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); if (NA_IsROBJ(ary)) rb_raise(rb_eTypeError,"cannot convert object-type NArray"); return rb_str_new(ary->ptr,ary->total*na_sizeof[ary->type]); } /* method: to_binary -- convert the data contents to a BYTE type NArray */ static VALUE na_to_binary(VALUE self) { struct NARRAY *a1, *a2; int i, *shape, rank; VALUE v; GetNArray(self,a1); rank = a1->rank+1; shape = ALLOCA_N(int,rank); shape[0] = na_sizeof[a1->type]; for (i=1; ishape[i-1]; v = na_make_object( NA_BYTE, rank, shape, cNArray ); GetNArray(v,a2); MEMCPY(a2->ptr,a1->ptr,char,a2->total); return v; } /* method: to_type_as_binary(type) */ static VALUE na_to_type_as_binary(VALUE self, VALUE vtype) { struct NARRAY *a1, *a2; int size, total, type; VALUE v; type = na_get_typecode(vtype); GetNArray(self,a1); size = a1->total * na_sizeof[a1->type]; if ( size % na_sizeof[type] != 0 ) rb_raise(rb_eRuntimeError, "bina1 size mismatch"); total = size / na_sizeof[type]; v = na_make_object( type, 1, &total, cNArray ); GetNArray(v,a2); MEMCPY(a2->ptr,a1->ptr,char,size); return v; } static void na_to_string_binary(int n, char *p1, int i1, char *p2, int i2) { for (; n>0; n--) { *(VALUE*)p1 = rb_str_new(p2,i2); p1+=i1; p2+=i2; } } /* method: to_string */ static VALUE na_to_string(VALUE self) { VALUE v; struct NARRAY *a1, *a2; GetNArray(self,a1); if (a1->total==0) v = na_make_empty(NA_ROBJ, CLASS_OF(self)); else if (a1->type==NA_BYTE) { if (a1->rank==1) return rb_str_new(a1->ptr,a1->shape[0]); v = na_make_object(NA_ROBJ, a1->rank-1, a1->shape+1, cNArray); GetNArray(v,a2); na_to_string_binary( a2->total, a2->ptr, sizeof(VALUE), a1->ptr, a1->shape[0] ); } else { v = na_make_object(NA_ROBJ, a1->rank, a1->shape, CLASS_OF(self)); GetNArray(v,a2); ToStrFuncs[a1->type]( a2->total, a2->ptr, sizeof(VALUE), a1->ptr, na_sizeof[a1->type] ); } return v; } /* singleton method: NArray.to_na( string, type, size1,size2,...,sizeN ) NArray.to_na( object ) */ static VALUE na_s_to_na(int argc, VALUE *argv, VALUE klass) { static int shape=1; VALUE v; struct NARRAY *ary; switch(TYPE(argv[0])) { case T_STRING: return na_str_to_na(argc-1,argv+1,argv[0]); case T_ARRAY: if (argc>1) rb_raise(rb_eArgError,"extra arguments"); return na_ary_to_nary( argv[0], klass ); default: v = na_make_object(na_object_type(argv[0]),1,&shape,klass); GetNArray(v,ary); SetFuncs[ary->type][NA_ROBJ](1, ary->ptr,0, argv,0); return v; } } /* singleton method: NArray[object] */ static VALUE na_s_bracket(int argc, VALUE *argv, VALUE klass) { VALUE v = rb_ary_new4(argc, argv); return na_ary_to_nary( v, klass ); } /* method: coerce(other) */ static VALUE na_coerce(VALUE self, VALUE other) { struct NARRAY *a1; GetNArray(self,a1); return rb_assoc_new( na_cast_object(other,a1->type), self ); } /* method: inspect() -- returns the inspect of the array */ static VALUE na_inspect(VALUE self) { VALUE str; struct NARRAY *ary; int i; char buf[256]; char *classname; char *ref = "%s(ref).%s(%i"; char *org = "%s.%s(%i"; GetNArray(self,ary); classname = rb_class2name(CLASS_OF(self)); str = rb_str_new(0,0); if (ary->rank < 1) { sprintf(buf, "%s.%s(): []", classname, na_typestring[ary->type]); rb_str_cat(str,buf,strlen(buf)); } else { sprintf(buf, (ary->ref==Qnil) ? org:ref, classname, na_typestring[ary->type], ary->shape[0]); rb_str_cat(str,buf,strlen(buf)); for (i=1; irank; i++) { sprintf(buf,",%i",ary->shape[i]); rb_str_cat(str,buf,strlen(buf)); } rb_str_cat(str,")",1); rb_str_cat(str,": \n",3); rb_str_concat(str, na_make_inspect(self)); } return str; } /* private function for reshape */ static void na_reshape(int argc, VALUE *argv, struct NARRAY *ary, VALUE self) { int *shape, class_dim; int i, total=1, unfixed=-1; VALUE klass; if (ary->total==0) rb_raise(rb_eRuntimeError, "cannot reshape empty array"); klass = CLASS_OF(self); class_dim = NUM2INT(rb_const_get(klass, na_id_class_dim)); if (argc == 0) { /* trim ranks of size=1 */ shape = ALLOCA_N(int,ary->rank+1); for (i=0; irank; i++) shape[i]=1; na_shrink_rank( self, class_dim, shape ); if (ary->rank==0) ary->rank=1; return; } /* get shape from argument */ shape = ALLOC_N(int,argc); for (i=0; i=0) { if (ary->total % total != 0) rb_raise(rb_eArgError, "Total size size must be divisor"); shape[unfixed] = ary->total / total; } else if (total != ary->total) rb_raise(rb_eArgError, "Total size must be same"); /* exchange */ xfree(ary->shape); ary->shape = shape; ary->rank = argc; } /* method: reshape!(size1,size2,...,sizeN) */ static VALUE na_reshape_bang(int argc, VALUE *argv, VALUE self) { struct NARRAY *ary; GetNArray(self,ary); na_reshape(argc, argv, ary, self); return self; } /* method: reshape(size1,size2,...,sizeN) */ static VALUE na_reshape_ref(int argc, VALUE *argv, VALUE self) { struct NARRAY *ary; GetNArray(self,ary); ary = na_ref_alloc_struct(self); na_reshape(argc, argv, ary, self); return na_wrap_struct(ary,self); } /* method: flatten! */ static VALUE na_flatten_bang(VALUE self) { struct NARRAY *ary; GetNArray(self,ary); if (ary->total==0 || ary->rank==0) rb_raise(rb_eRuntimeError, "cannot reshape empty array"); ary->shape[0] = ary->total; ary->rank = 1; return self; } /* method: flatten */ static VALUE na_flatten_ref(VALUE self) { return na_flatten_bang( na_wrap_struct( na_ref_alloc_struct(self), self )); } /* private function for newdim */ static void na_newdim(int argc, VALUE *argv, struct NARRAY *ary) { int *shape, *count; int i, j; if (argc==0) rb_raise(rb_eArgError, "Argument required"); if (ary->rank + argc > NA_MAX_RANK-1) rb_raise(rb_eArgError, "Exceed maximum ranks"); if (ary->total==0) rb_raise(rb_eRuntimeError, "cannot extend empty array"); /* count new rank */ count = ALLOCA_N(int,ary->rank+1); for (i=0; i<=ary->rank; i++) count[i]=0; for (i=0; iappend after last rank */ j += ary->rank+1; if (j<0 || j>ary->rank) /* range check */ rb_raise(rb_eArgError, "rank out of range"); count[j]++; } /* extend shape shape */ shape = ALLOC_N(int,ary->rank+argc); for (j=i=0; irank; i++) { while (count[i]-->0) shape[j++] = 1; shape[j++] = ary->shape[i]; } while (count[i]-->0) shape[j++] = 1; /* exchange shape */ xfree(ary->shape); ary->shape = shape; ary->rank += argc; } /* method: newdim!(size1,size2,...,sizeN) */ static VALUE na_newdim_bang(int argc, VALUE *argv, VALUE self) { struct NARRAY *ary; GetNArray(self,ary); na_newdim(argc, argv, ary); return self; } /* method: newdim(size1,size2,...,sizeN) */ VALUE na_newdim_ref(int argc, VALUE *argv, VALUE self) { struct NARRAY *ary; GetNArray(self,ary); ary = na_ref_alloc_struct(self); na_newdim(argc, argv, ary); return na_wrap_struct(ary,self); } /* method: fill!(val) */ VALUE na_fill(VALUE self, volatile VALUE val) { struct NARRAY *a1, *a2; GetNArray(self,a1); val = na_cast_unless_narray(val,a1->type); GetNArray(val,a2); if (a2->total != 1) rb_raise(rb_eArgError, "single-element argument required"); SetFuncs[a1->type][a2->type]( a1->total, a1->ptr, na_sizeof[a1->type], a2->ptr, 0 ); //na_touch_object(val); return self; } /* method: indgen!([start,[step]]) */ VALUE na_indgen(int argc, VALUE *argv, VALUE self) { int start=0, step=1; struct NARRAY *ary; if (argc>0) { start = NUM2INT(argv[0]); if (argc==2) step = NUM2INT(argv[1]); else if (argc>2) rb_raise(rb_eArgError, "wrong # of arguments (%d for <= 2)", argc); } GetNArray(self,ary); IndGenFuncs[ary->type]( ary->total, ary->ptr, na_sizeof[ary->type], start, step ); return self; } /* method: where2 idx_true, idx_false = narray.where2 */ static VALUE na_where2(volatile VALUE obj) { VALUE v1, v0; int n, i, n1, n0; char *c; int32_t *idx1, *idx0; struct NARRAY *ary, *a1, *a0; /* a1=true, a0=false */ obj = na_cast_object(obj,NA_BYTE); GetNArray(obj,ary); n = ary->total; /* Count true */ c = ary->ptr; n1 = 0; for (i=0; iptr; v0 = na_make_object( NA_LINT, 1, &n0, cNArray ); GetNArray(v0,a0); idx0 = (int32_t*) a0->ptr; /* Get Indices */ c = ary->ptr; for ( i=0; iptr[0]; } /* iterator: each() */ static VALUE na_each(VALUE obj) { int i, sz; VALUE v; struct NARRAY *ary; char *p; void (*func)(); GetNArray(obj,ary); p = ary->ptr; sz = na_sizeof[ary->type]; func = SetFuncs[NA_ROBJ][ary->type]; for ( i=ary->total; i-->0; ) { (*func)( 1, &v, 0, p, 0 ); rb_yield(v); p += sz; } return Qnil; } /* iterator: collect() */ static VALUE na_collect(VALUE obj1) { int i, sz; VALUE v, obj2; struct NARRAY *a1, *a2; char *p1, *p2; void (*get)(), (*set)(); GetNArray(obj1,a1); obj2 = na_make_object(a1->type, a1->rank, a1->shape, CLASS_OF(obj1)); GetNArray(obj2,a2); p1 = a1->ptr; p2 = a2->ptr; sz = na_sizeof[a1->type]; get = SetFuncs[NA_ROBJ][a1->type]; set = SetFuncs[a1->type][NA_ROBJ]; for ( i=a1->total; i-->0; ) { (*get)( 1, &v, 0, p1, 0 ); v = rb_yield(v); (*set)( 1, p2, 0, &v, 0 ); p1 += sz; p2 += sz; } return obj2; } /* iterator: collect!() */ static VALUE na_collect_bang(VALUE self) { int i, sz; VALUE v; struct NARRAY *a1; char *p1; void (*get)(), (*set)(); GetNArray(self,a1); p1 = a1->ptr; sz = na_sizeof[a1->type]; get = SetFuncs[NA_ROBJ][a1->type]; set = SetFuncs[a1->type][NA_ROBJ]; for ( i=a1->total; i-->0; ) { (*get)( 1, &v, 0, p1, 0 ); v = rb_yield(v); (*set)( 1, p1, 0, &v, 0 ); p1 += sz; } return self; } /* initialization of NArray Class */ void Init_narray() { /* require Complex class */ rb_require("complex"); cComplex = rb_const_get( rb_cObject, rb_intern("Complex") ); /* define NArray class */ cNArray = rb_define_class("NArray",rb_cObject); /* class methods */ /* rb_define_global_function("NArray",na_to_narray,-1); */ rb_define_singleton_method(cNArray,"new",na_s_new,-1); rb_define_singleton_method(cNArray,"byte",na_s_new_byte,-1); rb_define_singleton_method(cNArray,"sint",na_s_new_sint,-1); rb_define_singleton_method(cNArray,"lint",na_s_new_int,-1); rb_define_singleton_method(cNArray,"int", na_s_new_int,-1); rb_define_singleton_method(cNArray,"sfloat",na_s_new_sfloat,-1); rb_define_singleton_method(cNArray,"dfloat",na_s_new_float,-1); rb_define_singleton_method(cNArray,"float", na_s_new_float,-1); rb_define_singleton_method(cNArray,"scomplex",na_s_new_scomplex,-1); rb_define_singleton_method(cNArray,"dcomplex",na_s_new_complex,-1); rb_define_singleton_method(cNArray,"complex", na_s_new_complex,-1); rb_define_singleton_method(cNArray,"object",na_s_new_object,-1); rb_define_singleton_method(cNArray,"to_na",na_s_to_na,-1); rb_define_singleton_method(cNArray,"to_narray",na_s_to_na,-1); rb_define_singleton_method(cNArray,"[]",na_s_bracket,-1); /* methods */ rb_define_method(cNArray, "[]", na_aref,-1); rb_define_method(cNArray, "[]=", na_aset,-1); rb_define_method(cNArray, "slice", na_slice,-1); rb_define_method(cNArray, "shape", na_shape,0); rb_define_alias(cNArray, "sizes","shape"); rb_define_method(cNArray, "size", na_size,0); rb_define_alias(cNArray, "total","size"); rb_define_alias(cNArray, "length","size"); rb_define_method(cNArray, "rank", na_rank,0); rb_define_alias(cNArray, "dim","rank"); rb_define_alias(cNArray, "dimension","rank"); rb_define_method(cNArray, "typecode", na_typecode,0); rb_define_method(cNArray, "element_size", na_element_size,0); rb_define_method(cNArray, "empty?", na_is_empty,0); rb_define_method(cNArray, "clone", na_clone,0); rb_define_alias(cNArray, "dup","clone"); rb_define_method(cNArray, "inspect", na_inspect,0); rb_define_method(cNArray, "coerce", na_coerce,1); rb_define_method(cNArray, "reshape", na_reshape_ref,-1); rb_define_method(cNArray, "reshape!", na_reshape_bang,-1); rb_define_alias(cNArray, "shape=","reshape!"); rb_define_method(cNArray, "newdim", na_newdim_ref,-1); rb_define_alias(cNArray, "newrank","newdim"); rb_define_method(cNArray, "newdim!", na_newdim_bang,-1); rb_define_alias(cNArray, "newdim=","newdim!"); rb_define_alias(cNArray, "newrank!","newdim!"); rb_define_alias(cNArray, "newrank=","newdim!"); rb_define_method(cNArray, "flatten", na_flatten_ref,0); rb_define_method(cNArray, "flatten!", na_flatten_bang,0); rb_define_method(cNArray, "fill!", na_fill,1); rb_define_alias(cNArray, "fill","fill!"); rb_define_method(cNArray, "indgen!", na_indgen,-1); rb_define_alias(cNArray, "indgen","indgen!"); rb_define_method(cNArray, "where", na_where, 0); rb_define_method(cNArray, "where2", na_where2, 0); rb_define_method(cNArray, "each", na_each,0); rb_define_method(cNArray, "collect", na_collect,0); rb_define_method(cNArray, "collect!", na_collect_bang,0); /* rb_define_method(cNArray, "each_index", na_each_index,0); */ rb_define_method(cNArray, "to_a", na_to_array,0); rb_define_method(cNArray, "to_s", na_to_s, 0); rb_define_method(cNArray, "to_f", na_to_float, 0); rb_define_method(cNArray, "to_i", na_to_integer, 0); rb_define_method(cNArray, "to_type", na_to_type, 1); rb_define_method(cNArray, "to_binary", na_to_binary, 0); rb_define_method(cNArray, "to_type_as_binary", na_to_type_as_binary, 1); rb_define_method(cNArray, "to_string", na_to_string, 0); /*mask*/ rb_define_method(cNArray, "count_false", na_count_false, 0); rb_define_method(cNArray, "count_true", na_count_true, 0); rb_define_method(cNArray, "mask", na_aref_mask, 1); rb_define_const(cNArray, "NARRAY_VERSION", rb_str_new2(NARRAY_VERSION)); rb_define_const(cNArray, "BYTE", INT2FIX(NA_BYTE)); rb_define_const(cNArray, "SINT", INT2FIX(NA_SINT)); rb_define_const(cNArray, "LINT", INT2FIX(NA_LINT)); rb_define_const(cNArray, "INT", INT2FIX(NA_LINT)); rb_define_const(cNArray, "SFLOAT", INT2FIX(NA_SFLOAT)); rb_define_const(cNArray, "DFLOAT", INT2FIX(NA_DFLOAT)); rb_define_const(cNArray, "FLOAT", INT2FIX(NA_DFLOAT)); rb_define_const(cNArray, "SCOMPLEX", INT2FIX(NA_SCOMPLEX)); rb_define_const(cNArray, "DCOMPLEX", INT2FIX(NA_DCOMPLEX)); rb_define_const(cNArray, "COMPLEX", INT2FIX(NA_DCOMPLEX)); rb_define_const(cNArray, "ROBJ", INT2FIX(NA_ROBJ)); rb_define_const(cNArray, "OBJECT", INT2FIX(NA_ROBJ)); rb_define_const(cNArray, "NONE", INT2FIX(NA_NONE)); rb_define_const(cNArray, "CLASS_DIMENSION", INT2FIX(0)); #ifdef WORDS_BIGENDIAN rb_define_const(cNArray, "ENDIAN", INT2FIX(1)); #else #ifdef DYNAMIC_ENDIAN /* not supported yet */ rb_define_const(cNArray, "ENDIAN", INT2FIX(-1)); #else /* LITTLE_ENDIAN */ rb_define_const(cNArray, "ENDIAN", INT2FIX(0)); #endif #endif /* Reference */ rb_define_singleton_method(cNArray, "refer", na_s_refer,1); rb_define_singleton_method(cNArray, "ref", na_s_refer,1); rb_define_method(cNArray, "refer", na_refer,0); rb_define_method(cNArray, "original", na_original,0); Init_nmath(); Init_na_funcs(); Init_na_random(); cNArrayScalar = rb_define_class("NArrayScalar", cNArray); na_id_beg = rb_intern("begin"); na_id_end = rb_intern("end"); na_id_exclude_end = rb_intern("exclude_end?"); na_id_real = rb_intern("real"); na_id_imag = rb_intern("image"); na_id_new = rb_intern("new"); na_id_to_i = rb_intern("to_i"); na_id_usec = rb_intern("usec"); na_id_now = rb_intern("now"); na_id_compare = rb_intern("<=>"); na_id_and = rb_intern("&&"); na_id_or = rb_intern("||"); na_id_minus = rb_intern("-@"); na_id_abs = rb_intern("abs"); na_id_power = rb_intern("**"); na_id_add = rb_intern("+"); na_id_sbt = rb_intern("-"); na_id_mul = rb_intern("*"); na_id_div = rb_intern("/"); na_id_mod = rb_intern("%"); na_id_coerce_rev = rb_intern("coerce_rev"); na_id_class_dim = rb_intern("CLASS_DIMENSION"); #ifdef HAVE_FFTW_H Init_fftw(); #endif Init_na_linalg(); /* NArray extention script */ rb_require("narray_ext.rb"); }