Changeset: 5e84ba611fc7 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=5e84ba611fc7 Modified Files: clients/Tests/MAL-signatures.stable.out clients/Tests/MAL-signatures.stable.out.int128 clients/Tests/exports.stable.out gdk/gdk_calc.c gdk/gdk_calc.h monetdb5/modules/mal/01_batcalc.mal monetdb5/modules/mal/01_batcalc.mal.sh monetdb5/modules/mal/batcalc.c Branch: default Log Message:
Implemented batcalc.min and batcalc.max for when one argument is scalar. This fixes bug 4057. diffs (truncated from 620 to 300 lines): diff --git a/clients/Tests/MAL-signatures.stable.out b/clients/Tests/MAL-signatures.stable.out --- a/clients/Tests/MAL-signatures.stable.out +++ b/clients/Tests/MAL-signatures.stable.out @@ -4967,12 +4967,28 @@ Ready. [ "batcalc", "lsh_noerror", "pattern batcalc.lsh_noerror(v:sht,b:bat[:sht],s:bat[:oid]):bat[:sht] ", "CMDbatLSH;", "Return V << B with candidates list, out of range second operand causes NIL value" ] [ "batcalc", "max", "pattern batcalc.max(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] [ "batcalc", "max", "pattern batcalc.max(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] [ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "min", "pattern batcalc.min(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] [ "batcalc", "min", "pattern batcalc.min(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] [ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "mod_noerror", "pattern batcalc.mod_noerror(b1:bat[:bte],b2:bat[:bte]):bat[:bte] ", "CMDbatMOD;", "Return B1 % B2, divide by zero causes NIL value" ] [ "batcalc", "mod_noerror", "pattern batcalc.mod_noerror(b1:bat[:bte],b2:bat[:bte],s:bat[:oid]):bat[:bte] ", "CMDbatMOD;", "Return B1 % B2 with candidates list, divide by zero causes NIL value" ] [ "batcalc", "mod_noerror", "pattern batcalc.mod_noerror(b1:bat[:bte],b2:bat[:dbl]):bat[:dbl] ", "CMDbatMOD;", "Return B1 % B2, divide by zero causes NIL value" ] diff --git a/clients/Tests/MAL-signatures.stable.out.int128 b/clients/Tests/MAL-signatures.stable.out.int128 --- a/clients/Tests/MAL-signatures.stable.out.int128 +++ b/clients/Tests/MAL-signatures.stable.out.int128 @@ -6618,12 +6618,28 @@ Ready. [ "batcalc", "lsh_noerror", "pattern batcalc.lsh_noerror(v:sht,b:bat[:sht],s:bat[:oid]):bat[:sht] ", "CMDbatLSH;", "Return V << B with candidates list, out of range second operand causes NIL value" ] [ "batcalc", "max", "pattern batcalc.max(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] [ "batcalc", "max", "pattern batcalc.max(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] +[ "batcalc", "max", "pattern batcalc.max(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX;", "Return bat with maximum value of each pair of inputs" ] [ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "max_no_nil", "pattern batcalc.max_no_nil(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMAX_no_nil;", "Return bat with maximum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "min", "pattern batcalc.min(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] [ "batcalc", "min", "pattern batcalc.min(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] +[ "batcalc", "min", "pattern batcalc.min(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN;", "Return bat with minimum value of each pair of inputs" ] [ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b1:bat[:any_1],b2:bat[:any_1]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b1:bat[:any_1],b2:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b:bat[:any_1],v:any_1):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(b:bat[:any_1],v:any_1,s:bat[:oid]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(v:any_1,b:bat[:any_1]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] +[ "batcalc", "min_no_nil", "pattern batcalc.min_no_nil(v:any_1,b:bat[:any_1],s:bat[:oid]):bat[:any_1] ", "CMDbatMIN_no_nil;", "Return bat with minimum value of each pair of inputs, ignoring nil values" ] [ "batcalc", "mod_noerror", "pattern batcalc.mod_noerror(b1:bat[:bte],b2:bat[:bte]):bat[:bte] ", "CMDbatMOD;", "Return B1 % B2, divide by zero causes NIL value" ] [ "batcalc", "mod_noerror", "pattern batcalc.mod_noerror(b1:bat[:bte],b2:bat[:bte],s:bat[:oid]):bat[:bte] ", "CMDbatMOD;", "Return B1 % B2 with candidates list, divide by zero causes NIL value" ] [ "batcalc", "mod_noerror", "pattern batcalc.mod_noerror(b1:bat[:bte],b2:bat[:dbl]):bat[:dbl] ", "CMDbatMOD;", "Return B1 % B2, divide by zero causes NIL value" ] diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -46,6 +46,10 @@ BAT *BATcalccstgt(const ValRecord *v, BA BAT *BATcalccstle(const ValRecord *v, BAT *b, BAT *s); BAT *BATcalccstlsh(const ValRecord *v, BAT *b, BAT *s, int abort_on_error); BAT *BATcalccstlt(const ValRecord *v, BAT *b, BAT *s); +BAT *BATcalccstmax(const ValRecord *v, BAT *b, BAT *s); +BAT *BATcalccstmax_no_nil(const ValRecord *v, BAT *b, BAT *s); +BAT *BATcalccstmin(const ValRecord *v, BAT *b, BAT *s); +BAT *BATcalccstmin_no_nil(const ValRecord *v, BAT *b, BAT *s); BAT *BATcalccstmod(const ValRecord *v, BAT *b, BAT *s, int tp, int abort_on_error); BAT *BATcalccstmul(const ValRecord *v, BAT *b, BAT *s, int tp, int abort_on_error); BAT *BATcalccstne(const ValRecord *v, BAT *b, BAT *s); @@ -78,8 +82,12 @@ BAT *BATcalclt(BAT *b1, BAT *b2, BAT *s) BAT *BATcalcltcst(BAT *b, const ValRecord *v, BAT *s); BAT *BATcalcmax(BAT *b1, BAT *b2, BAT *s); BAT *BATcalcmax_no_nil(BAT *b1, BAT *b2, BAT *s); +BAT *BATcalcmaxcst(BAT *b, const ValRecord *v, BAT *s); +BAT *BATcalcmaxcst_no_nil(BAT *b, const ValRecord *v, BAT *s); BAT *BATcalcmin(BAT *b1, BAT *b2, BAT *s); BAT *BATcalcmin_no_nil(BAT *b1, BAT *b2, BAT *s); +BAT *BATcalcmincst(BAT *b, const ValRecord *v, BAT *s); +BAT *BATcalcmincst_no_nil(BAT *b, const ValRecord *v, BAT *s); BAT *BATcalcmod(BAT *b1, BAT *b2, BAT *s, int tp, int abort_on_error); BAT *BATcalcmodcst(BAT *b, const ValRecord *v, BAT *s, int tp, int abort_on_error); BAT *BATcalcmul(BAT *b1, BAT *b2, BAT *s, int tp, int abort_on_error); diff --git a/gdk/gdk_calc.c b/gdk/gdk_calc.c --- a/gdk/gdk_calc.c +++ b/gdk/gdk_calc.c @@ -1110,6 +1110,182 @@ BATcalcmin_no_nil(BAT *b1, BAT *b2, BAT } BAT * +BATcalcmincst(BAT *b, const ValRecord *v, BAT *s) +{ + BAT *bn; + BUN nils; + BUN start, end, cnt; + BUN i; + const oid *restrict cand = NULL, *candend = NULL; + const void *restrict nil; + const void *p1, *p2; + BATiter bi; + int (*cmp)(const void *, const void *); + + BATcheck(b, "BATcalcmincst", NULL); + if (ATOMtype(b->ttype) != v->vtype) { + GDKerror("BATcalcmincst: inputs have incompatible types\n"); + return NULL; + } + + CANDINIT(b, s, start, end, cnt, cand, candend); + + nil = ATOMnilptr(b->ttype); + cmp = ATOMcompare(b->ttype); + p2 = VALptr(v); + if (cmp(p2, nil) == 0 || + (b->ttype == TYPE_void && b->tseqbase == oid_nil)) + return BATconstant(b->hseqbase, b->ttype == TYPE_oid ? TYPE_void : b->ttype, nil, cnt, TRANSIENT); + + bn = COLnew(b->hseqbase, b->ttype, cnt, TRANSIENT); + if (bn == NULL) + return NULL; + bi = bat_iterator(b); + + for (i = 0; i < start; i++) + bunfastapp(bn, nil); + nils = start; + for (i = start; i < end; i++) { + if (cand) { + if (i < *cand - b->hseqbase) { + nils++; + bunfastapp(bn, nil); + continue; + } + assert(i == *cand - b->hseqbase); + if (++cand == candend) + end = i + 1; + } + p1 = BUNtail(bi, i); + if (cmp(p1, nil) == 0) { + nils++; + p1 = nil; + } else if (cmp(p1, p2) > 0) { + p1 = p2; + } + bunfastapp(bn, p1); + } + for (i = end; i < cnt; i++) + bunfastapp(bn, nil); + nils += cnt - end; + bn->tnil = nils > 0; + bn->tnonil = nils == 0; + if (cnt <= 1) { + bn->tsorted = 1; + bn->trevsorted = 1; + bn->tkey = 1; + bn->tdense = ATOMtype(b->ttype) == TYPE_oid; + if (bn->tdense) + bn->tseqbase = cnt == 1 ? *(oid*)Tloc(bn,0) : 0; + } else { + bn->tsorted = 0; + bn->trevsorted = 0; + bn->tkey = 0; + bn->tdense = 0; + } + return bn; + bunins_failed: + BBPreclaim(bn); + return NULL; +} + +BAT * +BATcalccstmin(const ValRecord *v, BAT *b, BAT *s) +{ + return BATcalcmincst(b, v, s); +} + +BAT * +BATcalcmincst_no_nil(BAT *b, const ValRecord *v, BAT *s) +{ + BAT *bn; + BUN nils; + BUN start, end, cnt; + BUN i; + const oid *restrict cand = NULL, *candend = NULL; + const void *restrict nil; + const void *p1, *p2; + BATiter bi; + int (*cmp)(const void *, const void *); + + BATcheck(b, "BATcalcmincst", NULL); + if (ATOMtype(b->ttype) != v->vtype) { + GDKerror("BATcalcmincst: inputs have incompatible types\n"); + return NULL; + } + + CANDINIT(b, s, start, end, cnt, cand, candend); + + nil = ATOMnilptr(b->ttype); + cmp = ATOMcompare(b->ttype); + p2 = VALptr(v); + if (b->ttype == TYPE_void && + b->tseqbase == oid_nil && + * (const oid *) p2 == oid_nil) + return BATconstant(b->hseqbase, TYPE_void, &oid_nil, cnt, TRANSIENT); + + bn = COLnew(b->hseqbase, ATOMtype(b->ttype), cnt, TRANSIENT); + if (bn == NULL) + return NULL; + bi = bat_iterator(b); + if (cmp(p2, nil) == 0) + p2 = NULL; + + for (i = 0; i < start; i++) + bunfastapp(bn, nil); + nils = start; + for (i = start; i < end; i++) { + if (cand) { + if (i < *cand - b->hseqbase) { + nils++; + bunfastapp(bn, nil); + continue; + } + assert(i == *cand - b->hseqbase); + if (++cand == candend) + end = i + 1; + } + p1 = BUNtail(bi, i); + if (p2) { + if (cmp(p1, nil) == 0) { + p1 = p2; + } else if (cmp(p1, p2) > 0) { + p1 = p2; + } + } + bunfastapp(bn, p1); + } + for (i = end; i < cnt; i++) + bunfastapp(bn, nil); + nils += cnt - end; + bn->tnil = nils > 0; + bn->tnonil = nils == 0; + if (cnt <= 1) { + bn->tsorted = 1; + bn->trevsorted = 1; + bn->tkey = 1; + bn->tdense = ATOMtype(b->ttype) == TYPE_oid; + if (bn->tdense) + bn->tseqbase = cnt == 1 ? *(oid*)Tloc(bn,0) : 0; + } else { + bn->tsorted = 0; + bn->trevsorted = 0; + bn->tkey = 0; + bn->tdense = 0; + } + return bn; + bunins_failed: + BBPreclaim(bn); + return NULL; +} + +BAT * +BATcalccstmin_no_nil(const ValRecord *v, BAT *b, BAT *s) +{ + return BATcalcmincst_no_nil(b, v, s); +} + +BAT * BATcalcmax(BAT *b1, BAT *b2, BAT *s) { BAT *bn; @@ -1275,6 +1451,182 @@ BATcalcmax_no_nil(BAT *b1, BAT *b2, BAT return NULL; } +BAT * +BATcalcmaxcst(BAT *b, const ValRecord *v, BAT *s) +{ + BAT *bn; + BUN nils; + BUN start, end, cnt; + BUN i; + const oid *restrict cand = NULL, *candend = NULL; + const void *restrict nil; + const void *p1, *p2; + BATiter bi; + int (*cmp)(const void *, const void *); + + BATcheck(b, "BATcalcmaxcst", NULL); + if (ATOMtype(b->ttype) != v->vtype) { + GDKerror("BATcalcmaxcst: inputs have incompatible types\n"); + return NULL; + } + _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list