ext/numo/narray/array.c in numo-narray-0.9.0.4 vs ext/numo/narray/array.c in numo-narray-0.9.0.5

- old
+ new

@@ -1,15 +1,14 @@ /* array.c Numerical Array Extension for Ruby - (C) Copyright 1999-2016 by Masahiro TANAKA + (C) Copyright 1999-2017 by Masahiro TANAKA */ #include <ruby.h> #include "numo/narray.h" -//#include "narray_local.h" -/* Multi-Dimensional Array Investigation */ +// mdai: Multi-Dimensional Array Investigation typedef struct { size_t shape; VALUE val; } na_mdai_item_t; @@ -23,10 +22,57 @@ // Order of Ruby object. enum { NA_NONE, NA_BIT, NA_INT32, NA_INT64, NA_RATIONAL, NA_DFLOAT, NA_DCOMPLEX, NA_ROBJ, NA_NTYPES }; +static ID id_begin; +static ID id_end; +static ID id_step; +static ID id_abs; +static ID id_cast; +static ID id_le; +static ID id_Complex; + +typedef struct { + int ndim; + size_t *shape; + VALUE dtype; +} na_compose_t; + +static size_t +na_compose_memsize(const void *ptr) +{ + const na_compose_t *nc = (const na_compose_t*)ptr; + + return sizeof(na_compose_t) + nc->ndim * sizeof(size_t); +} + +static void +na_compose_free(void *ptr) +{ + na_compose_t *nc = (na_compose_t*)ptr; + + if (nc->shape) + xfree(nc->shape); + xfree(nc); +} + +static void +na_compose_gc_mark(void* nc) +{ + rb_gc_mark(((na_compose_t*)nc)->dtype); +} + +static const rb_data_type_t compose_data_type = { + "Numo::NArray/compose", + {na_compose_gc_mark, na_compose_free, na_compose_memsize,}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED +}; + +#define WrapCompose(p) TypedData_Wrap_Struct(rb_cData, &compose_data_type, (void*)(p)); +#define GetCompose(v,p) TypedData_Get_Struct(v, na_compose_t, &compose_data_type, p) + static VALUE na_object_type(int type, VALUE v) { static VALUE int32_max = Qnil; if (NIL_P(int32_max)) @@ -45,12 +91,12 @@ if (type<NA_INT32) return NA_INT32; return type; case T_BIGNUM: if (type<NA_INT64) { - v = rb_funcall(v,rb_intern("abs"),0); - if (RTEST(rb_funcall(v,rb_intern("<="),1,int32_max))) { + v = rb_funcall(v,id_abs,0); + if (RTEST(rb_funcall(v,id_le,1,int32_max))) { if (type<NA_INT32) return NA_INT32; } else { return NA_INT64; } @@ -76,12 +122,12 @@ return type; #else case T_FIXNUM: case T_BIGNUM: if (type<NA_INT64) { - v = rb_funcall(v,rb_intern("abs"),0); - if (RTEST(rb_funcall(v,rb_intern("<="),1,int32_max))) { + v = rb_funcall(v,id_abs,0); + if (RTEST(rb_funcall(v,id_le,1,int32_max))) { if (type<NA_INT32) return NA_INT32; } else { return NA_INT64; } @@ -96,36 +142,36 @@ case T_NIL: return type; default: - if (CLASS_OF(v) == rb_const_get( rb_cObject, rb_intern("Complex") )) { + if (CLASS_OF(v) == rb_const_get( rb_cObject, id_Complex )) { return NA_DCOMPLEX; } } return NA_ROBJ; } #define MDAI_ATTR_TYPE(tp,v,attr) \ - {tp = na_object_type(tp,rb_funcall(v,rb_intern(attr),0));} + {tp = na_object_type(tp,rb_funcall(v,id_##attr,0));} void na_mdai_object_type(na_mdai_t *mdai, VALUE v) { if (IsNArray(v)) { if (NIL_P(mdai->na_type)) { mdai->na_type = CLASS_OF(v); } else { mdai->na_type = na_upcast(CLASS_OF(v), mdai->na_type); } } else if (rb_obj_is_kind_of(v, rb_cRange)) { - MDAI_ATTR_TYPE(mdai->type,v,"begin"); - MDAI_ATTR_TYPE(mdai->type,v,"end"); + MDAI_ATTR_TYPE(mdai->type,v,begin); + MDAI_ATTR_TYPE(mdai->type,v,end); } else if (rb_obj_is_kind_of(v, na_cStep)) { - MDAI_ATTR_TYPE(mdai->type,v,"begin"); - MDAI_ATTR_TYPE(mdai->type,v,"end"); - MDAI_ATTR_TYPE(mdai->type,v,"step"); + MDAI_ATTR_TYPE(mdai->type,v,begin); + MDAI_ATTR_TYPE(mdai->type,v,end); + MDAI_ATTR_TYPE(mdai->type,v,step); } else { mdai->type = na_object_type(mdai->type,v); } } @@ -164,12 +210,13 @@ mdai->item[i].val = Qnil; } } static void -na_mdai_free(na_mdai_t *mdai) +na_mdai_free(void *ptr) { + na_mdai_t *mdai = (na_mdai_t*)ptr; xfree(mdai->item); xfree(mdai); } @@ -253,19 +300,13 @@ nc->shape = NULL; nc->dtype = Qnil; if (ndim>0) { // Shape - //shape = ALLOC_N(size_t,i); - //for (i=0; i<*ndim; i++) { - // shape[i] = mdai->item[i].shape; - //} nc->shape = shape = ALLOC_N(size_t,ndim); for (i=0; i<ndim; i++) { shape[i] = mdai->item[i].shape; - //printf("shape[%d]=%d\n",i,shape[i]); - //rb_ary_push( shape, SIZET2NUM(mdai->item[i].shape) ); } // DataType switch(mdai->type) { case NA_BIT: @@ -299,25 +340,46 @@ nc->dtype = tp; } } +static size_t +na_mdai_memsize(const void *ptr) +{ + const na_mdai_t *mdai = (const na_mdai_t*)ptr; + + return sizeof(na_mdai_t) + mdai->capa * sizeof(na_mdai_item_t); +} + +static const rb_data_type_t mdai_data_type = { + "Numo::NArray/mdai", + {NULL, na_mdai_free, na_mdai_memsize,}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED +}; + VALUE na_ary_composition(VALUE ary) { volatile VALUE vmdai, vnc; na_mdai_t *mdai; na_compose_t *nc; int j; nc = ALLOC(na_compose_t); - vnc = Data_Wrap_Struct(rb_cData, 0, -1, nc); + vnc = WrapCompose(nc); if (TYPE(ary) == T_ARRAY) { mdai = na_mdai_alloc(ary); - vmdai = Data_Wrap_Struct(rb_cData, 0, na_mdai_free, mdai); - na_mdai_investigate(mdai, 1); - na_mdai_result(mdai, nc); + vmdai = TypedData_Wrap_Struct(rb_cData, &mdai_data_type, (void*)mdai); + if ( na_mdai_investigate(mdai, 1) ) { + // empty + nc->ndim = 1; + nc->shape = ALLOC_N(size_t, 1); + nc->shape[0] = 0; + nc->dtype = Qnil; + } else { + na_mdai_result(mdai, nc); + } rb_gc_force_recycle(vmdai); } else if (IsNArray(ary)) { narray_t *na; GetNArray(ary,na); nc->ndim = na->ndim; @@ -331,43 +393,109 @@ } return vnc; } +static void +na_ary_composition2(VALUE ary, VALUE *type, VALUE *shape) +{ + VALUE vnc, dshape; + na_compose_t *nc; + int i; + + // investigate MD-Array + vnc = na_ary_composition(ary); + GetCompose(vnc,nc); + dshape = rb_ary_new2(nc->ndim); + for (i=0; i<nc->ndim; i++) { + rb_ary_push(dshape, SIZET2NUM(nc->shape[i])); + } + if (shape) {*shape = dshape;} + if (type) {*type = nc->dtype;} + RB_GC_GUARD(vnc); +} + static VALUE na_s_array_shape(VALUE mod, VALUE ary) { - volatile VALUE vnc; VALUE shape; - na_compose_t *nc; - int i; if (TYPE(ary)!=T_ARRAY) { // 0-dimension return rb_ary_new(); } - // investigate MD-Array - vnc = na_ary_composition(ary); - Data_Get_Struct(vnc, na_compose_t, nc); - shape = rb_ary_new2(nc->ndim); - for (i=0; i<nc->ndim; i++) { - rb_ary_push( shape, SIZET2NUM(nc->shape[i]) ); - } + na_ary_composition2(ary, 0, &shape); return shape; } +static inline void +check_subclass_of_narray(VALUE dtype) { + if (RTEST(rb_obj_is_kind_of(dtype, rb_cClass))) { + if (RTEST(rb_funcall(dtype, id_le, 1, cNArray))) { + return; + } + } + rb_raise(nary_eCastError, "cannot convert to NArray"); +} + +/* + Generate new unallocated NArray instance with shape and type defined from obj. + Numo::NArray.new_like(obj) returns instance whose type is defined from obj. + Numo::DFloat.new_like(obj) returns DFloat instance. + + @overload new_like(obj) + @param [Numeric,Array,Numo::NArray] obj + @return [Numo::NArray] + @example + Numo::NArray.new_like([[1,2,3],[4,5,6]]) + => Numo::Int32#shape=[2,3](empty) + Numo::DFloat.new_like([[1,2],[3,4]]) + => Numo::DFloat#shape=[2,2](empty) + Numo::NArray.new_like([1,2i,3]) + => Numo::DComplex#shape=[3](empty) +*/ VALUE +na_s_new_like(VALUE type, VALUE obj) +{ + VALUE vnc, newary; + na_compose_t *nc; + + if (RTEST(rb_obj_is_kind_of(obj,rb_cNumeric))) { + // investigate type + if (type == cNArray) { + vnc = na_ary_composition(rb_ary_new3(1,obj)); + GetCompose(vnc,nc); + type = nc->dtype; + } + check_subclass_of_narray(type); + newary = nary_new(type, 0, 0); + } else { + // investigate MD-Array + vnc = na_ary_composition(obj); + GetCompose(vnc,nc); + if (type == cNArray) { + type = nc->dtype; + } + check_subclass_of_narray(type); + newary = nary_new(type, nc->ndim, nc->shape); + } + RB_GC_GUARD(vnc); + return newary; +} + + +VALUE na_ary_composition_dtype(VALUE ary) { volatile VALUE vnc; na_compose_t *nc; switch(TYPE(ary)) { case T_ARRAY: vnc = na_ary_composition(ary); - Data_Get_Struct(vnc, na_compose_t, nc); + GetCompose(vnc,nc); return nc->dtype; } return CLASS_OF(ary); } @@ -377,10 +505,11 @@ return na_ary_composition_dtype(ary); } + /* Generate NArray object. NArray datatype is automatically selected. @overload [](elements) @param [Numeric,Array] elements @return [NArray] @@ -391,20 +520,13 @@ VALUE dtype=Qnil; if (TYPE(ary)!=T_ARRAY) { rb_bug("Argument is not array"); } - dtype = na_ary_composition_dtype(ary); - - if (RTEST(rb_obj_is_kind_of(dtype,rb_cClass))) { - if (RTEST(rb_funcall(dtype,rb_intern("<="),1,cNArray))) { - return rb_funcall(dtype,rb_intern("cast"),1,ary); - } - } - rb_raise(nary_eCastError, "cannot convert to NArray"); - return Qnil; + check_subclass_of_narray(dtype); + return rb_funcall(dtype, id_cast, 1, ary); } VALUE nst_check_compatibility(VALUE self, VALUE ary); @@ -495,14 +617,14 @@ na_mdai_t *mdai; na_compose_t *nc; mdai = na_mdai_alloc(ary); mdai->na_type = nstruct; - vmdai = Data_Wrap_Struct(rb_cData, 0, na_mdai_free, mdai); + vmdai = TypedData_Wrap_Struct(rb_cData, &mdai_data_type, (void*)mdai); na_mdai_for_struct(mdai, 0); nc = ALLOC(na_compose_t); - vnc = Data_Wrap_Struct(rb_cData, 0, -1, nc); + vnc = WrapCompose(nc); na_mdai_result(mdai, nc); //fprintf(stderr,"nc->ndim=%d\n",nc->ndim); rb_gc_force_recycle(vmdai); return vnc; } @@ -513,8 +635,17 @@ Init_nary_array() { //rb_define_singleton_method(cNArray, "mdai", na_mdai, 1); rb_define_singleton_method(cNArray, "array_shape", na_s_array_shape, 1); rb_define_singleton_method(cNArray, "array_type", na_s_array_type, 1); + rb_define_singleton_method(cNArray, "new_like", na_s_new_like, 1); rb_define_singleton_method(cNArray, "[]", nary_s_bracket, -2); + + id_begin = rb_intern("begin"); + id_end = rb_intern("end"); + id_step = rb_intern("step"); + id_cast = rb_intern("cast"); + id_abs = rb_intern("abs"); + id_le = rb_intern("<="); + id_Complex = rb_intern("Complex"); }