Changeset: 8e5d8d710d5f for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=8e5d8d710d5f
Modified Files:
        monetdb5/modules/mal/array.mx
        sql/scripts/29_array.sql
        sql/test/sciql/Tests/07_tiling_01.sql
        sql/test/sciql/Tests/07_tiling_01.stable.out
        sql/test/sciql/Tests/07_tiling_02.sql
        sql/test/sciql/Tests/07_tiling_02.stable.out
        sql/test/sciql/Tests/07_tiling_03.sql
        sql/test/sciql/Tests/07_tiling_03.stable.out
        sql/test/sciql/Tests/07_tiling_04.sql
        sql/test/sciql/Tests/07_tiling_04.stable.out
Branch: sciql
Log Message:

added array.{min,max}()

for now the cured way with lots of copy&paste;
to be cleaned up soon ...


diffs (truncated from 2841 to 300 lines):

diff --git a/monetdb5/modules/mal/array.mx b/monetdb5/modules/mal/array.mx
--- a/monetdb5/modules/mal/array.mx
+++ b/monetdb5/modules/mal/array.mx
@@ -100,6 +100,14 @@ pattern avg(val:any, any...):dbl
 address ARRAYtilesAvg
 comment "Construct the average over all tiles";
 
+pattern min(val:any_1, any...):any_1
+address ARRAYtilesMin
+comment "Construct the minimum over all tiles";
+
+pattern max(val:any_1, any...):any_1
+address ARRAYtilesMax
+comment "Construct the maximum over all tiles";
+
 module batarray;
 
 # The BAT version of the AGGR functions over array tiles
@@ -115,6 +123,14 @@ pattern avg(val:bat[:oid,:any], any...):
 address ARRAYtilesAvg
 comment "Construct the average over all tiles";
 
+pattern min(val:bat[:oid,:any_1], any...):bat[:oid,:any_1]
+address ARRAYtilesMin
+comment "Construct the minimum over all tiles";
+
+pattern max(val:bat[:oid,:any_1], any...):bat[:oid,:any_1]
+address ARRAYtilesMax
+comment "Construct the maximum over all tiles";
+
 module array;
 
 # unused functions
@@ -199,12 +215,16 @@ array_export str ARRAYreplaceScalar(Clie
 array_export str ARRAYtiles(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 array_export str ARRAYtilesSum(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 array_export str ARRAYtilesAvg(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
+array_export str ARRAYtilesMin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
+array_export str ARRAYtilesMax(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 array_export str ARRAYembed(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 
 @= array_defs
 array_export str ARRAYseries_@1(int *ret, @1 *start, @1 *step, @1 *stop, int 
*grp, int *series);
 array_export str ARRAYtilesSum_@1(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 array_export str ARRAYtilesAvg_@1(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
+array_export str ARRAYtilesMin_@1(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
+array_export str ARRAYtilesMax_@1(Client cntxt, MalBlkPtr mb, MalStkPtr stk, 
InstrPtr pci);
 @h
 @:array_defs(bte)@
 @:array_defs(sht)@
@@ -940,6 +960,234 @@ ARRAYtilesAvg(Client cntxt, MalBlkPtr mb
        return MAL_SUCCEED;
 }
 
+@= tilesMinMax
+# define MINMAX_CLEANUP() \
+{ \
+       if (bVal) BBPreleaseref(bVal->batCacheid); \
+       for (i = 0; i < ndims; i++) { \
+               if(bDims[i]) BBPreleaseref(bDims[i]->batCacheid); \
+               if(bOffsets[i]) BBPreleaseref(bOffsets[i]->batCacheid); \
+       } \
+       if(bDims) GDKfree(bDims); \
+       if(bDimsT) GDKfree(bDimsT); \
+       if(bOffsets) GDKfree(bOffsets); \
+       if(bOffsetsT) GDKfree(bOffsetsT); \
+       if(dMin) GDKfree(dMin); \
+       if(dMax) GDKfree(dMax); \
+       if(dSize) GDKfree(dSize); \
+}
+/* 
+ * array.[min|max] inputs:
+ *  (cell_val:BAT,
+ *   dim_1:BAT,tile_member_offset_dim_1:BAT,size_dim_1, ...,
+ *   dim_n:BAT,tile_member_offset_dim_n:BAT,size_dim_n)
+ */
+str
+ARRAYtiles@2_@1(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
+{
+       BAT *bVal = NULL, *bRes = NULL, **bDims = NULL, **bOffsets = NULL;
+       int *ret = (int*) getArgReference(stk,pci,0), i = 0, ndims = 0, err = 0;
+       @1 *bValT = NULL, elm = 0;
+       @1 *bResT = NULL;
+       int **bDimsT = NULL, **bOffsetsT = NULL;
+       BUN p, r, arrcnt = 0, offcnt = 0;
+       @1 minmax = @1_nil;
+       bit first = TRUE;
+       /* FIXME: this code only deal with INT dimensions */
+       int cidx = 0, *dMin = NULL, *dMax = NULL, *dSize = NULL;
+       oid arrbase = 0, offbase = 0, vid = 0, mul = 0;
+
+       (void) cntxt;
+       (void) mb;
+
+       if ( (pci->argc - pci->retc - 1) % 3 != 0)
+               throw(MAL, "array.@3", "Unbalanced argument sets");
+
+       ndims = (pci->argc - pci->retc - 1) / 3;
+       bDims = (BAT**) GDKzalloc(sizeof(BAT*) * ndims);
+       bDimsT = (int**) GDKzalloc(sizeof(int*) * ndims);
+       bOffsets = (BAT**) GDKzalloc(sizeof(BAT*) * ndims);
+       bOffsetsT = (int**) GDKzalloc(sizeof(int*) * ndims);
+       dMin = (int*) GDKzalloc(sizeof(int) * ndims);
+       dMax = (int*) GDKzalloc(sizeof(int) * ndims);
+       dSize = (int*) GDKzalloc(sizeof(int) * ndims);
+       bVal = BATdescriptor(*(int*)getArgReference(stk,pci,1));
+       if(!bDims || !bDimsT || !bOffsets || !bOffsetsT || !dMin || !dMax || 
!dSize || !bVal) {
+               MINMAX_CLEANUP();
+               throw(MAL, "array.@3", RUNTIME_OBJECT_MISSING);
+       }
+       for (i = 0; i < ndims; i++) {
+               bDims[i] = BATdescriptor(*(int*)getArgReference(stk,pci,2+i*3));
+               bOffsets[i] = 
BATdescriptor(*(int*)getArgReference(stk,pci,2+i*3+1));
+               if (!bDims[i] || !bOffsets[i]) {
+                       MINMAX_CLEANUP();
+                       throw(MAL, "array.@3", RUNTIME_OBJECT_MISSING);
+               }
+               dSize[i] = *(int*)getArgReference(stk,pci,2+i*3+2);
+       }
+       /* type check the shapes, prepare iterators, and compute the min/max of 
the dimensions */
+       if (!BAThdense(bVal)) {
+               MINMAX_CLEANUP();
+               throw(MAL, "array.@3", "head of value BAT must be dense");
+       }
+       if (bVal->ttype != TYPE_@1) {
+               MINMAX_CLEANUP();
+               throw(MAL, "array.@3", "tail of value BAT must be of type @1");
+       }
+       arrcnt = BATcount(bVal);
+       arrbase = bVal->hseqbase;
+       offbase = bOffsets[0]->hseqbase;
+       offcnt = BATcount(bOffsets[0]);
+       for (i = 0; i < ndims; i++) {
+               if (!BAThdense(bDims[i])) {
+                       MINMAX_CLEANUP();
+                       throw(MAL, "array.@3", "head of all dimension BATs must 
be dense");
+               }
+               if (!BAThdense(bOffsets[i])) {
+                       MINMAX_CLEANUP();
+                       throw(MAL, "array.@3", "head of all offset BATs must be 
dense");
+               }
+               if (bDims[i]->hseqbase != arrbase || BATcount(bDims[i]) != 
arrcnt) {
+                       MINMAX_CLEANUP();
+                       throw(MAL, "array.@3", "head of all dimension BATs must 
be aligned with head of value BAT");
+               }
+               if (bOffsets[i]->hseqbase != offbase || BATcount(bOffsets[i]) 
!= offcnt) {
+                       MINMAX_CLEANUP();
+                       throw(MAL, "array.@3", "heads of all offset BATs must 
be aligned");
+               }
+               if (bDims[i]->ttype != TYPE_int || bDims[i]->ttype != 
bOffsets[i]->ttype) {
+                       MINMAX_CLEANUP();
+                       throw(MAL, "array.@3", SEMANTIC_TYPE_MISMATCH);
+               }
+               BATmin(bDims[i], &(dMin[i]));
+               BATmax(bDims[i], &(dMax[i]));
+       }
+
+       /* access tails as arrays */
+       bValT = (@1*) Tloc(bVal, BUNfirst(bVal));
+       for (i = 0; i < ndims; i++) {
+               bDimsT[i] = (int*) Tloc(bDims[i], BUNfirst(bDims[i]));
+               bOffsetsT[i] = (int*) Tloc(bOffsets[i], BUNfirst(bOffsets[i]));
+       }
+
+       /* For each anchor piont, compute all cells belong to this tile 
(bVal.head
+        * is the group nr.) and compute the SUM */
+       bRes =  BATnew(TYPE_void, TYPE_@1, BATcount(bVal));
+       bResT = (@1*) Tloc(bRes, BUNfirst(bRes));
+       for (p = 0 ; p < arrcnt ; p++) {
+               /* loop over all sets of offsets */
+               for (r = 0; r < offcnt ; r++) {
+                       vid = 0; /* index into bVal for the value of a 
qualified tile member */
+                       mul = 1;
+                       err = 0;
+                       /* for the index of the anchor point on dimension d_i, 
check if the
+                        * resulting index is within the dimension range after 
having
+                        * shifted according this set of offset on dimension 
d_i.
+                        * If yes, update 'vid' so that we know the OID of the 
qualified
+                        * cell at the end; otherwise, skip.
+                        */
+                       /* TODO: we can skip more.  If the j-th value 
bOffsets[i]
+                        * disqualifies the index on dimension d_i, we can jump 
to the next
+                        * of bOffsets[i] which value follows the j-th value */
+                       for (i = ndims - 1; i >= 0; i--) {
+                               cidx = bDimsT[i][p] + bOffsetsT[i][r];
+                               if (dMin[i] <= cidx && cidx <= dMax[i]) {
+                                       vid += mul * (cidx - dMin[i]);
+                               } else {
+                                       err = 1;
+                                       break; /* skip remaining dimensions */
+                               }
+                               mul *= dSize[i];
+                       }
+                       if (!err) {
+                               elm = bValT[vid];
+                               if (elm != @1_nil) {
+                                       if (first) {
+                                               minmax = elm;
+                                               first = FALSE;
+                                       }
+                                       else
+                                               minmax = @4(minmax,elm);
+                               }
+                       }
+               }
+               bResT[p] = minmax;
+       }
+       MINMAX_CLEANUP();
+       BATsetcount(bRes, arrcnt);
+       BATseqbase(bRes, arrbase);
+       bRes->hdense = TRUE;
+       BATkey(bRes, TRUE);
+       bRes->hsorted = 1;
+       bRes->hrevsorted = (arrcnt <= 1);
+       bRes->tsorted = (arrcnt <= 1);
+       bRes->trevsorted = (arrcnt <= 1);
+       BATkey(BATmirror(bRes), FALSE);
+       BBPkeepref(*ret = bRes->batCacheid);
+       return MAL_SUCCEED;
+}
+@-
+The compilating factor is that in general the tile enumeration is dense, while
+the tile structure can go over its boundaries. For this to control, we first
+embed the array into a slightly larger array, filled with nulls.
+
+@c
+@:tilesMinMax(bte,Min,min,MIN)@
+@:tilesMinMax(sht,Min,min,MIN)@
+@:tilesMinMax(int,Min,min,MIN)@
+@:tilesMinMax(lng,Min,min,MIN)@
+@:tilesMinMax(flt,Min,min,MIN)@
+@:tilesMinMax(dbl,Min,min,MIN)@
+@:tilesMinMax(bte,Max,max,MAX)@
+@:tilesMinMax(sht,Max,max,MAX)@
+@:tilesMinMax(int,Max,max,MAX)@
+@:tilesMinMax(lng,Max,max,MAX)@
+@:tilesMinMax(flt,Max,max,MAX)@
+@:tilesMinMax(dbl,Max,max,MAX)@
+str
+ARRAYtilesMin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) {
+       int type = getTailType(getArgType(mb,pci,1));
+       switch(type){
+       case TYPE_bte:
+               return ARRAYtilesMin_bte(cntxt,mb,stk,pci);
+       case TYPE_sht:
+               return ARRAYtilesMin_sht(cntxt,mb,stk,pci);
+       case TYPE_int:
+               return ARRAYtilesMin_int(cntxt,mb,stk,pci);
+       case TYPE_lng:
+               return ARRAYtilesMin_lng(cntxt,mb,stk,pci);
+       case TYPE_flt:
+               return ARRAYtilesMin_flt(cntxt,mb,stk,pci);
+       case TYPE_dbl:
+               return ARRAYtilesMin_dbl(cntxt,mb,stk,pci);
+       default:
+               throw(MAL, "array.min", "illegal/unsupported type");
+       }
+       return MAL_SUCCEED;
+}
+
+str
+ARRAYtilesMax(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) {
+       int type = getTailType(getArgType(mb,pci,1));
+       switch(type){
+       case TYPE_bte:
+               return ARRAYtilesMax_bte(cntxt,mb,stk,pci);
+       case TYPE_sht:
+               return ARRAYtilesMax_sht(cntxt,mb,stk,pci);
+       case TYPE_int:
+               return ARRAYtilesMax_int(cntxt,mb,stk,pci);
+       case TYPE_lng:
+               return ARRAYtilesMax_lng(cntxt,mb,stk,pci);
+       case TYPE_flt:
+               return ARRAYtilesMax_flt(cntxt,mb,stk,pci);
+       case TYPE_dbl:
+               return ARRAYtilesMax_dbl(cntxt,mb,stk,pci);
+       default:
+               throw(MAL, "array.max", "illegal/unsupported type");
+       }
+       return MAL_SUCCEED;
+}
+
 str
 ARRAYembed(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
 {
diff --git a/sql/scripts/29_array.sql b/sql/scripts/29_array.sql
--- a/sql/scripts/29_array.sql
+++ b/sql/scripts/29_array.sql
@@ -72,6 +72,20 @@ create function array_sum(val bigint,   
 create function array_sum(val real,     dim1 int, offsets1 int, size1 int) 
returns double external name "array".sum;
 create function array_sum(val double,   dim1 int, offsets1 int, size1 int) 
returns double external name "array".sum;
 
+create function array_min(val tinyint,  dim1 int, offsets1 int, size1 int) 
returns tinyint   external name "array".min;
+create function array_min(val smallint, dim1 int, offsets1 int, size1 int) 
returns smallint  external name "array".min;
+create function array_min(val int,      dim1 int, offsets1 int, size1 int) 
returns int       external name "array".min;
+create function array_min(val bigint,   dim1 int, offsets1 int, size1 int) 
returns bigint    external name "array".min;
+create function array_min(val real,     dim1 int, offsets1 int, size1 int) 
returns real      external name "array".min;
+create function array_min(val double,   dim1 int, offsets1 int, size1 int) 
returns double    external name "array".min;
+
+create function array_max(val tinyint,  dim1 int, offsets1 int, size1 int) 
returns tinyint   external name "array".max;
_______________________________________________
Checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list

Reply via email to