LCOV - code coverage report
Current view: top level - gdk - gdk_analytic_func.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 422 638 66.1 %
Date: 2021-10-13 02:24:04 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "gdk.h"
      11             : #include "gdk_analytic.h"
      12             : #include "gdk_calc_private.h"
      13             : 
      14             : BAT *
      15         218 : GDKinitialize_segment_tree(void)
      16             : {
      17             :         /* The tree is allocated using raw bytes, so use a GDK type of size 1 */
      18         218 :         BAT *st = COLnew(0, TYPE_bte, 0, TRANSIENT);
      19             : 
      20         218 :         if (!st)
      21             :                 return NULL;
      22         218 :         assert(st->tshift == 0);
      23         218 :         BATsetcount(st, 0);
      24         218 :         st->tsorted = st->trevsorted = st->tkey = st->tnonil = st->tnil = false;
      25         218 :         st->tnosorted = st->tnorevsorted = 0;
      26         218 :         return st;
      27             : }
      28             : 
      29             : gdk_return
      30       39550 : GDKrebuild_segment_tree(oid ncount, oid data_size, BAT *st, void **segment_tree, oid **levels_offset, oid *nlevels)
      31             : {
      32             :         oid total_size, next_tree_size = ncount, counter = ncount, next_levels = 1; /* there will be at least one level */
      33             : 
      34       39550 :         assert(ncount > 0);
      35             :         do { /* compute the next number of levels */
      36       69793 :                 counter = (oid) ceil((dbl)counter / SEGMENT_TREE_FANOUT);
      37       69793 :                 next_tree_size += counter;
      38       69793 :                 next_levels++;
      39       69793 :         } while (counter > 1);
      40             : 
      41       39550 :         *nlevels = next_levels; /* set the logical size of levels before the physical one */
      42       39550 :         next_tree_size *= data_size;
      43       39550 :         total_size = next_tree_size + next_levels * sizeof(oid);
      44             : 
      45       39550 :         if (total_size > BATcount(st)) {
      46         219 :                 total_size = (((total_size) + 1023) & ~1023); /* align to a multiple of 1024 bytes */
      47         219 :                 if (BATextend(st, total_size) != GDK_SUCCEED)
      48             :                         return GDK_FAIL;
      49         219 :                 BATsetcount(st, total_size);
      50         219 :                 *segment_tree = (void*)Tloc(st, 0);
      51         219 :                 *levels_offset = (oid*)((bte*)Tloc(st, 0) + next_tree_size); /* levels offset will be next to the segment tree */
      52             :         } else {
      53       39331 :                 *levels_offset = (oid*)(*(bte**)segment_tree + next_tree_size); /* no reallocation, just update location of levels offset */
      54             :         }
      55             :         return GDK_SUCCEED;
      56             : }
      57             : 
      58             : #define NTILE_CALC(TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION)        \
      59             :         do {                                                            \
      60             :                 UPCAST j = 0, ncnt = (UPCAST) (i - k);                  \
      61             :                 for (; k < i; k++, j++) {                            \
      62             :                         TPE val = NEXT_VALUE;                           \
      63             :                         if (is_##TPE##_nil(val)) {                      \
      64             :                                 has_nils = true;                        \
      65             :                                 rb[k] = TPE##_nil;                      \
      66             :                         } else {                                        \
      67             :                                 UPCAST nval = (UPCAST) LNG_HGE;         \
      68             :                                 VALIDATION /* validation must come after null check */ \
      69             :                                 if (nval >= ncnt) {                  \
      70             :                                         rb[k] = (TPE)(j + 1);           \
      71             :                                 } else {                                \
      72             :                                         UPCAST bsize = ncnt / nval;     \
      73             :                                         UPCAST top = ncnt - nval * bsize; \
      74             :                                         UPCAST small = top * (bsize + 1); \
      75             :                                         if ((UPCAST) j < small)              \
      76             :                                                 rb[k] = (TPE)(1 + j / (bsize + 1)); \
      77             :                                         else                            \
      78             :                                                 rb[k] = (TPE)(1 + top + (j - small) / bsize); \
      79             :                                 }                                       \
      80             :                         }                                               \
      81             :                 }                                                       \
      82             :         } while (0)
      83             : 
      84             : #define ANALYTICAL_NTILE(IMP, TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION) \
      85             :         do {                                                            \
      86             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
      87             :                 if (p) {                                                \
      88             :                         while (i < cnt) {                            \
      89             :                                 if (np[i])      {                       \
      90             : ntile##IMP##TPE:                                                        \
      91             :                                         NTILE_CALC(TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION); \
      92             :                                 }                                       \
      93             :                                 if (!last)                              \
      94             :                                         i++;                            \
      95             :                         }                                               \
      96             :                 }                                                       \
      97             :                 if (!last) {                                            \
      98             :                         last = true;                                    \
      99             :                         i = cnt;                                        \
     100             :                         goto ntile##IMP##TPE;                           \
     101             :                 }                                                       \
     102             :         } while (0)
     103             : 
     104             : #define ANALYTICAL_NTILE_SINGLE_IMP(TPE, LNG_HGE, UPCAST)               \
     105             :         do {                                                            \
     106             :                 TPE ntl = *(TPE*) ntile;                                \
     107             :                 if (!is_##TPE##_nil(ntl) && ntl <= 0) goto invalidntile; \
     108             :                 ANALYTICAL_NTILE(SINGLE, TPE, ntl, LNG_HGE, UPCAST, ;); \
     109             :         } while (0)
     110             : 
     111             : #define ANALYTICAL_NTILE_MULTI_IMP(TPE, LNG_HGE, UPCAST)                \
     112             :         do {                                                            \
     113             :                 const TPE *restrict nn = (TPE*)ni.base;                 \
     114             :                 ANALYTICAL_NTILE(MULTI, TPE, nn[k], LNG_HGE, UPCAST, if (val <= 0) goto invalidntile;); \
     115             :         } while (0)
     116             : 
     117             : gdk_return
     118          59 : GDKanalyticalntile(BAT *r, BAT *b, BAT *p, BAT *n, int tpe, const void *restrict ntile)
     119             : {
     120          59 :         BATiter bi = bat_iterator(b);
     121          59 :         BATiter pi = bat_iterator(p);
     122          59 :         BATiter ni = bat_iterator(n);
     123          59 :         lng i = 0, k = 0, cnt = (lng) BATcount(b);
     124          59 :         const bit *restrict np = pi.base;
     125             :         bool has_nils = false, last = false;
     126             : 
     127          59 :         assert((n && !ntile) || (!n && ntile));
     128             : 
     129          59 :         if (ntile) {
     130          32 :                 switch (tpe) {
     131          32 :                 case TYPE_bte:
     132         512 :                         ANALYTICAL_NTILE_SINGLE_IMP(bte, val, BUN);
     133             :                         break;
     134           0 :                 case TYPE_sht:
     135           0 :                         ANALYTICAL_NTILE_SINGLE_IMP(sht, val, BUN);
     136             :                         break;
     137           0 :                 case TYPE_int:
     138           0 :                         ANALYTICAL_NTILE_SINGLE_IMP(int, val, BUN);
     139             :                         break;
     140           0 :                 case TYPE_lng:
     141             : #if SIZEOF_OID == SIZEOF_INT
     142             :                         ANALYTICAL_NTILE_SINGLE_IMP(lng, val, lng);
     143             : #else
     144           0 :                         ANALYTICAL_NTILE_SINGLE_IMP(lng, val, BUN);
     145             : #endif
     146             :                         break;
     147             : #ifdef HAVE_HGE
     148           0 :                 case TYPE_hge:
     149             : #if SIZEOF_OID == SIZEOF_INT
     150             :                         ANALYTICAL_NTILE_SINGLE_IMP(hge, (val > (hge) GDK_int_max) ? GDK_int_max : (lng) val, lng);
     151             : #else
     152           0 :                         ANALYTICAL_NTILE_SINGLE_IMP(hge, (val > (hge) GDK_lng_max) ? GDK_lng_max : (lng) val, BUN);
     153             : #endif
     154             : #endif
     155             :                 default:
     156           0 :                         goto nosupport;
     157             :                 }
     158             :         } else {
     159          27 :                 switch (tpe) {
     160           1 :                 case TYPE_bte:
     161          12 :                         ANALYTICAL_NTILE_MULTI_IMP(bte, val, BUN);
     162             :                         break;
     163           0 :                 case TYPE_sht:
     164           0 :                         ANALYTICAL_NTILE_MULTI_IMP(sht, val, BUN);
     165             :                         break;
     166          26 :                 case TYPE_int:
     167         420 :                         ANALYTICAL_NTILE_MULTI_IMP(int, val, BUN);
     168             :                         break;
     169           0 :                 case TYPE_lng:
     170             : #if SIZEOF_OID == SIZEOF_INT
     171             :                         ANALYTICAL_NTILE_MULTI_IMP(lng, val, lng);
     172             : #else
     173           0 :                         ANALYTICAL_NTILE_MULTI_IMP(lng, val, BUN);
     174             : #endif
     175             :                         break;
     176             : #ifdef HAVE_HGE
     177           0 :                 case TYPE_hge:
     178             : #if SIZEOF_OID == SIZEOF_INT
     179             :                         ANALYTICAL_NTILE_MULTI_IMP(hge, (val > (hge) GDK_int_max) ? GDK_int_max : (lng) val, lng);
     180             : #else
     181           0 :                         ANALYTICAL_NTILE_MULTI_IMP(hge, (val > (hge) GDK_lng_max) ? GDK_lng_max : (lng) val, BUN);
     182             : #endif
     183             :                 break;
     184             : #endif
     185           0 :                 default:
     186           0 :                         goto nosupport;
     187             :                 }
     188             :         }
     189          59 :         bat_iterator_end(&bi);
     190          59 :         bat_iterator_end(&pi);
     191          59 :         bat_iterator_end(&ni);
     192          59 :         BATsetcount(r, BATcount(b));
     193          59 :         r->tnonil = !has_nils;
     194          59 :         r->tnil = has_nils;
     195          59 :         return GDK_SUCCEED;
     196           0 : nosupport:
     197           0 :         bat_iterator_end(&bi);
     198           0 :         bat_iterator_end(&pi);
     199           0 :         bat_iterator_end(&ni);
     200           0 :         GDKerror("42000!type %s not supported for the ntile type.\n", ATOMname(tpe));
     201           0 :         return GDK_FAIL;
     202           0 : invalidntile:
     203           0 :         bat_iterator_end(&bi);
     204           0 :         bat_iterator_end(&pi);
     205           0 :         bat_iterator_end(&ni);
     206           0 :         GDKerror("42000!ntile must be greater than zero.\n");
     207           0 :         return GDK_FAIL;
     208             : }
     209             : 
     210             : #define ANALYTICAL_FIRST_FIXED(TPE)                                     \
     211             :         do {                                                            \
     212             :                 const TPE *bp = (TPE*)bi.base;                          \
     213             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
     214             :                 for (; k < cnt; k++) {                                       \
     215             :                         const TPE *bs = bp + start[k], *be = bp + end[k]; \
     216             :                         TPE curval = (be > bs) ? *bs : TPE##_nil;    \
     217             :                         rb[k] = curval;                                 \
     218             :                         has_nils |= is_##TPE##_nil(curval);             \
     219             :                 }                                                       \
     220             :         } while (0)
     221             : 
     222             : gdk_return
     223          32 : GDKanalyticalfirst(BAT *r, BAT *b, BAT *s, BAT *e, int tpe)
     224             : {
     225          32 :         BATiter bi = bat_iterator(b);
     226          32 :         BATiter si = bat_iterator(s);
     227          32 :         BATiter ei = bat_iterator(e);
     228             :         bool has_nils = false;
     229          32 :         oid k = 0, cnt = BATcount(b);
     230          32 :         const oid *restrict start = si.base, *restrict end = ei.base;
     231          32 :         const void *nil = ATOMnilptr(tpe);
     232          32 :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
     233             : 
     234          32 :         switch (ATOMbasetype(tpe)) {
     235           1 :         case TYPE_bte:
     236          11 :                 ANALYTICAL_FIRST_FIXED(bte);
     237             :                 break;
     238           0 :         case TYPE_sht:
     239           0 :                 ANALYTICAL_FIRST_FIXED(sht);
     240             :                 break;
     241          23 :         case TYPE_int:
     242         244 :                 ANALYTICAL_FIRST_FIXED(int);
     243             :                 break;
     244           1 :         case TYPE_lng:
     245          12 :                 ANALYTICAL_FIRST_FIXED(lng);
     246             :                 break;
     247             : #ifdef HAVE_HGE
     248           0 :         case TYPE_hge:
     249           0 :                 ANALYTICAL_FIRST_FIXED(hge);
     250             :                 break;
     251             : #endif
     252           0 :         case TYPE_flt:
     253           0 :                 ANALYTICAL_FIRST_FIXED(flt);
     254             :                 break;
     255           2 :         case TYPE_dbl:
     256          14 :                 ANALYTICAL_FIRST_FIXED(dbl);
     257             :                 break;
     258           5 :         default:{
     259           5 :                 if (ATOMvarsized(tpe)) {
     260          50 :                         for (; k < cnt; k++) {
     261          45 :                                 const void *curval = (end[k] > start[k]) ? BUNtvar(bi, start[k]) : nil;
     262          45 :                                 if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     263           0 :                                         bat_iterator_end(&bi);
     264           0 :                                         bat_iterator_end(&si);
     265           0 :                                         bat_iterator_end(&ei);
     266           0 :                                         return GDK_FAIL;
     267             :                                 }
     268          45 :                                 has_nils |= atomcmp(curval, nil) == 0;
     269             :                         }
     270             :                 } else {
     271           0 :                         uint16_t width = r->twidth;
     272           0 :                         uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     273           0 :                         for (; k < cnt; k++) {
     274           0 :                                 const void *curval = (end[k] > start[k]) ? BUNtloc(bi, start[k]) : nil;
     275           0 :                                 memcpy(rcast, curval, width);
     276           0 :                                 rcast += width;
     277           0 :                                 has_nils |= atomcmp(curval, nil) == 0;
     278             :                         }
     279             :                 }
     280             :         }
     281             :         }
     282          32 :         bat_iterator_end(&bi);
     283          32 :         bat_iterator_end(&si);
     284          32 :         bat_iterator_end(&ei);
     285             : 
     286          32 :         BATsetcount(r, cnt);
     287          32 :         r->tnonil = !has_nils;
     288          32 :         r->tnil = has_nils;
     289          32 :         return GDK_SUCCEED;
     290             : }
     291             : 
     292             : #define ANALYTICAL_LAST_FIXED(TPE)                                      \
     293             :         do {                                                            \
     294             :                 const TPE *bp = (TPE*)bi.base;                          \
     295             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
     296             :                 for (; k < cnt; k++) {                                       \
     297             :                         const TPE *bs = bp + start[k], *be = bp + end[k]; \
     298             :                         TPE curval = (be > bs) ? *(be - 1) : TPE##_nil;      \
     299             :                         rb[k] = curval;                                 \
     300             :                         has_nils |= is_##TPE##_nil(curval);             \
     301             :                 }                                                       \
     302             :         } while (0)
     303             : 
     304             : gdk_return
     305          31 : GDKanalyticallast(BAT *r, BAT *b, BAT *s, BAT *e, int tpe)
     306             : {
     307          31 :         BATiter bi = bat_iterator(b);
     308          31 :         BATiter si = bat_iterator(s);
     309          31 :         BATiter ei = bat_iterator(e);
     310             :         bool has_nils = false;
     311          31 :         oid k = 0, cnt = BATcount(b);
     312          31 :         const oid *restrict start = si.base, *restrict end = ei.base;
     313          31 :         const void *nil = ATOMnilptr(tpe);
     314          31 :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
     315             : 
     316          31 :         switch (ATOMbasetype(tpe)) {
     317           1 :         case TYPE_bte:
     318          11 :                 ANALYTICAL_LAST_FIXED(bte);
     319             :                 break;
     320           0 :         case TYPE_sht:
     321           0 :                 ANALYTICAL_LAST_FIXED(sht);
     322             :                 break;
     323          22 :         case TYPE_int:
     324         339 :                 ANALYTICAL_LAST_FIXED(int);
     325             :                 break;
     326           1 :         case TYPE_lng:
     327          12 :                 ANALYTICAL_LAST_FIXED(lng);
     328             :                 break;
     329             : #ifdef HAVE_HGE
     330           0 :         case TYPE_hge:
     331           0 :                 ANALYTICAL_LAST_FIXED(hge);
     332             :                 break;
     333             : #endif
     334           0 :         case TYPE_flt:
     335           0 :                 ANALYTICAL_LAST_FIXED(flt);
     336             :                 break;
     337           2 :         case TYPE_dbl:
     338          14 :                 ANALYTICAL_LAST_FIXED(dbl);
     339             :                 break;
     340           5 :         default:{
     341           5 :                 if (ATOMvarsized(tpe)) {
     342          50 :                         for (; k < cnt; k++) {
     343          45 :                                 const void *curval = (end[k] > start[k]) ? BUNtvar(bi, end[k] - 1) : nil;
     344          45 :                                 if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     345           0 :                                         bat_iterator_end(&bi);
     346           0 :                                         bat_iterator_end(&si);
     347           0 :                                         bat_iterator_end(&ei);
     348           0 :                                         return GDK_FAIL;
     349             :                                 }
     350          45 :                                 has_nils |= atomcmp(curval, nil) == 0;
     351             :                         }
     352             :                 } else {
     353           0 :                         uint16_t width = r->twidth;
     354           0 :                         uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     355           0 :                         for (; k < cnt; k++) {
     356           0 :                                 const void *curval = (end[k] > start[k]) ? BUNtloc(bi, end[k] - 1) : nil;
     357           0 :                                 memcpy(rcast, curval, width);
     358           0 :                                 rcast += width;
     359           0 :                                 has_nils |= atomcmp(curval, nil) == 0;
     360             :                         }
     361             :                 }
     362             :         }
     363             :         }
     364          31 :         bat_iterator_end(&bi);
     365          31 :         bat_iterator_end(&si);
     366          31 :         bat_iterator_end(&ei);
     367          31 :         BATsetcount(r, cnt);
     368          31 :         r->tnonil = !has_nils;
     369          31 :         r->tnil = has_nils;
     370          31 :         return GDK_SUCCEED;
     371             : }
     372             : 
     373             : #define ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(TPE)                       \
     374             :         do {                                                            \
     375             :                 const TPE *bp = (TPE*)bi.base;                          \
     376             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
     377             :                 if (is_lng_nil(nth)) {                                  \
     378             :                         has_nils = true;                                \
     379             :                         for (; k < cnt; k++)                         \
     380             :                                 rb[k] = TPE##_nil;                      \
     381             :                 } else {                                                \
     382             :                         nth--;                                          \
     383             :                         for (; k < cnt; k++) {                               \
     384             :                                 const TPE *bs = bp + start[k];          \
     385             :                                 const TPE *be = bp + end[k];            \
     386             :                                 TPE curval = (be > bs && nth < (lng)(end[k] - start[k])) ? *(bs + nth) : TPE##_nil; \
     387             :                                 rb[k] = curval;                         \
     388             :                                 has_nils |= is_##TPE##_nil(curval);     \
     389             :                         }                                               \
     390             :                 }                                                       \
     391             :         } while (0)
     392             : 
     393             : #define ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(TPE)                        \
     394             :         do {                                                            \
     395             :                 const TPE *bp = (TPE*)bi.base;                          \
     396             :                 TPE curval, *rb = (TPE*)Tloc(r, 0);                     \
     397             :                 for (; k < cnt; k++) {                                       \
     398             :                         lng lnth = tp[k];                               \
     399             :                         const TPE *bs = bp + start[k];                  \
     400             :                         const TPE *be = bp + end[k];                    \
     401             :                         if (!is_lng_nil(lnth) && lnth <= 0) goto invalidnth; \
     402             :                         if (is_lng_nil(lnth) || be <= bs || lnth - 1 > (lng)(end[k] - start[k])) { \
     403             :                                 curval = TPE##_nil;                     \
     404             :                                 has_nils = true;                        \
     405             :                         } else {                                        \
     406             :                                 curval = *(bs + lnth - 1);              \
     407             :                                 has_nils |= is_##TPE##_nil(curval);     \
     408             :                         }                                               \
     409             :                         rb[k] = curval;                                 \
     410             :                 }                                                       \
     411             :         } while (0)
     412             : 
     413             : gdk_return
     414          40 : GDKanalyticalnthvalue(BAT *r, BAT *b, BAT *s, BAT *e, BAT *t, lng *pnth, int tpe)
     415             : {
     416          40 :         BATiter bi = bat_iterator(b);
     417          40 :         BATiter si = bat_iterator(s);
     418          40 :         BATiter ei = bat_iterator(e);
     419          40 :         BATiter ti = bat_iterator(t);
     420             :         bool has_nils = false;
     421          40 :         oid k = 0, cnt = bi.count;
     422          40 :         const oid *restrict start = si.base, *restrict end = ei.base;
     423          40 :         lng nth = pnth ? *pnth : 0;
     424          40 :         const lng *restrict tp = ti.base;
     425          40 :         const void *nil = ATOMnilptr(tpe);
     426          40 :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
     427             : 
     428          40 :         if (t && t->ttype != TYPE_lng)
     429           0 :                 goto nosupport;
     430             : 
     431          40 :         if (t) {
     432           5 :                 switch (ATOMbasetype(tpe)) {
     433           3 :                 case TYPE_bte:
     434          33 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(bte);
     435             :                         break;
     436           0 :                 case TYPE_sht:
     437           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(sht);
     438             :                         break;
     439           2 :                 case TYPE_int:
     440          22 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(int);
     441             :                         break;
     442           0 :                 case TYPE_lng:
     443           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(lng);
     444             :                         break;
     445             : #ifdef HAVE_HGE
     446           0 :                 case TYPE_hge:
     447           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(hge);
     448             :                         break;
     449             : #endif
     450           0 :                 case TYPE_flt:
     451           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(flt);
     452             :                         break;
     453           0 :                 case TYPE_dbl:
     454           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(dbl);
     455             :                         break;
     456           0 :                 default:{
     457             :                         const void *curval = nil;
     458           0 :                         if (ATOMvarsized(tpe)) {
     459           0 :                                 for (; k < cnt; k++) {
     460           0 :                                         lng lnth = tp[k];
     461           0 :                                         if (!is_lng_nil(nth) && nth <= 0) goto invalidnth;
     462           0 :                                         if (is_lng_nil(lnth) || end[k] <= start[k] || lnth - 1 > (lng)(end[k] - start[k])) {
     463             :                                                 curval = (void *) nil;
     464             :                                                 has_nils = true;
     465             :                                         } else {
     466           0 :                                                 curval = BUNtvar(bi, start[k] + (oid)(lnth - 1));
     467           0 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     468             :                                         }
     469           0 :                                         if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     470           0 :                                                 bat_iterator_end(&bi);
     471           0 :                                                 bat_iterator_end(&si);
     472           0 :                                                 bat_iterator_end(&ei);
     473           0 :                                                 bat_iterator_end(&ti);
     474           0 :                                                 return GDK_FAIL;
     475             :                                         }
     476             :                                 }
     477             :                         } else {
     478           0 :                                 uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     479           0 :                                 uint16_t width = r->twidth;
     480           0 :                                 for (; k < cnt; k++) {
     481           0 :                                         lng lnth = tp[k];
     482           0 :                                         if (!is_lng_nil(nth) && nth <= 0) goto invalidnth;
     483           0 :                                         if (is_lng_nil(lnth) || end[k] <= start[k] || lnth - 1 > (lng)(end[k] - start[k])) {
     484             :                                                 curval = (void *) nil;
     485             :                                                 has_nils = true;
     486             :                                         } else {
     487           0 :                                                 curval = BUNtloc(bi, start[k] + (oid)(lnth - 1));
     488           0 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     489             :                                         }
     490           0 :                                         memcpy(rcast, curval, width);
     491           0 :                                         rcast += width;
     492             :                                 }
     493             :                         }
     494             :                 }
     495             :                 }
     496             :         } else {
     497          35 :                 if (!is_lng_nil(nth) && nth <= 0) {
     498           0 :                         goto invalidnth;
     499             :                 }
     500          35 :                 switch (ATOMbasetype(tpe)) {
     501           1 :                 case TYPE_bte:
     502          11 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(bte);
     503             :                         break;
     504           0 :                 case TYPE_sht:
     505           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(sht);
     506             :                         break;
     507          23 :                 case TYPE_int:
     508         243 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(int);
     509             :                         break;
     510           0 :                 case TYPE_lng:
     511           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(lng);
     512             :                         break;
     513             : #ifdef HAVE_HGE
     514           0 :                 case TYPE_hge:
     515           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(hge);
     516             :                         break;
     517             : #endif
     518           0 :                 case TYPE_flt:
     519           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(flt);
     520             :                         break;
     521           0 :                 case TYPE_dbl:
     522           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(dbl);
     523             :                         break;
     524          11 :                 default:{
     525          11 :                         if (ATOMvarsized(tpe)) {
     526          11 :                                 if (is_lng_nil(nth)) {
     527             :                                         has_nils = true;
     528           0 :                                         for (; k < cnt; k++)
     529           0 :                                                 if (tfastins_nocheckVAR(r, k, nil) != GDK_SUCCEED) {
     530           0 :                                                         bat_iterator_end(&bi);
     531           0 :                                                         bat_iterator_end(&si);
     532           0 :                                                         bat_iterator_end(&ei);
     533           0 :                                                         bat_iterator_end(&ti);
     534           0 :                                                         return GDK_FAIL;
     535             :                                                 }
     536             :                                 } else {
     537          11 :                                         nth--;
     538         112 :                                         for (; k < cnt; k++) {
     539         101 :                                                 const void *curval = (end[k] > start[k] && nth < (lng)(end[k] - start[k])) ? BUNtvar(bi, start[k] + (oid) nth) : nil;
     540         101 :                                                 if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     541           0 :                                                         bat_iterator_end(&bi);
     542           0 :                                                         bat_iterator_end(&si);
     543           0 :                                                         bat_iterator_end(&ei);
     544           0 :                                                         bat_iterator_end(&ti);
     545           0 :                                                         return GDK_FAIL;
     546             :                                                 }
     547         101 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     548             :                                         }
     549             :                                 }
     550             :                         } else {
     551           0 :                                 uint16_t width = r->twidth;
     552           0 :                                 uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     553           0 :                                 if (is_lng_nil(nth)) {
     554             :                                         has_nils = true;
     555           0 :                                         for (; k < cnt; k++) {
     556           0 :                                                 memcpy(rcast, nil, width);
     557           0 :                                                 rcast += width;
     558             :                                         }
     559             :                                 } else {
     560           0 :                                         nth--;
     561           0 :                                         for (; k < cnt; k++) {
     562           0 :                                                 const void *curval = (end[k] > start[k] && nth < (lng)(end[k] - start[k])) ? BUNtloc(bi, start[k] + (oid) nth) : nil;
     563           0 :                                                 memcpy(rcast, curval, width);
     564           0 :                                                 rcast += width;
     565           0 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     566             :                                         }
     567             :                                 }
     568             :                         }
     569             :                 }
     570             :                 }
     571             :         }
     572          40 :         bat_iterator_end(&bi);
     573          40 :         bat_iterator_end(&si);
     574          40 :         bat_iterator_end(&ei);
     575          40 :         bat_iterator_end(&ti);
     576             : 
     577          40 :         BATsetcount(r, cnt);
     578          40 :         r->tnonil = !has_nils;
     579          40 :         r->tnil = has_nils;
     580          40 :         return GDK_SUCCEED;
     581             : nosupport:
     582           0 :         bat_iterator_end(&bi);
     583           0 :         bat_iterator_end(&si);
     584           0 :         bat_iterator_end(&ei);
     585           0 :         bat_iterator_end(&ti);
     586           0 :         GDKerror("42000!type %s not supported for the nth_value.\n", ATOMname(t->ttype));
     587           0 :         return GDK_FAIL;
     588           0 : invalidnth:
     589           0 :         bat_iterator_end(&bi);
     590           0 :         bat_iterator_end(&si);
     591           0 :         bat_iterator_end(&ei);
     592           0 :         bat_iterator_end(&ti);
     593           0 :         GDKerror("42000!nth_value must be greater than zero.\n");
     594           0 :         return GDK_FAIL;
     595             : }
     596             : 
     597             : #define ANALYTICAL_LAG_CALC(TPE)                                \
     598             :         do {                                                    \
     599             :                 for (i = 0; i < lag && rb < rp; i++, rb++)        \
     600             :                         *rb = def;                              \
     601             :                 has_nils |= (lag > 0 && is_##TPE##_nil(def));        \
     602             :                 for (; rb < rp; rb++, bp++) {                        \
     603             :                         next = *bp;                             \
     604             :                         *rb = next;                             \
     605             :                         has_nils |= is_##TPE##_nil(next);       \
     606             :                 }                                               \
     607             :         } while (0)
     608             : 
     609             : #define ANALYTICAL_LAG_IMP(TPE)                                         \
     610             :         do {                                                            \
     611             :                 TPE *rp, *rb, *rend,                                    \
     612             :                         def = *((TPE *) default_value), next;           \
     613             :                 const TPE *bp, *nbp;                                    \
     614             :                 bp = (TPE*)bi.base;                                     \
     615             :                 rb = rp = (TPE*)Tloc(r, 0);                             \
     616             :                 rend = rb + cnt;                                        \
     617             :                 if (lag == BUN_NONE) {                                  \
     618             :                         has_nils = true;                                \
     619             :                         for (; rb < rend; rb++)                              \
     620             :                                 *rb = TPE##_nil;                        \
     621             :                 } else if (p) {                                         \
     622             :                         pnp = np = (bit*)pi.base;                       \
     623             :                         end = np + cnt;                                 \
     624             :                         for (; np < end; np++) {                     \
     625             :                                 if (*np) {                              \
     626             :                                         ncnt = (np - pnp);              \
     627             :                                         rp += ncnt;                     \
     628             :                                         nbp = bp + ncnt;                \
     629             :                                         ANALYTICAL_LAG_CALC(TPE);       \
     630             :                                         bp = nbp;                       \
     631             :                                         pnp = np;                       \
     632             :                                 }                                       \
     633             :                         }                                               \
     634             :                         rp += (np - pnp);                               \
     635             :                         ANALYTICAL_LAG_CALC(TPE);                       \
     636             :                 } else {                                                \
     637             :                         rp += cnt;                                      \
     638             :                         ANALYTICAL_LAG_CALC(TPE);                       \
     639             :                 }                                                       \
     640             :         } while (0)
     641             : 
     642             : #define ANALYTICAL_LAG_OTHERS                                           \
     643             :         do {                                                            \
     644             :                 for (i = 0; i < lag && k < j; i++, k++) {         \
     645             :                         if (BUNappend(r, default_value, false) != GDK_SUCCEED) { \
     646             :                                 bat_iterator_end(&bi);                      \
     647             :                                 bat_iterator_end(&pi);                      \
     648             :                                 return GDK_FAIL;                        \
     649             :                         }                                               \
     650             :                 }                                                       \
     651             :                 has_nils |= (lag > 0 && atomcmp(default_value, nil) == 0); \
     652             :                 for (l = k - lag; k < j; k++, l++) {                 \
     653             :                         curval = BUNtail(bi, l);                        \
     654             :                         if (BUNappend(r, curval, false) != GDK_SUCCEED) { \
     655             :                                 bat_iterator_end(&bi);                      \
     656             :                                 bat_iterator_end(&pi);                      \
     657             :                                 return GDK_FAIL;                        \
     658             :                         }                                               \
     659             :                         has_nils |= atomcmp(curval, nil) == 0;          \
     660             :                 }                                                       \
     661             :         } while (0)
     662             : 
     663             : gdk_return
     664          30 : GDKanalyticallag(BAT *r, BAT *b, BAT *p, BUN lag, const void *restrict default_value, int tpe)
     665             : {
     666          30 :         BATiter bi = bat_iterator(b);
     667          30 :         BATiter pi = bat_iterator(p);
     668             :         int (*atomcmp) (const void *, const void *);
     669             :         const void *restrict nil;
     670          30 :         BUN i = 0, j = 0, k = 0, l = 0, ncnt, cnt = BATcount(b);
     671             :         bit *np, *pnp, *end;
     672             :         bool has_nils = false;
     673             : 
     674          30 :         assert(default_value);
     675             : 
     676          30 :         switch (ATOMbasetype(tpe)) {
     677           3 :         case TYPE_bte:
     678          33 :                 ANALYTICAL_LAG_IMP(bte);
     679             :                 break;
     680           0 :         case TYPE_sht:
     681           0 :                 ANALYTICAL_LAG_IMP(sht);
     682             :                 break;
     683          21 :         case TYPE_int:
     684         337 :                 ANALYTICAL_LAG_IMP(int);
     685             :                 break;
     686           1 :         case TYPE_lng:
     687          23 :                 ANALYTICAL_LAG_IMP(lng);
     688             :                 break;
     689             : #ifdef HAVE_HGE
     690           0 :         case TYPE_hge:
     691           0 :                 ANALYTICAL_LAG_IMP(hge);
     692             :                 break;
     693             : #endif
     694           0 :         case TYPE_flt:
     695           0 :                 ANALYTICAL_LAG_IMP(flt);
     696             :                 break;
     697           0 :         case TYPE_dbl:
     698           0 :                 ANALYTICAL_LAG_IMP(dbl);
     699             :                 break;
     700           5 :         default:{
     701             :                 const void *restrict curval;
     702           5 :                 nil = ATOMnilptr(tpe);
     703           5 :                 atomcmp = ATOMcompare(tpe);
     704           5 :                 if (lag == BUN_NONE) {
     705             :                         has_nils = true;
     706           0 :                         for (j = 0; j < cnt; j++) {
     707           0 :                                 if (BUNappend(r, nil, false) != GDK_SUCCEED) {
     708           0 :                                         bat_iterator_end(&bi);
     709           0 :                                         bat_iterator_end(&pi);
     710           0 :                                         return GDK_FAIL;
     711             :                                 }
     712             :                         }
     713           5 :                 } else if (p) {
     714           3 :                         pnp = np = (bit *) pi.base;
     715           3 :                         end = np + cnt;
     716          30 :                         for (; np < end; np++) {
     717          27 :                                 if (*np) {
     718           9 :                                         j += (np - pnp);
     719          31 :                                         ANALYTICAL_LAG_OTHERS;
     720             :                                         pnp = np;
     721             :                                 }
     722             :                         }
     723           3 :                         j += (np - pnp);
     724           8 :                         ANALYTICAL_LAG_OTHERS;
     725             :                 } else {
     726             :                         j += cnt;
     727          20 :                         ANALYTICAL_LAG_OTHERS;
     728             :                 }
     729             :         }
     730             :         }
     731          30 :         bat_iterator_end(&bi);
     732          30 :         bat_iterator_end(&pi);
     733          30 :         BATsetcount(r, cnt);
     734          30 :         r->tnonil = !has_nils;
     735          30 :         r->tnil = has_nils;
     736          30 :         return GDK_SUCCEED;
     737             : }
     738             : 
     739             : #define LEAD_CALC(TPE)                                                  \
     740             :         do {                                                            \
     741             :                 if (lead < ncnt) {                                   \
     742             :                         bp += lead;                                     \
     743             :                         l = ncnt - lead;                                \
     744             :                         for (i = 0; i < l; i++, rb++, bp++) {                \
     745             :                                 next = *bp;                             \
     746             :                                 *rb = next;                             \
     747             :                                 has_nils |= is_##TPE##_nil(next);       \
     748             :                         }                                               \
     749             :                 } else {                                                \
     750             :                         bp += ncnt;                                     \
     751             :                 }                                                       \
     752             :                 for (;rb < rp; rb++)                                 \
     753             :                         *rb = def;                                      \
     754             :                 has_nils |= (lead > 0 && is_##TPE##_nil(def));               \
     755             :         } while (0)
     756             : 
     757             : #define ANALYTICAL_LEAD_IMP(TPE)                                \
     758             :         do {                                                    \
     759             :                 TPE *rp, *rb, *bp, *rend,                       \
     760             :                         def = *((TPE *) default_value), next;   \
     761             :                 bp = (TPE*)bi.base;                             \
     762             :                 rb = rp = (TPE*)Tloc(r, 0);                     \
     763             :                 rend = rb + cnt;                                \
     764             :                 if (lead == BUN_NONE) {                         \
     765             :                         has_nils = true;                        \
     766             :                         for (; rb < rend; rb++)                      \
     767             :                                 *rb = TPE##_nil;                \
     768             :                 } else if (p) {                                 \
     769             :                         pnp = np = (bit*)pi.base;               \
     770             :                         end = np + cnt;                         \
     771             :                         for (; np < end; np++) {             \
     772             :                                 if (*np) {                      \
     773             :                                         ncnt = (np - pnp);      \
     774             :                                         rp += ncnt;             \
     775             :                                         LEAD_CALC(TPE);         \
     776             :                                         pnp = np;               \
     777             :                                 }                               \
     778             :                         }                                       \
     779             :                         ncnt = (np - pnp);                      \
     780             :                         rp += ncnt;                             \
     781             :                         LEAD_CALC(TPE);                         \
     782             :                 } else {                                        \
     783             :                         ncnt = cnt;                             \
     784             :                         rp += ncnt;                             \
     785             :                         LEAD_CALC(TPE);                         \
     786             :                 }                                               \
     787             :         } while (0)
     788             : 
     789             : #define ANALYTICAL_LEAD_OTHERS                                          \
     790             :         do {                                                            \
     791             :                 j += ncnt;                                              \
     792             :                 if (lead < ncnt) {                                   \
     793             :                         m = ncnt - lead;                                \
     794             :                         for (i = 0,n = k + lead; i < m; i++, n++) {  \
     795             :                                 curval = BUNtail(bi, n);                \
     796             :                                 if (BUNappend(r, curval, false) != GDK_SUCCEED) { \
     797             :                                         bat_iterator_end(&bi);              \
     798             :                                         bat_iterator_end(&pi);              \
     799             :                                         return GDK_FAIL;                \
     800             :                                 }                                       \
     801             :                                 has_nils |= atomcmp(curval, nil) == 0;  \
     802             :                         }                                               \
     803             :                         k += i;                                         \
     804             :                 }                                                       \
     805             :                 for (; k < j; k++) {                                 \
     806             :                         if (BUNappend(r, default_value, false) != GDK_SUCCEED) { \
     807             :                                 bat_iterator_end(&bi);                      \
     808             :                                 bat_iterator_end(&pi);                      \
     809             :                                 return GDK_FAIL;                        \
     810             :                         }                                               \
     811             :                 }                                                       \
     812             :                 has_nils |= (lead > 0 && atomcmp(default_value, nil) == 0); \
     813             :         } while (0)
     814             : 
     815             : gdk_return
     816          29 : GDKanalyticallead(BAT *r, BAT *b, BAT *p, BUN lead, const void *restrict default_value, int tpe)
     817             : {
     818          29 :         BATiter bi = bat_iterator(b);
     819          29 :         BATiter pi = bat_iterator(p);
     820             :         int (*atomcmp) (const void *, const void *);
     821             :         const void *restrict nil;
     822          29 :         BUN i = 0, j = 0, k = 0, l = 0, ncnt, cnt = BATcount(b);
     823             :         bit *np, *pnp, *end;
     824             :         bool has_nils = false;
     825             : 
     826          29 :         assert(default_value);
     827             : 
     828          29 :         switch (ATOMbasetype(tpe)) {
     829           4 :         case TYPE_bte:
     830          37 :                 ANALYTICAL_LEAD_IMP(bte);
     831             :                 break;
     832           0 :         case TYPE_sht:
     833           0 :                 ANALYTICAL_LEAD_IMP(sht);
     834             :                 break;
     835          18 :         case TYPE_int:
     836         314 :                 ANALYTICAL_LEAD_IMP(int);
     837             :                 break;
     838           1 :         case TYPE_lng:
     839          24 :                 ANALYTICAL_LEAD_IMP(lng);
     840             :                 break;
     841             : #ifdef HAVE_HGE
     842           0 :         case TYPE_hge:
     843           0 :                 ANALYTICAL_LEAD_IMP(hge);
     844             :                 break;
     845             : #endif
     846           0 :         case TYPE_flt:
     847           0 :                 ANALYTICAL_LEAD_IMP(flt);
     848             :                 break;
     849           0 :         case TYPE_dbl:
     850           0 :                 ANALYTICAL_LEAD_IMP(dbl);
     851             :                 break;
     852           6 :         default:{
     853             :                 BUN m = 0, n = 0;
     854             :                 const void *restrict curval;
     855           6 :                 nil = ATOMnilptr(tpe);
     856           6 :                 atomcmp = ATOMcompare(tpe);
     857           6 :                 if (lead == BUN_NONE) {
     858             :                         has_nils = true;
     859           0 :                         for (j = 0; j < cnt; j++) {
     860           0 :                                 if (BUNappend(r, nil, false) != GDK_SUCCEED) {
     861           0 :                                         bat_iterator_end(&bi);
     862           0 :                                         bat_iterator_end(&pi);
     863           0 :                                         return GDK_FAIL;
     864             :                                 }
     865             :                         }
     866           6 :                 } else if (p) {
     867           4 :                         pnp = np = (bit *) pi.base;
     868           4 :                         end = np + cnt;
     869          42 :                         for (; np < end; np++) {
     870          38 :                                 if (*np) {
     871          12 :                                         ncnt = (np - pnp);
     872          56 :                                         ANALYTICAL_LEAD_OTHERS;
     873             :                                         pnp = np;
     874             :                                 }
     875             :                         }
     876           4 :                         ncnt = (np - pnp);
     877          14 :                         ANALYTICAL_LEAD_OTHERS;
     878             :                 } else {
     879             :                         ncnt = cnt;
     880          22 :                         ANALYTICAL_LEAD_OTHERS;
     881             :                 }
     882             :         }
     883             :         }
     884          29 :         bat_iterator_end(&bi);
     885          29 :         bat_iterator_end(&pi);
     886          29 :         BATsetcount(r, cnt);
     887          29 :         r->tnonil = !has_nils;
     888          29 :         r->tnil = has_nils;
     889          29 :         return GDK_SUCCEED;
     890             : }
     891             : 
     892             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_UNBOUNDED_TILL_CURRENT_ROW(TPE, MIN_MAX) \
     893             :         do {                                                            \
     894             :                 TPE curval = TPE##_nil;                                 \
     895             :                 for (; k < i;) {                                     \
     896             :                         j = k;                                          \
     897             :                         do {                                            \
     898             :                                 if (!is_##TPE##_nil(bp[k])) {           \
     899             :                                         if (is_##TPE##_nil(curval))     \
     900             :                                                 curval = bp[k];         \
     901             :                                         else                            \
     902             :                                                 curval = MIN_MAX(bp[k], curval); \
     903             :                                 }                                       \
     904             :                                 k++;                                    \
     905             :                         } while (k < i && !op[k]);                   \
     906             :                         for (; j < k; j++)                           \
     907             :                                 rb[j] = curval;                         \
     908             :                         has_nils |= is_##TPE##_nil(curval);             \
     909             :                 }                                                       \
     910             :         } while (0)
     911             : 
     912             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_CURRENT_ROW_TILL_UNBOUNDED(TPE, MIN_MAX) \
     913             :         do {                                                            \
     914             :                 TPE curval = TPE##_nil;                                 \
     915             :                 l = i - 1;                                              \
     916             :                 for (j = l; ; j--) {                                    \
     917             :                         if (!is_##TPE##_nil(bp[j])) {                   \
     918             :                                 if (is_##TPE##_nil(curval))             \
     919             :                                         curval = bp[j];                 \
     920             :                                 else                                    \
     921             :                                         curval = MIN_MAX(bp[j], curval); \
     922             :                         }                                               \
     923             :                         if (op[j] || j == k) {                          \
     924             :                                 for (; ; l--) {                         \
     925             :                                         rb[l] = curval;                 \
     926             :                                         if (l == j)                     \
     927             :                                                 break;                  \
     928             :                                 }                                       \
     929             :                                 has_nils |= is_##TPE##_nil(curval);     \
     930             :                                 if (j == k)                             \
     931             :                                         break;                          \
     932             :                                 l = j - 1;                              \
     933             :                         }                                               \
     934             :                 }                                                       \
     935             :                 k = i;                                                  \
     936             :         } while (0)
     937             : 
     938             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_ALL_ROWS(TPE, MIN_MAX)            \
     939             :         do {                                                            \
     940             :                 TPE curval = TPE##_nil;                                 \
     941             :                 for (j = k; j < i; j++) {                            \
     942             :                         TPE v = bp[j];                                  \
     943             :                         if (!is_##TPE##_nil(v)) {                       \
     944             :                                 if (is_##TPE##_nil(curval))             \
     945             :                                         curval = v;                     \
     946             :                                 else                                    \
     947             :                                         curval = MIN_MAX(v, curval);    \
     948             :                         }                                               \
     949             :                 }                                                       \
     950             :                 for (; k < i; k++)                                   \
     951             :                         rb[k] = curval;                                 \
     952             :                 has_nils |= is_##TPE##_nil(curval);                     \
     953             :         } while (0)
     954             : 
     955             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_CURRENT_ROW(TPE, MIN_MAX) \
     956             :         do {                                                    \
     957             :                 for (; k < i; k++) {                         \
     958             :                         TPE v = bp[k];                          \
     959             :                         rb[k] = v;                              \
     960             :                         has_nils |= is_##TPE##_nil(v);          \
     961             :                 }                                               \
     962             :         } while (0)
     963             : 
     964             : #define INIT_AGGREGATE_MIN_MAX_FIXED(TPE, MIN_MAX, NOTHING)     \
     965             :         do {                                                    \
     966             :                 computed = TPE##_nil;                           \
     967             :         } while (0)
     968             : #define COMPUTE_LEVEL0_MIN_MAX_FIXED(X, TPE, MIN_MAX, NOTHING)  \
     969             :         do {                                                    \
     970             :                 computed = bp[j + X];                           \
     971             :         } while (0)
     972             : #define COMPUTE_LEVELN_MIN_MAX_FIXED(VAL, TPE, MIN_MAX, NOTHING)        \
     973             :         do {                                                            \
     974             :                 if (!is_##TPE##_nil(VAL)) {                             \
     975             :                         if (is_##TPE##_nil(computed))                   \
     976             :                                 computed = VAL;                         \
     977             :                         else                                            \
     978             :                                 computed = MIN_MAX(computed, VAL);      \
     979             :                 }                                                       \
     980             :         } while (0)
     981             : #define FINALIZE_AGGREGATE_MIN_MAX_FIXED(TPE, MIN_MAX, NOTHING) \
     982             :         do {                                                    \
     983             :                 rb[k] = computed;                               \
     984             :                 has_nils |= is_##TPE##_nil(computed);           \
     985             :         } while (0)
     986             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_OTHERS(TPE, MIN_MAX)              \
     987             :         do {                                                            \
     988             :                 oid ncount = i - k;                                     \
     989             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
     990             :                         goto cleanup;                                   \
     991             :                 populate_segment_tree(TPE, ncount, INIT_AGGREGATE_MIN_MAX_FIXED, COMPUTE_LEVEL0_MIN_MAX_FIXED, COMPUTE_LEVELN_MIN_MAX_FIXED, TPE, MIN_MAX, NOTHING); \
     992             :                 for (; k < i; k++)                                   \
     993             :                         compute_on_segment_tree(TPE, start[k] - j, end[k] - j, INIT_AGGREGATE_MIN_MAX_FIXED, COMPUTE_LEVELN_MIN_MAX_FIXED, FINALIZE_AGGREGATE_MIN_MAX_FIXED, TPE, MIN_MAX, NOTHING); \
     994             :                 j = k;                                                  \
     995             :         } while (0)
     996             : 
     997             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_UNBOUNDED_TILL_CURRENT_ROW(GT_LT) \
     998             :         do {                                                            \
     999             :                 const void *curval = nil;                               \
    1000             :                 if (ATOMvarsized(tpe)) {                                \
    1001             :                         for (; k < i;) {                             \
    1002             :                                 j = k;                                  \
    1003             :                                 do {                                    \
    1004             :                                         void *next = BUNtvar(bi, k);    \
    1005             :                                         if (atomcmp(next, nil) != 0) {  \
    1006             :                                                 if (atomcmp(curval, nil) == 0) \
    1007             :                                                         curval = next;  \
    1008             :                                                 else                    \
    1009             :                                                         curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1010             :                                         }                               \
    1011             :                                         k++;                            \
    1012             :                                 } while (k < i && !op[k]);           \
    1013             :                                 for (; j < k; j++)                   \
    1014             :                                         if ((res = tfastins_nocheckVAR(r, j, curval)) != GDK_SUCCEED) \
    1015             :                                                 goto cleanup;           \
    1016             :                                 has_nils |= atomcmp(curval, nil) == 0;  \
    1017             :                         }                                               \
    1018             :                 } else {                                                \
    1019             :                         for (; k < i;) {                             \
    1020             :                                 j = k;                                  \
    1021             :                                 do {                                    \
    1022             :                                         void *next = BUNtloc(bi, k);    \
    1023             :                                         if (atomcmp(next, nil) != 0) {  \
    1024             :                                                 if (atomcmp(curval, nil) == 0) \
    1025             :                                                         curval = next;  \
    1026             :                                                 else                    \
    1027             :                                                         curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1028             :                                         }                               \
    1029             :                                         k++;                            \
    1030             :                                 } while (k < i && !op[k]);           \
    1031             :                                 for (; j < k; j++) {                 \
    1032             :                                         memcpy(rcast, curval, width);   \
    1033             :                                         rcast += width;                 \
    1034             :                                 }                                       \
    1035             :                                 has_nils |= atomcmp(curval, nil) == 0;  \
    1036             :                         }                                               \
    1037             :                 }                                                       \
    1038             :         } while (0)
    1039             : 
    1040             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_CURRENT_ROW_TILL_UNBOUNDED(GT_LT) \
    1041             :         do {                                                            \
    1042             :                 const void *curval = nil;                               \
    1043             :                 l = i - 1;                                              \
    1044             :                 if (ATOMvarsized(tpe)) {                                \
    1045             :                         for (j = l; ; j--) {                            \
    1046             :                                 void *next = BUNtvar(bi, j);            \
    1047             :                                 if (atomcmp(next, nil) != 0) {          \
    1048             :                                         if (atomcmp(curval, nil) == 0)  \
    1049             :                                                 curval = next;          \
    1050             :                                         else                            \
    1051             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1052             :                                 }                                       \
    1053             :                                 if (op[j] || j == k) {                  \
    1054             :                                         for (; ; l--) {                 \
    1055             :                                                 if ((res = tfastins_nocheckVAR(r, l, curval)) != GDK_SUCCEED) \
    1056             :                                                         goto cleanup;   \
    1057             :                                                 if (l == j)             \
    1058             :                                                         break;          \
    1059             :                                         }                               \
    1060             :                                         has_nils |= atomcmp(curval, nil) == 0; \
    1061             :                                         if (j == k)                     \
    1062             :                                                 break;                  \
    1063             :                                         l = j - 1;                      \
    1064             :                                 }                                       \
    1065             :                         }                                               \
    1066             :                 } else {                                                \
    1067             :                         for (j = l; ; j--) {                            \
    1068             :                                 void *next = BUNtloc(bi, j);            \
    1069             :                                 if (atomcmp(next, nil) != 0) {          \
    1070             :                                         if (atomcmp(curval, nil) == 0)  \
    1071             :                                                 curval = next;          \
    1072             :                                         else                            \
    1073             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1074             :                                 }                                       \
    1075             :                                 if (op[j] || j == k) {                  \
    1076             :                                         BUN x = l * width;              \
    1077             :                                         for (; ; l--) {                 \
    1078             :                                                 memcpy(rcast + x, curval, width); \
    1079             :                                                 x -= width;             \
    1080             :                                                 if (l == j)             \
    1081             :                                                         break;          \
    1082             :                                         }                               \
    1083             :                                         has_nils |= atomcmp(curval, nil) == 0; \
    1084             :                                         if (j == k)                     \
    1085             :                                                 break;                  \
    1086             :                                         l = j - 1;                      \
    1087             :                                 }                                       \
    1088             :                         }                                               \
    1089             :                 }                                                       \
    1090             :                 k = i;                                                  \
    1091             :         } while (0)
    1092             : 
    1093             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_ALL_ROWS(GT_LT)                  \
    1094             :         do {                                                            \
    1095             :                 void *curval = (void*) nil;                             \
    1096             :                 if (ATOMvarsized(tpe)) {                                \
    1097             :                         for (j = k; j < i; j++) {                    \
    1098             :                                 void *next = BUNtvar(bi, j);            \
    1099             :                                 if (atomcmp(next, nil) != 0) {          \
    1100             :                                         if (atomcmp(curval, nil) == 0)  \
    1101             :                                                 curval = next;          \
    1102             :                                         else                            \
    1103             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1104             :                                 }                                       \
    1105             :                         }                                               \
    1106             :                         for (; k < i; k++)                           \
    1107             :                                 if ((res = tfastins_nocheckVAR(r, k, curval)) != GDK_SUCCEED) \
    1108             :                                         goto cleanup;                   \
    1109             :                 } else {                                                \
    1110             :                         for (j = k; j < i; j++) {                    \
    1111             :                                 void *next = BUNtloc(bi, j);            \
    1112             :                                 if (atomcmp(next, nil) != 0) {          \
    1113             :                                         if (atomcmp(curval, nil) == 0)  \
    1114             :                                                 curval = next;          \
    1115             :                                         else                            \
    1116             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1117             :                                 }                                       \
    1118             :                         }                                               \
    1119             :                         for (; k < i; k++) {                         \
    1120             :                                 memcpy(rcast, curval, width);           \
    1121             :                                 rcast += width;                         \
    1122             :                         }                                               \
    1123             :                 }                                                       \
    1124             :                 has_nils |= atomcmp(curval, nil) == 0;                  \
    1125             :         } while (0)
    1126             : 
    1127             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_CURRENT_ROW(GT_LT)               \
    1128             :         do {                                                            \
    1129             :                 if (ATOMvarsized(tpe)) {                                \
    1130             :                         for (; k < i; k++) {                         \
    1131             :                                 void *next = BUNtvar(bi, k);            \
    1132             :                                 if ((res = tfastins_nocheckVAR(r, k, next)) != GDK_SUCCEED) \
    1133             :                                         goto cleanup;                   \
    1134             :                                 has_nils |= atomcmp(next, nil) == 0;    \
    1135             :                         }                                               \
    1136             :                 } else {                                                \
    1137             :                         for (; k < i; k++) {                         \
    1138             :                                 void *next = BUNtloc(bi, k);            \
    1139             :                                 memcpy(rcast, next, width);             \
    1140             :                                 rcast += width;                         \
    1141             :                                 has_nils |= atomcmp(next, nil) == 0;    \
    1142             :                         }                                               \
    1143             :                 }                                                       \
    1144             :         } while (0)
    1145             : 
    1146             : #define INIT_AGGREGATE_MIN_MAX_OTHERS(GT_LT, NOTHING1, NOTHING2)        \
    1147             :         do {                                                            \
    1148             :                 computed = (void*) nil;                                 \
    1149             :         } while (0)
    1150             : #define COMPUTE_LEVEL0_MIN_MAX_OTHERS(X, GT_LT, NOTHING1, NOTHING2)     \
    1151             :         do {                                                            \
    1152             :                 computed = BUNtail(bi, j + X);                          \
    1153             :         } while (0)
    1154             : #define COMPUTE_LEVELN_MIN_MAX_OTHERS(VAL, GT_LT, NOTHING1, NOTHING2)   \
    1155             :         do {                                                            \
    1156             :                 if (atomcmp(VAL, nil) != 0) {                           \
    1157             :                         if (atomcmp(computed, nil) == 0)                \
    1158             :                                 computed = VAL;                         \
    1159             :                         else                                            \
    1160             :                                 computed = atomcmp(VAL, computed) GT_LT 0 ? computed : VAL; \
    1161             :                 }                                                       \
    1162             :         } while (0)
    1163             : #define FINALIZE_AGGREGATE_MIN_MAX_OTHERS(GT_LT, NOTHING1, NOTHING2)    \
    1164             :         do {                                                            \
    1165             :                 if (ATOMvarsized(tpe)) {                                \
    1166             :                         if ((res = tfastins_nocheckVAR(r, k, computed)) != GDK_SUCCEED) \
    1167             :                                 goto cleanup;                           \
    1168             :                 } else {                                                \
    1169             :                         memcpy(rcast, computed, width);                 \
    1170             :                         rcast += width;                                 \
    1171             :                 }                                                       \
    1172             :                 has_nils |= atomcmp(computed, nil) == 0;                \
    1173             :         } while (0)
    1174             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_OTHERS(GT_LT)                    \
    1175             :         do {                                                            \
    1176             :                 oid ncount = i - k;                                     \
    1177             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(void*), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1178             :                         goto cleanup;                                   \
    1179             :                 populate_segment_tree(void*, ncount, INIT_AGGREGATE_MIN_MAX_OTHERS, COMPUTE_LEVEL0_MIN_MAX_OTHERS, COMPUTE_LEVELN_MIN_MAX_OTHERS, GT_LT, NOTHING, NOTHING); \
    1180             :                 for (; k < i; k++)                                   \
    1181             :                         compute_on_segment_tree(void*, start[k] - j, end[k] - j, INIT_AGGREGATE_MIN_MAX_OTHERS, COMPUTE_LEVELN_MIN_MAX_OTHERS, FINALIZE_AGGREGATE_MIN_MAX_OTHERS, GT_LT, NOTHING, NOTHING); \
    1182             :                 j = k;                                                  \
    1183             :         } while (0)
    1184             : 
    1185             : #define ANALYTICAL_MIN_MAX_PARTITIONS(TPE, MIN_MAX, IMP)                \
    1186             :         do {                                                            \
    1187             :                 TPE *restrict bp = (TPE*)bi.base, *rb = (TPE*)Tloc(r, 0); \
    1188             :                 if (p) {                                                \
    1189             :                         while (i < cnt) {                            \
    1190             :                                 if (np[i])      {                       \
    1191             : minmaxfixed##TPE##IMP:                                                  \
    1192             :                                         ANALYTICAL_MIN_MAX_CALC_FIXED_##IMP(TPE, MIN_MAX); \
    1193             :                                 }                                       \
    1194             :                                 if (!last)                              \
    1195             :                                         i++;                            \
    1196             :                         }                                               \
    1197             :                 }                                                       \
    1198             :                 if (!last) { /* hack to reduce code explosion, there's no need to duplicate the code to iterate each partition */ \
    1199             :                         last = true;                                    \
    1200             :                         i = cnt;                                        \
    1201             :                         goto minmaxfixed##TPE##IMP;                     \
    1202             :                 }                                                       \
    1203             :         } while (0)
    1204             : 
    1205             : #ifdef HAVE_HGE
    1206             : #define ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)                          \
    1207             :         case TYPE_hge:                                                  \
    1208             :                 ANALYTICAL_MIN_MAX_PARTITIONS(hge, MIN_MAX, IMP);       \
    1209             :         break;
    1210             : #else
    1211             : #define ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)
    1212             : #endif
    1213             : 
    1214             : #define ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, IMP)                \
    1215             :         do {                                                            \
    1216             :                 switch (ATOMbasetype(tpe)) {                            \
    1217             :                 case TYPE_bte:                                          \
    1218             :                         ANALYTICAL_MIN_MAX_PARTITIONS(bte, MIN_MAX, IMP); \
    1219             :                         break;                                          \
    1220             :                 case TYPE_sht:                                          \
    1221             :                         ANALYTICAL_MIN_MAX_PARTITIONS(sht, MIN_MAX, IMP); \
    1222             :                         break;                                          \
    1223             :                 case TYPE_int:                                          \
    1224             :                         ANALYTICAL_MIN_MAX_PARTITIONS(int, MIN_MAX, IMP); \
    1225             :                         break;                                          \
    1226             :                 case TYPE_lng:                                          \
    1227             :                         ANALYTICAL_MIN_MAX_PARTITIONS(lng, MIN_MAX, IMP); \
    1228             :                         break;                                          \
    1229             :                         ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)          \
    1230             :                 case TYPE_flt:                                          \
    1231             :                         ANALYTICAL_MIN_MAX_PARTITIONS(flt, MIN_MAX, IMP); \
    1232             :                         break;                                          \
    1233             :                 case TYPE_dbl:                                          \
    1234             :                         ANALYTICAL_MIN_MAX_PARTITIONS(dbl, MIN_MAX, IMP); \
    1235             :                         break;                                          \
    1236             :                 default: {                                              \
    1237             :                         if (p) {                                        \
    1238             :                                 while (i < cnt) {                    \
    1239             :                                         if (np[i])      {               \
    1240             : minmaxvarsized##IMP:                                                    \
    1241             :                                                 ANALYTICAL_MIN_MAX_CALC_OTHERS_##IMP(GT_LT); \
    1242             :                                         }                               \
    1243             :                                         if (!last)                      \
    1244             :                                                 i++;                    \
    1245             :                                 }                                       \
    1246             :                         }                                               \
    1247             :                         if (!last) {                                    \
    1248             :                                 last = true;                            \
    1249             :                                 i = cnt;                                \
    1250             :                                 goto minmaxvarsized##IMP;               \
    1251             :                         }                                               \
    1252             :                 }                                                       \
    1253             :                 }                                                       \
    1254             :         } while (0)
    1255             : 
    1256             : #define ANALYTICAL_MIN_MAX(OP, MIN_MAX, GT_LT)                          \
    1257             : gdk_return                                                              \
    1258             : GDKanalytical##OP(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tpe, int frame_type) \
    1259             : {                                                                       \
    1260             :         BATiter pi = bat_iterator(p);                                   \
    1261             :         BATiter oi = bat_iterator(o);                                   \
    1262             :         BATiter bi = bat_iterator(b);                                   \
    1263             :         BATiter si = bat_iterator(s);                                   \
    1264             :         BATiter ei = bat_iterator(e);                                   \
    1265             :         bool has_nils = false, last = false;                            \
    1266             :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base, \
    1267             :                 *levels_offset = NULL, nlevels = 0;     \
    1268             :         bit *np = pi.base, *op = oi.base;                               \
    1269             :         const void *nil = ATOMnilptr(tpe);                              \
    1270             :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);  \
    1271             :         void *segment_tree = NULL;                                      \
    1272             :         gdk_return res = GDK_SUCCEED;                                   \
    1273             :         uint16_t width = r->twidth;                                  \
    1274             :         uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);               \
    1275             :         BAT *st = NULL; \
    1276             :                                                                         \
    1277             :         if (cnt > 0) {                                                       \
    1278             :                 switch (frame_type) {                                   \
    1279             :                 case 3: /* unbounded until current row */       {       \
    1280             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, UNBOUNDED_TILL_CURRENT_ROW); \
    1281             :                 } break;                                                \
    1282             :                 case 4: /* current row until unbounded */       {       \
    1283             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, CURRENT_ROW_TILL_UNBOUNDED); \
    1284             :                 } break;                                                \
    1285             :                 case 5: /* all rows */  {                               \
    1286             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, ALL_ROWS); \
    1287             :                 } break;                                                \
    1288             :                 case 6: /* current row */ {                             \
    1289             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, CURRENT_ROW); \
    1290             :                 } break;                                                \
    1291             :                 default: {                                              \
    1292             :                         if (!(st = GDKinitialize_segment_tree())) {     \
    1293             :                                 res = GDK_FAIL; \
    1294             :                                 goto cleanup;   \
    1295             :                         }       \
    1296             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, OTHERS); \
    1297             :                 }                                                       \
    1298             :                 }                                                       \
    1299             :         }                                                               \
    1300             :                                                                         \
    1301             :         BATsetcount(r, cnt);                                            \
    1302             :         r->tnonil = !has_nils;                                               \
    1303             :         r->tnil = has_nils;                                          \
    1304             : cleanup:                                                                \
    1305             :         bat_iterator_end(&pi);                                              \
    1306             :         bat_iterator_end(&oi);                                              \
    1307             :         bat_iterator_end(&bi);                                              \
    1308             :         bat_iterator_end(&si);                                              \
    1309             :         bat_iterator_end(&ei);                                              \
    1310             :         BBPreclaim(st);                                         \
    1311             :         return res;                                                     \
    1312             : }
    1313             : 
    1314        3243 : ANALYTICAL_MIN_MAX(min, MIN, >)
    1315    17456216 : ANALYTICAL_MIN_MAX(max, MAX, <)
    1316             : 
    1317             : /* Counting no nils for fixed sizes */
    1318             : #define ANALYTICAL_COUNT_FIXED_UNBOUNDED_TILL_CURRENT_ROW(TPE)          \
    1319             :         do {                                                            \
    1320             :                 curval = 0;                                             \
    1321             :                 if (count_all) {                                        \
    1322             :                         for (; k < i;) {                             \
    1323             :                                 j = k;                                  \
    1324             :                                 do {                                    \
    1325             :                                         k++;                            \
    1326             :                                 } while (k < i && !op[k]);           \
    1327             :                                 curval += k - j;                        \
    1328             :                                 for (; j < k; j++)                   \
    1329             :                                         rb[j] = curval;                 \
    1330             :                         }                                               \
    1331             :                 } else {                                                \
    1332             :                         for (; k < i;) {                             \
    1333             :                                 j = k;                                  \
    1334             :                                 do {                                    \
    1335             :                                         curval += !is_##TPE##_nil(bp[k]); \
    1336             :                                         k++;                            \
    1337             :                                 } while (k < i && !op[k]);           \
    1338             :                                 for (; j < k; j++)                   \
    1339             :                                         rb[j] = curval;                 \
    1340             :                         }                                               \
    1341             :                 }                                                       \
    1342             :         } while (0)
    1343             : 
    1344             : #define ANALYTICAL_COUNT_FIXED_CURRENT_ROW_TILL_UNBOUNDED(TPE)          \
    1345             :         do {                                                            \
    1346             :                 curval = 0;                                             \
    1347             :                 l = i - 1;                                              \
    1348             :                 if (count_all) {                                        \
    1349             :                         for (j = l; ; j--) {                            \
    1350             :                                 if (op[j] || j == k) {                  \
    1351             :                                         curval += l - j + 1;            \
    1352             :                                         for (; ; l--) {                 \
    1353             :                                                 rb[l] = curval;         \
    1354             :                                                 if (l == j)             \
    1355             :                                                         break;          \
    1356             :                                         }                               \
    1357             :                                         if (j == k)                     \
    1358             :                                                 break;                  \
    1359             :                                         l = j - 1;                      \
    1360             :                                 }                                       \
    1361             :                         }                                               \
    1362             :                 } else {                                                \
    1363             :                         for (j = l; ; j--) {                            \
    1364             :                                 curval += !is_##TPE##_nil(bp[j]);       \
    1365             :                                 if (op[j] || j == k) {                  \
    1366             :                                         for (; ; l--) {                 \
    1367             :                                                 rb[l] = curval;         \
    1368             :                                                 if (l == j)             \
    1369             :                                                         break;          \
    1370             :                                         }                               \
    1371             :                                         if (j == k)                     \
    1372             :                                                 break;                  \
    1373             :                                         l = j - 1;                      \
    1374             :                                 }                                       \
    1375             :                         }                                               \
    1376             :                 }                                                       \
    1377             :                 k = i;                                                  \
    1378             :         } while (0)
    1379             : 
    1380             : #define ANALYTICAL_COUNT_FIXED_ALL_ROWS(TPE)                            \
    1381             :         do {                                                            \
    1382             :                 if (count_all) {                                        \
    1383             :                         curval = (lng)(i - k);                          \
    1384             :                         for (; k < i; k++)                           \
    1385             :                                 rb[k] = curval;                         \
    1386             :                 } else {                                                \
    1387             :                         curval = 0;                                     \
    1388             :                         for (; j < i; j++)                           \
    1389             :                                 curval += !is_##TPE##_nil(bp[j]);       \
    1390             :                         for (; k < i; k++)                           \
    1391             :                                 rb[k] = curval;                         \
    1392             :                 }                                                       \
    1393             :         } while (0)
    1394             : 
    1395             : #define ANALYTICAL_COUNT_FIXED_CURRENT_ROW(TPE)                 \
    1396             :         do {                                                    \
    1397             :                 if (count_all) {                                \
    1398             :                         for (; k < i; k++)                   \
    1399             :                                 rb[k] = 1;                      \
    1400             :                 } else {                                        \
    1401             :                         for (; k < i; k++)                   \
    1402             :                                 rb[k] = !is_##TPE##_nil(bp[k]); \
    1403             :                 }                                               \
    1404             :         } while (0)
    1405             : 
    1406             : #define INIT_AGGREGATE_COUNT(TPE, NOTHING1, NOTHING2)   \
    1407             :         do {                                            \
    1408             :                 computed = 0;                           \
    1409             :         } while (0)
    1410             : #define COMPUTE_LEVEL0_COUNT_FIXED(X, TPE, NOTHING1, NOTHING2)  \
    1411             :         do {                                                    \
    1412             :                 computed = !is_##TPE##_nil(bp[j + X]);          \
    1413             :         } while (0)
    1414             : #define COMPUTE_LEVELN_COUNT(VAL, NOTHING1, NOTHING2, NOTHING3) \
    1415             :         do {                                                    \
    1416             :                 computed += VAL;                                \
    1417             :         } while (0)
    1418             : #define FINALIZE_AGGREGATE_COUNT(NOTHING1, NOTHING2, NOTHING3)  \
    1419             :         do {                                                    \
    1420             :                 rb[k] = computed;                               \
    1421             :         } while (0)
    1422             : #define ANALYTICAL_COUNT_FIXED_OTHERS(TPE)                              \
    1423             :         do {                                                            \
    1424             :                 if (count_all) { /* no segment tree required for the global case (it scales in O(n)) */ \
    1425             :                         for (; k < i; k++)                           \
    1426             :                                 rb[k] = (end[k] > start[k]) ? (lng)(end[k] - start[k]) : 0; \
    1427             :                 } else {                                                \
    1428             :                         oid ncount = i - k;                             \
    1429             :                         if ((res = GDKrebuild_segment_tree(ncount, sizeof(lng), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1430             :                                 goto cleanup;                           \
    1431             :                         populate_segment_tree(lng, ncount, INIT_AGGREGATE_COUNT, COMPUTE_LEVEL0_COUNT_FIXED, COMPUTE_LEVELN_COUNT, TPE, NOTHING, NOTHING); \
    1432             :                         for (; k < i; k++)                           \
    1433             :                                 compute_on_segment_tree(lng, start[k] - j, end[k] - j, INIT_AGGREGATE_COUNT, COMPUTE_LEVELN_COUNT, FINALIZE_AGGREGATE_COUNT, TPE, NOTHING, NOTHING); \
    1434             :                         j = k;                                          \
    1435             :                 }                                                       \
    1436             :         } while (0)
    1437             : 
    1438             : /* Counting no nils for other types */
    1439             : #define ANALYTICAL_COUNT_OTHERS_UNBOUNDED_TILL_CURRENT_ROW              \
    1440             :         do {                                                            \
    1441             :                 curval = 0;                                             \
    1442             :                 if (count_all) {                                        \
    1443             :                         for (; k < i;) {                             \
    1444             :                                 j = k;                                  \
    1445             :                                 do {                                    \
    1446             :                                         k++;                            \
    1447             :                                 } while (k < i && !op[k]);           \
    1448             :                                 curval += k - j;                        \
    1449             :                                 for (; j < k; j++)                   \
    1450             :                                         rb[j] = curval;                 \
    1451             :                         }                                               \
    1452             :                 } else {                                                \
    1453             :                         for (; k < i; ) {                            \
    1454             :                                 j = k;                                  \
    1455             :                                 do {                                    \
    1456             :                                         curval += cmp(BUNtail(bi, k), nil) != 0; \
    1457             :                                         k++;                            \
    1458             :                                 } while (k < i && !op[k]);           \
    1459             :                                 for (; j < k; j++)                   \
    1460             :                                         rb[j] = curval;                 \
    1461             :                         }                                               \
    1462             :                 }                                                       \
    1463             :         } while (0)
    1464             : 
    1465             : #define ANALYTICAL_COUNT_OTHERS_CURRENT_ROW_TILL_UNBOUNDED              \
    1466             :         do {                                                            \
    1467             :                 curval = 0;                                             \
    1468             :                 l = i - 1;                                              \
    1469             :                 if (count_all) {                                        \
    1470             :                         for (j = l; ; j--) {                            \
    1471             :                                 if (op[j] || j == k) {                  \
    1472             :                                         curval += l - j + 1;            \
    1473             :                                         for (; ; l--) {                 \
    1474             :                                                 rb[l] = curval;         \
    1475             :                                                 if (l == j)             \
    1476             :                                                         break;          \
    1477             :                                         }                               \
    1478             :                                         if (j == k)                     \
    1479             :                                                 break;                  \
    1480             :                                         l = j - 1;                      \
    1481             :                                 }                                       \
    1482             :                         }                                               \
    1483             :                 } else {                                                \
    1484             :                         for (j = l; ; j--) {                            \
    1485             :                                 curval += cmp(BUNtail(bi, j), nil) != 0; \
    1486             :                                 if (op[j] || j == k) {                  \
    1487             :                                         for (; ; l--) {                 \
    1488             :                                                 rb[l] = curval;         \
    1489             :                                                 if (l == j)             \
    1490             :                                                         break;          \
    1491             :                                         }                               \
    1492             :                                         if (j == k)                     \
    1493             :                                                 break;                  \
    1494             :                                         l = j - 1;                      \
    1495             :                                 }                                       \
    1496             :                         }                                               \
    1497             :                 }                                                       \
    1498             :                 k = i;                                                  \
    1499             :         } while (0)
    1500             : 
    1501             : #define ANALYTICAL_COUNT_OTHERS_ALL_ROWS                                \
    1502             :         do {                                                            \
    1503             :                 curval = 0;                                             \
    1504             :                 if (count_all) {                                        \
    1505             :                         curval = (lng)(i - k);                          \
    1506             :                 } else {                                                \
    1507             :                         for (; j < i; j++)                           \
    1508             :                                 curval += cmp(BUNtail(bi, j), nil) != 0; \
    1509             :                 }                                                       \
    1510             :                 for (; k < i; k++)                                   \
    1511             :                         rb[k] = curval;                                 \
    1512             :         } while (0)
    1513             : 
    1514             : #define ANALYTICAL_COUNT_OTHERS_CURRENT_ROW                             \
    1515             :         do {                                                            \
    1516             :                 if (count_all) {                                        \
    1517             :                         for (; k < i; k++)                           \
    1518             :                                 rb[k] = 1;                              \
    1519             :                 } else {                                                \
    1520             :                         for (; k < i; k++)                           \
    1521             :                                 rb[k] = cmp(BUNtail(bi, k), nil) != 0;  \
    1522             :                 }                                                       \
    1523             :         } while (0)
    1524             : 
    1525             : #define COMPUTE_LEVEL0_COUNT_OTHERS(X, NOTHING1, NOTHING2, NOTHING3)    \
    1526             :         do {                                                            \
    1527             :                 computed = cmp(BUNtail(bi, j + X), nil) != 0;           \
    1528             :         } while (0)
    1529             : #define ANALYTICAL_COUNT_OTHERS_OTHERS                                  \
    1530             :         do {                                                            \
    1531             :                 if (count_all) { /* no segment tree required for the global case (it scales in O(n)) */ \
    1532             :                         for (; k < i; k++)                           \
    1533             :                                 rb[k] = (end[k] > start[k]) ? (lng)(end[k] - start[k]) : 0; \
    1534             :                 } else {                                                \
    1535             :                         oid ncount = i - k;                             \
    1536             :                         if ((res = GDKrebuild_segment_tree(ncount, sizeof(lng), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1537             :                                 goto cleanup;                           \
    1538             :                         populate_segment_tree(lng, ncount, INIT_AGGREGATE_COUNT, COMPUTE_LEVEL0_COUNT_OTHERS, COMPUTE_LEVELN_COUNT, NOTHING, NOTHING, NOTHING); \
    1539             :                         for (; k < i; k++)                           \
    1540             :                                 compute_on_segment_tree(lng, start[k] - j, end[k] - j, INIT_AGGREGATE_COUNT, COMPUTE_LEVELN_COUNT, FINALIZE_AGGREGATE_COUNT, NOTHING, NOTHING, NOTHING); \
    1541             :                         j = k;                                          \
    1542             :                 }                                                       \
    1543             :         } while (0)
    1544             : 
    1545             : /* Now do the count analytic function branches */
    1546             : #define ANALYTICAL_COUNT_FIXED_PARTITIONS(TPE, IMP)                     \
    1547             :         do {                                                            \
    1548             :                 TPE *restrict bp = (TPE*) bheap;                        \
    1549             :                 if (p) {                                                \
    1550             :                         while (i < cnt) {                            \
    1551             :                                 if (np[i])      {                       \
    1552             : count##TPE##IMP:                                                        \
    1553             :                                         ANALYTICAL_COUNT_FIXED_##IMP(TPE); \
    1554             :                                 }                                       \
    1555             :                                 if (!last)                              \
    1556             :                                         i++;                            \
    1557             :                         }                                               \
    1558             :                 }                                                       \
    1559             :                 if (!last) {                                            \
    1560             :                         last = true;                                    \
    1561             :                         i = cnt;                                        \
    1562             :                         goto count##TPE##IMP;                           \
    1563             :                 }                                                       \
    1564             :         } while (0)
    1565             : 
    1566             : #ifdef HAVE_HGE
    1567             : #define ANALYTICAL_COUNT_LIMIT(IMP)                             \
    1568             :         case TYPE_hge:                                          \
    1569             :                 ANALYTICAL_COUNT_FIXED_PARTITIONS(hge, IMP);    \
    1570             :         break;
    1571             : #else
    1572             : #define ANALYTICAL_COUNT_LIMIT(IMP)
    1573             : #endif
    1574             : 
    1575             : #define ANALYTICAL_COUNT_BRANCHES(IMP)                                  \
    1576             :         do {                                                            \
    1577             :                 switch (ATOMbasetype(tpe)) {                            \
    1578             :                 case TYPE_bte:                                          \
    1579             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(bte, IMP);    \
    1580             :                         break;                                          \
    1581             :                 case TYPE_sht:                                          \
    1582             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(sht, IMP);    \
    1583             :                         break;                                          \
    1584             :                 case TYPE_int:                                          \
    1585             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(int, IMP);    \
    1586             :                         break;                                          \
    1587             :                 case TYPE_lng:                                          \
    1588             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(lng, IMP);    \
    1589             :                         break;                                          \
    1590             :                         ANALYTICAL_COUNT_LIMIT(IMP)                     \
    1591             :                 case TYPE_flt:                                          \
    1592             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(flt, IMP);    \
    1593             :                         break;                                          \
    1594             :                 case TYPE_dbl:                                          \
    1595             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(dbl, IMP);    \
    1596             :                         break;                                          \
    1597             :                 default: {                                              \
    1598             :                         if (p) {                                        \
    1599             :                                 while (i < cnt) {                    \
    1600             :                                         if (np[i])      {               \
    1601             : countothers##IMP:                                                       \
    1602             :                                                 ANALYTICAL_COUNT_OTHERS_##IMP; \
    1603             :                                         }                               \
    1604             :                                         if (!last)                      \
    1605             :                                                 i++;                    \
    1606             :                                 }                                       \
    1607             :                         }                                               \
    1608             :                         if (!last) {                                    \
    1609             :                                 last = true;                            \
    1610             :                                 i = cnt;                                \
    1611             :                                 goto countothers##IMP;                  \
    1612             :                         }                                               \
    1613             :                 }                                                       \
    1614             :                 }                                                       \
    1615             :         } while (0)
    1616             : 
    1617             : gdk_return
    1618         159 : GDKanalyticalcount(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, bit ignore_nils, int tpe, int frame_type)
    1619             : {
    1620         159 :         BATiter pi = bat_iterator(p);
    1621         159 :         BATiter oi = bat_iterator(o);
    1622         159 :         BATiter bi = bat_iterator(b);
    1623         159 :         BATiter si = bat_iterator(s);
    1624         159 :         BATiter ei = bat_iterator(e);
    1625         159 :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    1626         159 :                 *levels_offset = NULL, nlevels = 0;
    1627         159 :         lng curval = 0, *rb = (lng *) Tloc(r, 0);
    1628         159 :         bit *np = pi.base, *op = oi.base;
    1629         159 :         const void *restrict nil = ATOMnilptr(tpe);
    1630         159 :         int (*cmp) (const void *, const void *) = ATOMcompare(tpe);
    1631         159 :         const void *restrict bheap = bi.base;
    1632         159 :         bool count_all = !ignore_nils || b->tnonil, last = false;
    1633         159 :         void *segment_tree = NULL;
    1634             :         gdk_return res = GDK_SUCCEED;
    1635             :         BAT *st = NULL;
    1636             : 
    1637         159 :         if (cnt > 0) {
    1638         159 :                 switch (frame_type) {
    1639          38 :                 case 3: /* unbounded until current row */       {
    1640         988 :                         ANALYTICAL_COUNT_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    1641             :                 } break;
    1642           3 :                 case 4: /* current row until unbounded */       {
    1643          41 :                         ANALYTICAL_COUNT_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    1644             :                 } break;
    1645          32 :                 case 5: /* all rows */  {
    1646         681 :                         ANALYTICAL_COUNT_BRANCHES(ALL_ROWS);
    1647             :                 } break;
    1648           8 :                 case 6: /* current row */ {
    1649          96 :                         ANALYTICAL_COUNT_BRANCHES(CURRENT_ROW);
    1650             :                 } break;
    1651          78 :                 default: {
    1652          78 :                         if (!count_all && !(st = GDKinitialize_segment_tree())) {
    1653             :                                 res = GDK_FAIL;
    1654           0 :                                 goto cleanup;
    1655             :                         }
    1656        2948 :                         ANALYTICAL_COUNT_BRANCHES(OTHERS);
    1657             :                 }
    1658             :                 }
    1659             :         }
    1660             : 
    1661         159 :         BATsetcount(r, cnt);
    1662         159 :         r->tnonil = true;
    1663         159 :         r->tnil = false;
    1664         159 : cleanup:
    1665         159 :         bat_iterator_end(&pi);
    1666         159 :         bat_iterator_end(&oi);
    1667         159 :         bat_iterator_end(&bi);
    1668         159 :         bat_iterator_end(&si);
    1669         159 :         bat_iterator_end(&ei);
    1670         159 :         BBPreclaim(st);
    1671         159 :         return res;
    1672             : }
    1673             : 
    1674             : /* sum on fixed size integers */
    1675             : #define ANALYTICAL_SUM_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2)   \
    1676             :         do {                                                            \
    1677             :                 TPE2 curval = TPE2##_nil;                               \
    1678             :                 for (; k < i;) {                                     \
    1679             :                         j = k;                                          \
    1680             :                         do {                                            \
    1681             :                                 if (!is_##TPE1##_nil(bp[k])) {          \
    1682             :                                         if (is_##TPE2##_nil(curval))    \
    1683             :                                                 curval = (TPE2) bp[k];  \
    1684             :                                         else                            \
    1685             :                                                 ADD_WITH_CHECK(bp[k], curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
    1686             :                                 }                                       \
    1687             :                                 k++;                                    \
    1688             :                         } while (k < i && !op[k]);                   \
    1689             :                         for (; j < k; j++)                           \
    1690             :                                 rb[j] = curval;                         \
    1691             :                         has_nils |= is_##TPE2##_nil(curval);            \
    1692             :                 }                                                       \
    1693             :         } while (0)
    1694             : 
    1695             : #define ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2)   \
    1696             :         do {                                                            \
    1697             :                 TPE2 curval = TPE2##_nil;                               \
    1698             :                 l = i - 1;                                              \
    1699             :                 for (j = l; ; j--) {                                    \
    1700             :                         if (!is_##TPE1##_nil(bp[j])) {                  \
    1701             :                                 if (is_##TPE2##_nil(curval))            \
    1702             :                                         curval = (TPE2) bp[j];          \
    1703             :                                 else                                    \
    1704             :                                         ADD_WITH_CHECK(bp[j], curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
    1705             :                         }                                               \
    1706             :                         if (op[j] || j == k) {                          \
    1707             :                                 for (; ; l--) {                         \
    1708             :                                         rb[l] = curval;                 \
    1709             :                                         if (l == j)                     \
    1710             :                                                 break;                  \
    1711             :                                 }                                       \
    1712             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    1713             :                                 if (j == k)                             \
    1714             :                                         break;                          \
    1715             :                                 l = j - 1;                              \
    1716             :                         }                                               \
    1717             :                 }                                                       \
    1718             :                 k = i;                                                  \
    1719             :         } while (0)
    1720             : 
    1721             : #define ANALYTICAL_SUM_IMP_NUM_ALL_ROWS(TPE1, TPE2)                     \
    1722             :         do {                                                            \
    1723             :                 TPE2 curval = TPE2##_nil;                               \
    1724             :                 for (; j < i; j++) {                                 \
    1725             :                         TPE1 v = bp[j];                                 \
    1726             :                         if (!is_##TPE1##_nil(v)) {                      \
    1727             :                                 if (is_##TPE2##_nil(curval))            \
    1728             :                                         curval = (TPE2) v;              \
    1729             :                                 else                                    \
    1730             :                                         ADD_WITH_CHECK(v, curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
    1731             :                         }                                               \
    1732             :                 }                                                       \
    1733             :                 for (; k < i; k++)                                   \
    1734             :                         rb[k] = curval;                                 \
    1735             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    1736             :         } while (0)
    1737             : 
    1738             : #define ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW(TPE1, TPE2)  \
    1739             :         do {                                            \
    1740             :                 for (; k < i; k++) {                 \
    1741             :                         TPE1 v = bp[k];                 \
    1742             :                         if (is_##TPE1##_nil(v)) {       \
    1743             :                                 rb[k] = TPE2##_nil;     \
    1744             :                                 has_nils = true;        \
    1745             :                         } else  {                       \
    1746             :                                 rb[k] = (TPE2) v;       \
    1747             :                         }                               \
    1748             :                 }                                       \
    1749             :         } while (0)
    1750             : 
    1751             : #define INIT_AGGREGATE_SUM(NOTHING1, TPE2, NOTHING2)    \
    1752             :         do {                                            \
    1753             :                 computed = TPE2##_nil;                  \
    1754             :         } while (0)
    1755             : #define COMPUTE_LEVEL0_SUM(X, TPE1, TPE2, NOTHING)                      \
    1756             :         do {                                                            \
    1757             :                 TPE1 v = bp[j + X];                                     \
    1758             :                 computed = is_##TPE1##_nil(v) ? TPE2##_nil : (TPE2) v;  \
    1759             :         } while (0)
    1760             : #define COMPUTE_LEVELN_SUM_NUM(VAL, NOTHING1, TPE2, NOTHING2)           \
    1761             :         do {                                                            \
    1762             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    1763             :                         if (is_##TPE2##_nil(computed))                  \
    1764             :                                 computed = VAL;                         \
    1765             :                         else                                            \
    1766             :                                 ADD_WITH_CHECK(VAL, computed, TPE2, computed, GDK_##TPE2##_max, goto calc_overflow); \
    1767             :                 }                                                       \
    1768             :         } while (0)
    1769             : #define FINALIZE_AGGREGATE_SUM(NOTHING1, TPE2, NOTHING2)        \
    1770             :         do {                                                    \
    1771             :                 rb[k] = computed;                               \
    1772             :                 has_nils |= is_##TPE2##_nil(computed);          \
    1773             :         } while (0)
    1774             : #define ANALYTICAL_SUM_IMP_NUM_OTHERS(TPE1, TPE2)                       \
    1775             :         do {                                                            \
    1776             :                 oid ncount = i - k;                                     \
    1777             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1778             :                         goto cleanup;                                   \
    1779             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_SUM, COMPUTE_LEVEL0_SUM, COMPUTE_LEVELN_SUM_NUM, TPE1, TPE2, NOTHING); \
    1780             :                 for (; k < i; k++)                                   \
    1781             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_SUM, COMPUTE_LEVELN_SUM_NUM, FINALIZE_AGGREGATE_SUM, TPE1, TPE2, NOTHING); \
    1782             :                 j = k;                                                  \
    1783             :         } while (0)
    1784             : 
    1785             : /* sum on floating-points */
    1786             : /* TODO go through a version of dofsum which returns the current partials for all the cases */
    1787             : #define ANALYTICAL_SUM_IMP_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2)
    1788             : #define ANALYTICAL_SUM_IMP_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2)
    1789             : 
    1790             : #define ANALYTICAL_SUM_IMP_FP_ALL_ROWS(TPE1, TPE2)                      \
    1791             :         do {                                                            \
    1792             :                 TPE1 *bs = bp + k;                                      \
    1793             :                 BUN parcel = i - k;                                     \
    1794             :                 TPE2 curval = TPE2##_nil;                               \
    1795             :                 if (dofsum(bs, 0,                                       \
    1796             :                                 &(struct canditer){.tpe = cand_dense, .ncand = parcel,}, \
    1797             :                                 parcel, &curval, 1, TYPE_##TPE1,    \
    1798             :                                 TYPE_##TPE2, NULL, 0, 0, true,          \
    1799             :                                 false, true) == BUN_NONE) {             \
    1800             :                         goto bailout;                                   \
    1801             :                 }                                                       \
    1802             :                 for (; k < i; k++)                                   \
    1803             :                         rb[k] = curval;                                 \
    1804             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    1805             :         } while (0)
    1806             : 
    1807             : #define ANALYTICAL_SUM_IMP_FP_CURRENT_ROW(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW(TPE1, TPE2)
    1808             : #define ANALYTICAL_SUM_IMP_FP_OTHERS(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_OTHERS(TPE1, TPE2)
    1809             : 
    1810             : #define ANALYTICAL_SUM_CALC(TPE1, TPE2, IMP)                    \
    1811             :         do {                                                    \
    1812             :                 TPE1 *restrict bp = (TPE1*)bi.base;             \
    1813             :                 TPE2 *rb = (TPE2*)Tloc(r, 0);                   \
    1814             :                 if (p) {                                        \
    1815             :                         while (i < cnt) {                    \
    1816             :                                 if (np[i])      {               \
    1817             : sum##TPE1##TPE2##IMP:                                           \
    1818             :                                         IMP(TPE1, TPE2);        \
    1819             :                                 }                               \
    1820             :                                 if (!last)                      \
    1821             :                                         i++;                    \
    1822             :                         }                                       \
    1823             :                 }                                               \
    1824             :                 if (!last) {                                    \
    1825             :                         last = true;                            \
    1826             :                         i = cnt;                                \
    1827             :                         goto sum##TPE1##TPE2##IMP;              \
    1828             :                 }                                               \
    1829             :         } while (0)
    1830             : 
    1831             : #ifdef HAVE_HGE
    1832             : #define ANALYTICAL_SUM_LIMIT(IMP)                                       \
    1833             :         case TYPE_hge:{                                                 \
    1834             :                 switch (tp1) {                                          \
    1835             :                 case TYPE_bte:                                          \
    1836             :                         ANALYTICAL_SUM_CALC(bte, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1837             :                         break;                                          \
    1838             :                 case TYPE_sht:                                          \
    1839             :                         ANALYTICAL_SUM_CALC(sht, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1840             :                         break;                                          \
    1841             :                 case TYPE_int:                                          \
    1842             :                         ANALYTICAL_SUM_CALC(int, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1843             :                         break;                                          \
    1844             :                 case TYPE_lng:                                          \
    1845             :                         ANALYTICAL_SUM_CALC(lng, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1846             :                         break;                                          \
    1847             :                 case TYPE_hge:                                          \
    1848             :                         ANALYTICAL_SUM_CALC(hge, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1849             :                         break;                                          \
    1850             :                 default:                                                \
    1851             :                         goto nosupport;                                 \
    1852             :                 }                                                       \
    1853             :                 break;                                                  \
    1854             :         }
    1855             : #else
    1856             : #define ANALYTICAL_SUM_LIMIT(IMP)
    1857             : #endif
    1858             : 
    1859             : #define ANALYTICAL_SUM_BRANCHES(IMP)                                    \
    1860             :         do {                                                            \
    1861             :                 switch (tp2) {                                          \
    1862             :                 case TYPE_bte:{                                         \
    1863             :                         switch (tp1) {                                  \
    1864             :                         case TYPE_bte:                                  \
    1865             :                                 ANALYTICAL_SUM_CALC(bte, bte, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1866             :                                 break;                                  \
    1867             :                         default:                                        \
    1868             :                                 goto nosupport;                         \
    1869             :                         }                                               \
    1870             :                         break;                                          \
    1871             :                 }                                                       \
    1872             :                 case TYPE_sht:{                                         \
    1873             :                         switch (tp1) {                                  \
    1874             :                         case TYPE_bte:                                  \
    1875             :                                 ANALYTICAL_SUM_CALC(bte, sht, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1876             :                                 break;                                  \
    1877             :                         case TYPE_sht:                                  \
    1878             :                                 ANALYTICAL_SUM_CALC(sht, sht, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1879             :                                 break;                                  \
    1880             :                         default:                                        \
    1881             :                                 goto nosupport;                         \
    1882             :                         }                                               \
    1883             :                         break;                                          \
    1884             :                 }                                                       \
    1885             :                 case TYPE_int:{                                         \
    1886             :                         switch (tp1) {                                  \
    1887             :                         case TYPE_bte:                                  \
    1888             :                                 ANALYTICAL_SUM_CALC(bte, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1889             :                                 break;                                  \
    1890             :                         case TYPE_sht:                                  \
    1891             :                                 ANALYTICAL_SUM_CALC(sht, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1892             :                                 break;                                  \
    1893             :                         case TYPE_int:                                  \
    1894             :                                 ANALYTICAL_SUM_CALC(int, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1895             :                                 break;                                  \
    1896             :                         default:                                        \
    1897             :                                 goto nosupport;                         \
    1898             :                         }                                               \
    1899             :                         break;                                          \
    1900             :                 }                                                       \
    1901             :                 case TYPE_lng:{                                         \
    1902             :                         switch (tp1) {                                  \
    1903             :                         case TYPE_bte:                                  \
    1904             :                                 ANALYTICAL_SUM_CALC(bte, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1905             :                                 break;                                  \
    1906             :                         case TYPE_sht:                                  \
    1907             :                                 ANALYTICAL_SUM_CALC(sht, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1908             :                                 break;                                  \
    1909             :                         case TYPE_int:                                  \
    1910             :                                 ANALYTICAL_SUM_CALC(int, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1911             :                                 break;                                  \
    1912             :                         case TYPE_lng:                                  \
    1913             :                                 ANALYTICAL_SUM_CALC(lng, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1914             :                                 break;                                  \
    1915             :                         default:                                        \
    1916             :                                 goto nosupport;                         \
    1917             :                         }                                               \
    1918             :                         break;                                          \
    1919             :                 }                                                       \
    1920             :                 ANALYTICAL_SUM_LIMIT(IMP)                               \
    1921             :                 case TYPE_flt:{                                         \
    1922             :                         switch (tp1) {                                  \
    1923             :                         case TYPE_flt:                                  \
    1924             :                                 ANALYTICAL_SUM_CALC(flt, flt, ANALYTICAL_SUM_IMP_FP_##IMP); \
    1925             :                                 break;                                  \
    1926             :                         default:                                        \
    1927             :                                 goto nosupport;                         \
    1928             :                         }                                               \
    1929             :                         break;                                          \
    1930             :                 }                                                       \
    1931             :                 case TYPE_dbl:{                                         \
    1932             :                         switch (tp1) {                                  \
    1933             :                         case TYPE_flt:                                  \
    1934             :                                 ANALYTICAL_SUM_CALC(flt, dbl, ANALYTICAL_SUM_IMP_FP_##IMP); \
    1935             :                                 break;                                  \
    1936             :                         case TYPE_dbl:                                  \
    1937             :                                 ANALYTICAL_SUM_CALC(dbl, dbl, ANALYTICAL_SUM_IMP_FP_##IMP); \
    1938             :                                 break;                                  \
    1939             :                         default:                                        \
    1940             :                                 goto nosupport;                         \
    1941             :                         }                                               \
    1942             :                         break;                                          \
    1943             :                 }                                                       \
    1944             :                 default:                                                \
    1945             :                         goto nosupport;                                 \
    1946             :                 }                                                       \
    1947             :         } while (0)
    1948             : 
    1949             : gdk_return
    1950         115 : GDKanalyticalsum(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tp1, int tp2, int frame_type)
    1951             : {
    1952         115 :         BATiter pi = bat_iterator(p);
    1953         115 :         BATiter oi = bat_iterator(o);
    1954         115 :         BATiter bi = bat_iterator(b);
    1955         115 :         BATiter si = bat_iterator(s);
    1956         115 :         BATiter ei = bat_iterator(e);
    1957             :         bool has_nils = false, last = false;
    1958         115 :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    1959         115 :                 *levels_offset = NULL, nlevels = 0;
    1960         115 :         bit *np = pi.base, *op = oi.base;
    1961             :         int abort_on_error = 1;
    1962             :         BUN nils = 0;
    1963         115 :         void *segment_tree = NULL;
    1964             :         gdk_return res = GDK_SUCCEED;
    1965             :         BAT *st = NULL;
    1966             : 
    1967         115 :         if (cnt > 0) {
    1968         115 :                 switch (frame_type) {
    1969          39 :                 case 3: /* unbounded until current row */       {
    1970        1028 :                         ANALYTICAL_SUM_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    1971             :                 } break;
    1972           0 :                 case 4: /* current row until unbounded */       {
    1973           0 :                         ANALYTICAL_SUM_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    1974             :                 } break;
    1975          28 :                 case 5: /* all rows */  {
    1976       18539 :                         ANALYTICAL_SUM_BRANCHES(ALL_ROWS);
    1977             :                 } break;
    1978           2 :                 case 6: /* current row */ {
    1979          34 :                         ANALYTICAL_SUM_BRANCHES(CURRENT_ROW);
    1980             :                 } break;
    1981          46 :                 default: {
    1982          46 :                         if (!(st = GDKinitialize_segment_tree())) {
    1983             :                                 res = GDK_FAIL;
    1984           0 :                                 goto cleanup;
    1985             :                         }
    1986     8374161 :                         ANALYTICAL_SUM_BRANCHES(OTHERS);
    1987             :                 }
    1988             :                 }
    1989             :         }
    1990             : 
    1991         115 :         BATsetcount(r, cnt);
    1992         115 :         r->tnonil = !has_nils;
    1993         115 :         r->tnil = has_nils;
    1994         115 :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
    1995           0 : bailout:
    1996           0 :         GDKerror("42000!error while calculating floating-point sum\n");
    1997             :         res = GDK_FAIL;
    1998           0 :         goto cleanup;
    1999           0 : calc_overflow:
    2000           0 :         GDKerror("22003!overflow in calculation.\n");
    2001             :         res = GDK_FAIL;
    2002         115 : cleanup:
    2003         115 :         bat_iterator_end(&pi);
    2004         115 :         bat_iterator_end(&oi);
    2005         115 :         bat_iterator_end(&bi);
    2006         115 :         bat_iterator_end(&si);
    2007         115 :         bat_iterator_end(&ei);
    2008         115 :         BBPreclaim(st);
    2009         115 :         return res;
    2010           0 : nosupport:
    2011           0 :         GDKerror("42000!type combination (sum(%s)->%s) not supported.\n", ATOMname(tp1), ATOMname(tp2));
    2012             :         res = GDK_FAIL;
    2013           0 :         goto cleanup;
    2014             : }
    2015             : 
    2016             : /* product on integers */
    2017             : #define PROD_NUM(TPE1, TPE2, TPE3, ARG)                                 \
    2018             :         do {                                                            \
    2019             :                 if (!is_##TPE1##_nil(ARG)) {                            \
    2020             :                         if (is_##TPE2##_nil(curval))                    \
    2021             :                                 curval = (TPE2) ARG;                    \
    2022             :                         else                                            \
    2023             :                                 MUL4_WITH_CHECK(ARG, curval, TPE2, curval, GDK_##TPE2##_max, TPE3, goto calc_overflow); \
    2024             :                 }                                                       \
    2025             :         } while(0)
    2026             : 
    2027             : #define ANALYTICAL_PROD_CALC_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, TPE3) \
    2028             :         do {                                                            \
    2029             :                 TPE2 curval = TPE2##_nil;                               \
    2030             :                 for (; k < i;) {                                     \
    2031             :                         j = k;                                          \
    2032             :                         do {                                            \
    2033             :                                 PROD_NUM(TPE1, TPE2, TPE3, bp[k]);      \
    2034             :                                 k++;                                    \
    2035             :                         } while (k < i && !op[k]);                   \
    2036             :                         for (; j < k; j++)                           \
    2037             :                                 rb[j] = curval;                         \
    2038             :                         has_nils |= is_##TPE2##_nil(curval);            \
    2039             :                 }                                                       \
    2040             :         } while (0)
    2041             : 
    2042             : #define ANALYTICAL_PROD_CALC_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, TPE3) \
    2043             :         do {                                                            \
    2044             :                 TPE2 curval = TPE2##_nil;                               \
    2045             :                 l = i - 1;                                              \
    2046             :                 for (j = l; ; j--) {                                    \
    2047             :                         PROD_NUM(TPE1, TPE2, TPE3, bp[j]);              \
    2048             :                         if (op[j] || j == k) {                          \
    2049             :                                 for (; ; l--) {                         \
    2050             :                                         rb[l] = curval;                 \
    2051             :                                         if (l == j)                     \
    2052             :                                                 break;                  \
    2053             :                                 }                                       \
    2054             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    2055             :                                 if (j == k)                             \
    2056             :                                         break;                          \
    2057             :                                 l = j - 1;                              \
    2058             :                         }                                               \
    2059             :                 }                                                       \
    2060             :                 k = i;                                                  \
    2061             :         } while (0)
    2062             : 
    2063             : #define ANALYTICAL_PROD_CALC_NUM_ALL_ROWS(TPE1, TPE2, TPE3)     \
    2064             :         do {                                                    \
    2065             :                 TPE2 curval = TPE2##_nil;                       \
    2066             :                 for (; j < i; j++) {                         \
    2067             :                         TPE1 v = bp[j];                         \
    2068             :                         PROD_NUM(TPE1, TPE2, TPE3, v);          \
    2069             :                 }                                               \
    2070             :                 for (; k < i; k++)                           \
    2071             :                         rb[k] = curval;                         \
    2072             :                 has_nils |= is_##TPE2##_nil(curval);            \
    2073             :         } while (0)
    2074             : 
    2075             : #define ANALYTICAL_PROD_CALC_NUM_CURRENT_ROW(TPE1, TPE2, TPE3)  \
    2076             :         do {                                                    \
    2077             :                 for (; k < i; k++) {                         \
    2078             :                         TPE1 v = bp[k];                         \
    2079             :                         if (is_##TPE1##_nil(v)) {               \
    2080             :                                 rb[k] = TPE2##_nil;             \
    2081             :                                 has_nils = true;                \
    2082             :                         } else  {                               \
    2083             :                                 rb[k] = (TPE2) v;               \
    2084             :                         }                                       \
    2085             :                 }                                               \
    2086             :         } while (0)
    2087             : 
    2088             : #define INIT_AGGREGATE_PROD(NOTHING1, TPE2, NOTHING2)   \
    2089             :         do {                                            \
    2090             :                 computed = TPE2##_nil;                  \
    2091             :         } while (0)
    2092             : #define COMPUTE_LEVEL0_PROD(X, TPE1, TPE2, NOTHING)                     \
    2093             :         do {                                                            \
    2094             :                 TPE1 v = bp[j + X];                                     \
    2095             :                 computed = is_##TPE1##_nil(v) ? TPE2##_nil : (TPE2) v;  \
    2096             :         } while (0)
    2097             : #define COMPUTE_LEVELN_PROD_NUM(VAL, NOTHING, TPE2, TPE3)               \
    2098             :         do {                                                            \
    2099             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    2100             :                         if (is_##TPE2##_nil(computed))                  \
    2101             :                                 computed = VAL;                         \
    2102             :                         else                                            \
    2103             :                                 MUL4_WITH_CHECK(VAL, computed, TPE2, computed, GDK_##TPE2##_max, TPE3, goto calc_overflow); \
    2104             :                 }                                                       \
    2105             :         } while (0)
    2106             : #define FINALIZE_AGGREGATE_PROD(NOTHING1, TPE2, NOTHING2)       \
    2107             :         do {                                                    \
    2108             :                 rb[k] = computed;                               \
    2109             :                 has_nils |= is_##TPE2##_nil(computed);          \
    2110             :         } while (0)
    2111             : #define ANALYTICAL_PROD_CALC_NUM_OTHERS(TPE1, TPE2, TPE3)               \
    2112             :         do {                                                            \
    2113             :                 oid ncount = i - k;                                     \
    2114             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2115             :                         goto cleanup;                                   \
    2116             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_NUM, TPE1, TPE2, TPE3); \
    2117             :                 for (; k < i; k++)                                   \
    2118             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_NUM, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, TPE3); \
    2119             :                 j = k;                                                  \
    2120             :         } while (0)
    2121             : 
    2122             : /* product on integers while checking for overflows on the output  */
    2123             : #define PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, ARG)                       \
    2124             :         do {                                                            \
    2125             :                 if (!is_##TPE1##_nil(ARG)) {                            \
    2126             :                         if (is_##TPE2##_nil(curval))                    \
    2127             :                                 curval = (TPE2) ARG;                    \
    2128             :                         else                                            \
    2129             :                                 REAL_IMP(ARG, curval, curval, GDK_##TPE2##_max, goto calc_overflow); \
    2130             :                 }                                                       \
    2131             :         } while(0)
    2132             : 
    2133             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, REAL_IMP) \
    2134             :         do {                                                            \
    2135             :                 TPE2 curval = TPE2##_nil;                               \
    2136             :                 for (; k < i;) {                                     \
    2137             :                         j = k;                                          \
    2138             :                         do {                                            \
    2139             :                                 PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, bp[k]); \
    2140             :                                 k++;                                    \
    2141             :                         } while (k < i && !op[k]);                   \
    2142             :                         for (; j < k; j++)                           \
    2143             :                                 rb[j] = curval;                         \
    2144             :                         has_nils |= is_##TPE2##_nil(curval);            \
    2145             :                 }                                                       \
    2146             :         } while (0)
    2147             : 
    2148             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, REAL_IMP) \
    2149             :         do {                                                            \
    2150             :                 TPE2 curval = TPE2##_nil;                               \
    2151             :                 l = i - 1;                                              \
    2152             :                 for (j = l; ; j--) {                                    \
    2153             :                         PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, bp[j]);    \
    2154             :                         if (op[j] || j == k) {                          \
    2155             :                                 for (; ; l--) {                         \
    2156             :                                         rb[l] = curval;                 \
    2157             :                                         if (l == j)                     \
    2158             :                                                 break;                  \
    2159             :                                 }                                       \
    2160             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    2161             :                                 if (j == k)                             \
    2162             :                                         break;                          \
    2163             :                                 l = j - 1;                              \
    2164             :                         }                                               \
    2165             :                 }                                                       \
    2166             :                 k = i;                                                  \
    2167             :         } while (0)
    2168             : 
    2169             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_ALL_ROWS(TPE1, TPE2, REAL_IMP)   \
    2170             :         do {                                                            \
    2171             :                 TPE2 curval = TPE2##_nil;                               \
    2172             :                 for (; j < i; j++) {                                 \
    2173             :                         TPE1 v = bp[j];                                 \
    2174             :                         PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, v);        \
    2175             :                 }                                                       \
    2176             :                 for (; k < i; k++)                                   \
    2177             :                         rb[k] = curval;                                 \
    2178             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    2179             :         } while (0)
    2180             : 
    2181             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_CURRENT_ROW(TPE1, TPE2, REAL_IMP) \
    2182             :         do {                                                            \
    2183             :                 for (; k < i; k++) {                                 \
    2184             :                         TPE1 v = bp[k];                                 \
    2185             :                         if (is_##TPE1##_nil(v)) {                       \
    2186             :                                 rb[k] = TPE2##_nil;                     \
    2187             :                                 has_nils = true;                        \
    2188             :                         } else  {                                       \
    2189             :                                 rb[k] = (TPE2) v;                       \
    2190             :                         }                                               \
    2191             :                 }                                                       \
    2192             :         } while (0)
    2193             : 
    2194             : #define COMPUTE_LEVELN_PROD_NUM_LIMIT(VAL, NOTHING, TPE2, REAL_IMP)     \
    2195             :         do {                                                            \
    2196             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    2197             :                         if (is_##TPE2##_nil(computed))                  \
    2198             :                                 computed = VAL;                         \
    2199             :                         else                                            \
    2200             :                                 REAL_IMP(VAL, computed, computed, GDK_##TPE2##_max, goto calc_overflow); \
    2201             :                 }                                                       \
    2202             :         } while (0)
    2203             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_OTHERS(TPE1, TPE2, REAL_IMP)     \
    2204             :         do {                                                            \
    2205             :                 oid ncount = i - k;                                     \
    2206             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2207             :                         goto cleanup;                                   \
    2208             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_NUM_LIMIT, TPE1, TPE2, REAL_IMP); \
    2209             :                 for (; k < i; k++)                                   \
    2210             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_NUM_LIMIT, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, REAL_IMP); \
    2211             :                 j = k;                                                  \
    2212             :         } while (0)
    2213             : 
    2214             : /* product on floating-points */
    2215             : #define PROD_FP(TPE1, TPE2, ARG)                                        \
    2216             :         do {                                                            \
    2217             :                 if (!is_##TPE1##_nil(ARG)) {                            \
    2218             :                         if (is_##TPE2##_nil(curval)) {                  \
    2219             :                                 curval = (TPE2) ARG;                    \
    2220             :                         } else if (ABSOLUTE(curval) > 1 && GDK_##TPE2##_max / ABSOLUTE(ARG) < ABSOLUTE(curval)) { \
    2221             :                                 if (abort_on_error)                     \
    2222             :                                         goto calc_overflow;             \
    2223             :                                 curval = TPE2##_nil;                    \
    2224             :                                 nils++;                                 \
    2225             :                         } else {                                        \
    2226             :                                 curval *= ARG;                          \
    2227             :                         }                                               \
    2228             :                 }                                                       \
    2229             :         } while(0)
    2230             : 
    2231             : #define ANALYTICAL_PROD_CALC_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, ARG3)    /* ARG3 is ignored here */ \
    2232             :         do {                                                            \
    2233             :                 TPE2 curval = TPE2##_nil;                               \
    2234             :                 for (; k < i;) {                                     \
    2235             :                         j = k;                                          \
    2236             :                         do {                                            \
    2237             :                                 PROD_FP(TPE1, TPE2, bp[k]);             \
    2238             :                                 k++;                                    \
    2239             :                         } while (k < i && !op[k]);                   \
    2240             :                         for (; j < k; j++)                           \
    2241             :                                 rb[j] = curval;                         \
    2242             :                         has_nils |= is_##TPE2##_nil(curval);            \
    2243             :                 }                                                       \
    2244             :         } while (0)
    2245             : 
    2246             : #define ANALYTICAL_PROD_CALC_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, ARG3)    /* ARG3 is ignored here */ \
    2247             :         do {                                                            \
    2248             :                 TPE2 curval = TPE2##_nil;                               \
    2249             :                 l = i - 1;                                              \
    2250             :                 for (j = l; ; j--) {                                    \
    2251             :                         PROD_FP(TPE1, TPE2, bp[j]);                     \
    2252             :                         if (op[j] || j == k) {                          \
    2253             :                                 for (; ; l--) {                         \
    2254             :                                         rb[l] = curval;                 \
    2255             :                                         if (l == j)                     \
    2256             :                                                 break;                  \
    2257             :                                 }                                       \
    2258             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    2259             :                                 if (j == k)                             \
    2260             :                                         break;                          \
    2261             :                                 l = j - 1;                              \
    2262             :                         }                                               \
    2263             :                 }                                                       \
    2264             :                 k = i;                                                  \
    2265             :         } while (0)
    2266             : 
    2267             : #define ANALYTICAL_PROD_CALC_FP_ALL_ROWS(TPE1, TPE2, ARG3)      /* ARG3 is ignored here */ \
    2268             :         do {                                                            \
    2269             :                 TPE2 curval = TPE2##_nil;                               \
    2270             :                 for (; j < i; j++) {                                 \
    2271             :                         TPE1 v = bp[j];                                 \
    2272             :                         PROD_FP(TPE1, TPE2, v);                         \
    2273             :                 }                                                       \
    2274             :                 for (; k < i; k++)                                   \
    2275             :                         rb[k] = curval;                                 \
    2276             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    2277             :         } while (0)
    2278             : 
    2279             : #define ANALYTICAL_PROD_CALC_FP_CURRENT_ROW(TPE1, TPE2, ARG3)   /* ARG3 is ignored here */ \
    2280             :         do {                                                            \
    2281             :                 for (; k < i; k++) {                                 \
    2282             :                         TPE1 v = bp[k];                                 \
    2283             :                         if (is_##TPE1##_nil(v)) {                       \
    2284             :                                 rb[k] = TPE2##_nil;                     \
    2285             :                                 has_nils = true;                        \
    2286             :                         } else  {                                       \
    2287             :                                 rb[k] = (TPE2) v;                       \
    2288             :                         }                                               \
    2289             :                 }                                                       \
    2290             :         } while (0)
    2291             : 
    2292             : #define COMPUTE_LEVELN_PROD_FP(VAL, NOTHING1, TPE2, NOTHING2)           \
    2293             :         do {                                                            \
    2294             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    2295             :                         if (is_##TPE2##_nil(computed)) {                \
    2296             :                                 computed = VAL;                         \
    2297             :                         } else if (ABSOLUTE(computed) > 1 && GDK_##TPE2##_max / ABSOLUTE(VAL) < ABSOLUTE(computed)) { \
    2298             :                                 if (abort_on_error)                     \
    2299             :                                         goto calc_overflow;             \
    2300             :                                 computed = TPE2##_nil;                  \
    2301             :                                 nils++;                                 \
    2302             :                         } else {                                        \
    2303             :                                 computed *= VAL;                        \
    2304             :                         }                                               \
    2305             :                 }                                                       \
    2306             :         } while (0)
    2307             : #define ANALYTICAL_PROD_CALC_FP_OTHERS(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
    2308             :         do {                                                            \
    2309             :                 oid ncount = i - k;                                     \
    2310             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2311             :                         goto cleanup;                                   \
    2312             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_FP, TPE1, TPE2, ARG3); \
    2313             :                 for (; k < i; k++)                                   \
    2314             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_FP, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, ARG3); \
    2315             :                 j = k;                                                  \
    2316             :         } while (0)
    2317             : 
    2318             : #define ANALYTICAL_PROD_CALC_NUM_PARTITIONS(TPE1, TPE2, TPE3_OR_REAL_IMP, IMP) \
    2319             :         do {                                                            \
    2320             :                 TPE1 *restrict bp = (TPE1*)bi.base;                     \
    2321             :                 TPE2 *rb = (TPE2*)Tloc(r, 0);                           \
    2322             :                 if (p) {                                                \
    2323             :                         while (i < cnt) {                            \
    2324             :                                 if (np[i])      {                       \
    2325             : prod##TPE1##TPE2##IMP:                                                  \
    2326             :                                         IMP(TPE1, TPE2, TPE3_OR_REAL_IMP); \
    2327             :                                 }                                       \
    2328             :                                 if (!last)                              \
    2329             :                                         i++;                            \
    2330             :                         }                                               \
    2331             :                 }                                                       \
    2332             :                 if (!last) {                                            \
    2333             :                         last = true;                                    \
    2334             :                         i = cnt;                                        \
    2335             :                         goto prod##TPE1##TPE2##IMP;                     \
    2336             :                 }                                                       \
    2337             :         } while (0)
    2338             : 
    2339             : #ifdef HAVE_HGE
    2340             : #define ANALYTICAL_PROD_LIMIT(IMP)                                      \
    2341             :         case TYPE_lng:{                                                 \
    2342             :                 switch (tp1) {                                          \
    2343             :                 case TYPE_bte:                                          \
    2344             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2345             :                         break;                                          \
    2346             :                 case TYPE_sht:                                          \
    2347             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2348             :                         break;                                          \
    2349             :                 case TYPE_int:                                          \
    2350             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2351             :                         break;                                          \
    2352             :                 case TYPE_lng:                                          \
    2353             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2354             :                         break;                                          \
    2355             :                 default:                                                \
    2356             :                         goto nosupport;                                 \
    2357             :                 }                                                       \
    2358             :                 break;                                                  \
    2359             :         }                                                               \
    2360             :         case TYPE_hge:{                                                 \
    2361             :                 switch (tp1) {                                          \
    2362             :                 case TYPE_bte:                                          \
    2363             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2364             :                         break;                                          \
    2365             :                 case TYPE_sht:                                          \
    2366             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2367             :                         break;                                          \
    2368             :                 case TYPE_int:                                          \
    2369             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2370             :                         break;                                          \
    2371             :                 case TYPE_lng:                                          \
    2372             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2373             :                         break;                                          \
    2374             :                 case TYPE_hge:                                          \
    2375             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(hge, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2376             :                         break;                                          \
    2377             :                 default:                                                \
    2378             :                         goto nosupport;                                 \
    2379             :                 }                                                       \
    2380             :                 break;                                                  \
    2381             :         }
    2382             : #else
    2383             : #define ANALYTICAL_PROD_LIMIT(IMP)                                      \
    2384             :         case TYPE_lng:{                                                 \
    2385             :                 switch (tp1) {                                          \
    2386             :                 case TYPE_bte:                                          \
    2387             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2388             :                         break;                                          \
    2389             :                 case TYPE_sht:                                          \
    2390             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2391             :                         break;                                          \
    2392             :                 case TYPE_int:                                          \
    2393             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2394             :                         break;                                          \
    2395             :                 case TYPE_lng:                                          \
    2396             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2397             :                         break;                                          \
    2398             :                 default:                                                \
    2399             :                         goto nosupport;                                 \
    2400             :                 }                                                       \
    2401             :                 break;                                                  \
    2402             :         }
    2403             : #endif
    2404             : 
    2405             : #define ANALYTICAL_PROD_BRANCHES(IMP)                                   \
    2406             :         do {                                                            \
    2407             :                 switch (tp2) {                                          \
    2408             :                 case TYPE_bte:{                                         \
    2409             :                         switch (tp1) {                                  \
    2410             :                         case TYPE_bte:                                  \
    2411             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, bte, sht, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2412             :                                 break;                                  \
    2413             :                         default:                                        \
    2414             :                                 goto nosupport;                         \
    2415             :                         }                                               \
    2416             :                         break;                                          \
    2417             :                 }                                                       \
    2418             :                 case TYPE_sht:{                                         \
    2419             :                         switch (tp1) {                                  \
    2420             :                         case TYPE_bte:                                  \
    2421             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, sht, int, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2422             :                                 break;                                  \
    2423             :                         case TYPE_sht:                                  \
    2424             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, sht, int, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2425             :                                 break;                                  \
    2426             :                         default:                                        \
    2427             :                                 goto nosupport;                         \
    2428             :                         }                                               \
    2429             :                         break;                                          \
    2430             :                 }                                                       \
    2431             :                 case TYPE_int:{                                         \
    2432             :                         switch (tp1) {                                  \
    2433             :                         case TYPE_bte:                                  \
    2434             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2435             :                                 break;                                  \
    2436             :                         case TYPE_sht:                                  \
    2437             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2438             :                                 break;                                  \
    2439             :                         case TYPE_int:                                  \
    2440             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2441             :                                 break;                                  \
    2442             :                         default:                                        \
    2443             :                                 goto nosupport;                         \
    2444             :                         }                                               \
    2445             :                         break;                                          \
    2446             :                 }                                                       \
    2447             :                 ANALYTICAL_PROD_LIMIT(IMP)                              \
    2448             :                 case TYPE_flt:{                                         \
    2449             :                         switch (tp1) {                                  \
    2450             :                         case TYPE_flt:                                  \
    2451             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(flt, flt, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
    2452             :                                 break;                                  \
    2453             :                         default:                                        \
    2454             :                                 goto nosupport;                         \
    2455             :                         }                                               \
    2456             :                         break;                                          \
    2457             :                 }                                                       \
    2458             :                 case TYPE_dbl:{                                         \
    2459             :                         switch (tp1) {                                  \
    2460             :                         case TYPE_flt:                                  \
    2461             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(flt, dbl, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
    2462             :                                 break;                                  \
    2463             :                         case TYPE_dbl:                                  \
    2464             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(dbl, dbl, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
    2465             :                                 break;                                  \
    2466             :                         default:                                        \
    2467             :                                 goto nosupport;                         \
    2468             :                         }                                               \
    2469             :                         break;                                          \
    2470             :                 }                                                       \
    2471             :                 default:                                                \
    2472             :                         goto nosupport;                                 \
    2473             :                 }                                                       \
    2474             :         } while (0)
    2475             : 
    2476             : gdk_return
    2477          31 : GDKanalyticalprod(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tp1, int tp2, int frame_type)
    2478             : {
    2479          31 :         BATiter pi = bat_iterator(p);
    2480          31 :         BATiter oi = bat_iterator(o);
    2481          31 :         BATiter bi = bat_iterator(b);
    2482          31 :         BATiter si = bat_iterator(s);
    2483          31 :         BATiter ei = bat_iterator(e);
    2484             :         bool has_nils = false, last = false;
    2485          31 :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    2486          31 :                 *levels_offset = NULL, nlevels = 0;
    2487          31 :         bit *np = pi.base, *op = oi.base;
    2488             :         int abort_on_error = 1;
    2489             :         BUN nils = 0;
    2490          31 :         void *segment_tree = NULL;
    2491             :         gdk_return res = GDK_SUCCEED;
    2492             :         BAT *st = NULL;
    2493             : 
    2494          31 :         if (cnt > 0) {
    2495          31 :                 switch (frame_type) {
    2496          12 :                 case 3: /* unbounded until current row */       {
    2497         403 :                         ANALYTICAL_PROD_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    2498             :                 } break;
    2499           0 :                 case 4: /* current row until unbounded */       {
    2500           0 :                         ANALYTICAL_PROD_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    2501             :                 } break;
    2502           7 :                 case 5: /* all rows */  {
    2503         191 :                         ANALYTICAL_PROD_BRANCHES(ALL_ROWS);
    2504             :                 } break;
    2505           0 :                 case 6: /* current row */ {
    2506           0 :                         ANALYTICAL_PROD_BRANCHES(CURRENT_ROW);
    2507             :                 } break;
    2508          12 :                 default: {
    2509          12 :                         if (!(st = GDKinitialize_segment_tree())) {
    2510             :                                 res = GDK_FAIL;
    2511           0 :                                 goto cleanup;
    2512             :                         }
    2513         956 :                         ANALYTICAL_PROD_BRANCHES(OTHERS);
    2514             :                 }
    2515             :                 }
    2516             :         }
    2517             : 
    2518          31 :         BATsetcount(r, cnt);
    2519          31 :         r->tnonil = !has_nils;
    2520          31 :         r->tnil = has_nils;
    2521          31 :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
    2522           0 : calc_overflow:
    2523           0 :         GDKerror("22003!overflow in calculation.\n");
    2524             :         res = GDK_FAIL;
    2525          31 : cleanup:
    2526          31 :         bat_iterator_end(&pi);
    2527          31 :         bat_iterator_end(&oi);
    2528          31 :         bat_iterator_end(&bi);
    2529          31 :         bat_iterator_end(&si);
    2530          31 :         bat_iterator_end(&ei);
    2531          31 :         BBPreclaim(st);
    2532          31 :         return res;
    2533           0 : nosupport:
    2534           0 :         GDKerror("42000!type combination (prod(%s)->%s) not supported.\n", ATOMname(tp1), ATOMname(tp2));
    2535             :         res = GDK_FAIL;
    2536           0 :         goto cleanup;
    2537             : }
    2538             : 
    2539             : #ifdef HAVE_HGE
    2540             : #define LNG_HGE         hge
    2541             : #define GDK_LNG_HGE_max GDK_hge_max
    2542             : #define LNG_HGE_nil     hge_nil
    2543             : #else
    2544             : #define LNG_HGE         lng
    2545             : #define GDK_LNG_HGE_max GDK_lng_max
    2546             : #define LNG_HGE_nil     lng_nil
    2547             : #endif
    2548             : 
    2549             : /* average on integers */
    2550             : #define ANALYTICAL_AVERAGE_CALC_NUM_STEP1(TPE, IMP, ARG)                \
    2551             :         if (!is_##TPE##_nil(ARG)) {                                     \
    2552             :                 ADD_WITH_CHECK(ARG, sum, LNG_HGE, sum, GDK_LNG_HGE_max, goto avg_overflow##TPE##IMP); \
    2553             :                 /* count only when no overflow occurs */                \
    2554             :                 n++;                                                    \
    2555             :         }
    2556             : 
    2557             : #define ANALYTICAL_AVERAGE_CALC_NUM_STEP2(TPE, IMP)             \
    2558             :                         if (0) {                                \
    2559             : avg_overflow##TPE##IMP:                                         \
    2560             :                                 assert(n > 0);                       \
    2561             :                                 if (sum >= 0) {                      \
    2562             :                                         a = (TPE) (sum / n);    \
    2563             :                                         rr = (lng) (sum % n);   \
    2564             :                                 } else {                        \
    2565             :                                         sum = -sum;             \
    2566             :                                         a = - (TPE) (sum / n);  \
    2567             :                                         rr = (lng) (sum % n);   \
    2568             :                                         if (r) {                \
    2569             :                                                 a--;            \
    2570             :                                                 rr = n - rr;    \
    2571             :                                         }                       \
    2572             :                                 }
    2573             : 
    2574             : #define ANALYTICAL_AVG_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE, IMP)     \
    2575             :         do {                                                            \
    2576             :                 TPE a = 0;                                              \
    2577             :                 dbl curval = dbl_nil;                                   \
    2578             :                 for (; k < i;) {                                     \
    2579             :                         j = k;                                          \
    2580             :                         do {                                            \
    2581             :                                 ANALYTICAL_AVERAGE_CALC_NUM_STEP1(TPE, IMP, bp[k]) \
    2582             :                                 ANALYTICAL_AVERAGE_CALC_NUM_STEP2(TPE, IMP) \
    2583             :                                         while (k < i && !op[k]) {    \
    2584             :                                                 TPE v = bp[k++];        \
    2585             :                                                 if (is_##TPE##_nil(v))  \
    2586             :                                                         continue;       \
    2587             :                                                 AVERAGE_ITER(TPE, v, a, rr, n); \
    2588             :                                         }                               \
    2589             :                                         curval = a + (dbl) rr / n;      \
    2590             :                                         goto calc_done##TPE##IMP;       \
    2591             :                                 }                                       \
    2592             :                                 k++;                                    \
    2593             :                         } while (k < i && !op[k]);                   \
    2594             :                         curval = n > 0 ? (dbl) sum / n : dbl_nil;    \
    2595             : calc_done##TPE##IMP:                                                    \
    2596             :                         for (; j < k; j++)                           \
    2597             :                                 rb[j] = curval;                         \
    2598             :                         has_nils |= (n == 0);                           \
    2599             :                 }                                                       \
    2600             :                 n = 0;                                                  \
    2601             :                 sum = 0;                                                \
    2602             :         } while (0)
    2603             : 
    2604             : #define ANALYTICAL_AVG_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE, IMP)     \
    2605             :         do {                                                            \
    2606             :                 TPE a = 0;                                              \
    2607             :                 dbl curval = dbl_nil;                                   \
    2608             :                 l = i - 1;                                              \
    2609             :                 for (j = l; ; j--) {                                    \
    2610             :                         ANALYTICAL_AVERAGE_CALC_NUM_STEP1(TPE, IMP, bp[j]) \
    2611             :                         ANALYTICAL_AVERAGE_CALC_NUM_STEP2(TPE, IMP)     \
    2612             :                                 while (!(op[j] || j == k)) {            \
    2613             :                                         TPE v = bp[j--];                \
    2614             :                                         if (is_##TPE##_nil(v))          \
    2615             :                                                 continue;               \
    2616             :                                         AVERAGE_ITER(TPE, v, a, rr, n); \
    2617             :                                 }                                       \
    2618             :                                 curval = a + (dbl) rr / n;              \
    2619             :                                 goto calc_done##TPE##IMP;               \
    2620             :                         }                                               \
    2621             :                         if (op[j] || j == k) {                          \
    2622             :                                 curval = n > 0 ? (dbl) sum / n : dbl_nil; \
    2623             : calc_done##TPE##IMP:                                                    \
    2624             :                                 for (; ; l--) {                         \
    2625             :                                         rb[l] = curval;                 \
    2626             :                                         if (l == j)                     \
    2627             :                                                 break;                  \
    2628             :                                 }                                       \
    2629             :                                 has_nils |= (n == 0);                   \
    2630             :                                 if (j == k)                             \
    2631             :                                         break;                          \
    2632             :                                 l = j - 1;                              \
    2633             :                         }                                               \
    2634             :                 }                                                       \
    2635             :                 n = 0;                                                  \
    2636             :                 sum = 0;                                                \
    2637             :                 k = i;                                                  \
    2638             :         } while (0)
    2639             : 
    2640             : #define ANALYTICAL_AVG_IMP_NUM_ALL_ROWS(TPE, IMP)                       \
    2641             :         do {                                                            \
    2642             :                 TPE a = 0;                                              \
    2643             :                 for (; j < i; j++) {                                 \
    2644             :                         TPE v = bp[j];                                  \
    2645             :                         ANALYTICAL_AVERAGE_CALC_NUM_STEP1(TPE, IMP, v)  \
    2646             :                         ANALYTICAL_AVERAGE_CALC_NUM_STEP2(TPE, IMP)     \
    2647             :                                 for (; j < i; j++) {                 \
    2648             :                                         v = bp[j];                      \
    2649             :                                         if (is_##TPE##_nil(v))          \
    2650             :                                                 continue;               \
    2651             :                                         AVERAGE_ITER(TPE, v, a, rr, n); \
    2652             :                                 }                                       \
    2653             :                                 curval = a + (dbl) rr / n;              \
    2654             :                                 goto calc_done##TPE##IMP;               \
    2655             :                         }                                               \
    2656             :                 }                                                       \
    2657             :                 curval = n > 0 ? (dbl) sum / n : dbl_nil;            \
    2658             : calc_done##TPE##IMP:                                                    \
    2659             :                 for (; k < i; k++)                                   \
    2660             :                         rb[k] = curval;                                 \
    2661             :                 has_nils |= (n == 0);                                   \
    2662             :                 n = 0;                                                  \
    2663             :                 sum = 0;                                                \
    2664             :         } while (0)
    2665             : 
    2666             : #define ANALYTICAL_AVG_IMP_NUM_CURRENT_ROW(TPE, IMP)    \
    2667             :         do {                                            \
    2668             :                 for (; k < i; k++) {                 \
    2669             :                         TPE v = bp[k];                  \
    2670             :                         if (is_##TPE##_nil(v)) {        \
    2671             :                                 rb[k] = dbl_nil;        \
    2672             :                                 has_nils = true;        \
    2673             :                         } else  {                       \
    2674             :                                 rb[k] = (dbl) v;        \
    2675             :                         }                               \
    2676             :                 }                                       \
    2677             :         } while (0)
    2678             : 
    2679             : #define avg_num_deltas(TPE) typedef struct avg_num_deltas##TPE { TPE a; lng n; lng rr;} avg_num_deltas##TPE;
    2680             : avg_num_deltas(bte)
    2681             : avg_num_deltas(sht)
    2682             : avg_num_deltas(int)
    2683             : avg_num_deltas(lng)
    2684             : 
    2685             : #define INIT_AGGREGATE_AVG_NUM(TPE, NOTHING1, NOTHING2) \
    2686             :         do {                                            \
    2687             :                 computed = (avg_num_deltas##TPE) {0};   \
    2688             :         } while (0)
    2689             : #define COMPUTE_LEVEL0_AVG_NUM(X, TPE, NOTHING1, NOTHING2)              \
    2690             :         do {                                                            \
    2691             :                 TPE v = bp[j + X];                                      \
    2692             :                 computed = is_##TPE##_nil(v) ? (avg_num_deltas##TPE){0} : (avg_num_deltas##TPE) {.a = v, .n = 1}; \
    2693             :         } while (0)
    2694             : #define COMPUTE_LEVELN_AVG_NUM(VAL, TPE, NOTHING1, NOTHING2)            \
    2695             :         do {                                                            \
    2696             :                 if (VAL.n)                                              \
    2697             :                         AVERAGE_ITER(TPE, VAL.a, computed.a, computed.rr, computed.n); \
    2698             :         } while (0)
    2699             : #define FINALIZE_AGGREGATE_AVG_NUM(TPE, NOTHING1, NOTHING2)             \
    2700             :         do {                                                            \
    2701             :                 if (computed.n == 0) {                                  \
    2702             :                         rb[k] = dbl_nil;                                \
    2703             :                         has_nils = true;                                \
    2704             :                 } else {                                                \
    2705             :                         rb[k] = computed.a + (dbl) computed.rr / computed.n; \
    2706             :                 }                                                       \
    2707             :         } while (0)
    2708             : #define ANALYTICAL_AVG_IMP_NUM_OTHERS(TPE, IMP)                         \
    2709             :         do {                                                            \
    2710             :                 oid ncount = i - k;                                     \
    2711             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(avg_num_deltas##TPE), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2712             :                         goto cleanup;                                   \
    2713             :                 populate_segment_tree(avg_num_deltas##TPE, ncount, INIT_AGGREGATE_AVG_NUM, COMPUTE_LEVEL0_AVG_NUM, COMPUTE_LEVELN_AVG_NUM, TPE, NOTHING, NOTHING); \
    2714             :                 for (; k < i; k++)                                   \
    2715             :                         compute_on_segment_tree(avg_num_deltas##TPE, start[k] - j, end[k] - j, INIT_AGGREGATE_AVG_NUM, COMPUTE_LEVELN_AVG_NUM, FINALIZE_AGGREGATE_AVG_NUM, TPE, NOTHING, NOTHING); \
    2716             :                 j = k;                                                  \
    2717             :         } while (0)
    2718             : 
    2719             : /* average on floating-points */
    2720             : #define ANALYTICAL_AVG_IMP_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE, IMP)      \
    2721             :         do {                                                            \
    2722             :                 TPE a = 0;                                              \
    2723             :                 dbl curval = dbl_nil;                                   \
    2724             :                 for (; k < i;) {                                     \
    2725             :                         j = k;                                          \
    2726             :                         do {                                            \
    2727             :                                 if (!is_##TPE##_nil(bp[k]))             \
    2728             :                                         AVERAGE_ITER_FLOAT(TPE, bp[k], a, n); \
    2729             :                                 k++;                                    \
    2730             :                         } while (k < i && !op[k]);                   \
    2731             :                         if (n > 0)                                   \
    2732             :                                 curval = a;                             \
    2733             :                         else                                            \
    2734             :                                 has_nils = true;                        \
    2735             :                         for (; j < k; j++)                           \
    2736             :                                 rb[j] = curval;                         \
    2737             :                 }                                                       \
    2738             :                 n = 0;                                                  \
    2739             :         } while (0)
    2740             : 
    2741             : #define ANALYTICAL_AVG_IMP_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE, IMP)      \
    2742             :         do {                                                            \
    2743             :                 TPE a = 0;                                              \
    2744             :                 dbl curval = dbl_nil;                                   \
    2745             :                 l = i - 1;                                              \
    2746             :                 for (j = l; ; j--) {                                    \
    2747             :                         if (!is_##TPE##_nil(bp[j]))                     \
    2748             :                                 AVERAGE_ITER_FLOAT(TPE, bp[j], a, n);   \
    2749             :                         if (op[j] || j == k) {                          \
    2750             :                                 for (; ; l--) {                         \
    2751             :                                         rb[l] = curval;                 \
    2752             :                                         if (l == j)                     \
    2753             :                                                 break;                  \
    2754             :                                 }                                       \
    2755             :                                 has_nils |= is_##TPE##_nil(curval);     \
    2756             :                                 if (j == k)                             \
    2757             :                                         break;                          \
    2758             :                                 l = j - 1;                              \
    2759             :                         }                                               \
    2760             :                 }                                                       \
    2761             :                 n = 0;                                                  \
    2762             :                 k = i;                                                  \
    2763             :         } while (0)
    2764             : 
    2765             : #define ANALYTICAL_AVG_IMP_FP_ALL_ROWS(TPE, IMP)                        \
    2766             :         do {                                                            \
    2767             :                 TPE a = 0;                                              \
    2768             :                 dbl curval = dbl_nil;                                   \
    2769             :                 for (; j < i; j++) {                                 \
    2770             :                         TPE v = bp[j];                                  \
    2771             :                         if (!is_##TPE##_nil(v))                         \
    2772             :                                 AVERAGE_ITER_FLOAT(TPE, v, a, n);       \
    2773             :                 }                                                       \
    2774             :                 if (n > 0)                                           \
    2775             :                         curval = a;                                     \
    2776             :                 else                                                    \
    2777             :                         has_nils = true;                                \
    2778             :                 for (; k < i; k++)                                   \
    2779             :                         rb[k] = curval;                                 \
    2780             :                 n = 0;                                                  \
    2781             :         } while (0)
    2782             : 
    2783             : #define ANALYTICAL_AVG_IMP_FP_CURRENT_ROW(TPE, IMP)      ANALYTICAL_AVG_IMP_NUM_CURRENT_ROW(TPE, IMP)
    2784             : 
    2785             : #define avg_fp_deltas(TPE) typedef struct avg_fp_deltas_##TPE {TPE a; lng n;} avg_fp_deltas_##TPE;
    2786             : avg_fp_deltas(flt)
    2787             : avg_fp_deltas(dbl)
    2788             : 
    2789             : #define INIT_AGGREGATE_AVG_FP(TPE, NOTHING1, NOTHING2)  \
    2790             :         do {                                            \
    2791             :                 computed = (avg_fp_deltas_##TPE) {0};   \
    2792             :         } while (0)
    2793             : #define COMPUTE_LEVEL0_AVG_FP(X, TPE, NOTHING1, NOTHING2)               \
    2794             :         do {                                                            \
    2795             :                 TPE v = bp[j + X];                                      \
    2796             :                 computed = is_##TPE##_nil(v) ? (avg_fp_deltas_##TPE) {0} : (avg_fp_deltas_##TPE) {.n = 1, .a = v}; \
    2797             :         } while (0)
    2798             : #define COMPUTE_LEVELN_AVG_FP(VAL, TPE, NOTHING1, NOTHING2)             \
    2799             :         do {                                                            \
    2800             :                 if (VAL.n)                                              \
    2801             :                         AVERAGE_ITER_FLOAT(TPE, VAL.a, computed.a, computed.n); \
    2802             :         } while (0)
    2803             : #define FINALIZE_AGGREGATE_AVG_FP(TPE, NOTHING1, NOTHING2)      \
    2804             :         do {                                                    \
    2805             :                 if (computed.n == 0) {                          \
    2806             :                         rb[k] = dbl_nil;                        \
    2807             :                         has_nils = true;                        \
    2808             :                 } else {                                        \
    2809             :                         rb[k] = computed.a;                     \
    2810             :                 }                                               \
    2811             :         } while (0)
    2812             : #define ANALYTICAL_AVG_IMP_FP_OTHERS(TPE, IMP)                          \
    2813             :         do {                                                            \
    2814             :                 oid ncount = i - k;                                     \
    2815             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(avg_fp_deltas_##TPE), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2816             :                         goto cleanup;                                   \
    2817             :                 populate_segment_tree(avg_fp_deltas_##TPE, ncount, INIT_AGGREGATE_AVG_FP, COMPUTE_LEVEL0_AVG_FP, COMPUTE_LEVELN_AVG_FP, TPE, NOTHING, NOTHING); \
    2818             :                 for (; k < i; k++)                                   \
    2819             :                         compute_on_segment_tree(avg_fp_deltas_##TPE, start[k] - j, end[k] - j, INIT_AGGREGATE_AVG_FP, COMPUTE_LEVELN_AVG_FP, FINALIZE_AGGREGATE_AVG_FP, TPE, NOTHING, NOTHING); \
    2820             :                 j = k;                                                  \
    2821             :         } while (0)
    2822             : 
    2823             : #define ANALYTICAL_AVG_PARTITIONS(TPE, IMP, REAL_IMP)           \
    2824             :         do {                                                    \
    2825             :                 TPE *restrict bp = (TPE*)bi.base;               \
    2826             :                 if (p) {                                        \
    2827             :                         while (i < cnt) {                    \
    2828             :                                 if (np[i])      {               \
    2829             : avg##TPE##IMP:                                                  \
    2830             :                                         REAL_IMP(TPE, IMP);     \
    2831             :                                 }                               \
    2832             :                                 if (!last)                      \
    2833             :                                         i++;                    \
    2834             :                         }                                       \
    2835             :                 }                                               \
    2836             :                 if (!last) {                                    \
    2837             :                         last = true;                            \
    2838             :                         i = cnt;                                \
    2839             :                         goto avg##TPE##IMP;                     \
    2840             :                 }                                               \
    2841             :         } while (0)
    2842             : 
    2843             : #ifdef HAVE_HGE
    2844             : avg_num_deltas(hge)
    2845             : #define ANALYTICAL_AVG_LIMIT(IMP)                                       \
    2846             :         case TYPE_hge:                                                  \
    2847             :                 ANALYTICAL_AVG_PARTITIONS(hge, IMP, ANALYTICAL_AVG_IMP_NUM_##IMP); \
    2848             :                 break;
    2849             : #else
    2850             : #define ANALYTICAL_AVG_LIMIT(IMP)
    2851             : #endif
    2852             : 
    2853             : #define ANALYTICAL_AVG_BRANCHES(IMP)                                    \
    2854             :         do {                                                            \
    2855             :                 switch (tpe) {                                          \
    2856             :                 case TYPE_bte:                                          \
    2857             :                         ANALYTICAL_AVG_PARTITIONS(bte, IMP, ANALYTICAL_AVG_IMP_NUM_##IMP); \
    2858             :                         break;                                          \
    2859             :                 case TYPE_sht:                                          \
    2860             :                         ANALYTICAL_AVG_PARTITIONS(sht, IMP, ANALYTICAL_AVG_IMP_NUM_##IMP); \
    2861             :                         break;                                          \
    2862             :                 case TYPE_int:                                          \
    2863             :                         ANALYTICAL_AVG_PARTITIONS(int, IMP, ANALYTICAL_AVG_IMP_NUM_##IMP); \
    2864             :                         break;                                          \
    2865             :                 case TYPE_lng:                                          \
    2866             :                         ANALYTICAL_AVG_PARTITIONS(lng, IMP, ANALYTICAL_AVG_IMP_NUM_##IMP); \
    2867             :                         break;                                          \
    2868             :                 ANALYTICAL_AVG_LIMIT(IMP)                               \
    2869             :                 case TYPE_flt:                                          \
    2870             :                         ANALYTICAL_AVG_PARTITIONS(flt, IMP, ANALYTICAL_AVG_IMP_FP_##IMP); \
    2871             :                         break;                                          \
    2872             :                 case TYPE_dbl:                                          \
    2873             :                         ANALYTICAL_AVG_PARTITIONS(dbl, IMP, ANALYTICAL_AVG_IMP_FP_##IMP); \
    2874             :                         break;                                          \
    2875             :                 default:                                                \
    2876             :                         goto nosupport;                                 \
    2877             :                 }                                                       \
    2878             :         } while (0)
    2879             : 
    2880             : gdk_return
    2881          70 : GDKanalyticalavg(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tpe, int frame_type)
    2882             : {
    2883          70 :         BATiter pi = bat_iterator(p);
    2884          70 :         BATiter oi = bat_iterator(o);
    2885          70 :         BATiter bi = bat_iterator(b);
    2886          70 :         BATiter si = bat_iterator(s);
    2887          70 :         BATiter ei = bat_iterator(e);
    2888             :         bool has_nils = false, last = false;
    2889          70 :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    2890          70 :                 *levels_offset = NULL, nlevels = 0;
    2891             :         lng n = 0, rr = 0;
    2892          70 :         dbl *rb = (dbl *) Tloc(r, 0), curval = dbl_nil;
    2893          70 :         bit *np = pi.base, *op = oi.base;
    2894             :         bool abort_on_error = true;
    2895             :         BUN nils = 0;
    2896          70 :         void *segment_tree = NULL;
    2897             :         gdk_return res = GDK_SUCCEED;
    2898             : #ifdef HAVE_HGE
    2899             :         hge sum = 0;
    2900             : #else
    2901             :         lng sum = 0;
    2902             : #endif
    2903             :         BAT *st = NULL;
    2904             : 
    2905          70 :         if (cnt > 0) {
    2906          70 :                 switch (frame_type) {
    2907          24 :                 case 3: /* unbounded until current row */       {
    2908         579 :                         ANALYTICAL_AVG_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    2909             :                 } break;
    2910           1 :                 case 4: /* current row until unbounded */       {
    2911          11 :                         ANALYTICAL_AVG_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    2912             :                 } break;
    2913          16 :                 case 5: /* all rows */  {
    2914         337 :                         ANALYTICAL_AVG_BRANCHES(ALL_ROWS);
    2915             :                 } break;
    2916           0 :                 case 6: /* current row */ {
    2917           0 :                         ANALYTICAL_AVG_BRANCHES(CURRENT_ROW);
    2918             :                 } break;
    2919          29 :                 default: {
    2920          29 :                         if (!(st = GDKinitialize_segment_tree())) {
    2921             :                                 res = GDK_FAIL;
    2922           0 :                                 goto cleanup;
    2923             :                         }
    2924        2083 :                         ANALYTICAL_AVG_BRANCHES(OTHERS);
    2925             :                 }
    2926             :                 }
    2927             :         }
    2928             : 
    2929          70 :         BATsetcount(r, cnt);
    2930          70 :         r->tnonil = !has_nils;
    2931          70 :         r->tnil = has_nils;
    2932          70 : cleanup:
    2933          70 :         bat_iterator_end(&pi);
    2934          70 :         bat_iterator_end(&oi);
    2935          70 :         bat_iterator_end(&bi);
    2936          70 :         bat_iterator_end(&si);
    2937          70 :         bat_iterator_end(&ei);
    2938          70 :         BBPreclaim(st);
    2939          70 :         return res;
    2940           0 : nosupport:
    2941           0 :         GDKerror("42000!average of type %s to dbl unsupported.\n", ATOMname(tpe));
    2942             :         res = GDK_FAIL;
    2943           0 :         goto cleanup;
    2944             : }
    2945             : 
    2946             : #ifdef TRUNCATE_NUMBERS
    2947             : #define ANALYTICAL_AVERAGE_INT_CALC_FINALIZE(avg, rem, ncnt)    \
    2948             :         do {                                                    \
    2949             :                 if (rem > 0 && avg < 0)                           \
    2950             :                         avg++;                                  \
    2951             :         } while(0)
    2952             : #else
    2953             : #define ANALYTICAL_AVERAGE_INT_CALC_FINALIZE(avg, rem, ncnt)    \
    2954             :         do {                                                    \
    2955             :                 if (rem > 0) {                                       \
    2956             :                         if (avg < 0) {                               \
    2957             :                                 if (2*rem > ncnt)            \
    2958             :                                         avg++;                  \
    2959             :                         } else {                                \
    2960             :                                 if (2*rem >= ncnt)           \
    2961             :                                         avg++;                  \
    2962             :                         }                                       \
    2963             :                 }                                               \
    2964             :         } while(0)
    2965             : #endif
    2966             : 
    2967             : #define ANALYTICAL_AVG_INT_UNBOUNDED_TILL_CURRENT_ROW(TPE)              \
    2968             :         do {                                                            \
    2969             :                 TPE avg = 0;                                            \
    2970             :                 for (; k < i;) {                                     \
    2971             :                         j = k;                                          \
    2972             :                         do {                                            \
    2973             :                                 if (!is_##TPE##_nil(bp[k]))             \
    2974             :                                         AVERAGE_ITER(TPE, bp[k], avg, rem, ncnt); \
    2975             :                                 k++;                                    \
    2976             :                         } while (k < i && !op[k]);                   \
    2977             :                         if (ncnt == 0) {                                \
    2978             :                                 has_nils = true;                        \
    2979             :                                 for (; j < k; j++)                   \
    2980             :                                         rb[j] = TPE##_nil;              \
    2981             :                         } else {                                        \
    2982             :                                 TPE avgfinal = avg;                     \
    2983             :                                 ANALYTICAL_AVERAGE_INT_CALC_FINALIZE(avgfinal, rem, ncnt); \
    2984             :                                 for (; j < k; j++)                   \
    2985             :                                         rb[j] = avgfinal;               \
    2986             :                         }                                               \
    2987             :                 }                                                       \
    2988             :                 rem = 0;                                                \
    2989             :                 ncnt = 0;                                               \
    2990             :         } while (0)
    2991             : 
    2992             : #define ANALYTICAL_AVG_INT_CURRENT_ROW_TILL_UNBOUNDED(TPE)              \
    2993             :         do {                                                            \
    2994             :                 TPE avg = 0;                                            \
    2995             :                 l = i - 1;                                              \
    2996             :                 for (j = l; ; j--) {                                    \
    2997             :                         if (!is_##TPE##_nil(bp[j]))                     \
    2998             :                                 AVERAGE_ITER(TPE, bp[j], avg, rem, ncnt); \
    2999             :                         if (op[j] || j == k) {                          \
    3000             :                                 if (ncnt == 0) {                        \
    3001             :                                         has_nils = true;                \
    3002             :                                         for (; ; l--) {                 \
    3003             :                                                 rb[l] = TPE##_nil;      \
    3004             :                                                 if (l == j)             \
    3005             :                                                         break;          \
    3006             :                                         }                               \
    3007             :                                 } else {                                \
    3008             :                                         TPE avgfinal = avg;             \
    3009             :                                         ANALYTICAL_AVERAGE_INT_CALC_FINALIZE(avgfinal, rem, ncnt); \
    3010             :                                         for (; ; l--) {                 \
    3011             :                                                 rb[l] = avgfinal;       \
    3012             :                                                 if (l == j)             \
    3013             :                                                         break;          \
    3014             :                                         }                               \
    3015             :                                 }                                       \
    3016             :                                 if (j == k)                             \
    3017             :                                         break;                          \
    3018             :                                 l = j - 1;                              \
    3019             :                         }                                               \
    3020             :                 }                                                       \
    3021             :                 rem = 0;                                                \
    3022             :                 ncnt = 0;                                               \
    3023             :                 k = i;                                                  \
    3024             :         } while (0)
    3025             : 
    3026             : #define ANALYTICAL_AVG_INT_ALL_ROWS(TPE)                                \
    3027             :         do {                                                            \
    3028             :                 TPE avg = 0;                                            \
    3029             :                 for (; j < i; j++) {                                 \
    3030             :                         TPE v = bp[j];                                  \
    3031             :                         if (!is_##TPE##_nil(v))                         \
    3032             :                                 AVERAGE_ITER(TPE, v, avg, rem, ncnt);   \
    3033             :                 }                                                       \
    3034             :                 if (ncnt == 0) {                                        \
    3035             :                         for (; k < i; k++)                           \
    3036             :                                 rb[k] = TPE##_nil;                      \
    3037             :                         has_nils = true;                                \
    3038             :                 } else {                                                \
    3039             :                         ANALYTICAL_AVERAGE_INT_CALC_FINALIZE(avg, rem, ncnt); \
    3040             :                         for (; k < i; k++)                           \
    3041             :                                 rb[k] = avg;                            \
    3042             :                 }                                                       \
    3043             :                 rem = 0;                                                \
    3044             :                 ncnt = 0;                                               \
    3045             :         } while (0)
    3046             : 
    3047             : #define ANALYTICAL_AVG_INT_CURRENT_ROW(TPE)             \
    3048             :         do {                                            \
    3049             :                 for (; k < i; k++) {                 \
    3050             :                         TPE v = bp[k];                  \
    3051             :                         rb[k] = bp[k];                  \
    3052             :                         has_nils |= is_##TPE##_nil(v);  \
    3053             :                 }                                       \
    3054             :         } while (0)
    3055             : 
    3056             : #define avg_int_deltas(TPE) typedef struct avg_int_deltas_##TPE { TPE avg; lng rem, ncnt;} avg_int_deltas_##TPE;
    3057             : avg_int_deltas(bte)
    3058             : avg_int_deltas(sht)
    3059             : avg_int_deltas(int)
    3060             : avg_int_deltas(lng)
    3061             : 
    3062             : #define INIT_AGGREGATE_AVG_INT(TPE, NOTHING1, NOTHING2) \
    3063             :         do {                                            \
    3064             :                 computed = (avg_int_deltas_##TPE) {0};  \
    3065             :         } while (0)
    3066             : #define COMPUTE_LEVEL0_AVG_INT(X, TPE, NOTHING1, NOTHING2)              \
    3067             :         do {                                                            \
    3068             :                 TPE v = bp[j + X];                                      \
    3069             :                 computed = is_##TPE##_nil(v) ? (avg_int_deltas_##TPE) {0} : (avg_int_deltas_##TPE) {.avg = v, .ncnt = 1}; \
    3070             :         } while (0)
    3071             : #define COMPUTE_LEVELN_AVG_INT(VAL, TPE, NOTHING1, NOTHING2)            \
    3072             :         do {                                                            \
    3073             :                 if (VAL.ncnt)                                           \
    3074             :                         AVERAGE_ITER(TPE, VAL.avg, computed.avg, computed.rem, computed.ncnt); \
    3075             :         } while (0)
    3076             : #define FINALIZE_AGGREGATE_AVG_INT(TPE, NOTHING1, NOTHING2)             \
    3077             :         do {                                                            \
    3078             :                 if (computed.ncnt == 0) {                               \
    3079             :                         has_nils = true;                                \
    3080             :                         rb[k] = TPE##_nil;                              \
    3081             :                 } else {                                                \
    3082             :                         ANALYTICAL_AVERAGE_INT_CALC_FINALIZE(computed.avg, computed.rem, computed.ncnt); \
    3083             :                         rb[k] = computed.avg;                           \
    3084             :                 }                                                       \
    3085             :         } while (0)
    3086             : #define ANALYTICAL_AVG_INT_OTHERS(TPE)                                  \
    3087             :         do {                                                            \
    3088             :                 oid ncount = i - k;                                     \
    3089             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(avg_int_deltas_##TPE), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    3090             :                         goto cleanup;                                   \
    3091             :                 populate_segment_tree(avg_int_deltas_##TPE, ncount, INIT_AGGREGATE_AVG_INT, COMPUTE_LEVEL0_AVG_INT, COMPUTE_LEVELN_AVG_INT, TPE, NOTHING, NOTHING); \
    3092             :                 for (; k < i; k++)                                   \
    3093             :                         compute_on_segment_tree(avg_int_deltas_##TPE, start[k] - j, end[k] - j, INIT_AGGREGATE_AVG_INT, COMPUTE_LEVELN_AVG_INT, FINALIZE_AGGREGATE_AVG_INT, TPE, NOTHING, NOTHING); \
    3094             :                 j = k;                                                  \
    3095             :         } while (0)
    3096             : 
    3097             : #define ANALYTICAL_AVG_INT_PARTITIONS(TPE, IMP)                         \
    3098             :         do {                                                            \
    3099             :                 TPE *restrict bp = (TPE*)bi.base, *rb = (TPE *) Tloc(r, 0); \
    3100             :                 if (p) {                                                \
    3101             :                         while (i < cnt) {                            \
    3102             :                                 if (np[i])      {                       \
    3103             : avg##TPE##IMP:                                                          \
    3104             :                                         IMP(TPE);                       \
    3105             :                                 }                                       \
    3106             :                                 if (!last)                              \
    3107             :                                         i++;                            \
    3108             :                         }                                               \
    3109             :                 }                                                       \
    3110             :                 if (!last) {                                            \
    3111             :                         last = true;                                    \
    3112             :                         i = cnt;                                        \
    3113             :                         goto avg##TPE##IMP;                             \
    3114             :                 }                                                       \
    3115             :         } while (0)
    3116             : 
    3117             : #ifdef HAVE_HGE
    3118             : avg_int_deltas(hge)
    3119             : #define ANALYTICAL_AVG_INT_LIMIT(IMP)                                   \
    3120             :         case TYPE_hge:                                                  \
    3121             :                 ANALYTICAL_AVG_INT_PARTITIONS(hge, ANALYTICAL_AVG_INT_##IMP); \
    3122             :                 break;
    3123             : #else
    3124             : #define ANALYTICAL_AVG_INT_LIMIT(IMP)
    3125             : #endif
    3126             : 
    3127             : #define ANALYTICAL_AVG_INT_BRANCHES(IMP)                                \
    3128             :         do {                                                            \
    3129             :                 switch (tpe) {                                          \
    3130             :                 case TYPE_bte:                                          \
    3131             :                         ANALYTICAL_AVG_INT_PARTITIONS(bte, ANALYTICAL_AVG_INT_##IMP); \
    3132             :                         break;                                          \
    3133             :                 case TYPE_sht:                                          \
    3134             :                         ANALYTICAL_AVG_INT_PARTITIONS(sht, ANALYTICAL_AVG_INT_##IMP); \
    3135             :                         break;                                          \
    3136             :                 case TYPE_int:                                          \
    3137             :                         ANALYTICAL_AVG_INT_PARTITIONS(int, ANALYTICAL_AVG_INT_##IMP); \
    3138             :                         break;                                          \
    3139             :                 case TYPE_lng:                                          \
    3140             :                         ANALYTICAL_AVG_INT_PARTITIONS(lng, ANALYTICAL_AVG_INT_##IMP); \
    3141             :                         break;                                          \
    3142             :                 ANALYTICAL_AVG_INT_LIMIT(IMP)                           \
    3143             :                 default:                                                \
    3144             :                         goto nosupport;                                 \
    3145             :                 }                                                       \
    3146             :         } while (0)
    3147             : 
    3148             : gdk_return
    3149          48 : GDKanalyticalavginteger(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tpe, int frame_type)
    3150             : {
    3151          48 :         BATiter pi = bat_iterator(p);
    3152          48 :         BATiter oi = bat_iterator(o);
    3153          48 :         BATiter bi = bat_iterator(b);
    3154          48 :         BATiter si = bat_iterator(s);
    3155          48 :         BATiter ei = bat_iterator(e);
    3156             :         bool has_nils = false, last = false;
    3157          48 :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    3158          48 :                 *levels_offset = NULL, nlevels = 0;
    3159             :         lng rem = 0, ncnt = 0;
    3160          48 :         bit *np = pi.base, *op = oi.base;
    3161          48 :         void *segment_tree = NULL;
    3162             :         gdk_return res = GDK_SUCCEED;
    3163             :         BAT *st = NULL;
    3164             : 
    3165          48 :         if (cnt > 0) {
    3166          48 :                 switch (frame_type) {
    3167          18 :                 case 3: /* unbounded until current row */       {
    3168         708 :                         ANALYTICAL_AVG_INT_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    3169             :                 } break;
    3170           0 :                 case 4: /* current row until unbounded */       {
    3171           0 :                         ANALYTICAL_AVG_INT_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    3172             :                 } break;
    3173          17 :                 case 5: /* all rows */  {
    3174      308509 :                         ANALYTICAL_AVG_INT_BRANCHES(ALL_ROWS);
    3175             :                 } break;
    3176           0 :                 case 6: /* current row */ {
    3177           0 :                         ANALYTICAL_AVG_INT_BRANCHES(CURRENT_ROW);
    3178             :                 } break;
    3179          13 :                 default: {
    3180          13 :                         if (!(st = GDKinitialize_segment_tree())) {
    3181             :                                 res = GDK_FAIL;
    3182           0 :                                 goto cleanup;
    3183             :                         }
    3184        1203 :                         ANALYTICAL_AVG_INT_BRANCHES(OTHERS);
    3185             :                 }
    3186             :                 }
    3187             :         }
    3188             : 
    3189          48 :         BATsetcount(r, cnt);
    3190          48 :         r->tnonil = !has_nils;
    3191          48 :         r->tnil = has_nils;
    3192          48 : cleanup:
    3193          48 :         bat_iterator_end(&pi);
    3194          48 :         bat_iterator_end(&oi);
    3195          48 :         bat_iterator_end(&bi);
    3196          48 :         bat_iterator_end(&si);
    3197          48 :         bat_iterator_end(&ei);
    3198          48 :         BBPreclaim(st);
    3199          48 :         return res;
    3200           0 : nosupport:
    3201           0 :         GDKerror("42000!average of type %s to %s unsupported.\n", ATOMname(tpe), ATOMname(tpe));
    3202             :         res = GDK_FAIL;
    3203           0 :         goto cleanup;
    3204             : }
    3205             : 
    3206             : #define ANALYTICAL_STDEV_VARIANCE_UNBOUNDED_TILL_CURRENT_ROW(TPE, SAMPLE, OP) \
    3207             :         do {                                                            \
    3208             :                 TPE *restrict bp = (TPE*)bi.base;                       \
    3209             :                 for (; k < i;) {                                     \
    3210             :                         j = k;                                          \
    3211             :                         do {                                            \
    3212             :                                 TPE v = bp[k];                          \
    3213             :                                 if (!is_##TPE##_nil(v))  {              \
    3214             :                                         n++;                            \
    3215             :                                         delta = (dbl) v - mean;         \
    3216             :                                         mean += delta / n;              \
    3217             :                                         m2 += delta * ((dbl) v - mean); \
    3218             :                                 }                                       \
    3219             :                                 k++;                                    \
    3220             :                         } while (k < i && !op[k]);                   \
    3221             :                         if (isinf(m2)) {                                \
    3222             :                                 goto overflow;                          \
    3223             :                         } else if (n > SAMPLE) {                     \
    3224             :                                 for (; j < k; j++)                   \
    3225             :                                         rb[j] = OP;                     \
    3226             :                         } else {                                        \
    3227             :                                 for (; j < k; j++)                   \
    3228             :                                         rb[j] = dbl_nil;                \
    3229             :                                 has_nils = true;                        \
    3230             :                         }                                               \
    3231             :                 }                                                       \
    3232             :                 n = 0;                                                  \
    3233             :                 mean = 0;                                               \
    3234             :                 m2 = 0;                                                 \
    3235             :         } while (0)
    3236             : 
    3237             : #define ANALYTICAL_STDEV_VARIANCE_CURRENT_ROW_TILL_UNBOUNDED(TPE, SAMPLE, OP) \
    3238             :         do {                                                            \
    3239             :                 TPE *restrict bp = (TPE*)bi.base;                       \
    3240             :                 l = i - 1;                                              \
    3241             :                 for (j = l; ; j--) {                                    \
    3242             :                         TPE v = bp[j];                                  \
    3243             :                         if (!is_##TPE##_nil(v)) {                       \
    3244             :                                 n++;                                    \
    3245             :                                 delta = (dbl) v - mean;                 \
    3246             :                                 mean += delta / n;                      \
    3247             :                                 m2 += delta * ((dbl) v - mean);         \
    3248             :                         }                                               \
    3249             :                         if (op[j] || j == k) {                          \
    3250             :                                 if (isinf(m2)) {                        \
    3251             :                                         goto overflow;                  \
    3252             :                                 } else if (n > SAMPLE) {             \
    3253             :                                         for (; ; l--) {                 \
    3254             :                                                 rb[l] = OP;             \
    3255             :                                                 if (l == j)             \
    3256             :                                                         break;          \
    3257             :                                         }                               \
    3258             :                                 } else {                                \
    3259             :                                         for (; ; l--) {                 \
    3260             :                                                 rb[l] = dbl_nil;        \
    3261             :                                                 if (l == j)             \
    3262             :                                                         break;          \
    3263             :                                         }                               \
    3264             :                                         has_nils = true;                \
    3265             :                                 }                                       \
    3266             :                                 if (j == k)                             \
    3267             :                                         break;                          \
    3268             :                                 l = j - 1;                              \
    3269             :                         }                                               \
    3270             :                 }                                                       \
    3271             :                 n = 0;                                                  \
    3272             :                 mean = 0;                                               \
    3273             :                 m2 = 0;                                                 \
    3274             :                 k = i;                                                  \
    3275             :         } while (0)
    3276             : 
    3277             : #define ANALYTICAL_STDEV_VARIANCE_ALL_ROWS(TPE, SAMPLE, OP)     \
    3278             :         do {                                                    \
    3279             :                 TPE *restrict bp = (TPE*)bi.base;               \
    3280             :                 for (; j < i; j++) {                         \
    3281             :                         TPE v = bp[j];                          \
    3282             :                         if (is_##TPE##_nil(v))                  \
    3283             :                                 continue;                       \
    3284             :                         n++;                                    \
    3285             :                         delta = (dbl) v - mean;                 \
    3286             :                         mean += delta / n;                      \
    3287             :                         m2 += delta * ((dbl) v - mean);         \
    3288             :                 }                                               \
    3289             :                 if (isinf(m2)) {                                \
    3290             :                         goto overflow;                          \
    3291             :                 } else if (n > SAMPLE) {                     \
    3292             :                         for (; k < i; k++)                   \
    3293             :                                 rb[k] = OP;                     \
    3294             :                 } else {                                        \
    3295             :                         for (; k < i; k++)                   \
    3296             :                                 rb[k] = dbl_nil;                \
    3297             :                         has_nils = true;                        \
    3298             :                 }                                               \
    3299             :                 n = 0;                                          \
    3300             :                 mean = 0;                                       \
    3301             :                 m2 = 0;                                         \
    3302             :         } while (0)
    3303             : 
    3304             : #define ANALYTICAL_STDEV_VARIANCE_CURRENT_ROW(TPE, SAMPLE, OP)  \
    3305             :         do {                                                    \
    3306             :                 for (; k < i; k++)                           \
    3307             :                         rb[k] = SAMPLE == 1 ? dbl_nil : 0;      \
    3308             :                 has_nils = is_dbl_nil(rb[k - 1]);               \
    3309             :         } while (0)
    3310             : 
    3311             : typedef struct stdev_var_deltas {
    3312             :         BUN n;
    3313             :         dbl mean, delta, m2;
    3314             : } stdev_var_deltas;
    3315             : 
    3316             : #define INIT_AGGREGATE_STDEV_VARIANCE(TPE, SAMPLE, OP)  \
    3317             :         do {                                            \
    3318             :                 computed = (stdev_var_deltas) {0};      \
    3319             :         } while (0)
    3320             : #define COMPUTE_LEVEL0_STDEV_VARIANCE(X, TPE, SAMPLE, OP)               \
    3321             :         do {                                                            \
    3322             :                 TPE v = bp[j + X];                                      \
    3323             :                 computed = is_##TPE##_nil(v) ? (stdev_var_deltas) {0} : (stdev_var_deltas) {.n = 1, .mean = (dbl)v, .delta = (dbl)v}; \
    3324             :         } while (0)
    3325             : #define COMPUTE_LEVELN_STDEV_VARIANCE(VAL, TPE, SAMPLE, OP)             \
    3326             :         do {                                                            \
    3327             :                 if (VAL.n) {                                            \
    3328             :                         computed.n++;                                   \
    3329             :                         computed.delta = VAL.delta - computed.mean;     \
    3330             :                         computed.mean += computed.delta / computed.n;   \
    3331             :                         computed.m2 += computed.delta * (VAL.delta - computed.mean); \
    3332             :                 }                                                       \
    3333             :         } while (0)
    3334             : #define FINALIZE_AGGREGATE_STDEV_VARIANCE(TPE, SAMPLE, OP)      \
    3335             :         do {                                                    \
    3336             :                 dbl m2 = computed.m2;                           \
    3337             :                 BUN n = computed.n;                             \
    3338             :                 if (isinf(m2)) {                                \
    3339             :                         goto overflow;                          \
    3340             :                 } else if (n > SAMPLE) {                     \
    3341             :                         rb[k] = OP;                             \
    3342             :                 } else {                                        \
    3343             :                         rb[k] = dbl_nil;                        \
    3344             :                         has_nils = true;                        \
    3345             :                 }                                               \
    3346             :         } while (0)
    3347             : #define ANALYTICAL_STDEV_VARIANCE_OTHERS(TPE, SAMPLE, OP)               \
    3348             :         do {                                                            \
    3349             :                 TPE *restrict bp = (TPE*)bi.base;                       \
    3350             :                 oid ncount = i - k;                                     \
    3351             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(stdev_var_deltas), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    3352             :                         goto cleanup;                                   \
    3353             :                 populate_segment_tree(stdev_var_deltas, ncount, INIT_AGGREGATE_STDEV_VARIANCE, COMPUTE_LEVEL0_STDEV_VARIANCE, COMPUTE_LEVELN_STDEV_VARIANCE, TPE, SAMPLE, OP); \
    3354             :                 for (; k < i; k++)                                   \
    3355             :                         compute_on_segment_tree(stdev_var_deltas, start[k] - j, end[k] - j, INIT_AGGREGATE_STDEV_VARIANCE, COMPUTE_LEVELN_STDEV_VARIANCE, FINALIZE_AGGREGATE_STDEV_VARIANCE, TPE, SAMPLE, OP); \
    3356             :                 j = k;                                                  \
    3357             :         } while (0)
    3358             : 
    3359             : #define ANALYTICAL_STATISTICS_PARTITIONS(TPE, SAMPLE, OP, IMP)  \
    3360             :         do {                                                    \
    3361             :                 if (p) {                                        \
    3362             :                         while (i < cnt) {                    \
    3363             :                                 if (np[i])      {               \
    3364             : statistics##TPE##IMP:                                           \
    3365             :                                         IMP(TPE, SAMPLE, OP);   \
    3366             :                                 }                               \
    3367             :                                 if (!last)                      \
    3368             :                                         i++;                    \
    3369             :                         }                                       \
    3370             :                 }                                               \
    3371             :                 if (!last) {                                    \
    3372             :                         last = true;                            \
    3373             :                         i = cnt;                                \
    3374             :                         goto statistics##TPE##IMP;              \
    3375             :                 }                                               \
    3376             :         } while (0)
    3377             : 
    3378             : #ifdef HAVE_HGE
    3379             : #define ANALYTICAL_STATISTICS_LIMIT(IMP, SAMPLE, OP)                    \
    3380             :         case TYPE_hge:                                                  \
    3381             :                 ANALYTICAL_STATISTICS_PARTITIONS(hge, SAMPLE, OP, ANALYTICAL_##IMP); \
    3382             :                 break;
    3383             : #else
    3384             : #define ANALYTICAL_STATISTICS_LIMIT(IMP, SAMPLE, OP)
    3385             : #endif
    3386             : 
    3387             : #define ANALYTICAL_STATISTICS_BRANCHES(IMP, SAMPLE, OP)                 \
    3388             :         do {                                                            \
    3389             :                 switch (tpe) {                                          \
    3390             :                 case TYPE_bte:                                          \
    3391             :                         ANALYTICAL_STATISTICS_PARTITIONS(bte, SAMPLE, OP, ANALYTICAL_##IMP); \
    3392             :                         break;                                          \
    3393             :                 case TYPE_sht:                                          \
    3394             :                         ANALYTICAL_STATISTICS_PARTITIONS(sht, SAMPLE, OP, ANALYTICAL_##IMP); \
    3395             :                         break;                                          \
    3396             :                 case TYPE_int:                                          \
    3397             :                         ANALYTICAL_STATISTICS_PARTITIONS(int, SAMPLE, OP, ANALYTICAL_##IMP); \
    3398             :                         break;                                          \
    3399             :                 case TYPE_lng:                                          \
    3400             :                         ANALYTICAL_STATISTICS_PARTITIONS(lng, SAMPLE, OP, ANALYTICAL_##IMP); \
    3401             :                         break;                                          \
    3402             :                 case TYPE_flt:                                          \
    3403             :                         ANALYTICAL_STATISTICS_PARTITIONS(flt, SAMPLE, OP, ANALYTICAL_##IMP); \
    3404             :                         break;                                          \
    3405             :                 case TYPE_dbl:                                          \
    3406             :                         ANALYTICAL_STATISTICS_PARTITIONS(dbl, SAMPLE, OP, ANALYTICAL_##IMP); \
    3407             :                         break;                                          \
    3408             :                 ANALYTICAL_STATISTICS_LIMIT(IMP, SAMPLE, OP)            \
    3409             :                 default:                                                \
    3410             :                         goto nosupport;                                 \
    3411             :                 }                                                       \
    3412             :         } while (0)
    3413             : 
    3414             : #define GDK_ANALYTICAL_STDEV_VARIANCE(NAME, SAMPLE, OP, DESC)           \
    3415             : gdk_return                                                              \
    3416             : GDKanalytical_##NAME(BAT *r, BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tpe, int frame_type) \
    3417             : {                                                                       \
    3418             :         BATiter pi = bat_iterator(p);                                   \
    3419             :         BATiter oi = bat_iterator(o);                                   \
    3420             :         BATiter bi = bat_iterator(b);                                   \
    3421             :         BATiter si = bat_iterator(s);                                   \
    3422             :         BATiter ei = bat_iterator(e);                                   \
    3423             :         bool has_nils = false, last = false;                            \
    3424             :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base, \
    3425             :                 *levels_offset = NULL, nlevels = 0;     \
    3426             :         lng n = 0;                                                      \
    3427             :         bit *np = pi.base, *op = oi.base;                               \
    3428             :         dbl *rb = (dbl *) Tloc(r, 0), mean = 0, m2 = 0, delta;          \
    3429             :         void *segment_tree = NULL;                                      \
    3430             :         gdk_return res = GDK_SUCCEED;                                   \
    3431             :         BAT *st = NULL; \
    3432             :                                                                         \
    3433             :         if (cnt > 0) {                                                       \
    3434             :                 switch (frame_type) {                                   \
    3435             :                 case 3: /* unbounded until current row */       {       \
    3436             :                         ANALYTICAL_STATISTICS_BRANCHES(STDEV_VARIANCE_UNBOUNDED_TILL_CURRENT_ROW, SAMPLE, OP); \
    3437             :                 } break;                                                \
    3438             :                 case 4: /* current row until unbounded */       {       \
    3439             :                         ANALYTICAL_STATISTICS_BRANCHES(STDEV_VARIANCE_CURRENT_ROW_TILL_UNBOUNDED, SAMPLE, OP); \
    3440             :                 } break;                                                \
    3441             :                 case 5: /* all rows */  {                               \
    3442             :                         ANALYTICAL_STATISTICS_BRANCHES(STDEV_VARIANCE_ALL_ROWS, SAMPLE, OP); \
    3443             :                 } break;                                                \
    3444             :                 case 6: /* current row */ {                             \
    3445             :                         ANALYTICAL_STATISTICS_BRANCHES(STDEV_VARIANCE_CURRENT_ROW, SAMPLE, OP); \
    3446             :                 } break;                                                \
    3447             :                 default: {                                              \
    3448             :                         if (!(st = GDKinitialize_segment_tree())) {     \
    3449             :                                 res = GDK_FAIL; \
    3450             :                                 goto cleanup;   \
    3451             :                         }       \
    3452             :                         ANALYTICAL_STATISTICS_BRANCHES(STDEV_VARIANCE_OTHERS, SAMPLE, OP); \
    3453             :                 }                                                       \
    3454             :                 }                                                       \
    3455             :         }                                                               \
    3456             :                                                                         \
    3457             :         BATsetcount(r, cnt);                                            \
    3458             :         r->tnonil = !has_nils;                                               \
    3459             :         r->tnil = has_nils;                                          \
    3460             :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */ \
    3461             : overflow:                                                               \
    3462             :         GDKerror("22003!overflow in calculation.\n");                 \
    3463             :         res = GDK_FAIL;                                                 \
    3464             : cleanup:                                                                \
    3465             :         bat_iterator_end(&pi);                                              \
    3466             :         bat_iterator_end(&oi);                                              \
    3467             :         bat_iterator_end(&bi);                                              \
    3468             :         bat_iterator_end(&si);                                              \
    3469             :         bat_iterator_end(&ei);                                              \
    3470             :         BBPreclaim(st); \
    3471             :         return res;                                                     \
    3472             : nosupport:                                                              \
    3473             :         GDKerror("42000!%s of type %s unsupported.\n", DESC, ATOMname(tpe)); \
    3474             :         res = GDK_FAIL;                                                 \
    3475             :         goto cleanup;                                                   \
    3476             : }
    3477             : 
    3478         819 : GDK_ANALYTICAL_STDEV_VARIANCE(stddev_samp, 1, sqrt(m2 / (n - 1)), "standard deviation")
    3479         328 : GDK_ANALYTICAL_STDEV_VARIANCE(stddev_pop, 0, sqrt(m2 / n), "standard deviation")
    3480         331 : GDK_ANALYTICAL_STDEV_VARIANCE(variance_samp, 1, m2 / (n - 1), "variance")
    3481         952 : GDK_ANALYTICAL_STDEV_VARIANCE(variance_pop, 0, m2 / n, "variance")
    3482             : 
    3483             : #define ANALYTICAL_COVARIANCE_UNBOUNDED_TILL_CURRENT_ROW(TPE, SAMPLE, OP) \
    3484             :         do {                                                            \
    3485             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3486             :                 for (; k < i;) {                                     \
    3487             :                         j = k;                                          \
    3488             :                         do {                                            \
    3489             :                                 TPE v1 = bp1[k], v2 = bp2[k];           \
    3490             :                                 if (!is_##TPE##_nil(v1) && !is_##TPE##_nil(v2)) { \
    3491             :                                         n++;                            \
    3492             :                                         delta1 = (dbl) v1 - mean1;      \
    3493             :                                         mean1 += delta1 / n;            \
    3494             :                                         delta2 = (dbl) v2 - mean2;      \
    3495             :                                         mean2 += delta2 / n;            \
    3496             :                                         m2 += delta1 * ((dbl) v2 - mean2); \
    3497             :                                 }                                       \
    3498             :                                 k++;                                    \
    3499             :                         } while (k < i && !op[k]);                   \
    3500             :                         if (isinf(m2))                                  \
    3501             :                                 goto overflow;                          \
    3502             :                         if (n > SAMPLE) {                            \
    3503             :                                 for (; j < k; j++)                   \
    3504             :                                         rb[j] = OP;                     \
    3505             :                         } else {                                        \
    3506             :                                 for (; j < k; j++)                   \
    3507             :                                         rb[j] = dbl_nil;                \
    3508             :                                 has_nils = true;                        \
    3509             :                         }                                               \
    3510             :                 }                                                       \
    3511             :                 n = 0;                                                  \
    3512             :                 mean1 = 0;                                              \
    3513             :                 mean2 = 0;                                              \
    3514             :                 m2 = 0;                                                 \
    3515             :         } while (0)
    3516             : 
    3517             : #define ANALYTICAL_COVARIANCE_CURRENT_ROW_TILL_UNBOUNDED(TPE, SAMPLE, OP) \
    3518             :         do {                                                            \
    3519             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3520             :                 l = i - 1;                                              \
    3521             :                 for (j = l; ; j--) {                                    \
    3522             :                         TPE v1 = bp1[j], v2 = bp2[j];                   \
    3523             :                         if (!is_##TPE##_nil(v1) && !is_##TPE##_nil(v2)) { \
    3524             :                                 n++;                                    \
    3525             :                                 delta1 = (dbl) v1 - mean1;              \
    3526             :                                 mean1 += delta1 / n;                    \
    3527             :                                 delta2 = (dbl) v2 - mean2;              \
    3528             :                                 mean2 += delta2 / n;                    \
    3529             :                                 m2 += delta1 * ((dbl) v2 - mean2);      \
    3530             :                         }                                               \
    3531             :                         if (op[j] || j == k) {                          \
    3532             :                                 if (isinf(m2))                          \
    3533             :                                         goto overflow;                  \
    3534             :                                 if (n > SAMPLE) {                    \
    3535             :                                         for (; ; l--) {                 \
    3536             :                                                 rb[l] = OP;             \
    3537             :                                                 if (l == j)             \
    3538             :                                                         break;          \
    3539             :                                         }                               \
    3540             :                                 } else {                                \
    3541             :                                         for (; ; l--) {                 \
    3542             :                                                 rb[l] = dbl_nil;        \
    3543             :                                                 if (l == j)             \
    3544             :                                                         break;          \
    3545             :                                         }                               \
    3546             :                                         has_nils = true;                \
    3547             :                                 }                                       \
    3548             :                                 if (j == k)                             \
    3549             :                                         break;                          \
    3550             :                                 l = j - 1;                              \
    3551             :                         }                                               \
    3552             :                 }                                                       \
    3553             :                 n = 0;                                                  \
    3554             :                 mean1 = 0;                                              \
    3555             :                 mean2 = 0;                                              \
    3556             :                 m2 = 0;                                                 \
    3557             :                 k = i;                                                  \
    3558             :         } while (0)
    3559             : 
    3560             : #define ANALYTICAL_COVARIANCE_ALL_ROWS(TPE, SAMPLE, OP)                 \
    3561             :         do {                                                            \
    3562             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3563             :                 for (; j < i; j++) {                                 \
    3564             :                         TPE v1 = bp1[j], v2 = bp2[j];                   \
    3565             :                         if (!is_##TPE##_nil(v1) && !is_##TPE##_nil(v2)) { \
    3566             :                                 n++;                                    \
    3567             :                                 delta1 = (dbl) v1 - mean1;              \
    3568             :                                 mean1 += delta1 / n;                    \
    3569             :                                 delta2 = (dbl) v2 - mean2;              \
    3570             :                                 mean2 += delta2 / n;                    \
    3571             :                                 m2 += delta1 * ((dbl) v2 - mean2);      \
    3572             :                         }                                               \
    3573             :                 }                                                       \
    3574             :                 if (isinf(m2))                                          \
    3575             :                         goto overflow;                                  \
    3576             :                 if (n > SAMPLE) {                                    \
    3577             :                         for (; k < i; k++)                           \
    3578             :                                 rb[k] = OP;                             \
    3579             :                 } else {                                                \
    3580             :                         for (; k < i; k++)                           \
    3581             :                                 rb[k] = dbl_nil;                        \
    3582             :                         has_nils = true;                                \
    3583             :                 }                                                       \
    3584             :                 n = 0;                                                  \
    3585             :                 mean1 = 0;                                              \
    3586             :                 mean2 = 0;                                              \
    3587             :                 m2 = 0;                                                 \
    3588             :         } while (0)
    3589             : 
    3590             : #define ANALYTICAL_COVARIANCE_CURRENT_ROW(TPE, SAMPLE, OP)      \
    3591             :         do {                                                    \
    3592             :                 for (; k < i; k++)                           \
    3593             :                         rb[k] = SAMPLE == 1 ? dbl_nil : 0;      \
    3594             :                 has_nils = is_dbl_nil(rb[k - 1]);               \
    3595             :         } while (0)
    3596             : 
    3597             : typedef struct covariance_deltas {
    3598             :         BUN n;
    3599             :         dbl mean1, mean2, delta1, delta2, m2;
    3600             : } covariance_deltas;
    3601             : 
    3602             : #define INIT_AGGREGATE_COVARIANCE(TPE, SAMPLE, OP)      \
    3603             :         do {                                            \
    3604             :                 computed = (covariance_deltas) {0};     \
    3605             :         } while (0)
    3606             : #define COMPUTE_LEVEL0_COVARIANCE(X, TPE, SAMPLE, OP)                   \
    3607             :         do {                                                            \
    3608             :                 TPE v1 = bp1[j + X], v2 = bp2[j + X];                   \
    3609             :                 computed = is_##TPE##_nil(v1) || is_##TPE##_nil(v2) ? (covariance_deltas) {0} \
    3610             :                                                                                                                         : (covariance_deltas) {.n = 1, .mean1 = (dbl)v1, .mean2 = (dbl)v2, .delta1 = (dbl)v1, .delta2 = (dbl)v2}; \
    3611             :         } while (0)
    3612             : #define COMPUTE_LEVELN_COVARIANCE(VAL, TPE, SAMPLE, OP)                 \
    3613             :         do {                                                            \
    3614             :                 if (VAL.n) {                                            \
    3615             :                         computed.n++;                                   \
    3616             :                         computed.delta1 = VAL.delta1 - computed.mean1;  \
    3617             :                         computed.mean1 += computed.delta1 / computed.n; \
    3618             :                         computed.delta2 = VAL.delta2 - computed.mean2;  \
    3619             :                         computed.mean2 += computed.delta2 / computed.n; \
    3620             :                         computed.m2 += computed.delta1 * (VAL.delta2 - computed.mean2); \
    3621             :                 }                                                       \
    3622             :         } while (0)
    3623             : #define FINALIZE_AGGREGATE_COVARIANCE(TPE, SAMPLE, OP) FINALIZE_AGGREGATE_STDEV_VARIANCE(TPE, SAMPLE, OP)
    3624             : #define ANALYTICAL_COVARIANCE_OTHERS(TPE, SAMPLE, OP)                   \
    3625             :         do {                                                            \
    3626             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3627             :                 oid ncount = i - k;                                     \
    3628             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(covariance_deltas), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    3629             :                         goto cleanup;                                   \
    3630             :                 populate_segment_tree(covariance_deltas, ncount, INIT_AGGREGATE_COVARIANCE, COMPUTE_LEVEL0_COVARIANCE, COMPUTE_LEVELN_COVARIANCE, TPE, SAMPLE, OP); \
    3631             :                 for (; k < i; k++)                                   \
    3632             :                         compute_on_segment_tree(covariance_deltas, start[k] - j, end[k] - j, INIT_AGGREGATE_COVARIANCE, COMPUTE_LEVELN_COVARIANCE, FINALIZE_AGGREGATE_COVARIANCE, TPE, SAMPLE, OP); \
    3633             :                 j = k;                                                  \
    3634             :         } while (0)
    3635             : 
    3636             : #define GDK_ANALYTICAL_COVARIANCE(NAME, SAMPLE, OP)                     \
    3637             : gdk_return                                                              \
    3638             : GDKanalytical_##NAME(BAT *r, BAT *p, BAT *o, BAT *b1, BAT *b2, BAT *s, BAT *e, int tpe, int frame_type) \
    3639             : {                                                                       \
    3640             :         BATiter pi = bat_iterator(p);                                   \
    3641             :         BATiter oi = bat_iterator(o);                                   \
    3642             :         BATiter b1i = bat_iterator(b1);                                 \
    3643             :         BATiter b2i = bat_iterator(b2);                                 \
    3644             :         BATiter si = bat_iterator(s);                                   \
    3645             :         BATiter ei = bat_iterator(e);                                   \
    3646             :         bool has_nils = false, last = false;                            \
    3647             :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b1), *restrict start = si.base, *restrict end = ei.base, \
    3648             :                 *levels_offset = NULL, nlevels = 0;     \
    3649             :         lng n = 0;                                                      \
    3650             :         bit *np = pi.base, *op = oi.base;                               \
    3651             :         dbl *rb = (dbl *) Tloc(r, 0), mean1 = 0, mean2 = 0, m2 = 0, delta1, delta2; \
    3652             :         void *segment_tree = NULL;                                      \
    3653             :         gdk_return res = GDK_SUCCEED;                                   \
    3654             :         BAT *st = NULL; \
    3655             :                                                                         \
    3656             :         if (cnt > 0) {                                                       \
    3657             :                 switch (frame_type) {                                   \
    3658             :                 case 3: /* unbounded until current row */       {       \
    3659             :                         ANALYTICAL_STATISTICS_BRANCHES(COVARIANCE_UNBOUNDED_TILL_CURRENT_ROW, SAMPLE, OP); \
    3660             :                 } break;                                                \
    3661             :                 case 4: /* current row until unbounded */       {       \
    3662             :                         ANALYTICAL_STATISTICS_BRANCHES(COVARIANCE_CURRENT_ROW_TILL_UNBOUNDED, SAMPLE, OP); \
    3663             :                 } break;                                                \
    3664             :                 case 5: /* all rows */  {                               \
    3665             :                         ANALYTICAL_STATISTICS_BRANCHES(COVARIANCE_ALL_ROWS, SAMPLE, OP); \
    3666             :                 } break;                                                \
    3667             :                 case 6: /* current row */ {                             \
    3668             :                         ANALYTICAL_STATISTICS_BRANCHES(COVARIANCE_CURRENT_ROW, SAMPLE, OP); \
    3669             :                 } break;                                                \
    3670             :                 default: {                                              \
    3671             :                         if (!(st = GDKinitialize_segment_tree())) {     \
    3672             :                                 res = GDK_FAIL; \
    3673             :                                 goto cleanup;   \
    3674             :                         }       \
    3675             :                         ANALYTICAL_STATISTICS_BRANCHES(COVARIANCE_OTHERS, SAMPLE, OP); \
    3676             :                 }                                                       \
    3677             :                 }                                                       \
    3678             :         }                                                               \
    3679             :                                                                         \
    3680             :         BATsetcount(r, cnt);                                            \
    3681             :         r->tnonil = !has_nils;                                               \
    3682             :         r->tnil = has_nils;                                          \
    3683             :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */ \
    3684             : overflow:                                                               \
    3685             :         GDKerror("22003!overflow in calculation.\n");                 \
    3686             :         res = GDK_FAIL;                                                 \
    3687             : cleanup:                                                                \
    3688             :         bat_iterator_end(&pi);                                              \
    3689             :         bat_iterator_end(&oi);                                              \
    3690             :         bat_iterator_end(&b1i);                                             \
    3691             :         bat_iterator_end(&b2i);                                             \
    3692             :         bat_iterator_end(&si);                                              \
    3693             :         bat_iterator_end(&ei);                                              \
    3694             :         BBPreclaim(st); \
    3695             :         return res;                                                     \
    3696             : nosupport:                                                              \
    3697             :         GDKerror("42000!covariance of type %s unsupported.\n", ATOMname(tpe)); \
    3698             :         res = GDK_FAIL;                                                 \
    3699             :         goto cleanup;                                                   \
    3700             : }
    3701             : 
    3702        1339 : GDK_ANALYTICAL_COVARIANCE(covariance_samp, 1, m2 / (n - 1))
    3703        1421 : GDK_ANALYTICAL_COVARIANCE(covariance_pop, 0, m2 / n)
    3704             : 
    3705             : #define ANALYTICAL_CORRELATION_UNBOUNDED_TILL_CURRENT_ROW(TPE, SAMPLE, OP)      /* SAMPLE and OP not used */ \
    3706             :         do {                                                            \
    3707             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3708             :                 for (; k < i;) {                                     \
    3709             :                         j = k;                                          \
    3710             :                         do {                                            \
    3711             :                                 TPE v1 = bp1[k], v2 = bp2[k];           \
    3712             :                                 if (!is_##TPE##_nil(v1) && !is_##TPE##_nil(v2)) { \
    3713             :                                         n++;                            \
    3714             :                                         delta1 = (dbl) v1 - mean1;      \
    3715             :                                         mean1 += delta1 / n;            \
    3716             :                                         delta2 = (dbl) v2 - mean2;      \
    3717             :                                         mean2 += delta2 / n;            \
    3718             :                                         aux = (dbl) v2 - mean2;         \
    3719             :                                         up += delta1 * aux;             \
    3720             :                                         down1 += delta1 * ((dbl) v1 - mean1); \
    3721             :                                         down2 += delta2 * aux;          \
    3722             :                                 }                                       \
    3723             :                                 k++;                                    \
    3724             :                         } while (k < i && !op[k]);                   \
    3725             :                         if (isinf(up) || isinf(down1) || isinf(down2))  \
    3726             :                                 goto overflow;                          \
    3727             :                         if (n != 0 && down1 != 0 && down2 != 0) {       \
    3728             :                                 rr = (up / n) / (sqrt(down1 / n) * sqrt(down2 / n)); \
    3729             :                                 assert(!is_dbl_nil(rr));                \
    3730             :                         } else {                                        \
    3731             :                                 rr = dbl_nil;                           \
    3732             :                                 has_nils = true;                        \
    3733             :                         }                                               \
    3734             :                         for (; j < k; j++)                           \
    3735             :                                 rb[j] = rr;                             \
    3736             :                 }                                                       \
    3737             :                 n = 0;                                                  \
    3738             :                 mean1 = 0;                                              \
    3739             :                 mean2 = 0;                                              \
    3740             :                 up = 0;                                                 \
    3741             :                 down1 = 0;                                              \
    3742             :                 down2 = 0;                                              \
    3743             :         } while (0)
    3744             : 
    3745             : #define ANALYTICAL_CORRELATION_CURRENT_ROW_TILL_UNBOUNDED(TPE, SAMPLE, OP)      /* SAMPLE and OP not used */ \
    3746             :         do {                                                            \
    3747             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3748             :                 l = i - 1;                                              \
    3749             :                 for (j = l; ; j--) {                                    \
    3750             :                         TPE v1 = bp1[j], v2 = bp2[j];                   \
    3751             :                         if (!is_##TPE##_nil(v1) && !is_##TPE##_nil(v2)) { \
    3752             :                                 n++;                                    \
    3753             :                                 delta1 = (dbl) v1 - mean1;              \
    3754             :                                 mean1 += delta1 / n;                    \
    3755             :                                 delta2 = (dbl) v2 - mean2;              \
    3756             :                                 mean2 += delta2 / n;                    \
    3757             :                                 aux = (dbl) v2 - mean2;                 \
    3758             :                                 up += delta1 * aux;                     \
    3759             :                                 down1 += delta1 * ((dbl) v1 - mean1);   \
    3760             :                                 down2 += delta2 * aux;                  \
    3761             :                         }                                               \
    3762             :                         if (op[j] || j == k) {                          \
    3763             :                                 if (isinf(up) || isinf(down1) || isinf(down2)) \
    3764             :                                         goto overflow;                  \
    3765             :                                 if (n != 0 && down1 != 0 && down2 != 0) { \
    3766             :                                         rr = (up / n) / (sqrt(down1 / n) * sqrt(down2 / n)); \
    3767             :                                         assert(!is_dbl_nil(rr));        \
    3768             :                                 } else {                                \
    3769             :                                         rr = dbl_nil;                   \
    3770             :                                         has_nils = true;                \
    3771             :                                 }                                       \
    3772             :                                 for (; ; l--) {                         \
    3773             :                                         rb[l] = rr;                     \
    3774             :                                         if (l == j)                     \
    3775             :                                                 break;                  \
    3776             :                                 }                                       \
    3777             :                                 if (j == k)                             \
    3778             :                                         break;                          \
    3779             :                                 l = j - 1;                              \
    3780             :                         }                                               \
    3781             :                 }                                                       \
    3782             :                 n = 0;                                                  \
    3783             :                 mean1 = 0;                                              \
    3784             :                 mean2 = 0;                                              \
    3785             :                 up = 0;                                                 \
    3786             :                 down1 = 0;                                              \
    3787             :                 down2 = 0;                                              \
    3788             :                 k = i;                                                  \
    3789             :         } while (0)
    3790             : 
    3791             : #define ANALYTICAL_CORRELATION_ALL_ROWS(TPE, SAMPLE, OP)        /* SAMPLE and OP not used */ \
    3792             :         do {                                                            \
    3793             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3794             :                 for (; j < i; j++) {                                 \
    3795             :                         TPE v1 = bp1[j], v2 = bp2[j];                   \
    3796             :                         if (!is_##TPE##_nil(v1) && !is_##TPE##_nil(v2)) { \
    3797             :                                 n++;                                    \
    3798             :                                 delta1 = (dbl) v1 - mean1;              \
    3799             :                                 mean1 += delta1 / n;                    \
    3800             :                                 delta2 = (dbl) v2 - mean2;              \
    3801             :                                 mean2 += delta2 / n;                    \
    3802             :                                 aux = (dbl) v2 - mean2;                 \
    3803             :                                 up += delta1 * aux;                     \
    3804             :                                 down1 += delta1 * ((dbl) v1 - mean1);   \
    3805             :                                 down2 += delta2 * aux;                  \
    3806             :                         }                                               \
    3807             :                 }                                                       \
    3808             :                 if (isinf(up) || isinf(down1) || isinf(down2))          \
    3809             :                         goto overflow;                                  \
    3810             :                 if (n != 0 && down1 != 0 && down2 != 0) {               \
    3811             :                         rr = (up / n) / (sqrt(down1 / n) * sqrt(down2 / n)); \
    3812             :                         assert(!is_dbl_nil(rr));                        \
    3813             :                 } else {                                                \
    3814             :                         rr = dbl_nil;                                   \
    3815             :                         has_nils = true;                                \
    3816             :                 }                                                       \
    3817             :                 for (; k < i ; k++)                                  \
    3818             :                         rb[k] = rr;                                     \
    3819             :                 n = 0;                                                  \
    3820             :                 mean1 = 0;                                              \
    3821             :                 mean2 = 0;                                              \
    3822             :                 up = 0;                                                 \
    3823             :                 down1 = 0;                                              \
    3824             :                 down2 = 0;                                              \
    3825             :         } while (0)
    3826             : 
    3827             : #define ANALYTICAL_CORRELATION_CURRENT_ROW(TPE, SAMPLE, OP)     /* SAMPLE and OP not used */ \
    3828             :         do {                                                            \
    3829             :                 for (; k < i; k++)                                   \
    3830             :                         rb[k] = dbl_nil;                                \
    3831             :                 has_nils = true;                                        \
    3832             :         } while (0)
    3833             : 
    3834             : 
    3835             : typedef struct correlation_deltas {
    3836             :         BUN n;
    3837             :         dbl mean1, mean2, delta1, delta2, up, down1, down2;
    3838             : } correlation_deltas;
    3839             : 
    3840             : #define INIT_AGGREGATE_CORRELATION(TPE, SAMPLE, OP)     \
    3841             :         do {                                            \
    3842             :                 computed = (correlation_deltas) {0};    \
    3843             :         } while (0)
    3844             : #define COMPUTE_LEVEL0_CORRELATION(X, TPE, SAMPLE, OP)                  \
    3845             :         do {                                                            \
    3846             :                 TPE v1 = bp1[j + X], v2 = bp2[j + X];                   \
    3847             :                 computed = is_##TPE##_nil(v1) || is_##TPE##_nil(v2) ? (correlation_deltas) {0} \
    3848             :                                                                                                                         : (correlation_deltas) {.n = 1, .mean1 = (dbl)v1, .mean2 = (dbl)v2, .delta1 = (dbl)v1, .delta2 = (dbl)v2}; \
    3849             :         } while (0)
    3850             : #define COMPUTE_LEVELN_CORRELATION(VAL, TPE, SAMPLE, OP)                \
    3851             :         do {                                                            \
    3852             :                 if (VAL.n) {                                            \
    3853             :                         computed.n++;                                   \
    3854             :                         computed.delta1 = VAL.delta1 - computed.mean1;  \
    3855             :                         computed.mean1 += computed.delta1 / computed.n; \
    3856             :                         computed.delta2 = VAL.delta2 - computed.mean2;  \
    3857             :                         computed.mean2 += computed.delta2 / computed.n; \
    3858             :                         dbl aux = VAL.delta2 - computed.mean2;          \
    3859             :                         computed.up += computed.delta1 * aux;           \
    3860             :                         computed.down1 += computed.delta1 * (VAL.delta1 - computed.mean1); \
    3861             :                         computed.down2 += computed.delta2 * aux;        \
    3862             :                 }                                                       \
    3863             :         } while (0)
    3864             : #define FINALIZE_AGGREGATE_CORRELATION(TPE, SAMPLE, OP)                 \
    3865             :         do {                                                            \
    3866             :                 n = computed.n;                                         \
    3867             :                 up = computed.up;                                       \
    3868             :                 down1 = computed.down1;                                 \
    3869             :                 down2 = computed.down2;                                 \
    3870             :                 if (isinf(up) || isinf(down1) || isinf(down2))          \
    3871             :                         goto overflow;                                  \
    3872             :                 if (n != 0 && down1 != 0 && down2 != 0) {               \
    3873             :                         rr = (up / n) / (sqrt(down1 / n) * sqrt(down2 / n)); \
    3874             :                         assert(!is_dbl_nil(rr));                        \
    3875             :                 } else {                                                \
    3876             :                         rr = dbl_nil;                                   \
    3877             :                         has_nils = true;                                \
    3878             :                 }                                                       \
    3879             :                 rb[k] = rr;                                             \
    3880             :         } while (0)
    3881             : #define ANALYTICAL_CORRELATION_OTHERS(TPE, SAMPLE, OP)  /* SAMPLE and OP not used */ \
    3882             :         do {                                                            \
    3883             :                 TPE *bp1 = (TPE*)b1i.base, *bp2 = (TPE*)b2i.base;       \
    3884             :                 oid ncount = i - k;                                     \
    3885             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(correlation_deltas), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    3886             :                         goto cleanup;                                   \
    3887             :                 populate_segment_tree(correlation_deltas, ncount, INIT_AGGREGATE_CORRELATION, COMPUTE_LEVEL0_CORRELATION, COMPUTE_LEVELN_CORRELATION, TPE, SAMPLE, OP); \
    3888             :                 for (; k < i; k++)                                   \
    3889             :                         compute_on_segment_tree(correlation_deltas, start[k] - j, end[k] - j, INIT_AGGREGATE_CORRELATION, COMPUTE_LEVELN_CORRELATION, FINALIZE_AGGREGATE_CORRELATION, TPE, SAMPLE, OP); \
    3890             :                 j = k;                                                  \
    3891             :         } while (0)
    3892             : 
    3893             : gdk_return
    3894          47 : GDKanalytical_correlation(BAT *r, BAT *p, BAT *o, BAT *b1, BAT *b2, BAT *s, BAT *e, int tpe, int frame_type)
    3895             : {
    3896             :         bool has_nils = false, last = false;
    3897          47 :         BATiter pi = bat_iterator(p);
    3898          47 :         BATiter oi = bat_iterator(o);
    3899          47 :         BATiter b1i = bat_iterator(b1);
    3900          47 :         BATiter b2i = bat_iterator(b2);
    3901          47 :         BATiter si = bat_iterator(s);
    3902          47 :         BATiter ei = bat_iterator(e);
    3903          47 :         oid i = 0, j = 0, k = 0, l = 0, cnt = BATcount(b1),
    3904          47 :                 *levels_offset = NULL, nlevels = 0;
    3905          47 :         const oid *restrict start = si.base, *restrict end = ei.base;
    3906             :         lng n = 0;
    3907          47 :         const bit *np = pi.base, *op = oi.base;
    3908          47 :         dbl *rb = (dbl *) Tloc(r, 0), mean1 = 0, mean2 = 0, up = 0, down1 = 0, down2 = 0, delta1, delta2, aux, rr;
    3909          47 :         void *segment_tree = NULL;
    3910             :         gdk_return res = GDK_SUCCEED;
    3911             :         BAT *st = NULL;
    3912             : 
    3913          47 :         if (cnt > 0) {
    3914          47 :                 switch (frame_type) {
    3915          18 :                 case 3: /* unbounded until current row */       {
    3916         516 :                         ANALYTICAL_STATISTICS_BRANCHES(CORRELATION_UNBOUNDED_TILL_CURRENT_ROW, ;, ;);
    3917             :                 } break;
    3918           0 :                 case 4: /* current row until unbounded */       {
    3919           0 :                         ANALYTICAL_STATISTICS_BRANCHES(CORRELATION_CURRENT_ROW_TILL_UNBOUNDED, ;, ;);
    3920             :                 } break;
    3921          18 :                 case 5: /* all rows */  {
    3922         449 :                         ANALYTICAL_STATISTICS_BRANCHES(CORRELATION_ALL_ROWS, ;, ;);
    3923             :                 } break;
    3924           0 :                 case 6: /* current row */ {
    3925           0 :                         ANALYTICAL_STATISTICS_BRANCHES(CORRELATION_CURRENT_ROW, ;, ;);
    3926             :                 } break;
    3927          11 :                 default: {
    3928          11 :                         if (!(st = GDKinitialize_segment_tree())) {
    3929             :                                 res = GDK_FAIL;
    3930           0 :                                 goto cleanup;
    3931             :                         }
    3932         973 :                         ANALYTICAL_STATISTICS_BRANCHES(CORRELATION_OTHERS, ;, ;);
    3933             :                 }
    3934             :                 }
    3935             :         }
    3936             : 
    3937          46 :         BATsetcount(r, cnt);
    3938          46 :         r->tnonil = !has_nils;
    3939          46 :         r->tnil = has_nils;
    3940          46 :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
    3941           1 : overflow:
    3942           1 :         GDKerror("22003!overflow in calculation.\n");
    3943             :         res = GDK_FAIL;
    3944          47 : cleanup:
    3945          47 :         bat_iterator_end(&pi);
    3946          47 :         bat_iterator_end(&oi);
    3947          47 :         bat_iterator_end(&b1i);
    3948          47 :         bat_iterator_end(&b2i);
    3949          47 :         bat_iterator_end(&si);
    3950          47 :         bat_iterator_end(&ei);
    3951          47 :         BBPreclaim(st);
    3952          47 :         return res;
    3953           0 :   nosupport:
    3954           0 :         GDKerror("42000!correlation of type %s unsupported.\n", ATOMname(tpe));
    3955             :         res = GDK_FAIL;
    3956           0 :         goto cleanup;
    3957             : }

Generated by: LCOV version 1.14