Changeset: f85ae0bfc50d for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=f85ae0bfc50d
Added Files:
sql/test/analytics/Tests/analytics15.sql
sql/test/analytics/Tests/analytics15.stable.err
sql/test/analytics/Tests/analytics15.stable.out
Modified Files:
gdk/gdk_analytic.h
gdk/gdk_analytic_func.c
sql/backends/monet5/sql_rank.c
sql/test/analytics/Tests/All
Branch: statistics-analytics
Log Message:
Implemented covar_pop and covar_samp as window functions
diffs (truncated from 1528 to 300 lines):
diff --git a/gdk/gdk_analytic.h b/gdk/gdk_analytic.h
--- a/gdk/gdk_analytic.h
+++ b/gdk/gdk_analytic.h
@@ -43,7 +43,7 @@ gdk_export gdk_return GDKanalytical_stdd
gdk_export gdk_return GDKanalytical_variance_samp(BAT *r, BAT *b, BAT *s, BAT
*e, int tpe);
gdk_export gdk_return GDKanalytical_variance_pop(BAT *r, BAT *b, BAT *s, BAT
*e, int tpe);
gdk_export gdk_return GDKanalytical_covariance_pop(BAT *r, BAT *b1, BAT *b2,
BAT *s, BAT *e, int tpe);
-gdk_export gdk_return GDKanalytical_covariance_sample(BAT *r, BAT *b1, BAT
*b2, BAT *s, BAT *e, int tpe);
+gdk_export gdk_return GDKanalytical_covariance_samp(BAT *r, BAT *b1, BAT *b2,
BAT *s, BAT *e, int tpe);
gdk_export gdk_return GDKanalytical_quantile(BAT *r, BAT *b, BAT *s, BAT *e,
BAT *q, const void *restrict quantile, int tp1, int tp2);
gdk_export gdk_return GDKanalytical_quantile_avg(BAT *r, BAT *b, BAT *s, BAT
*e, BAT *q, const void *restrict quantile, int tp1, int tp2);
diff --git a/gdk/gdk_analytic_func.c b/gdk/gdk_analytic_func.c
--- a/gdk/gdk_analytic_func.c
+++ b/gdk/gdk_analytic_func.c
@@ -1797,6 +1797,92 @@ GDK_ANALYTICAL_STDEV_VARIANCE(stddev_pop
GDK_ANALYTICAL_STDEV_VARIANCE(variance_samp, 1, m2 / (n - 1), "variance")
GDK_ANALYTICAL_STDEV_VARIANCE(variance_pop, 0, m2 / n, "variance")
+#define ANALYTICAL_COVARIANCE_CALC(TPE, SAMPLE, OP) \
+ do { \
+ TPE *bp1 = (TPE*)Tloc(b1, 0), *bp2 = (TPE*)Tloc(b2, 0), *bs1,
*be1, *bs2, v1, v2; \
+ for (; i < cnt; i++, rb++) { \
+ bs1 = bp1 + start[i]; \
+ be1 = bp1 + end[i]; \
+ bs2 = bp2 + start[i]; \
+ for (; bs1 < be1; bs1++, bs2++) { \
+ v1 = *bs1; \
+ v2 = *bs2; \
+ if (is_##TPE##_nil(v1) || is_##TPE##_nil(v2))
\
+ continue; \
+ n++; \
+ delta1 = (dbl) v1 - mean1; \
+ mean1 += delta1 / n; \
+ delta2 = (dbl) v2 - mean2; \
+ mean2 += delta2 / n; \
+ m2 += delta1 * ((dbl) v2 - mean2); \
+ } \
+ if (n > SAMPLE) { \
+ *rb = OP; \
+ } else { \
+ *rb = dbl_nil; \
+ nils++; \
+ } \
+ n = 0; \
+ mean1 = 0; \
+ mean2 = 0; \
+ m2 = 0; \
+ } \
+ } while (0)
+
+#ifdef HAVE_HGE
+#define ANALYTICAL_COVARIANCE_LIMIT(SAMPLE, OP) \
+ case TYPE_hge: \
+ ANALYTICAL_COVARIANCE_CALC(hge, SAMPLE, OP); \
+ break;
+#else
+#define ANALYTICAL_COVARIANCE_LIMIT(SAMPLE, OP)
+#endif
+
+#define GDK_ANALYTICAL_COVARIANCE(NAME, SAMPLE, OP) \
+gdk_return \
+GDKanalytical_##NAME(BAT *r, BAT *b1, BAT *b2, BAT *s, BAT *e, int tpe) \
+{ \
+ BUN i = 0, cnt = BATcount(b1), n = 0, nils = 0; \
+ lng *restrict start, *restrict end; \
+ dbl *restrict rb = (dbl *) Tloc(r, 0), mean1 = 0, mean2 = 0, m2 = 0,
delta1, delta2; \
+ \
+ assert(s && e && BATcount(b1) == BATcount(b2)); \
+ start = (lng *) Tloc(s, 0); \
+ end = (lng *) Tloc(e, 0); \
+ \
+ switch (tpe) { \
+ case TYPE_bte: \
+ ANALYTICAL_COVARIANCE_CALC(bte, SAMPLE, OP); \
+ break; \
+ case TYPE_sht: \
+ ANALYTICAL_COVARIANCE_CALC(sht, SAMPLE, OP); \
+ break; \
+ case TYPE_int: \
+ ANALYTICAL_COVARIANCE_CALC(int, SAMPLE, OP); \
+ break; \
+ case TYPE_lng: \
+ ANALYTICAL_COVARIANCE_CALC(lng, SAMPLE, OP); \
+ break; \
+ ANALYTICAL_COVARIANCE_LIMIT(SAMPLE, OP) \
+ case TYPE_flt:\
+ ANALYTICAL_COVARIANCE_CALC(flt, SAMPLE, OP); \
+ break; \
+ case TYPE_dbl: \
+ ANALYTICAL_COVARIANCE_CALC(dbl, SAMPLE, OP); \
+ break; \
+ default: \
+ GDKerror("%s: covariance of type %s unsupported.\n", __func__,
ATOMname(tpe)); \
+ return GDK_FAIL; \
+ } \
+ BATsetcount(r, cnt); \
+ r->tnonil = nils == 0; \
+ r->tnil = nils > 0; \
+ return GDK_SUCCEED; \
+}
+
+GDK_ANALYTICAL_COVARIANCE(covariance_samp, 1, m2 / (n - 1))
+GDK_ANALYTICAL_COVARIANCE(covariance_pop, 0, m2 / n)
+
/* There will be always at least one value for the quantile, because we don't
implement the exclude clause yet */
#define ANALYTICAL_QUANTILE_IMP_FIXED(TPE1, TPE2, NEXT_QUA)
\
@@ -2104,27 +2190,3 @@ quantile_nosupport:
GDKerror("%s: type %s not supported for the quantile.\n", __func__,
ATOMname(tp2));
return GDK_FAIL;
}
-
-gdk_return
-GDKanalytical_covariance_pop(BAT *r, BAT *b1, BAT *b2, BAT *s, BAT *e, int tpe)
-{
- (void) r;
- (void) b1;
- (void) b2;
- (void) s;
- (void) e;
- (void) tpe;
- return GDK_SUCCEED;
-}
-
-gdk_return
-GDKanalytical_covariance_sample(BAT *r, BAT *b1, BAT *b2, BAT *s, BAT *e, int
tpe)
-{
- (void) r;
- (void) b1;
- (void) b2;
- (void) s;
- (void) e;
- (void) tpe;
- return GDK_SUCCEED;
-}
diff --git a/sql/backends/monet5/sql_rank.c b/sql/backends/monet5/sql_rank.c
--- a/sql/backends/monet5/sql_rank.c
+++ b/sql/backends/monet5/sql_rank.c
@@ -1647,7 +1647,7 @@ SQLvar_pop(Client cntxt, MalBlkPtr mb, M
static str
do_covariance_and_correlation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
InstrPtr pci, const char* op, const char* err,
- gdk_return
(*func)(BAT *, BAT *, BAT *, BAT *, BAT *, int))
+ gdk_return
(*func)(BAT *, BAT *, BAT *, BAT *, BAT *, int), BUN minimum)
{
BAT *r = NULL, *b = NULL, *c = NULL, *s = NULL, *e = NULL;
int tp1, tp2;
@@ -1681,46 +1681,63 @@ do_covariance_and_correlation(Client cnt
throw(SQL, op, SQLSTATE(HY005) "Cannot access column
descriptor");
voidresultBAT(r, TYPE_dbl, BATcount(b), b, op);
- if (isaBatType(getArgType(mb, pci, 3))) {
- s = BATdescriptor(*getArgReference_bat(stk, pci, 3));
- if (!s) {
- BBPunfix(b->batCacheid);
- BBPunfix(r->batCacheid);
- throw(SQL, op, SQLSTATE(HY005) "Cannot access
column descriptor");
- }
+ s = BATdescriptor(*getArgReference_bat(stk, pci, 3));
+ if (!s) {
+ BBPunfix(b->batCacheid);
+ BBPunfix(r->batCacheid);
+ throw(SQL, op, SQLSTATE(HY005) "Cannot access column
descriptor");
}
- if (isaBatType(getArgType(mb, pci, 4))) {
- e = BATdescriptor(*getArgReference_bat(stk, pci, 4));
- if (!e) {
- BBPunfix(b->batCacheid);
- BBPunfix(r->batCacheid);
- if (s) BBPunfix(s->batCacheid);
- throw(SQL, op, SQLSTATE(HY005) "Cannot access
column descriptor");
- }
+ e = BATdescriptor(*getArgReference_bat(stk, pci, 4));
+ if (!e) {
+ BBPunfix(b->batCacheid);
+ BBPunfix(r->batCacheid);
+ BBPunfix(s->batCacheid);
+ throw(SQL, op, SQLSTATE(HY005) "Cannot access column
descriptor");
}
if (is_a_bat2) {
c = BATdescriptor(*getArgReference_bat(stk, pci, 2));
if (!e) {
BBPunfix(b->batCacheid);
BBPunfix(r->batCacheid);
- if (s) BBPunfix(s->batCacheid);
- if (e) BBPunfix(e->batCacheid);
+ BBPunfix(s->batCacheid);
+ BBPunfix(e->batCacheid);
throw(SQL, op, SQLSTATE(HY005) "Cannot access
column descriptor");
}
gdk_res = func(r, b, c, s, e, tp1);
} else {
- BUN cnt = BATcount(b);
+ BUN cnt = BATcount(b), n = 0;
+ BATiter bi = bat_iterator(b); /* corner case, second
column is a constant, calculate it this way... */
+ void *curval;
+ const void *restrict nil = ATOMnilptr(tp1);
+ int (*cmp) (const void *, const void *) =
ATOMcompare(tp1);
ValRecord *input2 = &(stk)->stk[(pci)->argv[2]];
dbl *restrict rb = (dbl*) Tloc(r, 0), res =
VALisnil(input2) ? dbl_nil : 0;
+ lng *restrict start = (lng*) Tloc(s, 0), *restrict end
= (lng*) Tloc(e, 0);
+ bool has_nils = VALisnil(input2);
- for (BUN i = 0 ; i < cnt; i++)
- rb[i] = res;
+ for (BUN i = 0; i < cnt; i++) {
+ for (lng j = start[i] ; j < end[i] ; j++) {
+ curval = BUNtail(bi, j);
+ if (!cmp(curval, nil))
+ continue;
+ n++;
+ }
+ if (n > minimum) { /* covariance_samp requires
at least one value */
+ rb[i] = res;
+ } else {
+ rb[i] = dbl_nil;
+ has_nils = true;
+ }
+ n = 0;
+ }
BATsetcount(r, cnt);
+ r->tnonil = !has_nils;
+ r->tnil = has_nils;
}
BBPunfix(b->batCacheid);
- if (s) BBPunfix(s->batCacheid);
- if (e) BBPunfix(e->batCacheid);
+ BBPunfix(s->batCacheid);
+ BBPunfix(e->batCacheid);
if (c) BBPunfix(c->batCacheid);
if (gdk_res == GDK_SUCCEED)
BBPkeepref(*res = r->batCacheid);
@@ -1754,14 +1771,14 @@ str
SQLcovar_samp(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
return do_covariance_and_correlation(cntxt, mb, stk, pci,
"sql.covariance", SQLSTATE(42000) "covariance(:any_1,:any_1,:lng,:lng)",
-
GDKanalytical_covariance_pop);
+
GDKanalytical_covariance_samp, 1);
}
str
SQLcovar_pop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
{
return do_covariance_and_correlation(cntxt, mb, stk, pci,
"sql.covariancep", SQLSTATE(42000) "covariancep(:any_1,:any_1,:lng,:lng)",
-
GDKanalytical_covariance_sample);
+
GDKanalytical_covariance_pop, 0);
}
#define QUANTILE_SINGLE_IMP(TPE) \
diff --git a/sql/test/analytics/Tests/All b/sql/test/analytics/Tests/All
--- a/sql/test/analytics/Tests/All
+++ b/sql/test/analytics/Tests/All
@@ -18,3 +18,4 @@ analytics13
# Statistical window function tests
analytics14
+analytics15
diff --git a/sql/test/analytics/Tests/analytics15.sql
b/sql/test/analytics/Tests/analytics15.sql
new file mode 100644
--- /dev/null
+++ b/sql/test/analytics/Tests/analytics15.sql
@@ -0,0 +1,98 @@
+start transaction;
+create table analytics (aa int, bb int);
+insert into analytics values (15, 3), (3, 1), (2, 1), (5, 3), (NULL, 2), (3,
2), (4, 1), (6, 3), (8, 2), (NULL, 4);
+
+select covar_samp(aa, aa) over (partition by bb) from analytics;
+select covar_samp(aa, aa) over (partition by bb order by bb asc) from
analytics;
+select covar_samp(aa, aa) over (partition by bb order by bb desc) from
analytics;
+select covar_samp(aa, aa) over (order by bb desc) from analytics;
+
+select covar_samp(bb, bb) over (partition by bb) from analytics;
+select covar_samp(bb, bb) over (partition by bb order by bb asc) from
analytics;
+select covar_samp(bb, bb) over (partition by bb order by bb desc) from
analytics;
+select covar_samp(bb, bb) over (order by bb desc) from analytics;
+
+
+select covar_pop(aa, aa) over (partition by bb) from analytics;
+select covar_pop(aa, aa) over (partition by bb order by bb asc) from analytics;
+select covar_pop(aa, aa) over (partition by bb order by bb desc) from
analytics;
+select covar_pop(aa, aa) over (order by bb desc) from analytics;
+
+select covar_pop(bb, bb) over (partition by bb) from analytics;
+select covar_pop(bb, bb) over (partition by bb order by bb asc) from analytics;
+select covar_pop(bb, bb) over (partition by bb order by bb desc) from
analytics;
+select covar_pop(bb, bb) over (order by bb desc) from analytics;
+
+
+select covar_samp(aa, bb) over (partition by bb) from analytics;
+select covar_samp(aa, bb) over (partition by bb order by bb asc) from
analytics;
+select covar_samp(aa, bb) over (partition by bb order by bb desc) from
analytics;
+select covar_samp(aa, bb) over (order by bb desc) from analytics;
+
+select covar_samp(bb, aa) over (partition by bb) from analytics;
+select covar_samp(bb, aa) over (partition by bb order by bb asc) from
analytics;
+select covar_samp(bb, aa) over (partition by bb order by bb desc) from
analytics;
+select covar_samp(bb, aa) over (order by bb desc) from analytics;
+
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list