/* $Id: flow_objects.c,v 1.2 2006-03-15 04:37:08 matju Exp $ GridFlow Copyright (c) 2001,2002,2003,2004,2005 by Mathieu Bouchard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See file ../COPYING for further informations on licensing terms. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "grid.h.fcs" // BAD HACK: GCC complains: unimplemented (--debug|--debug-harder mode only) #ifdef HAVE_DEBUG #define SCOPY(a,b,n) COPY(a,b,n) #else #define SCOPY(a,b,n) SCopy::f(a,b) #endif template class SCopy { public: template static inline void __attribute__((always_inline)) f(Pt a, Pt b) { *a=*b; SCopy::f(a+1,b+1);}}; template <> class SCopy<0> { public: template static inline void __attribute__((always_inline)) f(Pt a, Pt b) {}}; /*template <> class SCopy<4> { public: template static inline void __attribute__((always_inline)) f(Pt a, Pt b) { *a=*b; SCopy<3>::f(a+1,b+1);} // wouldn't gcc 2.95 complain here? static inline void __attribute__((always_inline)) f(Pt a, Pt b) { *(int32 *)a=*(int32 *)b; } };*/ Numop *op_add, *op_sub, *op_mul, *op_div, *op_mod, *op_shl, *op_and, *op_put; static void expect_dim_dim_list (P d) { if (d->n!=1) RAISE("dimension list should be Dim[n], not %s",d->to_s());} //static void expect_min_one_dim (P d) { // if (d->n<1) RAISE("minimum 1 dimension");} static void expect_max_one_dim (P d) { if (d->n>1) { RAISE("expecting Dim[] or Dim[n], got %s",d->to_s()); }} //static void expect_exactly_one_dim (P d) { // if (d->n!=1) { RAISE("expecting Dim[n], got %s",d->to_s()); }} //**************************************************************** \class GridCast < GridObject struct GridCast : GridObject { \attr NumberTypeE nt; \decl void initialize (NumberTypeE nt); \grin 0 }; GRID_INLET(GridCast,0) { out = new GridOutlet(this,0,in->dim,nt); } GRID_FLOW { out->send(n,data); } GRID_END \def void initialize (NumberTypeE nt) { rb_call_super(argc,argv); this->nt = nt; } \classinfo { IEVAL(rself,"install '#cast',1,1"); } \end class GridCast //**************************************************************** //{ ?,Dim[B] -> Dim[*Cs] } // out0 nt to be specified explicitly \class GridImport < GridObject struct GridImport : GridObject { \attr NumberTypeE cast; \attr P dim; // size of grids to send PtrGrid dim_grid; GridImport() { dim_grid.constrain(expect_dim_dim_list); } ~GridImport() {} \decl void initialize(Ruby x, NumberTypeE cast=int32_e); \decl void _0_cast(NumberTypeE cast); \decl void _0_reset(); \decl void _0_symbol(Symbol x); \decl void _0_list(...); \decl void _1_per_message(); \grin 0 \grin 1 int32 template void process (int n, Pt data) { while (n) { if (!out || !out->dim) out = new GridOutlet(this,0,dim?dim:in[0]->dim,cast); int32 n2 = min((int32)n,out->dim->prod()-out->dex); out->send(n2,data); n-=n2; data+=n2; } } }; GRID_INLET(GridImport,0) {} GRID_FLOW { process(n,data); } GRID_END GRID_INPUT(GridImport,1,dim_grid) { dim = dim_grid->to_dim(); } GRID_END \def void _0_symbol(Symbol x) { const char *name = rb_sym_name(argv[0]); int n = strlen(name); if (!dim) out=new GridOutlet(this,0,new Dim(n)); process(n,Pt((uint8 *)name,n)); } \def void _0_cast(NumberTypeE cast) { this->cast = cast; } \def void _0_list(...) { if (in.size()<1 || !in[0]) _0_grid(0,0); //HACK: enable grid inlet... in[0]->from_ruby_list(argc,argv,cast); } \def void _1_per_message() { dim=0; dim_grid=0; } \def void initialize(Ruby x, NumberTypeE cast) { rb_call_super(argc,argv); this->cast = cast; if (argv[0]!=SYM(per_message)) { dim_grid=new Grid(argv[0]); dim = dim_grid->to_dim(); } } \def void _0_reset() { STACK_ARRAY(int32,foo,1); *foo=0; while (out->dim) out->send(1,foo); } \classinfo { IEVAL(rself,"install '#import',2,1"); } \end class GridImport //**************************************************************** /*{ Dim[*As] -> ? }*/ /* in0: integer nt */ \class GridExport < GridObject struct GridExport : GridObject { \grin 0 }; template static Ruby INTORFLOAT2NUM(T value) {return INT2NUM(value);} static Ruby INTORFLOAT2NUM(int64 value) {return gf_ll2num(value);} static Ruby INTORFLOAT2NUM(float32 value) {return rb_float_new(value);} static Ruby INTORFLOAT2NUM(float64 value) {return rb_float_new(value);} static Ruby INTORFLOAT2NUM(ruby value) {return value.r;} GRID_INLET(GridExport,0) { } GRID_FLOW { for (int i=0; i ? }*/ /* in0: integer nt */ \class GridExportList < GridObject struct GridExportList : GridObject { Ruby /*Array*/ list; int n; \grin 0 }; GRID_INLET(GridExportList,0) { int n = in->dim->prod(); if (n>250000) RAISE("list too big (%d elements)", n); list = rb_ary_new2(n+2); this->n = n; rb_ivar_set(rself,SI(@list),list); // keep rb_ary_store(list,0,INT2NUM(0)); rb_ary_store(list,1,bsym._list); } GRID_FLOW { for (int i=0; idex+i+2,INTORFLOAT2NUM(*data)); } GRID_FINISH { send_out(rb_ary_len(list),rb_ary_ptr(list)); list = 0; rb_ivar_set(rself,SI(@list),Qnil); // unkeep } GRID_END \classinfo { IEVAL(rself,"install '#export_list',1,1"); } \end class GridExportList /* **************************************************************** */ // GridStore ("@store") is the class for storing a grid and restituting // it on demand. The right inlet receives the grid. The left inlet receives // either a bang (which forwards the whole image) or a grid describing what // to send. //{ Dim[*As,B],Dim[*Cs,*Ds] -> Dim[*As,*Ds] } // in0: integer nt // in1: whatever nt // out0: same nt as in1 \class GridStore < GridObject struct GridStore : GridObject { PtrGrid r; // can't be \attr PtrGrid put_at; // can't be //\attr \attr Numop *op; int32 wdex [Dim::MAX_DIM]; // temporary buffer, copy of put_at int32 fromb[Dim::MAX_DIM]; int32 to2 [Dim::MAX_DIM]; int lsd; // lsd = Last Same Dimension (for put_at) int d; // goes with wdex \decl void initialize (Grid *r=0); \decl void _0_bang (); \decl void _0_op (Numop *op); \decl void _1_reassign (); \decl void _1_put_at (Grid *index); \grin 0 int \grin 1 GridStore() { put_at.constrain(expect_max_one_dim); } template void compute_indices(Pt v, int nc, int nd); }; // takes the backstore of a grid and puts it back into place. a backstore // is a grid that is filled while the grid it would replace has not // finished being used. static void snap_backstore (PtrGrid &r) { if (r.next) {r=r.next.p; r.next=0;} } template void GridStore::compute_indices(Pt v, int nc, int nd) { for (int i=0; idim->v[i]; bool fast = lowest_bit(wrap)==highest_bit(wrap); // is power of two? if (i) { if (fast) op_shl->map(nd,v,(T)highest_bit(wrap)); else op_mul->map(nd,v,(T)wrap); } if (fast) op_and->map(nd,v+nd*i,(T)(wrap-1)); else op_mod->map(nd,v+nd*i,(T)(wrap)); if (i) op_add->zip(nd,v,v+nd*i); } } // !@#$ i should ensure that n is not exceedingly large // !@#$ worse: the size of the foo buffer may still be too large GRID_INLET(GridStore,0) { // snap_backstore must be done before *anything* else snap_backstore(r); int na = in->dim->n; int nb = r->dim->n; int nc = in->dim->get(na-1); STACK_ARRAY(int32,v,Dim::MAX_DIM); if (na<1) RAISE("must have at least 1 dimension.",na,1,1+nb); int lastindexable = r->dim->prod()/r->dim->prod(nc) - 1; int ngreatest = nt_greatest((T *)0); if (lastindexable > ngreatest) { RAISE("lastindexable=%d > ngreatest=%d (ask matju)",lastindexable,ngreatest); } if (nc > nb) RAISE("wrong number of elements in last dimension: " "got %d, expecting <= %d", nc, nb); int nd = nb - nc + na - 1; COPY(v,in->dim->v,na-1); COPY(v+na-1,r->dim->v+nc,nb-nc); out=new GridOutlet(this,0,new Dim(nd,v),r->nt); if (nc>0) in->set_factor(nc); } GRID_FLOW { int na = in->dim->n; int nc = in->dim->get(na-1); int size = r->dim->prod(nc); assert((n % nc) == 0); int nd = n/nc; STACK_ARRAY(T,w,n); Pt v=w; if (sizeof(T)==1 && nc==1 && r->dim->v[0]<=256) { // bug? shouldn't modulo be done here? v=data; } else { COPY(v,data,n); for (int k=0,i=0; i p = (Pt)*r; \ if (size<=16) { \ Pt foo = ARRAY_NEW(type,nd*size); \ int i=0; \ switch (size) { \ case 1: for (; igive(size*nd,foo-size*nd); \ } else { \ for (int i=0; isend(size,p+size*v[i]); \ } \ } TYPESWITCH(r->nt,FOO,) #undef FOO } GRID_FINISH { if (in->dim->prod()==0) { int n = in->dim->prod(0,-2); int size = r->dim->prod(); #define FOO(T) while (n--) out->send(size,(Pt)*r); TYPESWITCH(r->nt,FOO,) #undef FOO } } GRID_END GRID_INLET(GridStore,1) { NumberTypeE nt = NumberTypeE_type_of(*data); if (!put_at) { // reassign if (in[0].dim) r.next = new Grid(in->dim,nt); else r = new Grid(in->dim,nt); return; } // put_at ( ... ) //!@#$ should check types. if (r->nt!=in->nt) RAISE("shoo"); int nn=r->dim->n, na=put_at->dim->v[0], nb=in->dim->n; STACK_ARRAY(int32,sizeb,nn); for (int i=0; i(wdex,nn) ,(Pt)*put_at ,put_at->dim->prod()); COPY(Pt(fromb,nn)+nn-na,(Pt)*put_at ,na); COPY(Pt(sizeb,nn)+nn-nb,(Pt)in->dim->v,nb); for (int i=0; i=nn-in->dim->n) { lsd--; int cs = in->dim->prod(lsd-nn+in->dim->n); if (cs>GridOutlet::MAX_PACKET_SIZE || fromb[lsd]!=0 || sizeb[lsd]!=r->dim->v[lsd]) break; } lsd++; int cs = in->dim->prod(lsd-nn+in->dim->n); in->set_factor(cs); } GRID_FLOW { if (!put_at) { // reassign COPY(((Pt)*(r.next ? r.next.p : &*r.p))+in->dex, data, n); return; } // put_at ( ... ) int nn=r->dim->n; int cs = in->factor(); // chunksize STACK_ARRAY(int32,v,lsd); Pt x = Pt(wdex,nn); while (n) { // here d is the dim# to reset; d=n for none for(;dzip(cs,(Pt)*r+v[0]*cs,data); data+=cs; n-=cs; // find next set of indices; here d is the dim# to increment for(;;) { d--; if (d<0) goto end; x[d]++; if (x[d]op=op; } \def void _0_bang () { rb_funcall(rself,SI(_0_list),3,INT2NUM(0),SYM(#),INT2NUM(0)); } \def void _1_reassign () { put_at=0; } \def void _1_put_at (Grid *index) { put_at=index; } \def void initialize (Grid *r) { rb_call_super(argc,argv); this->r = r?r:new Grid(new Dim(),int32_e,true); op = op_put; } \classinfo { IEVAL(rself,"install '#store',2,1"); } \end class GridStore //**************************************************************** //{ Dim[*As] -> Dim[*As] } or //{ Dim[*As],Dim[*Bs] -> Dim[*As] } \class GridOp < GridObject struct GridOp : GridObject { \attr Numop *op; PtrGrid r; \decl void initialize(Numop *op, Grid *r=0); \grin 0 \grin 1 \decl void _0_op(Numop *op); }; GRID_INLET(GridOp,0) { snap_backstore(r); SAME_TYPE(in,r); out=new GridOutlet(this,0,in->dim,in->nt); in->set_mode(6); } GRID_ALLOC { //out->ask(in->allocn,(Pt &)in->alloc,in->allocfactor,in->allocmin,in->allocmax); } GRID_FLOW { Pt rdata = (Pt)*r; int loop = r->dim->prod(); if (sizeof(T)==8) { fprintf(stderr,"1: data=%p rdata=%p\n",data.p,rdata.p); WATCH(n,data); } if (loop>1) { if (in->dex+n <= loop) { op->zip(n,data,rdata+in->dex); } else { // !@#$ should prebuild and reuse this array when "loop" is small STACK_ARRAY(T,data2,n); int ii = mod(in->dex,loop); int m = min(loop-ii,n); COPY(data2,rdata+ii,m); int nn = m+((n-m)/loop)*loop; for (int i=m; inn) COPY(data2+nn,rdata,n-nn); if (sizeof(T)==8) { fprintf(stderr,"2: data=%p data2=%p\n",data.p,data2.p); WATCH(n,data); WATCH(n,data2); } op->zip(n,data,data2); if (sizeof(T)==8) {WATCH(n,data); WATCH(n,data2);} } } else { op->map(n,data,*rdata); } out->give(n,data); } GRID_END GRID_INPUT2(GridOp,1,r) {} GRID_END \def void _0_op(Numop *op) { this->op=op; } \def void initialize(Numop *op, Grid *r=0) { rb_call_super(argc,argv); this->op=op; this->r = r?r:new Grid(new Dim(),int32_e,true); } \classinfo { IEVAL(rself,"install '#',2,1"); } \end class GridOp //**************************************************************** \class GridFold < GridObject struct GridFold : GridObject { \attr Numop *op; \attr PtrGrid seed; \decl void initialize (Numop *op); \decl void _0_op (Numop *op); \decl void _0_seed (Grid *seed); \grin 0 }; GRID_INLET(GridFold,0) { //{ Dim[*As,B,*Cs],Dim[*Cs] -> Dim[*As,*Cs] } if (seed) SAME_TYPE(in,seed); int an = in->dim->n; int bn = seed?seed->dim->n:0; if (an<=bn) RAISE("minimum 1 more dimension than the seed (%d vs %d)",an,bn); STACK_ARRAY(int32,v,an-1); int yi = an-bn-1; COPY(v,in->dim->v,yi); COPY(v+yi,in->dim->v+an-bn,bn); if (seed) SAME_DIM(an-(yi+1),in->dim,(yi+1),seed->dim,0); out=new GridOutlet(this,0,new Dim(an-1,v),in->nt); int k = seed ? seed->dim->prod() : 1; in->set_factor(in->dim->get(yi)*k); } GRID_FLOW { int an = in->dim->n; int bn = seed?seed->dim->n:0; int yn = in->dim->v[an-bn-1]; int zn = in->dim->prod(an-bn); STACK_ARRAY(T,buf,n/yn); int nn=n; int yzn=yn*zn; for (int i=0; n; i+=zn, data+=yzn, n-=yzn) { if (seed) COPY(buf+i,((Pt)*seed),zn); else CLEAR(buf+i,zn); op->fold(zn,yn,buf+i,data); } out->send(nn/yn,buf); } GRID_END \def void _0_op (Numop *op ) { this->op =op; } \def void _0_seed (Grid *seed) { this->seed=seed; } \def void initialize (Numop *op) { rb_call_super(argc,argv); this->op=op; } \classinfo { IEVAL(rself,"install '#fold',1,1"); } \end class GridFold \class GridScan < GridObject struct GridScan : GridObject { \attr Numop *op; \attr PtrGrid seed; \decl void initialize (Numop *op); \decl void _0_op (Numop *op); \decl void _0_seed (Grid *seed); \grin 0 }; GRID_INLET(GridScan,0) { //{ Dim[*As,B,*Cs],Dim[*Cs] -> Dim[*As,B,*Cs] } if (seed) SAME_TYPE(in,seed); int an = in->dim->n; int bn = seed?seed->dim->n:0; if (an<=bn) RAISE("minimum 1 more dimension than the right hand"); if (seed) SAME_DIM(bn,in->dim,an-bn,seed->dim,0); out=new GridOutlet(this,0,in->dim,in->nt); in->set_factor(in->dim->prod(an-bn-1)); } GRID_FLOW { int an = in->dim->n; int bn = seed?seed->dim->n:0; int yn = in->dim->v[an-bn-1]; int zn = in->dim->prod(an-bn); int factor = in->factor(); STACK_ARRAY(T,buf,n); COPY(buf,data,n); if (seed) { for (int i=0; iscan(zn,yn,(Pt)*seed,buf+i); } else { STACK_ARRAY(T,seed,zn); CLEAR(seed,zn); for (int i=0; iscan(zn,yn,seed,buf+i); } out->send(n,buf); } GRID_END \def void _0_op (Numop *op ) { this->op =op; } \def void _0_seed (Grid *seed) { this->seed=seed; } \def void initialize (Numop *op) { rb_call_super(argc,argv); this->op = op; } \classinfo { IEVAL(rself,"install '#scan',1,1"); } \end class GridScan //**************************************************************** //{ Dim[*As,C],Dim[C,*Bs] -> Dim[*As,*Bs] } \class GridInner < GridObject struct GridInner : GridObject { \attr Numop *op_para; \attr Numop *op_fold; \attr PtrGrid seed; PtrGrid r; PtrGrid r2; GridInner() {} \decl void initialize (Grid *r=0); \decl void _0_op (Numop *op); \decl void _0_fold (Numop *op); \decl void _0_seed (Grid *seed); \grin 0 \grin 1 }; template void inner_child_a (Pt buf, Pt data, int rrows, int rcols, int chunk) { Pt bt = buf, dt = data; for (int j=0; jmap(rcols,bt,*dt); } template void inner_child_b (Pt buf, Pt data, int rrows, int chunk) { Pt bt = buf, dt = data; for (int j=0; j a = in->dim; P b = r->dim; if (a->n<1) RAISE("a: minimum 1 dimension"); if (b->n<1) RAISE("b: minimum 1 dimension"); if (seed->dim->n != 0) RAISE("seed must be a scalar"); int a_last = a->get(a->n-1); int n = a->n+b->n-2; SAME_DIM(1,a,a->n-1,b,0); STACK_ARRAY(int32,v,n); COPY(v,a->v,a->n-1); COPY(v+a->n-1,b->v+1,b->n-1); out=new GridOutlet(this,0,new Dim(n,v),in->nt); in->set_factor(a_last); int rrows = in->factor(); int rsize = r->dim->prod(); int rcols = rsize/rrows; Pt rdata = (Pt)*r; int chunk = GridOutlet::MAX_PACKET_SIZE/rsize; r2=new Grid(new Dim(chunk*rsize),r->nt); Pt buf3 = (Pt)*r2; for (int i=0; ifactor(); int rsize = r->dim->prod(); int rcols = rsize/rrows; int chunk = GridOutlet::MAX_PACKET_SIZE/rsize; STACK_ARRAY(T,buf ,chunk*rcols); STACK_ARRAY(T,buf2,chunk*rcols); int off = chunk; while (n) { if (chunk*rrows>n) chunk=n/rrows; op_put->map(chunk*rcols,buf2,*(T *)*seed); for (int i=0; i(buf,data+i,rrows,chunk); break; case 2: inner_child_b(buf,data+i,rrows,chunk); break; case 3: inner_child_b(buf,data+i,rrows,chunk); break; case 4: inner_child_b(buf,data+i,rrows,chunk); break; default: inner_child_a(buf,data+i,rrows,rcols,chunk); } op_para->zip(chunk*rcols,buf,(Pt)*r2+i*off*rcols); op_fold->zip(chunk*rcols,buf2,buf); } out->send(chunk*rcols,buf2); n-=chunk*rrows; data+=chunk*rrows; } } GRID_FINISH { r2=0; } GRID_END GRID_INPUT(GridInner,1,r) {} GRID_END \def void initialize (Grid *r) { rb_call_super(argc,argv); this->op_para = op_mul; this->op_fold = op_add; this->seed = new Grid(new Dim(),int32_e,true); this->r = r ? r : new Grid(new Dim(),int32_e,true); } \def void _0_op (Numop *op ) { this->op_para=op; } \def void _0_fold (Numop *op ) { this->op_fold=op; } \def void _0_seed (Grid *seed) { this->seed=seed; } \classinfo { IEVAL(rself,"install '#inner',2,1"); } \end class GridInner /* **************************************************************** */ /*{ Dim[*As],Dim[*Bs] -> Dim[*As,*Bs] }*/ \class GridOuter < GridObject struct GridOuter : GridObject { \attr Numop *op; PtrGrid r; \decl void initialize (Numop *op, Grid *r=0); \grin 0 \grin 1 }; GRID_INLET(GridOuter,0) { SAME_TYPE(in,r); P a = in->dim; P b = r->dim; int n = a->n+b->n; STACK_ARRAY(int32,v,n); COPY(v,a->v,a->n); COPY(v+a->n,b->v,b->n); out=new GridOutlet(this,0,new Dim(n,v),in->nt); } GRID_FLOW { int b_prod = r->dim->prod(); if (b_prod > 4) { STACK_ARRAY(T,buf,b_prod); while (n) { for (int j=0; jzip(b_prod,buf,(Pt)*r); out->send(b_prod,buf); data++; n--; } return; } n*=b_prod; Pt buf = ARRAY_NEW(T,n); STACK_ARRAY(T,buf2,b_prod*64); for (int i=0; i<64; i++) COPY(buf2+i*b_prod,(Pt)*r,b_prod); switch (b_prod) { #define Z buf[k++]=data[i] case 1: for (int i=0,k=0; kzip(ch,buf+j,buf2); op->zip(n-nn,buf+nn,buf2); out->give(n,buf); } GRID_END GRID_INPUT(GridOuter,1,r) {} GRID_END \def void initialize (Numop *op, Grid *r) { rb_call_super(argc,argv); this->op = op; this->r = r ? r : new Grid(new Dim(),int32_e,true); } \classinfo { IEVAL(rself,"install '#outer',2,1"); } \end class GridOuter //**************************************************************** //{ Dim[],Dim[],Dim[] -> Dim[A] } or //{ Dim[B],Dim[B],Dim[B] -> Dim[*As,B] } \class GridFor < GridObject struct GridFor : GridObject { \attr PtrGrid from; \attr PtrGrid to; \attr PtrGrid step; GridFor () { from.constrain(expect_max_one_dim); to .constrain(expect_max_one_dim); step.constrain(expect_max_one_dim); } \decl void initialize (Grid *from, Grid *to, Grid *step); \decl void _0_set (Grid *r=0); \decl void _0_bang (); \grin 0 int \grin 1 int \grin 2 int template void trigger (T bogus); }; \def void initialize (Grid *from, Grid *to, Grid *step) { rb_call_super(argc,argv); this->from=from; this->to =to; this->step=step; } template void GridFor::trigger (T bogus) { int n = from->dim->prod(); int32 nn[n+1]; STACK_ARRAY(T,x,64*n); Pt fromb = (Pt)*from; Pt tob = (Pt)*to ; Pt stepb = (Pt)*step; STACK_ARRAY(T,to2,n); for (int i=step->dim->prod()-1; i>=0; i--) if (!stepb[i]) RAISE("step must not contain zeroes"); for (int i=0; i d; if (from->dim->n==0) { d = new Dim(*nn); } else { nn[n]=n; d = new Dim(n+1,nn); } int total = d->prod(); out=new GridOutlet(this,0,d,from->nt); if (total==0) return; int k=0; for(int d=0;;d++) { // here d is the dim# to reset; d=n for none for(;dsend(k,x); k=0; COPY(x,x+63*n,n);} else { COPY(x+k,x+k-n,n);} d--; // here d is the dim# to increment for(;;d--) { if (d<0) goto end; x[k+d]+=stepb[d]; if (x[k+d]!=to2[d]) break; } } end: if (k) out->send(k,x); } \def void _0_bang () { SAME_TYPE(from,to); SAME_TYPE(from,step); if (!from->dim->equal(to->dim) || !to->dim->equal(step->dim)) RAISE("dimension mismatch"); #define FOO(T) trigger((T)0); TYPESWITCH_JUSTINT(from->nt,FOO,); #undef FOO } \def void _0_set (Grid *r) { from=new Grid(argv[0]); } GRID_INPUT(GridFor,2,step) {} GRID_END GRID_INPUT(GridFor,1,to) {} GRID_END GRID_INPUT(GridFor,0,from) {_0_bang(0,0);} GRID_END \classinfo { IEVAL(rself,"install '#for',3,1"); } \end class GridFor //**************************************************************** \class GridFinished < GridObject struct GridFinished : GridObject { \grin 0 }; GRID_INLET(GridFinished,0) { in->set_mode(0); } GRID_FINISH { Ruby a[] = { INT2NUM(0), bsym._bang }; send_out(COUNT(a),a); } GRID_END \classinfo { IEVAL(rself,"install '#finished',1,1"); } \end class GridFinished \class GridDim < GridObject struct GridDim : GridObject { \grin 0 }; GRID_INLET(GridDim,0) { GridOutlet out(this,0,new Dim(in->dim->n)); out.send(in->dim->n,Pt(in->dim->v,in->dim->n)); in->set_mode(0); } GRID_END \classinfo { IEVAL(rself,"install '#dim',1,1"); } \end class GridDim \class GridType < GridObject struct GridType : GridObject { \grin 0 }; GRID_INLET(GridType,0) { Ruby a[] = { INT2NUM(0), SYM(symbol), number_type_table[in->nt].sym }; send_out(COUNT(a),a); in->set_mode(0); } GRID_END \classinfo { IEVAL(rself,"install '#type',1,1"); } \end class GridType //**************************************************************** //{ Dim[*As],Dim[B] -> Dim[*Cs] } \class GridRedim < GridObject struct GridRedim : GridObject { \attr P dim; PtrGrid dim_grid; PtrGrid temp; // temp->dim is not of the same shape as dim GridRedim() { dim_grid.constrain(expect_dim_dim_list); } ~GridRedim() {} \decl void initialize (Grid *d); \grin 0 \grin 1 int32 }; GRID_INLET(GridRedim,0) { int a = in->dim->prod(), b = dim->prod(); if (ant); out=new GridOutlet(this,0,dim,in->nt); } GRID_FLOW { int i = in->dex; if (!temp) { int b = dim->prod(); int n2 = min(n,b-i); if (n2>0) out->send(n2,data); // discard other values if any } else { int a = in->dim->prod(); int n2 = min(n,a-i); COPY((Pt)*temp+i,data,n2); if (n2>0) out->send(n2,data); } } GRID_FINISH { if (!!temp) { int a = in->dim->prod(), b = dim->prod(); if (a) { for (int i=a; isend(min(a,b-i),(Pt)*temp); } else { STACK_ARRAY(T,foo,1); foo[0]=0; for (int i=0; isend(1,foo); } } temp=0; } GRID_END GRID_INPUT(GridRedim,1,dim_grid) { dim = dim_grid->to_dim(); } GRID_END \def void initialize (Grid *d) { rb_call_super(argc,argv); dim_grid=d; dim = dim_grid->to_dim(); } \classinfo { IEVAL(rself,"install '#redim',2,1"); } \end class GridRedim //**************************************************************** \class GridJoin < GridObject struct GridJoin : GridObject { \attr int which_dim; PtrGrid r; \grin 0 \grin 1 \decl void initialize (int which_dim=-1, Grid *r=0); }; GRID_INLET(GridJoin,0) { NOTEMPTY(r); SAME_TYPE(in,r); P d = in->dim; if (d->n != r->dim->n) RAISE("wrong number of dimensions"); int w = which_dim; if (w<0) w+=d->n; if (w<0 || w>=d->n) RAISE("can't join on dim number %d on %d-dimensional grids", which_dim,d->n); STACK_ARRAY(int32,v,d->n); for (int i=0; in; i++) { v[i] = d->get(i); if (i==w) { v[i]+=r->dim->v[i]; } else { if (v[i]!=r->dim->v[i]) RAISE("dimensions mismatch: dim #%i, left is %d, right is %d",i,v[i],r->dim->v[i]); } } out=new GridOutlet(this,0,new Dim(d->n,v),in->nt); if (d->prod(w)) in->set_factor(d->prod(w)); } GRID_FLOW { int w = which_dim; if (w<0) w+=in->dim->n; int a = in->factor(); int b = r->dim->prod(w); Pt data2 = (Pt)*r + in->dex*b/a; if (a==3 && b==1) { int m = n+n*b/a; STACK_ARRAY(T,data3,m); Pt data4 = data3; while (n) { SCOPY(data4,data,3); SCOPY(data4+3,data2,1); n-=3; data+=3; data2+=1; data4+=4; } out->send(m,data3); } else if (a+b<=16) { int m = n+n*b/a; STACK_ARRAY(T,data3,m); int i=0; while (n) { COPY(data3+i,data,a); data+=a; i+=a; n-=a; COPY(data3+i,data2,b); data2+=b; i+=b; } out->send(m,data3); } else { while (n) { out->send(a,data); out->send(b,data2); data+=a; data2+=b; n-=a; } } } GRID_FINISH { if (in->dim->prod()==0) out->send(r->dim->prod(),(Pt)*r); } GRID_END GRID_INPUT(GridJoin,1,r) {} GRID_END \def void initialize (int which_dim, Grid *r) { rb_call_super(argc,argv); this->which_dim = which_dim; if (r) this->r=r; } \classinfo { IEVAL(rself,"install '@join',2,1"); } \end class GridJoin //**************************************************************** \class GridGrade < GridObject struct GridGrade : GridObject { \grin 0 }; template struct GradeFunction { static int comparator (const void *a, const void *b) { return **(T**)a - **(T**)b;}}; #define FOO(S) \ template <> struct GradeFunction { \ static int comparator (const void *a, const void *b) { \ S x = **(S**)a - **(S**)b; \ return x<0 ? -1 : x>0;}}; FOO(int64) FOO(float32) FOO(float64) #undef FOO GRID_INLET(GridGrade,0) { out=new GridOutlet(this,0,in->dim,in->nt); in->set_factor(in->dim->get(in->dim->n-1)); } GRID_FLOW { int m = in->factor(); STACK_ARRAY(T*,foo,m); STACK_ARRAY(T,bar,m); for (; n; n-=m,data+=m) { for (int i=0; i::comparator); for (int i=0; isend(m,bar); } } GRID_END \classinfo { IEVAL(rself,"install '#grade',1,1"); } \end class GridGrade //**************************************************************** //\class GridMedian < GridObject //**************************************************************** \class GridTranspose < GridObject struct GridTranspose : GridObject { \attr int dim1; \attr int dim2; int d1,d2,na,nb,nc,nd; // temporaries \decl void initialize (int dim1=0, int dim2=1); \decl void _1_float (int dim1); \decl void _2_float (int dim2); \grin 0 }; \def void _1_float (int dim1) { this->dim1=dim1; } \def void _2_float (int dim2) { this->dim2=dim2; } GRID_INLET(GridTranspose,0) { STACK_ARRAY(int32,v,in->dim->n); COPY(v,in->dim->v,in->dim->n); d1=dim1; d2=dim2; if (d1<0) d1+=in->dim->n; if (d2<0) d2+=in->dim->n; if (d1>=in->dim->n || d2>=in->dim->n || d1<0 || d2<0) RAISE("would swap dimensions %d and %d but this grid has only %d dimensions", dim1,dim2,in->dim->n); memswap(v+d1,v+d2,1); if (d1==d2) { out=new GridOutlet(this,0,new Dim(in->dim->n,v), in->nt); } else { nd = in->dim->prod(1+max(d1,d2)); nc = in->dim->v[max(d1,d2)]; nb = in->dim->prod(1+min(d1,d2))/nc/nd; na = in->dim->v[min(d1,d2)]; out=new GridOutlet(this,0,new Dim(in->dim->n,v), in->nt); in->set_factor(na*nb*nc*nd); } // Turns a Grid[*,na,*nb,nc,*nd] into a Grid[*,nc,*nb,na,*nd]. } GRID_FLOW { STACK_ARRAY(T,res,na*nb*nc*nd); if (dim1==dim2) { out->send(n,data); return; } int prod = na*nb*nc*nd; for (; n; n-=prod, data+=prod) { for (int a=0; asend(na*nb*nc*nd,res); } } GRID_END \def void initialize (int dim1=0, int dim2=1) { rb_call_super(argc,argv); this->dim1 = dim1; this->dim2 = dim2; } \classinfo { IEVAL(rself,"install '#transpose',3,1"); } \end class GridTranspose //**************************************************************** \class GridReverse < GridObject struct GridReverse : GridObject { \attr int dim1; // dimension to act upon int d; // temporaries \decl void initialize (int dim1=0); \decl void _1_float (int dim1); \grin 0 }; \def void _1_float (int dim1) { this->dim1=dim1; } GRID_INLET(GridReverse,0) { d=dim1; if (d<0) d+=in->dim->n; if (d>=in->dim->n || d<0) RAISE("would reverse dimension %d but this grid has only %d dimensions", dim1,in->dim->n); out=new GridOutlet(this,0,new Dim(in->dim->n,in->dim->v), in->nt); in->set_factor(in->dim->prod(d)); } GRID_FLOW { int f1=in->factor(), f2=in->dim->prod(d+1); while (n) { int hf1=f1/2; Pt data2 = data+f1-f2; for (int i=0; isend(f1,data); data+=f1; n-=f1; } } GRID_END \def void initialize (int dim1=0) { rb_call_super(argc,argv); this->dim1 = dim1; } \classinfo { IEVAL(rself,"install '#reverse',2,1"); } \end class GridReverse //**************************************************************** \class GridCentroid < GridObject struct GridCentroid : GridObject { \decl void initialize (); \grin 0 int int sumx,sumy,sum,y; // temporaries }; GRID_INLET(GridCentroid,0) { if (in->dim->n != 3) RAISE("expecting 3 dims"); if (in->dim->v[2] != 1) RAISE("expecting 1 channel"); in->set_factor(in->dim->prod(1)); out=new GridOutlet(this,0,new Dim(2), in->nt); sumx=0; sumy=0; sum=0; y=0; } GRID_FLOW { int sx = in->dim->v[1]; while (n) { for (int x=0; xsend(2,blah); rb_funcall(rself,SI(send_out),2,INT2NUM(1),INT2NUM(blah[0])); rb_funcall(rself,SI(send_out),2,INT2NUM(2),INT2NUM(blah[1])); } GRID_END \def void initialize () { rb_call_super(argc,argv); } \classinfo { IEVAL(rself,"install '#centroid',1,3"); } \end class GridCentroid //**************************************************************** \class GridPerspective < GridObject struct GridPerspective : GridObject { \attr int32 z; \grin 0 \decl void initialize (int32 z=256); }; GRID_INLET(GridPerspective,0) { int n = in->dim->n; STACK_ARRAY(int32,v,n); COPY(v,in->dim->v,n); v[n-1]--; in->set_factor(in->dim->get(in->dim->n-1)); out=new GridOutlet(this,0,new Dim(n,v),in->nt); } GRID_FLOW { int m = in->factor(); for (; n; n-=m,data+=m) { op_mul->map(m-1,data,(T)z); op_div->map(m-1,data,data[m-1]); out->send(m-1,data); } } GRID_END \def void initialize (int32 z) {rb_call_super(argc,argv); this->z=z; } \classinfo { IEVAL(rself,"install '#perspective',1,1"); } \end class GridPerspective static Numop *OP(Ruby x) { return FIX2PTR(Numop,rb_hash_aref(op_dict,x)); } void startup_flow_objects () { op_add = OP(SYM(+)); op_sub = OP(SYM(-)); op_mul = OP(SYM(*)); op_shl = OP(SYM(<<)); op_mod = OP(SYM(%)); op_and = OP(SYM(&)); op_div = OP(SYM(/)); op_put = OP(SYM(put)); \startall }