Skip to content
Browse files

Rewritten to C, reorganized to match PGXN structure, added META.json …

…etc.
  • Loading branch information...
1 parent 5ab59fe commit fa3b7bbda678ec239861d7d5ff9d7bd85ccfead0 @tvondra committed Nov 5, 2011
Showing with 1,378 additions and 498 deletions.
  1. +34 −0 META.json
  2. +9 −1 Makefile
  3. +13 −26 README
  4. +253 −0 sql/trimmed_aggregates--1.0.sql
  5. +1,069 −0 src/trimmed.c
  6. +0 −471 trimmed_aggregates--1.0.sql
View
34 META.json
@@ -0,0 +1,34 @@
+{
+ "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.0.0",
+ "maintainer": "Tomas Vondra <tv@fuzzy.cz>",
+ "license": "gpl_3",
+ "prereqs": {
+ "runtime": {
+ "requires": {
+ "PostgreSQL": "8.4.0"
+ }
+ }
+ },
+ "provides": {
+ "quantile": {
+ "file": "sql/trimmed_aggregates--1.0.sql",
+ "version": "1.0.0"
+ }
+ },
+ "resources": {
+ "repository": {
+ "url": "https://tvondra@github.com/tvondra/trimmed_aggregates.git",
+ "web": "http://github.com/tvondra/trimmed_aggregates",
+ "type": "git"
+ }
+ },
+ "tags" : ["aggregate", "outlier", "trimmed", "variance", "average", "sample", "estimate"],
+ "meta-spec": {
+ "version": "1.0.0",
+ "url": "http://pgxn.org/meta/spec.txt"
+ },
+ "release_status" : "testing"
+}
View
10 Makefile
@@ -1,8 +1,16 @@
+MODULE_big = trimmed_aggregates
+OBJS = src/trimmed.o
+
EXTENSION = trimmed_aggregates
-DATA = trimmed_aggregates--1.0.sql
+DATA = sql/trimmed_aggregates--1.0.sql
+MODULES = trimmed_aggregates
CFLAGS=`pg_config --includedir-server`
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
+
+trimmed_aggregates.so: src/trimmed.o
+
+src/trimmed.o: src/trimmed.c
View
39 README
@@ -18,51 +18,38 @@ http://www.postgresql.org/docs/9.1/static/functions-aggregate.html, i.e.
AVG, VARIANCE, VAR_POP, VAR_SAMP, STDDEV, STDDEV_POP and STDDEV_SAMP
== AVG ==
- avg_trimmed(value numeric, low_cut float, high_cut float)
- avg_trimmed(value numeric, both_cut float)
- == VARIANCE ==
- var_trimmed(value numeric, low_cut float, high_cut float);
- var_trimmed(value numeric, both_cut float);
+ avg_trimmed(value, low_cut, high_cut)
- == VAR_POP (population variance) ==
- var_pop_trimmed(value numeric, low_cut float, high_cut float)
- var_pop_trimmed(value numeric, both_cut float)
+ == VARIANCE ==
- == VAR_SAMP (sample variance) ==
- var_samp_trimmed(value numeric, low_cut float, high_cut float)
- var_samp_trimmed(value numeric, both_cut float)
+ var_trimmed(value, low_cut, high_cut);
+ var_pop_trimmed(value, low_cut, high_cut)
+ var_samp_trimmed(value, low_cut, high_cut)
== STDDEV (standard deviation) ==
- stddev_trimmed(value numeric, low_cut float, high_cut float)
- stddev_trimmed(value numeric, both_cut float)
- == STDDEV_POP (population standard deviation) ==
- stddev_pop_trimmed(value numeric, low_cut float, high_cut float)
- stddev_pop_trimmed(value numeric, both_cut float)
-
- == STDDEV_SAMP (sample standard deviation) ==
- stddev_samp_trimmed(value numeric, low_cut float, high_cut float)
- stddev_samp_trimmed(value numeric, both_cut float)
+ stddev_trimmed(value, low_cut, high_cut)
+ 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.
Using the aggregates
--------------------
All the aggregates are used the same way so let's see how to use the
avg_trimmed aggregate. For example this
- SELECT avg_trimmed(i, 0.1) FROM generate_series(1,1000) s(i);
+ SELECT avg_trimmed(i, 0.1, 0.1) FROM generate_series(1,1000) s(i);
means 10% of the values will be removed on both ends, and the average
-will be computed using the middle 80%.
-
-The more complicated version allows you to remove different number of
-lowest and highest values, so this
+will be computed using the middle 80%. On the other hand this
SELECT avg_trimmed(i, 0.2, 0.1) FROM generate_series(1,1000) s(i);
means 20% of the lowest and 10% of the highest values will be removed,
-and the average will be computed using the remaining 70% of values.
+so the average will be computed using the remaining 70% of values.
Installation
View
253 sql/trimmed_aggregates--1.0.sql
@@ -0,0 +1,253 @@
+/* accumulating data */
+CREATE OR REPLACE FUNCTION trimmed_append_double(p_pointer bigint, p_element double precision, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS bigint
+ AS 'trimmed_aggregates', 'trimmed_append_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_append_int32(p_pointer bigint, p_element int, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS bigint
+ AS 'trimmed_aggregates', 'trimmed_append_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_append_int64(p_pointer bigint, p_element bigint, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS bigint
+ AS 'trimmed_aggregates', 'trimmed_append_int64'
+ LANGUAGE C IMMUTABLE;
+
+/* average */
+CREATE OR REPLACE FUNCTION trimmed_avg_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_avg_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_avg_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_avg_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_avg_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_avg_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE avg_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_avg_double
+);
+
+CREATE AGGREGATE avg_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_avg_int32
+);
+
+CREATE AGGREGATE avg_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_avg_int64
+);
+
+/* variance */
+CREATE OR REPLACE FUNCTION trimmed_var_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE var_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_double
+);
+
+CREATE AGGREGATE var_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_int32
+);
+
+CREATE AGGREGATE var_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_int64
+);
+
+/* variance (population estimate) */
+CREATE OR REPLACE FUNCTION trimmed_var_pop_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_pop_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_pop_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_pop_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_pop_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_pop_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE var_pop_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_pop_double
+);
+
+CREATE AGGREGATE var_pop_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_pop_int32
+);
+
+CREATE AGGREGATE var_pop_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_pop_int64
+);
+
+/* variance (sample estimate) */
+CREATE OR REPLACE FUNCTION trimmed_var_samp_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_samp_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_samp_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_samp_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_var_samp_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_var_samp_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE var_samp_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_samp_double
+);
+
+CREATE AGGREGATE var_samp_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_samp_int32
+);
+
+CREATE AGGREGATE var_samp_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_var_samp_int64
+);
+
+/* variance */
+CREATE OR REPLACE FUNCTION trimmed_stddev_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE stddev_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_double
+);
+
+CREATE AGGREGATE stddev_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_int32
+);
+
+CREATE AGGREGATE stddev_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_int64
+);
+
+/* variance (population estimate) */
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE stddev_pop_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_pop_double
+);
+
+CREATE AGGREGATE stddev_pop_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_pop_int32
+);
+
+CREATE AGGREGATE stddev_pop_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_pop_int64
+);
+
+/* variance (sample estimate) */
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_double(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_double'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_int32(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_int32'
+ LANGUAGE C IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_int64(p_pointer bigint)
+ RETURNS double precision
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_int64'
+ LANGUAGE C IMMUTABLE;
+
+CREATE AGGREGATE stddev_samp_trimmed(double precision, double precision, double precision) (
+ SFUNC = trimmed_append_double,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_samp_double
+);
+
+CREATE AGGREGATE stddev_samp_trimmed(int, double precision, double precision) (
+ SFUNC = trimmed_append_int32,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_samp_int32
+);
+
+CREATE AGGREGATE stddev_samp_trimmed(bigint, double precision, double precision) (
+ SFUNC = trimmed_append_int64,
+ STYPE = bigint,
+ FINALFUNC = trimmed_stddev_samp_int64
+);
View
1,069 src/trimmed.c
@@ -0,0 +1,1069 @@
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "postgres.h"
+#include "utils/palloc.h"
+#include "utils/array.h"
+#include "utils/lsyscache.h"
+#include "nodes/memnodes.h"
+#include "fmgr.h"
+#include "catalog/pg_type.h"
+
+#include "funcapi.h"
+
+#ifdef PG_MODULE_MAGIC
+PG_MODULE_MAGIC;
+#endif
+
+#define SLICE_SIZE 1024
+
+/* Structures used to keep the data - the 'elements' array is extended
+ * on the fly if needed. */
+
+typedef struct struct_double {
+
+ int nelements;
+ int next;
+
+ double cut_lower;
+ double cut_upper;
+
+ double * elements;
+
+} struct_double;
+
+typedef struct struct_int32 {
+
+ int nelements;
+ int next;
+
+ double cut_lower;
+ double cut_upper;
+
+ int32 * elements;
+
+} struct_int32;
+
+typedef struct struct_int64 {
+
+ int nelements;
+ int next;
+
+ double cut_lower;
+ double cut_upper;
+
+ int64 * elements;
+
+} struct_int64;
+
+/* comparators, used for qsort */
+
+static int double_comparator(const void *a, const void *b);
+static int int32_comparator(const void *a, const void *b);
+static int int64_comparator(const void *a, const void *b);
+
+/* ACCUMULATE DATA */
+
+PG_FUNCTION_INFO_V1(trimmed_append_double);
+PG_FUNCTION_INFO_V1(trimmed_append_int32);
+PG_FUNCTION_INFO_V1(trimmed_append_int64);
+
+Datum trimmed_append_double(PG_FUNCTION_ARGS);
+Datum trimmed_append_int32(PG_FUNCTION_ARGS);
+Datum trimmed_append_int64(PG_FUNCTION_ARGS);
+
+/* AVERAGE */
+
+PG_FUNCTION_INFO_V1(trimmed_avg_double);
+PG_FUNCTION_INFO_V1(trimmed_avg_int32);
+PG_FUNCTION_INFO_V1(trimmed_avg_int64);
+
+Datum trimmed_avg_double(PG_FUNCTION_ARGS);
+Datum trimmed_avg_int32(PG_FUNCTION_ARGS);
+Datum trimmed_avg_int64(PG_FUNCTION_ARGS);
+
+/* VARIANCE */
+
+/* exact */
+PG_FUNCTION_INFO_V1(trimmed_var_double);
+PG_FUNCTION_INFO_V1(trimmed_var_int32);
+PG_FUNCTION_INFO_V1(trimmed_var_int64);
+
+Datum trimmed_var_double(PG_FUNCTION_ARGS);
+Datum trimmed_var_int32(PG_FUNCTION_ARGS);
+Datum trimmed_var_int64(PG_FUNCTION_ARGS);
+
+/* population estimate */
+PG_FUNCTION_INFO_V1(trimmed_var_pop_double);
+PG_FUNCTION_INFO_V1(trimmed_var_pop_int32);
+PG_FUNCTION_INFO_V1(trimmed_var_pop_int64);
+
+Datum trimmed_var_pop_double(PG_FUNCTION_ARGS);
+Datum trimmed_var_pop_int32(PG_FUNCTION_ARGS);
+Datum trimmed_var_pop_int64(PG_FUNCTION_ARGS);
+
+/* sample estimate */
+PG_FUNCTION_INFO_V1(trimmed_var_samp_double);
+PG_FUNCTION_INFO_V1(trimmed_var_samp_int32);
+PG_FUNCTION_INFO_V1(trimmed_var_samp_int64);
+
+Datum trimmed_var_samp_double(PG_FUNCTION_ARGS);
+Datum trimmed_var_samp_int32(PG_FUNCTION_ARGS);
+Datum trimmed_var_samp_int64(PG_FUNCTION_ARGS);
+
+/* STANDARD DEVIATION */
+
+/* exact */
+PG_FUNCTION_INFO_V1(trimmed_stddev_double);
+PG_FUNCTION_INFO_V1(trimmed_stddev_int32);
+PG_FUNCTION_INFO_V1(trimmed_stddev_int64);
+
+Datum trimmed_stddev_double(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_int32(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_int64(PG_FUNCTION_ARGS);
+
+/* population estimate */
+PG_FUNCTION_INFO_V1(trimmed_stddev_pop_double);
+PG_FUNCTION_INFO_V1(trimmed_stddev_pop_int32);
+PG_FUNCTION_INFO_V1(trimmed_stddev_pop_int64);
+
+Datum trimmed_stddev_pop_double(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_pop_int32(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_pop_int64(PG_FUNCTION_ARGS);
+
+/* sample estimate */
+PG_FUNCTION_INFO_V1(trimmed_stddev_samp_double);
+PG_FUNCTION_INFO_V1(trimmed_stddev_samp_int32);
+PG_FUNCTION_INFO_V1(trimmed_stddev_samp_int64);
+
+Datum trimmed_stddev_samp_double(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_samp_int32(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_samp_int64(PG_FUNCTION_ARGS);
+
+
+/* These functions use a bit dirty trick to pass the data - the int
+ * value is actually a pointer to the array allocated in the parent
+ * memory context. A bit ugly but works fine.
+ *
+ * The memory consumption might be a problem, as all the values are
+ * kept in the memory - for example 1.000.000 of 8-byte values (bigint)
+ * requires about 8MB of memory.
+ */
+
+Datum
+trimmed_append_double(PG_FUNCTION_ARGS)
+{
+
+ struct_double * data;
+
+ double element;
+
+ MemoryContext oldcontext = MemoryContextSwitchTo(CurrentMemoryContext->parent);
+
+ if (PG_ARGISNULL(0)) {
+
+ data = (struct_double*)palloc(sizeof(struct_double));
+ data->elements = (double*)palloc(SLICE_SIZE*sizeof(double));
+ data->nelements = SLICE_SIZE;
+ data->next = 0;
+
+ /* how much to cut */
+ data->cut_lower = PG_GETARG_FLOAT8(2);
+ data->cut_upper = PG_GETARG_FLOAT8(3);
+
+ } else {
+ data = (struct_double*)PG_GETARG_INT64(0);
+ }
+
+ if (! PG_ARGISNULL(1)) {
+
+ element = PG_GETARG_FLOAT8(1);
+
+ if (data->next > data->nelements-1) {
+ data->elements = (double*)repalloc(data->elements, sizeof(double)*(data->nelements + SLICE_SIZE));
+ data->nelements = data->nelements + SLICE_SIZE;
+ }
+
+ data->elements[data->next++] = element;
+ }
+
+ MemoryContextSwitchTo(oldcontext);
+
+ PG_RETURN_INT64((int64)data);
+
+}
+
+Datum
+trimmed_append_int32(PG_FUNCTION_ARGS)
+{
+
+ struct_int32 * data;
+
+ int32 element;
+
+ MemoryContext oldcontext = MemoryContextSwitchTo(CurrentMemoryContext->parent);
+
+ if (PG_ARGISNULL(0)) {
+
+ data = (struct_int32*)palloc(sizeof(struct_int32));
+ data->elements = (int32*)palloc(SLICE_SIZE*sizeof(int32));
+ data->nelements = SLICE_SIZE;
+ data->next = 0;
+
+ /* how much to cut */
+ data->cut_lower = PG_GETARG_FLOAT8(2);
+ data->cut_upper = PG_GETARG_FLOAT8(3);
+
+ } else {
+ data = (struct_int32*)PG_GETARG_INT64(0);
+ }
+
+ if (! PG_ARGISNULL(1)) {
+
+ element = PG_GETARG_INT32(1);
+
+ if (data->next > data->nelements-1) {
+ data->elements = (int32*)repalloc(data->elements, sizeof(int32)*(data->nelements + SLICE_SIZE));
+ data->nelements = data->nelements + SLICE_SIZE;
+ }
+
+ data->elements[data->next++] = element;
+
+ }
+
+ MemoryContextSwitchTo(oldcontext);
+
+ PG_RETURN_INT64((int64)data);
+
+}
+
+Datum
+trimmed_append_int64(PG_FUNCTION_ARGS)
+{
+
+ struct_int64 * data;
+
+ int64 element;
+
+ MemoryContext oldcontext = MemoryContextSwitchTo(CurrentMemoryContext->parent);
+
+ if (PG_ARGISNULL(0)) {
+
+ data = (struct_int64*)palloc(sizeof(struct_int64));
+ data->elements = (int64*)palloc(SLICE_SIZE*sizeof(int64));
+ data->nelements = SLICE_SIZE;
+ data->next = 0;
+
+ /* how much to cut */
+ data->cut_lower = PG_GETARG_FLOAT8(2);
+ data->cut_upper = PG_GETARG_FLOAT8(3);
+
+ } else {
+ data = (struct_int64*)PG_GETARG_INT64(0);
+ }
+
+ if (! PG_ARGISNULL(1)) {
+
+ element = PG_GETARG_INT64(1);
+
+ if (data->next > data->nelements-1) {
+ data->elements = (int64*)repalloc(data->elements, sizeof(int64)*(data->nelements + SLICE_SIZE));
+ data->nelements = data->nelements + SLICE_SIZE;
+ }
+
+ data->elements[data->next++] = element;
+
+ }
+
+ MemoryContextSwitchTo(oldcontext);
+
+ PG_RETURN_INT64((int64)data);
+
+}
+
+Datum
+trimmed_avg_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ int from, to;
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ qsort(data->elements, data->next, sizeof(double), &double_comparator);
+
+ for (i = from; i < to; i++) {
+ result = result + data->elements[i]/(to - from + 1);
+ }
+
+ PG_RETURN_FLOAT8(result);
+
+}
+
+Datum
+trimmed_avg_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ int from, to;
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ qsort(data->elements, data->next, sizeof(int32), &int32_comparator);
+
+ for (i = from; i < to; i++) {
+ result = result + data->elements[i]/(to - from + 1);
+ }
+
+ PG_RETURN_FLOAT8(result);
+
+}
+
+Datum
+trimmed_avg_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ int from, to;
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ qsort(data->elements, data->next, sizeof(int64), &int64_comparator);
+
+ for (i = from; i < to; i++) {
+ result = result + data->elements[i]/(to - from + 1);
+ }
+
+ PG_RETURN_FLOAT8(result);
+
+}
+
+Datum
+trimmed_var_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ double avg = 0;
+ int from, to, cnt;
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ avg = avg + data->elements[i]/cnt;
+ }
+
+ for (i = from; i < to; i++) {
+ result = result + (data->elements[i] - avg)*(data->elements[i] - avg)/cnt;
+ }
+
+ PG_RETURN_FLOAT8(result);
+
+}
+
+Datum
+trimmed_var_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ double avg = 0;
+ int from, to, cnt;
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ avg = avg + ((double)data->elements[i])/cnt;
+ }
+
+ for (i = from; i < to; i++) {
+ result = result + (data->elements[i] - avg)*(data->elements[i] - avg)/cnt;
+ }
+
+ PG_RETURN_FLOAT8(result);
+
+}
+
+Datum
+trimmed_var_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ double avg = 0;
+ int from, to, cnt;
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ avg = avg + ((double)data->elements[i])/cnt;
+ }
+
+ for (i = from; i < to; i++) {
+ result = result + (data->elements[i] - avg)*(data->elements[i] - avg)/cnt;
+ }
+
+ PG_RETURN_FLOAT8(result);
+
+}
+
+Datum
+trimmed_var_pop_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 ((cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt));
+
+}
+
+Datum
+trimmed_var_pop_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 ((cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt));
+
+}
+
+Datum
+trimmed_var_pop_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 ((cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt));
+
+}
+
+Datum
+trimmed_var_samp_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 ((cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1)));
+
+}
+
+Datum
+trimmed_var_samp_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 ((cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1)));
+
+}
+
+Datum
+trimmed_var_samp_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 ((cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1)));
+
+}
+
+Datum
+trimmed_stddev_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ double avg = 0;
+ int from, to, cnt;
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ avg = avg + data->elements[i]/cnt;
+ }
+
+ for (i = from; i < to; i++) {
+ result = result + (data->elements[i] - avg)*(data->elements[i] - avg)/cnt;
+ }
+
+ PG_RETURN_FLOAT8 (sqrt(result));
+
+}
+
+Datum
+trimmed_stddev_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ double avg = 0;
+ int from, to, cnt;
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ avg = avg + ((double)data->elements[i])/cnt;
+ }
+
+ for (i = from; i < to; i++) {
+ result = result + (data->elements[i] - avg)*(data->elements[i] - avg)/cnt;
+ }
+
+ PG_RETURN_FLOAT8 (sqrt(result));
+
+}
+
+Datum
+trimmed_stddev_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double result = 0;
+ double avg = 0;
+ int from, to, cnt;
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ avg = avg + ((double)data->elements[i])/cnt;
+ }
+
+ for (i = from; i < to; i++) {
+ result = result + (data->elements[i] - avg)*(data->elements[i] - avg)/cnt;
+ }
+
+ PG_RETURN_FLOAT8 (sqrt(result));
+
+}
+
+
+Datum
+trimmed_stddev_pop_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 (sqrt((cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt)));
+
+}
+
+Datum
+trimmed_stddev_pop_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 (sqrt((cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt)));
+
+}
+
+Datum
+trimmed_stddev_pop_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 (sqrt((cnt * sum_x2 - sum_x * sum_x) / (cnt * cnt)));
+
+}
+
+Datum
+trimmed_stddev_samp_double(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_double * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_double*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 (sqrt((cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1))));
+
+}
+
+Datum
+trimmed_stddev_samp_int32(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int32 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int32*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 (sqrt((cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1))));
+
+}
+
+Datum
+trimmed_stddev_samp_int64(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ double sum_x = 0, sum_x2 = 0;
+ int from, to, cnt;
+
+
+ struct_int64 * data;
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_int64*)PG_GETARG_INT64(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);
+
+ for (i = from; i < to; i++) {
+ sum_x = sum_x + data->elements[i];
+ sum_x2 = sum_x2 + data->elements[i]*data->elements[i];
+ }
+
+ PG_RETURN_FLOAT8 (sqrt((cnt * sum_x2 - sum_x * sum_x) / (cnt * (cnt - 1))));
+
+}
+
+static int double_comparator(const void *a, const void *b) {
+ double af = (*(double*)a);
+ double bf = (*(double*)b);
+ return (af > bf) - (af < bf);
+}
+
+static int int32_comparator(const void *a, const void *b) {
+ int32 af = (*(int32*)a);
+ int32 bf = (*(int32*)b);
+ return (af > bf) - (af < bf);
+}
+
+static int int64_comparator(const void *a, const void *b) {
+ int64 af = (*(int64*)a);
+ int64 bf = (*(int64*)b);
+ return (af > bf) - (af < bf);
+}
View
471 trimmed_aggregates--1.0.sql
@@ -1,471 +0,0 @@
-/* a custom data type serving as a state for the trimmed aggregate functions */
-CREATE TYPE trimmed_agg_state AS (
- vals numeric[],
- low_cut float,
- high_cut float
-);
-
-/* appends data to the array and sets the low/high cut */
-CREATE OR REPLACE FUNCTION trimmed_append(p_state trimmed_agg_state, p_element numeric, p_low float, p_high float) RETURNS trimmed_agg_state
-AS $$
-BEGIN
- p_state.vals := array_append(p_state.vals, p_element);
- p_state.low_cut := p_low;
- p_state.high_cut := p_high;
- RETURN p_state;
-END
-$$ LANGUAGE plpgsql;
-
-/* appends data to the state, when there is a single cut value */
-CREATE OR REPLACE FUNCTION trimmed_append(p_state trimmed_agg_state, p_element numeric, p_cut float) RETURNS trimmed_agg_state
-AS $$
-BEGIN
- p_state.vals := array_append(p_state.vals, p_element);
- p_state.low_cut := p_cut;
- p_state.high_cut := p_cut;
- RETURN p_state;
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute average (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION avg_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_result := v_result + v_tmp[v_idx];
- v_cnt := v_cnt + 1;
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN v_result/v_cnt;
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute variance (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION var_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_average numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
- v_sum_x numeric := 0;
- v_sum_x2 numeric := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_average := v_average + v_tmp[v_idx];
- v_cnt := v_cnt + 1;
- END IF;
- END LOOP;
-
- v_average := v_average / v_cnt;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_result := v_result + (v_tmp[v_idx] - v_average) * (v_tmp[v_idx] - v_average);
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN v_result/v_cnt;
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute variance (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION var_pop_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_average numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
- v_sum_x numeric := 0;
- v_sum_x2 numeric := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_cnt := v_cnt + 1;
- v_sum_x := v_sum_x + v_tmp[v_idx];
- v_sum_x2 := v_sum_x2 + v_tmp[v_idx] * v_tmp[v_idx];
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN (v_cnt * v_sum_x2 - v_sum_x * v_sum_x) / (v_cnt * v_cnt);
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute variance (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION var_samp_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_average numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
- v_sum_x numeric := 0;
- v_sum_x2 numeric := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_cnt := v_cnt + 1;
- v_sum_x := v_sum_x + v_tmp[v_idx];
- v_sum_x2 := v_sum_x2 + v_tmp[v_idx] * v_tmp[v_idx];
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN (v_cnt * v_sum_x2 - v_sum_x * v_sum_x) / (v_cnt * (v_cnt - 1));
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute standard deviation (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION stddev_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_average numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_average := v_average + v_tmp[v_idx];
- v_cnt := v_cnt + 1;
- END IF;
- END LOOP;
-
- v_average := v_average / v_cnt;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_result := v_result + (v_tmp[v_idx] - v_average) * (v_tmp[v_idx] - v_average);
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN sqrt(v_result/v_cnt);
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute variance (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION stddev_pop_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_average numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
- v_sum_x numeric := 0;
- v_sum_x2 numeric := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_cnt := v_cnt + 1;
- v_sum_x := v_sum_x + v_tmp[v_idx];
- v_sum_x2 := v_sum_x2 + v_tmp[v_idx] * v_tmp[v_idx];
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN sqrt((v_cnt * v_sum_x2 - v_sum_x * v_sum_x) / (v_cnt * v_cnt));
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-/* processes the aggregate state to compute variance (at the end of aggregate evaluation) */
-CREATE OR REPLACE FUNCTION stddev_samp_trimmed_final(p_state trimmed_agg_state) RETURNS numeric
-AS $$
-DECLARE
- v_result numeric := 0;
- v_average numeric := 0;
- v_tmp numeric[];
- v_length int;
- v_from int;
- v_to int;
- v_cnt int := 0;
- v_sum_x numeric := 0;
- v_sum_x2 numeric := 0;
-BEGIN
-
- SELECT ARRAY(
- SELECT p_state.vals[s.i] AS "foo"
- FROM
- generate_series(array_lower(p_state.vals,1), array_upper(p_state.vals,1)) AS s(i)
- ORDER BY foo
- ) INTO v_tmp;
-
- v_length := array_length(p_state.vals, 1);
-
- v_from := 1 + floor(v_length*p_state.low_cut);
- v_to := v_length - floor(v_length*p_state.high_cut);
-
- IF (v_from > v_to) THEN
- RETURN NULL;
- END IF;
-
- FOR v_idx IN v_from..v_to LOOP
- IF (v_tmp[v_idx] IS NOT NULL) THEN
- v_cnt := v_cnt + 1;
- v_sum_x := v_sum_x + v_tmp[v_idx];
- v_sum_x2 := v_sum_x2 + v_tmp[v_idx] * v_tmp[v_idx];
- END IF;
- END LOOP;
-
- IF (v_cnt > 0) THEN
- RETURN sqrt((v_cnt * v_sum_x2 - v_sum_x * v_sum_x) / (v_cnt * (v_cnt - 1)));
- ELSE
- RETURN 0;
- END IF;
-
-END
-$$ LANGUAGE plpgsql;
-
-
-/* trimmed average */
-CREATE AGGREGATE avg_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = avg_trimmed_final
-);
-
-/* trimmed average */
-CREATE AGGREGATE avg_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = avg_trimmed_final
-);
-
-/* trimmed variance */
-CREATE AGGREGATE var_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = var_trimmed_final
-);
-
-/* trimmed variance */
-CREATE AGGREGATE var_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = var_trimmed_final
-);
-
-/* trimmed variance (population) */
-CREATE AGGREGATE var_pop_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = var_pop_trimmed_final
-);
-
-/* trimmed variance (population) */
-CREATE AGGREGATE var_pop_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = var_pop_trimmed_final
-);
-
-/* trimmed variance (sample) */
-CREATE AGGREGATE var_samp_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = var_samp_trimmed_final
-);
-
-/* trimmed variance (sample) */
-CREATE AGGREGATE var_samp_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = var_samp_trimmed_final
-);
-
-/* trimmed standard deviation */
-CREATE AGGREGATE stddev_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = stddev_trimmed_final
-);
-
-/* trimmed standard deviation */
-CREATE AGGREGATE stddev_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = stddev_trimmed_final
-);
-
-/* trimmed standard deviation (population) */
-CREATE AGGREGATE stddev_pop_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = stddev_pop_trimmed_final
-);
-
-/* trimmed standard deviation (population) */
-CREATE AGGREGATE stddev_pop_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = stddev_pop_trimmed_final
-);
-
-/* trimmed standard deviation (sample) */
-CREATE AGGREGATE stddev_samp_trimmed(numeric, float, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = stddev_samp_trimmed_final
-);
-
-/* trimmed standard deviation (sample) */
-CREATE AGGREGATE stddev_samp_trimmed(numeric, float) (
- SFUNC = trimmed_append,
- STYPE = trimmed_agg_state,
- FINALFUNC = stddev_samp_trimmed_final
-);

0 comments on commit fa3b7bb

Please sign in to comment.
Something went wrong with that request. Please try again.