Changeset: bfb1f607de02 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=bfb1f607de02
Modified Files:
        clients/Tests/exports.stable.out
        gdk/gdk_aggr.c
        gdk/gdk_calc.h
        monetdb5/modules/kernel/aggr.c
        monetdb5/modules/kernel/aggr.mal
        monetdb5/modules/kernel/aggr.mal.sh
        monetdb5/modules/kernel/algebra.mx
Branch: default
Log Message:

Implemented standard deviation (sample and population) in single scan.
This implementation is currently not yet used by SQL.
See bug 3178.


diffs (truncated from 883 to 300 lines):

diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out
--- a/clients/Tests/exports.stable.out
+++ b/clients/Tests/exports.stable.out
@@ -90,6 +90,8 @@ BAT *BATcalcorcst(BAT *b, const ValRecor
 BAT *BATcalcrsh(BAT *b1, BAT *b2, BAT *s, int abort_on_error);
 BAT *BATcalcrshcst(BAT *b, const ValRecord *v, BAT *s, int abort_on_error);
 BAT *BATcalcsign(BAT *b, BAT *s);
+dbl BATcalcstdev_population(dbl *avgp, BAT *b);
+dbl BATcalcstdev_sample(dbl *avgp, BAT *b);
 BAT *BATcalcsub(BAT *b1, BAT *b2, BAT *s, int tp, int abort_on_error);
 BAT *BATcalcsubcst(BAT *b, const ValRecord *v, BAT *s, int tp, int 
abort_on_error);
 BAT *BATcalcxor(BAT *b1, BAT *b2, BAT *s);
@@ -124,6 +126,8 @@ BAT *BATgroupmedian(BAT *b, BAT *g, BAT 
 BAT *BATgroupmin(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int 
abort_on_error);
 BAT *BATgroupprod(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int 
abort_on_error);
 BAT *BATgroupsize(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int 
abort_on_error);
+BAT *BATgroupstdev_population(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int 
skip_nils, int abort_on_error);
+BAT *BATgroupstdev_sample(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int 
skip_nils, int abort_on_error);
 BAT *BATgroupsum(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int 
abort_on_error);
 BUN BATgrows(BAT *b);
 BAT *BAThash(BAT *b, BUN masksize);
@@ -621,6 +625,10 @@ str AGGRprod3_lng(bat *retval, bat *bid,
 str AGGRprod3_sht(bat *retval, bat *bid, bat *gid, bat *eid);
 str AGGRprod3_wrd(bat *retval, bat *bid, bat *gid, bat *eid);
 str AGGRsize2(bat *retval, bat *bid, bat *eid);
+str AGGRstdev2_dbl(bat *retval, bat *bid, bat *eid);
+str AGGRstdev3_dbl(bat *retval, bat *bid, bat *gid, bat *eid);
+str AGGRstdevp2_dbl(bat *retval, bat *bid, bat *eid);
+str AGGRstdevp3_dbl(bat *retval, bat *bid, bat *gid, bat *eid);
 str AGGRsubavg_dbl(bat *retval, bat *bid, bat *gid, bat *eid, int *skip_nils, 
int *abort_on_error);
 str AGGRsubavgcand_dbl(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, 
int *skip_nils, int *abort_on_error);
 str AGGRsubcount(bat *retval, bat *bid, bat *gid, bat *eid, int *skip_nils);
@@ -649,6 +657,10 @@ str AGGRsubprodcand_int(bat *retval, bat
 str AGGRsubprodcand_lng(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, 
int *skip_nils, int *abort_on_error);
 str AGGRsubprodcand_sht(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, 
int *skip_nils, int *abort_on_error);
 str AGGRsubprodcand_wrd(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, 
int *skip_nils, int *abort_on_error);
+str AGGRsubstdev_dbl(bat *retval, bat *bid, bat *gid, bat *eid, int 
*skip_nils, int *abort_on_error);
+str AGGRsubstdevcand_dbl(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, 
int *skip_nils, int *abort_on_error);
+str AGGRsubstdevp_dbl(bat *retval, bat *bid, bat *gid, bat *eid, int 
*skip_nils, int *abort_on_error);
+str AGGRsubstdevpcand_dbl(bat *retval, bat *bid, bat *gid, bat *eid, bat *sid, 
int *skip_nils, int *abort_on_error);
 str AGGRsubsum_bte(bat *retval, bat *bid, bat *gid, bat *eid, int *skip_nils, 
int *abort_on_error);
 str AGGRsubsum_dbl(bat *retval, bat *bid, bat *gid, bat *eid, int *skip_nils, 
int *abort_on_error);
 str AGGRsubsum_flt(bat *retval, bat *bid, bat *gid, bat *eid, int *skip_nils, 
int *abort_on_error);
@@ -792,13 +804,8 @@ str ALGslice_wrd(int *ret, bat *bid, wrd
 str ALGsplit(int *result, int *bid);
 str ALGssort(int *result, int *bid);
 str ALGssort_rev(int *result, int *bid);
-str ALGstdev_bte(dbl *res, int *bid);
-str ALGstdev_dbl(dbl *res, int *bid);
-str ALGstdev_flt(dbl *res, int *bid);
-str ALGstdev_int(dbl *res, int *bid);
-str ALGstdev_lng(dbl *res, int *bid);
-str ALGstdev_sht(dbl *res, int *bid);
-str ALGstdev_wrd(dbl *res, int *bid);
+str ALGstdev(dbl *res, int *bid);
+str ALGstdevp(dbl *res, int *bid);
 str ALGsubselect1(bat *result, bat *bid, const void *low, const void *high, 
const bit *li, const bit *hi, const bit *anti);
 str ALGsubselect2(bat *result, bat *bid, bat *sid, const void *low, const void 
*high, const bit *li, const bit *hi, const bit *anti);
 str ALGsubslice_wrd(int *ret, bat *bid, wrd *start, wrd *end);
diff --git a/gdk/gdk_aggr.c b/gdk/gdk_aggr.c
--- a/gdk/gdk_aggr.c
+++ b/gdk/gdk_aggr.c
@@ -2114,3 +2114,294 @@ BATgroupmedian(BAT *b, BAT *g, BAT *e, B
        BBPunfix(bn->batCacheid);
        return NULL;
 }
+
+/* ---------------------------------------------------------------------- */
+/* standard deviation (both biases and non-biased) */
+
+#define AGGR_STDEV(TYPE)                                               \
+       do {                                                            \
+               TYPE x;                                                 \
+               for (i = 0; i < cnt; i++) {                             \
+                       x = ((const TYPE *) values)[i];                 \
+                       if (x == TYPE##_nil)                            \
+                               continue;                               \
+                       n++;                                            \
+                       delta = (dbl) x - mean;                         \
+                       mean += delta / n;                              \
+                       m2 += delta * ((dbl) x - mean);                 \
+               }                                                       \
+       } while (0)
+
+static dbl
+calcstdev(dbl *avgp, const void *values, BUN cnt, int tp, int issample)
+{
+       BUN n = 0, i;
+       dbl mean = 0;
+       dbl m2 = 0;
+       dbl delta;
+
+       assert(issample == 0 || issample == 1);
+
+       switch (ATOMstorage(tp)) {
+       case TYPE_bte:
+               AGGR_STDEV(bte);
+               break;
+       case TYPE_sht:
+               AGGR_STDEV(sht);
+               break;
+       case TYPE_int:
+               AGGR_STDEV(int);
+               break;
+       case TYPE_lng:
+               AGGR_STDEV(lng);
+               break;
+       case TYPE_flt:
+               AGGR_STDEV(flt);
+               break;
+       case TYPE_dbl:
+               AGGR_STDEV(dbl);
+               break;
+       default:
+               return dbl_nil;
+       }
+       if (n <= (BUN) issample) {
+               if (avgp)
+                       *avgp = dbl_nil;
+               return dbl_nil;
+       }
+       if (avgp)
+               *avgp = mean;
+       return sqrt(m2 / (n - issample));
+}
+
+dbl
+BATcalcstdev_population(dbl *avgp, BAT *b)
+{
+       return calcstdev(avgp, (const void *) Tloc(b, BUNfirst(b)),
+                        BATcount(b), b->ttype, 0);
+}
+
+dbl
+BATcalcstdev_sample(dbl *avgp, BAT *b)
+{
+       return calcstdev(avgp, (const void *) Tloc(b, BUNfirst(b)),
+                        BATcount(b), b->ttype, 1);
+}
+
+#undef AGGR_STDEV
+#define AGGR_STDEV(TYPE)                                               \
+       do {                                                            \
+               const TYPE *vals = (const TYPE *) Tloc(b, BUNfirst(b)); \
+               for (i = start; i < end; i++, vals++) {                 \
+                       if (cand) {                                     \
+                               if (i < *cand - b->hseqbase) {          \
+                                       if (gids)                       \
+                                               gids++;                 \
+                                       continue;                       \
+                               }                                       \
+                               assert(i == *cand - b->hseqbase);       \
+                               if (++cand == candend)                  \
+                                       end = i + 1;                    \
+                       }                                               \
+                       if (gids == NULL ||                             \
+                           (*gids >= min && *gids <= max)) {           \
+                               gid = gids ? *gids - min : (oid) i;     \
+                               if (*vals == TYPE##_nil) {              \
+                                       if (!skip_nils)                 \
+                                               cnts[gid] = BUN_NONE;   \
+                               } else if (cnts[gid] != BUN_NONE) {     \
+                                       cnts[gid]++;                    \
+                                       delta[gid] = (dbl) *vals - mean[gid]; \
+                                       mean[gid] += delta[gid] / cnts[gid]; \
+                                       m2[gid] += delta[gid] * ((dbl) *vals - 
mean[gid]); \
+                               }                                       \
+                       }                                               \
+                       if (gids)                                       \
+                               gids++;                                 \
+               }                                                       \
+               for (i = 0; i < ngrp; i++) {                            \
+                       if (cnts[i] == 0 || cnts[i] == BUN_NONE) {      \
+                               dbls[i] = dbl_nil;                      \
+                               mean[i] = dbl_nil;                      \
+                               nils++;                                 \
+                       } else if (cnts[i] == 1) {                      \
+                               dbls[i] = 0;                            \
+                       } else {                                        \
+                               dbls[i] = m2[i] / (cnts[i] - issample); \
+                       }                                               \
+               }                                                       \
+       } while (0)
+
+/* Calculate group standard deviation (population (i.e. biased) or
+ * sample (i.e. non-biased)) with optional candidates list.
+ *
+ * Note that this helper function is prepared to return two BATs: one
+ * (as return value) with the standard deviation per group, and one
+ * (as return argument) with the average per group.  This isn't
+ * currently used since it doesn't fit into the mold of grouped
+ * aggregates. */
+static BAT *
+dogroupstdev(BAT **avgb, BAT *b, BAT *g, BAT *e, BAT *s, int tp,
+            int skip_nils, int issample, const char *func)
+{
+       const oid *gids;
+       oid gid;
+       oid min, max;
+       BUN i, ngrp;
+       BUN nils = 0;
+       BUN *cnts = NULL;
+       dbl *dbls, *mean, *delta, *m2;
+       BAT *bn = NULL;
+       BUN start, end, cnt;
+       const oid *cand = NULL, *candend = NULL;
+       const char *err;
+
+       assert(tp == TYPE_dbl);
+       (void) tp;              /* compatibility (with other BATgroup*
+                                * functions) argument */
+
+       if ((err = BATgroupaggrinit(b, g, e, s, &min, &max, &ngrp, &start, &end,
+                                   &cnt, &cand, &candend)) != NULL) {
+               GDKerror("%s: %s\n", func, err);
+               return NULL;
+       }
+       if (g == NULL) {
+               GDKerror("%s: b and g must be aligned\n", func);
+               return NULL;
+       }
+
+       if (BATcount(b) == 0 || ngrp == 0) {
+               /* trivial: no products, so return bat aligned with g
+                * with nil in the tail */
+               bn = BATconstant(TYPE_dbl, &dbl_nil, ngrp);
+               BATseqbase(bn, ngrp == 0 ? 0 : min);
+               return bn;
+       }
+
+       if ((e == NULL ||
+            (BATcount(e) == BATcount(b) && e->hseqbase == b->hseqbase)) &&
+           (BATtdense(g) || (g->tkey && g->T->nonil))) {
+               /* trivial: singleton groups, so all results are equal
+                * to zero (population) or nil (sample) */
+               dbl v = issample ? dbl_nil : 0;
+               bn = BATconstant(TYPE_dbl, &v, ngrp);
+               BATseqbase(bn, ngrp == 0 ? 0 : min);
+               return bn;
+       }
+
+       delta = GDKmalloc(ngrp * sizeof(dbl));
+       m2 = GDKmalloc(ngrp * sizeof(dbl));
+       cnts = GDKzalloc(ngrp * sizeof(BUN));
+       if (avgb) {
+               if ((*avgb = BATnew(TYPE_void, TYPE_dbl, ngrp)) == NULL) {
+                       mean = NULL;
+                       goto alloc_fail;
+               }
+               mean = (dbl *) Tloc(*avgb, BUNfirst(*avgb));
+       } else {
+               mean = GDKmalloc(ngrp * sizeof(dbl));
+       }
+       if (mean == NULL || delta == NULL || m2 == NULL || cnts == NULL)
+               goto alloc_fail;
+
+       bn = BATnew(TYPE_void, TYPE_dbl, ngrp);
+       if (bn == NULL)
+               goto alloc_fail;
+       dbls = (dbl *) Tloc(bn, BUNfirst(bn));
+
+       for (i = 0; i < ngrp; i++) {
+               mean[i] = 0;
+               delta[i] = 0;
+               m2[i] = 0;
+       }
+
+       if (BATtdense(g))
+               gids = NULL;
+       else
+               gids = (const oid *) Tloc(g, BUNfirst(g) + start);
+
+       switch (ATOMstorage(b->ttype)) {
+       case TYPE_bte:
+               AGGR_STDEV(bte);
+               break;
+       case TYPE_sht:
+               AGGR_STDEV(sht);
+               break;
+       case TYPE_int:
+               AGGR_STDEV(int);
+               break;
+       case TYPE_lng:
+               AGGR_STDEV(lng);
+               break;
+       case TYPE_flt:
+               AGGR_STDEV(flt);
+               break;
+       case TYPE_dbl:
+               AGGR_STDEV(dbl);
+               break;
+       default:
+               if (avgb)
+                       BBPreclaim(*avgb);
+               else
+                       GDKfree(mean);
+               GDKfree(delta);
+               GDKfree(m2);
+               GDKfree(cnts);
+               BBPunfix(bn->batCacheid);
_______________________________________________
checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list

Reply via email to