Changeset: 16361d60ba35 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=16361d60ba35
Modified Files:
        gdk/gdk_aggr.c
        gdk/gdk_calc.h
        monetdb5/modules/kernel/00_aggr_hge.mal
        monetdb5/modules/kernel/00_aggr_hge.mal.sh
        monetdb5/modules/kernel/aggr.c
        monetdb5/modules/kernel/aggr.mal
        monetdb5/modules/kernel/aggr.mal.sh
        monetdb5/modules/kernel/algebra.c
        monetdb5/modules/kernel/algebra.h
        monetdb5/modules/kernel/algebra.mal
        sql/backends/monet5/sql_upgrades.c
        sql/scripts/39_analytics.sql
        sql/scripts/39_analytics_hge.sql
Branch: statistics-analytics
Log Message:

Implementing missing covar_samp and covar_pop aggregates


diffs (truncated from 937 to 300 lines):

diff --git a/gdk/gdk_aggr.c b/gdk/gdk_aggr.c
--- a/gdk/gdk_aggr.c
+++ b/gdk/gdk_aggr.c
@@ -3151,6 +3151,76 @@ BATcalcvariance_sample(dbl *avgp, BAT *b
                            "BATcalcvariance_sample");
 }
 
+#define AGGR_COVARIANCE_SINGLE(TYPE)   \
+       do {    \
+               TYPE x, y;      \
+               for (i = 0; i < cnt; i++) {             \
+                       x = ((const TYPE *) v1)[i];     \
+                       y = ((const TYPE *) v2)[i];     \
+                       if (is_##TYPE##_nil(x) || is_##TYPE##_nil(y))   \
+                               continue;               \
+                       n++;                            \
+                       delta1 = (dbl) x - mean1;               \
+                       mean1 += delta1 / n;            \
+                       delta2 = (dbl) y - mean2;               \
+                       mean2 += delta2 / n;            \
+                       m2 += delta1 * ((dbl) y - mean2);       \
+               }       \
+       } while (0)
+
+static dbl
+calccovariance(const void *restrict v1, const void *restrict v2, BUN cnt, int 
tp, bool issample, const char *func)
+{
+       BUN n = 0, i;
+       dbl mean1 = 0, mean2 = 0, m2 = 0, delta1, delta2;
+
+       switch (tp) {
+       case TYPE_bte:
+               AGGR_COVARIANCE_SINGLE(bte);
+               break;
+       case TYPE_sht:
+               AGGR_COVARIANCE_SINGLE(sht);
+               break;
+       case TYPE_int:
+               AGGR_COVARIANCE_SINGLE(int);
+               break;
+       case TYPE_lng:
+               AGGR_COVARIANCE_SINGLE(lng);
+               break;
+#ifdef HAVE_HGE
+       case TYPE_hge:
+               AGGR_COVARIANCE_SINGLE(hge);
+               break;
+#endif
+       case TYPE_flt:
+               AGGR_COVARIANCE_SINGLE(flt);
+               break;
+       case TYPE_dbl:
+               AGGR_COVARIANCE_SINGLE(dbl);
+               break;
+       default:
+               GDKerror("%s: type (%s) not supported.\n", func, ATOMname(tp));
+               return dbl_nil;
+       }
+       if (n <= (BUN) issample)
+               return dbl_nil;
+       return m2 / (n - issample);
+}
+
+dbl
+BATcalccovariance_population(BAT *b1, BAT *b2)
+{
+       return calccovariance((const void *) Tloc(b1, 0), (const void *) 
Tloc(b2, 0),
+                                                 BATcount(b1), b1->ttype, 
false, "BATcalccovariance_population");
+}
+
+dbl
+BATcalccovariance_sample(BAT *b1, BAT *b2)
+{
+       return calccovariance((const void *) Tloc(b1, 0), (const void *) 
Tloc(b2, 0),
+                                                 BATcount(b1), b1->ttype, 
true, "BATcalccovariance_sample");
+}
+
 #define AGGR_STDEV(TYPE)                                               \
        do {                                                            \
                const TYPE *restrict vals = (const TYPE *) Tloc(b, 0);  \
@@ -3382,3 +3452,179 @@ BATgroupvariance_population(BAT *b, BAT 
        return dogroupstdev(NULL, b, g, e, s, tp, skip_nils, false, true,
                            "BATgroupvariance_population");
 }
+
+#define AGGR_COVARIANCE(TYPE)                                          \
+       do {                                                            \
+               const TYPE *restrict vals1 = (const TYPE *) Tloc(b1, 0);        
\
+               const TYPE *restrict vals2 = (const TYPE *) Tloc(b2, 0);        
\
+               while (ncand > 0) {                                     \
+                       ncand--;                                        \
+                       i = canditer_next(&ci) - b1->hseqbase;          \
+                       if (gids == NULL ||                             \
+                           (gids[i] >= min && gids[i] <= max)) {       \
+                               if (gids)                               \
+                                       gid = gids[i] - min;            \
+                               else                                    \
+                                       gid = (oid) i;                  \
+                               if (is_##TYPE##_nil(vals1[i]) || 
is_##TYPE##_nil(vals2[i])) {           \
+                                       if (!skip_nils)                 \
+                                               cnts[gid] = BUN_NONE;   \
+                               } else if (cnts[gid] != BUN_NONE) {     \
+                                       cnts[gid]++;                    \
+                                       delta1[gid] = (dbl) vals1[i] - 
mean1[gid]; \
+                                       mean1[gid] += delta1[gid] / cnts[gid]; \
+                                       delta2[gid] = (dbl) vals2[i] - 
mean2[gid]; \
+                                       mean2[gid] += delta2[gid] / cnts[gid]; \
+                                       m2[gid] += delta1[gid] * ((dbl) 
vals2[i] - mean2[gid]); \
+                               }                                       \
+                       }                                               \
+               }                                                       \
+               for (i = 0; i < ngrp; i++) {                            \
+                       if (cnts[i] == 0 || cnts[i] == BUN_NONE) {      \
+                               dbls[i] = dbl_nil;                      \
+                               mean1[i] = dbl_nil;                     \
+                               mean2[i] = dbl_nil;     \
+                               nils++;                                 \
+                       } else if (cnts[i] == 1) {                      \
+                               dbls[i] = issample ? dbl_nil : 0;       \
+                               nils2++;                                \
+                       } else {                                        \
+                               dbls[i] = m2[i] / (cnts[i] - issample); \
+                       }                                               \
+               }                                                       \
+       } while (0)
+
+static BAT *
+dogroupcovariance(BAT *b1, BAT *b2, BAT *g, BAT *e, BAT *s, int tp,
+                                 bool skip_nils, bool issample, const char 
*func)
+{
+       const oid *restrict gids;
+       oid gid, min, max;
+       BUN i, ngrp, nils = 0, nils2 = 0, ncand;
+       BUN *restrict cnts = NULL;
+       dbl *restrict dbls, *restrict mean1, *restrict mean2, *restrict delta1, 
*restrict delta2, *restrict m2;
+       BAT *bn = NULL;
+       struct canditer ci;
+       const char *err;
+
+       assert(tp == TYPE_dbl && BATcount(b1) == BATcount(b2) && b1->ttype == 
b2->ttype && BATtdense(b1) == BATtdense(b2));
+       (void) tp;
+
+       if ((err = BATgroupaggrinit(b1, g, e, s, &min, &max, &ngrp, &ci, 
&ncand)) != NULL) {
+               GDKerror("%s: %s\n", func, err);
+               return NULL;
+       }
+       if (g == NULL) {
+               GDKerror("%s: b1, b2 and g must be aligned\n", func);
+               return NULL;
+       }
+
+       if (BATcount(b1) == 0 || ngrp == 0)
+               return BATconstant(ngrp == 0 ? 0 : min, TYPE_dbl, &dbl_nil, 
ngrp, TRANSIENT);
+
+       if ((e == NULL ||
+            (BATcount(e) == BATcount(b1) && (e->hseqbase == b1->hseqbase || 
e->hseqbase == b2->hseqbase))) &&
+           (BATtdense(g) || (g->tkey && g->tnonil)) &&
+           (issample || (b1->tnonil && b2->tnonil))) {
+               /* trivial: singleton groups, so all results are equal
+                * to zero (population) or nil (sample) */
+               dbl v = issample ? dbl_nil : 0;
+               return BATconstant(ngrp == 0 ? 0 : min, TYPE_dbl, &v, ngrp, 
TRANSIENT);
+       }
+
+       delta1 = GDKmalloc(ngrp * sizeof(dbl));
+       delta2 = GDKmalloc(ngrp * sizeof(dbl));
+       m2 = GDKzalloc(ngrp * sizeof(dbl));
+       cnts = GDKzalloc(ngrp * sizeof(BUN));
+       mean1 = GDKzalloc(ngrp * sizeof(dbl));
+       mean2 = GDKzalloc(ngrp * sizeof(dbl));
+
+       if (mean1 == NULL || mean2 == NULL || delta1 == NULL || delta2 == NULL 
|| m2 == NULL || cnts == NULL)
+               goto alloc_fail;
+
+       bn = COLnew(min, TYPE_dbl, ngrp, TRANSIENT);
+       if (bn == NULL)
+               goto alloc_fail;
+       dbls = (dbl *) Tloc(bn, 0);
+
+       if (!g || BATtdense(g))
+               gids = NULL;
+       else
+               gids = (const oid *) Tloc(g, 0);
+
+       switch (b1->ttype) {
+       case TYPE_bte:
+               AGGR_COVARIANCE(bte);
+               break;
+       case TYPE_sht:
+               AGGR_COVARIANCE(sht);
+               break;
+       case TYPE_int:
+               AGGR_COVARIANCE(int);
+               break;
+       case TYPE_lng:
+               AGGR_COVARIANCE(lng);
+               break;
+#ifdef HAVE_HGE
+       case TYPE_hge:
+               AGGR_COVARIANCE(hge);
+               break;
+#endif
+       case TYPE_flt:
+               AGGR_COVARIANCE(flt);
+               break;
+       case TYPE_dbl:
+               AGGR_COVARIANCE(dbl);
+               break;
+       default:
+               BBPreclaim(bn);
+               GDKfree(mean1);
+               GDKfree(mean2);
+               GDKfree(delta1);
+               GDKfree(delta2);
+               GDKfree(m2);
+               GDKfree(cnts);
+               GDKerror("%s: type (%s) not supported.\n", func, 
ATOMname(b1->ttype));
+               return NULL;
+       }
+       GDKfree(mean1);
+       GDKfree(mean2);
+
+       if (issample)
+               nils += nils2;
+       GDKfree(delta1);
+       GDKfree(delta2);
+       GDKfree(m2);
+       GDKfree(cnts);
+       BATsetcount(bn, ngrp);
+       bn->tkey = ngrp <= 1;
+       bn->tsorted = ngrp <= 1;
+       bn->trevsorted = ngrp <= 1;
+       bn->tnil = nils != 0;
+       bn->tnonil = nils == 0;
+       return bn;
+alloc_fail:
+       BBPreclaim(bn);
+       GDKfree(mean1);
+       GDKfree(mean2);
+       GDKfree(delta1);
+       GDKfree(delta2);
+       GDKfree(m2);
+       GDKfree(cnts);
+       GDKerror("%s: cannot allocate enough memory.\n", func);
+       return NULL;
+}
+
+BAT *
+BATgroupcovariance_sample(BAT *b1, BAT *b2, BAT *g, BAT *e, BAT *s, int tp, 
bool skip_nils, bool abort_on_error)
+{
+       (void) abort_on_error;
+       return dogroupcovariance(b1, b2, g, e, s, tp, skip_nils, true, 
"BATgroupcovariance_sample");
+}
+
+BAT *
+BATgroupcovariance_population(BAT *b1, BAT *b2, BAT *g, BAT *e, BAT *s, int 
tp, bool skip_nils, bool abort_on_error)
+{
+       (void) abort_on_error;
+       return dogroupcovariance(b1, b2, g, e, s, tp, skip_nils, false, 
"BATgroupcovariance_population");
+}
diff --git a/gdk/gdk_calc.h b/gdk/gdk_calc.h
--- a/gdk/gdk_calc.h
+++ b/gdk/gdk_calc.h
@@ -154,6 +154,10 @@ gdk_export dbl BATcalcvariance_populatio
 gdk_export dbl BATcalcvariance_sample(dbl *avgp, BAT *b);
 gdk_export BAT *BATgroupvariance_sample(BAT *b, BAT *g, BAT *e, BAT *s, int 
tp, bool skip_nils, bool abort_on_error);
 gdk_export BAT *BATgroupvariance_population(BAT *b, BAT *g, BAT *e, BAT *s, 
int tp, bool skip_nils, bool abort_on_error);
+gdk_export dbl BATcalccovariance_sample(BAT *b1, BAT *b2);
+gdk_export dbl BATcalccovariance_population(BAT *b1, BAT *b2);
+gdk_export BAT *BATgroupcovariance_sample(BAT *b1, BAT *b2, BAT *g, BAT *e, 
BAT *s, int tp, bool skip_nils, bool abort_on_error);
+gdk_export BAT *BATgroupcovariance_population(BAT *b1, BAT *b2, BAT *g, BAT 
*e, BAT *s, int tp, bool skip_nils, bool abort_on_error);
 
 gdk_export BAT *BATgroupstr_group_concat(BAT *b, BAT *g, BAT *e, BAT *s, bool 
skip_nils, bool abort_on_error, const char *separator);
 gdk_export gdk_return BATstr_group_concat(ValPtr res, BAT *b, BAT *s, bool 
skip_nils, bool abort_on_error, bool nil_if_empty, const char *separator);
diff --git a/monetdb5/modules/kernel/00_aggr_hge.mal 
b/monetdb5/modules/kernel/00_aggr_hge.mal
--- a/monetdb5/modules/kernel/00_aggr_hge.mal
+++ b/monetdb5/modules/kernel/00_aggr_hge.mal
@@ -210,3 +210,27 @@ command subvariancep(b:bat[:hge],g:bat[:
 address AGGRsubvariancepcand_dbl
 comment "Grouped variance (population/biased) aggregate with candidates list";
 
+command covariance(b:bat[:hge],c:bat[:hge],g:bat[:oid],e:bat[:any_1]) 
:bat[:dbl]
+address AGGRcovariance
+comment "Covariance sample aggregate";
+
+command 
subcovariance(b:bat[:hge],c:bat[:hge],g:bat[:oid],e:bat[:any_1],skip_nils:bit,abort_on_error:bit)
 :bat[:dbl]
+address AGGRsubcovariance
+comment "Grouped covariance sample aggregate";
+
+command 
subcovariance(b:bat[:hge],c:bat[:hge],g:bat[:oid],e:bat[:any_1],s:bat[:oid],skip_nils:bit,abort_on_error:bit)
 :bat[:dbl]
+address AGGRsubcovariancecand
+comment "Grouped covariance sample aggregate with candidate list";
+
+command covariancep(b:bat[:hge],c:bat[:hge],g:bat[:oid],e:bat[:any_1]) 
:bat[:dbl]
+address AGGRcovariancep
+comment "Covariance population aggregate";
+
+command 
subcovariancep(b:bat[:hge],c:bat[:hge],g:bat[:oid],e:bat[:any_1],skip_nils:bit,abort_on_error:bit)
 :bat[:dbl]
+address AGGRsubcovariancep
+comment "Grouped covariance population aggregate";
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to