Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented combined aggregates (computing all the values at once).

This shares memory and CPU so if you need more of the values this
is much more efficient than computing them separately.

The version got bumped to 1.2.0, the META.json and README were
updated to match this.
  • Loading branch information...
commit b746f261fcaa6f66b871a9fa849dc163d97e844f 1 parent 0ddfcf8
@tvondra authored
View
11 META.json
@@ -2,7 +2,7 @@
"name": "trimmed_aggregates",
"abstract": "Aggregate for computing trimmed avg/stddev/var (with outliers removed).",
"description": "An extension written in C that allows you to remove outliers before computing the basic statistical aggregates (AVG/STDDEV/VARIANCE).",
- "version": "1.1.0",
+ "version": "1.2.0",
"maintainer": "Tomas Vondra <tv@fuzzy.cz>",
"license": "gpl_3",
"prereqs": {
@@ -14,12 +14,9 @@
},
"provides": {
"quantile": {
- "file": "sql/trimmed_aggregates--1.0.sql",
- "version": "1.0.0"
- },
- "quantile": {
- "file": "sql/trimmed_aggregates--1.1.sql",
- "version": "1.1.0"
+ "file": "sql/trimmed_aggregates--1.2.sql",
+ "docfile": "README.md",
+ "version": "1.2.0"
}
},
"resources": {
View
22 README.md
@@ -33,8 +33,12 @@ AVG, VARIANCE, VAR_POP, VAR_SAMP, STDDEV, STDDEV_POP and STDDEV_SAMP
stddev_pop_trimmed(value, low_cut, high_cut)
stddev_samp_trimmed(value, low_cut, high_cut)
-All those functions are overloaded for double precision, int32 and
-int64 data types.
+* combined aggregate (computes all seven values at once)
+
+ trimmed(value, low_cut, high_cut)
+
+All those functions are overloaded for numeric, double precision, int32
+and int64 data types.
Using the aggregates
--------------------
@@ -51,6 +55,20 @@ will be computed using the middle 80%. On the other hand this
means 20% of the lowest and 10% of the highest values will be removed,
so the average will be computed using the remaining 70% of values.
+The combined aggregate computes and returns all values at once as an
+array. The values are stored in this order
+
+* average
+* var_pop
+* var_samp
+* variance
+* stddev_pop
+* stddev_samp
+* stddev
+
+If you need more of the values at once this may be much more efficient
+as it shares the memory and can compute the values with only two passes
+through the data (to compute exact variance and stddev).
Installation
------------
View
381 sql/trimmed_aggregates--1.2.sql
@@ -0,0 +1,381 @@
+/* accumulating data */
+CREATE OR REPLACE FUNCTION trimmed_append_double(p_pointer internal, p_element double precision, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS internal
+ AS 'trimmed_aggregates', 'trimmed_append_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_append_int32(p_pointer internal, p_element int, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS internal
+ AS 'trimmed_aggregates', 'trimmed_append_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_append_int64(p_pointer internal, p_element bigint, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS internal
+ AS 'trimmed_aggregates', 'trimmed_append_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_append_numeric(p_pointer internal, p_element numeric, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS internal
+ AS 'trimmed_aggregates', 'trimmed_append_numeric'
+ LANGUAGE C IMMUTABLE;
+
+/* average */
+CREATE OR REPLACE FUNCTION trimmed_avg_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_avg_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_avg_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_avg_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_avg_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_avg_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_avg_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_avg_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE avg_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_avg_double
+);
+
+CREATE AGGREGATE avg_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_avg_int32
+);
+
+CREATE AGGREGATE avg_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_avg_int64
+);
+
+CREATE AGGREGATE avg_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_avg_numeric
+);
+
+/* variance */
+CREATE OR REPLACE FUNCTION trimmed_var_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_var_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE var_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_double
+);
+
+CREATE AGGREGATE var_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_int32
+);
+
+CREATE AGGREGATE var_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_int64
+);
+
+CREATE AGGREGATE var_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_numeric
+);
+
+/* variance (population estimate) */
+CREATE OR REPLACE FUNCTION trimmed_var_pop_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_pop_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_pop_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_pop_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_pop_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_pop_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_pop_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_var_pop_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE var_pop_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_pop_double
+);
+
+CREATE AGGREGATE var_pop_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_pop_int32
+);
+
+CREATE AGGREGATE var_pop_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_pop_int64
+);
+
+CREATE AGGREGATE var_pop_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_pop_numeric
+);
+
+/* variance (sample estimate) */
+CREATE OR REPLACE FUNCTION trimmed_var_samp_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_samp_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_samp_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_samp_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_samp_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_samp_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_samp_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_var_samp_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE var_samp_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_samp_double
+);
+
+CREATE AGGREGATE var_samp_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_samp_int32
+);
+
+CREATE AGGREGATE var_samp_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_samp_int64
+);
+
+CREATE AGGREGATE var_samp_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_samp_numeric
+);
+
+/* variance */
+CREATE OR REPLACE FUNCTION trimmed_stddev_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_stddev_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE stddev_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_double
+);
+
+CREATE AGGREGATE stddev_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_int32
+);
+
+CREATE AGGREGATE stddev_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_int64
+);
+
+CREATE AGGREGATE stddev_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_numeric
+);
+
+/* variance (population estimate) */
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE stddev_pop_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_pop_double
+);
+
+CREATE AGGREGATE stddev_pop_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_pop_int32
+);
+
+CREATE AGGREGATE stddev_pop_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_pop_int64
+);
+
+CREATE AGGREGATE stddev_pop_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_pop_numeric
+);
+
+/* variance (sample estimate) */
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_double(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_int32(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_int64(p_pointer internal)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_numeric'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE stddev_samp_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_samp_double
+);
+
+CREATE AGGREGATE stddev_samp_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_samp_int32
+);
+
+CREATE AGGREGATE stddev_samp_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_samp_int64
+);
+
+CREATE AGGREGATE stddev_samp_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_samp_numeric
+);
+
+/* aggregate producing complete result (average, variances etc.) */
+
+CREATE OR REPLACE FUNCTION trimmed_double_array(p_pointer internal)
+ RETURNS double precision[]
+ AS 'trimmed_aggregates', 'trimmed_double_array'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_int32_array(p_pointer internal)
+ RETURNS double precision[]
+ AS 'trimmed_aggregates', 'trimmed_int32_array'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_int64_array(p_pointer internal)
+ RETURNS double precision[]
+ AS 'trimmed_aggregates', 'trimmed_int64_array'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_numeric_array(p_pointer internal)
+ RETURNS numeric[]
+ AS 'trimmed_aggregates', 'trimmed_numeric_array'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = internal,
+ FINALFUNC = trimmed_double_array
+);
+
+CREATE AGGREGATE trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = internal,
+ FINALFUNC = trimmed_int32_array
+);
+
+CREATE AGGREGATE trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = internal,
+ FINALFUNC = trimmed_int64_array
+);
+
+CREATE AGGREGATE trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_numeric_array
+);
View
309 src/trimmed.c
@@ -115,6 +115,12 @@ static int int32_comparator(const void *a, const void *b);
static int int64_comparator(const void *a, const void *b);
static int numeric_comparator(const void *a, const void *b);
+static Datum
+double_to_array(FunctionCallInfo fcinfo, double * d, int len);
+
+static Datum
+numeric_to_array(FunctionCallInfo fcinfo, Numeric * d, int len);
+
/* ACCUMULATE DATA */
PG_FUNCTION_INFO_V1(trimmed_append_double);
@@ -209,6 +215,18 @@ Datum trimmed_stddev_samp_int32(PG_FUNCTION_ARGS);
Datum trimmed_stddev_samp_int64(PG_FUNCTION_ARGS);
Datum trimmed_stddev_samp_numeric(PG_FUNCTION_ARGS);
+/* AVERAGE */
+
+PG_FUNCTION_INFO_V1(trimmed_double_array);
+PG_FUNCTION_INFO_V1(trimmed_int32_array);
+PG_FUNCTION_INFO_V1(trimmed_int64_array);
+PG_FUNCTION_INFO_V1(trimmed_numeric_array);
+
+Datum trimmed_double_array(PG_FUNCTION_ARGS);
+Datum trimmed_int32_array(PG_FUNCTION_ARGS);
+Datum trimmed_int64_array(PG_FUNCTION_ARGS);
+Datum trimmed_numeric_array(PG_FUNCTION_ARGS);
+
/* numeric helper */
static Numeric create_numeric(int value);
static Numeric add_numeric(Numeric a, Numeric b);
@@ -460,6 +478,65 @@ trimmed_avg_double(PG_FUNCTION_ARGS)
}
Datum
+trimmed_double_array(PG_FUNCTION_ARGS)
+{
+
+ int i;
+
+ /* average, var_pop, var_samp, variance, stddev_pop, stddev_samp, stddev */
+ double result[7] = {0, 0, 0, 0, 0, 0, 0};
+
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+ struct_double * data;
+
+ CHECK_AGG_CONTEXT("trimmed_double_array", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+ cnt = (to - from);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ qsort(data->elements, data->next, sizeof(double), &double_comparator);
+
+ /* average */
+ result[0] = 0;
+ result[1] = 1;
+ result[2] = 2;
+ for (i = from; i < to; i++) {
+ result[0] += data->elements[i]/cnt;
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ result[1] = (cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt); /* var_pop */
+ result[2] = (cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1)); /* var_samp */
+
+ /* variance */
+ result[3] = 0;
+ for (i = from; i < to; i++) {
+ result[3] += (data->elements[i] - result[0])*(data->elements[i] - result[0])/cnt;
+ }
+
+ result[4] = sqrt(result[1]); /* stddev_pop */
+ result[5] = sqrt(result[2]); /* stddev_samp */
+ result[6] = sqrt(result[3]); /* stddev */
+
+ return double_to_array(fcinfo, result, 7);
+
+}
+
+Datum
trimmed_avg_int32(PG_FUNCTION_ARGS)
{
@@ -496,6 +573,64 @@ trimmed_avg_int32(PG_FUNCTION_ARGS)
}
Datum
+trimmed_int32_array(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ /* average, var_pop, var_samp, variance, stddev_pop, stddev_samp, stddev */
+ double result[7] = {0, 0, 0, 0, 0, 0, 0};
+
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+ struct_int32 * data;
+
+ CHECK_AGG_CONTEXT("trimmed_int32_array", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+ cnt = (to - from);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ qsort(data->elements, data->next, sizeof(int32), &int32_comparator);
+
+ /* average */
+ result[0] = 0;
+ result[1] = 0;
+ result[2] = 0;
+ for (i = from; i < to; i++) {
+ result[0] += (double)data->elements[i]/cnt;
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + ((double)data->elements[i])*((double)data->elements[i]);
+ }
+
+ result[1] = (cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt); /* var_pop */
+ result[2] = (cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1)); /* var_samp */
+
+ /* variance */
+ result[3] = 0;
+ for (i = from; i < to; i++) {
+ result[3] += ((double)data->elements[i] - result[0])*((double)data->elements[i] - result[0])/cnt;
+ }
+
+ result[4] = sqrt(result[1]); /* stddev_pop */
+ result[5] = sqrt(result[2]); /* stddev_samp */
+ result[6] = sqrt(result[3]); /* stddev */
+
+ return double_to_array(fcinfo, result, 7);
+
+}
+
+Datum
trimmed_avg_int64(PG_FUNCTION_ARGS)
{
@@ -532,6 +667,64 @@ trimmed_avg_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_int64_array(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ /* average, var_pop, var_samp, variance, stddev_pop, stddev_samp, stddev */
+ double result[7] = {0, 0, 0, 0, 0, 0, 0};
+
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+ struct_int64 * data;
+
+ CHECK_AGG_CONTEXT("trimmed_int64_array", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+ cnt = (to - from);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ qsort(data->elements, data->next, sizeof(int64), &int64_comparator);
+
+ /* average */
+ result[0] = 0;
+ result[1] = 0;
+ result[2] = 0;
+ for (i = from; i < to; i++) {
+ result[0] += (double)data->elements[i]/cnt;
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + ((double)data->elements[i])*((double)data->elements[i]);
+ }
+
+ result[1] = (cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt); /* var_pop */
+ result[2] = (cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1)); /* var_samp */
+
+ /* variance */
+ result[3] = 0;
+ for (i = from; i < to; i++) {
+ result[3] += ((double)data->elements[i] - result[0])*((double)data->elements[i] - result[0])/cnt;
+ }
+
+ result[4] = sqrt(result[1]); /* stddev_pop */
+ result[5] = sqrt(result[2]); /* stddev_samp */
+ result[6] = sqrt(result[3]); /* stddev */
+
+ return double_to_array(fcinfo, result, 7);
+
+}
+
+Datum
trimmed_avg_numeric(PG_FUNCTION_ARGS)
{
@@ -571,6 +764,74 @@ trimmed_avg_numeric(PG_FUNCTION_ARGS)
}
Datum
+trimmed_numeric_array(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ /* average, var_pop, var_samp, variance, stddev_pop, stddev_samp, stddev */
+ Numeric result[7];
+ Numeric sum_x, sum_x2;
+
+ Numeric cntNumeric, cntNumeric_1;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_numeric_array", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ /* create numeric values */
+ cntNumeric = create_numeric(to-from);
+ cntNumeric_1 = create_numeric(to-from-1);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ /* average */
+ result[0] = create_numeric(0);
+ result[1] = create_numeric(0);
+ result[2] = create_numeric(0);
+
+ sum_x = create_numeric(0);
+ sum_x2 = create_numeric(0);
+
+ // cntNumeric = DatumGetNumeric(DirectFunctionCall1(int8_numeric, Int32GetDatum(cnt)));
+
+ for (i = from; i < to; i++) {
+ result[0] = add_numeric(result[0], div_numeric(data->elements[i], cntNumeric));
+ sum_x = add_numeric(sum_x, data->elements[i]);
+ sum_x2 = add_numeric(sum_x2, mul_numeric(data->elements[i], data->elements[i]));
+ }
+
+ result[1] = div_numeric(sub_numeric(mul_numeric(cntNumeric, sum_x2), mul_numeric(sum_x, sum_x)), mul_numeric(cntNumeric, cntNumeric)); /* var_pop */
+ result[2] = div_numeric(sub_numeric(mul_numeric(cntNumeric, sum_x2), mul_numeric(sum_x, sum_x)), mul_numeric(cntNumeric, cntNumeric_1)); /* var_samp */
+
+ /* variance */
+ result[3] = create_numeric(0);
+ for (i = from; i < to; i++) {
+ result[3] = add_numeric(result[3], div_numeric(mul_numeric(sub_numeric(data->elements[i],result[0]), sub_numeric(data->elements[i],result[0])), cntNumeric));
+ }
+
+ result[4] = sqrt_numeric(result[1]); /* stddev_pop */
+ result[5] = sqrt_numeric(result[2]); /* stddev_samp */
+ result[6] = sqrt_numeric(result[3]); /* stddev */
+
+ return numeric_to_array(fcinfo, result, 7);
+
+}
+
+Datum
trimmed_var_double(PG_FUNCTION_ARGS)
{
@@ -1652,4 +1913,50 @@ static Numeric sqrt_numeric(Numeric a) {
/* return the result */
return DatumGetNumeric(numeric_sqrt(&fcinfo));
-}
+}
+
+
+/*
+ * Helper functions used to prepare the resulting array (when there's
+ * an array of quantiles).
+ */
+static Datum
+double_to_array(FunctionCallInfo fcinfo, double * d, int len) {
+
+ ArrayBuildState *astate = NULL;
+ int i;
+
+ for (i = 0; i < len; i++) {
+
+ /* stash away this field */
+ astate = accumArrayResult(astate,
+ Float8GetDatum(d[i]),
+ false,
+ FLOAT8OID,
+ CurrentMemoryContext);
+ }
+
+ PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate,
+ CurrentMemoryContext));
+}
+
+static Datum
+numeric_to_array(FunctionCallInfo fcinfo, Numeric * d, int len) {
+
+ ArrayBuildState *astate = NULL;
+ int i;
+
+ for (i = 0; i < len; i++) {
+
+ /* stash away this field */
+ astate = accumArrayResult(astate,
+ NumericGetDatum(d[i]),
+ false,
+ NUMERICOID,
+ CurrentMemoryContext);
+
+ }
+
+ PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate,
+ CurrentMemoryContext));
+}
Please sign in to comment.
Something went wrong with that request. Please try again.