summaryrefslogtreecommitdiff
path: root/contrib/cube/cube.c
diff options
context:
space:
mode:
authorPavan Deolasee2016-10-27 15:02:55 +0000
committerPavan Deolasee2016-10-27 15:02:55 +0000
commitc52792488cd87e67e62ec61f5b56f461900353b4 (patch)
tree02b4a719f979659de8f73fce6c1ca65cef2e323f /contrib/cube/cube.c
parent891e6be57e5580b54a9df9fd42cb9bd10d0e7b21 (diff)
parentb5bce6c1ec6061c8a4f730d927e162db7e2ce365 (diff)
Merge commit 'b5bce6c1ec6061c8a4f730d927e162db7e2ce365'
Diffstat (limited to 'contrib/cube/cube.c')
-rw-r--r--contrib/cube/cube.c214
1 files changed, 211 insertions, 3 deletions
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 113c66383a..3feddef8f3 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -40,6 +40,8 @@ PG_FUNCTION_INFO_V1(cube_c_f8_f8);
PG_FUNCTION_INFO_V1(cube_dim);
PG_FUNCTION_INFO_V1(cube_ll_coord);
PG_FUNCTION_INFO_V1(cube_ur_coord);
+PG_FUNCTION_INFO_V1(cube_coord);
+PG_FUNCTION_INFO_V1(cube_coord_llur);
PG_FUNCTION_INFO_V1(cube_subset);
/*
@@ -53,6 +55,7 @@ PG_FUNCTION_INFO_V1(g_cube_penalty);
PG_FUNCTION_INFO_V1(g_cube_picksplit);
PG_FUNCTION_INFO_V1(g_cube_union);
PG_FUNCTION_INFO_V1(g_cube_same);
+PG_FUNCTION_INFO_V1(g_cube_distance);
/*
** B-tree support functions
@@ -79,7 +82,9 @@ PG_FUNCTION_INFO_V1(cube_size);
/*
** miscellaneous
*/
+PG_FUNCTION_INFO_V1(distance_taxicab);
PG_FUNCTION_INFO_V1(cube_distance);
+PG_FUNCTION_INFO_V1(distance_chebyshev);
PG_FUNCTION_INFO_V1(cube_is_point);
PG_FUNCTION_INFO_V1(cube_enlarge);
@@ -814,7 +819,7 @@ cube_inter(PG_FUNCTION_ARGS)
Max(LL_COORD(b, i), UR_COORD(b, i))
);
}
- /* continue on the higher dimemsions only present in 'a' */
+ /* continue on the higher dimensions only present in 'a' */
for (; i < DIM(a); i++)
{
result->x[i] = Max(0,
@@ -1257,6 +1262,147 @@ cube_distance(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(sqrt(distance));
}
+Datum
+distance_taxicab(PG_FUNCTION_ARGS)
+{
+ NDBOX *a = PG_GETARG_NDBOX(0),
+ *b = PG_GETARG_NDBOX(1);
+ bool swapped = false;
+ double distance;
+ int i;
+
+ /* swap the box pointers if needed */
+ if (DIM(a) < DIM(b))
+ {
+ NDBOX *tmp = b;
+
+ b = a;
+ a = tmp;
+ swapped = true;
+ }
+
+ distance = 0.0;
+ /* compute within the dimensions of (b) */
+ for (i = 0; i < DIM(b); i++)
+ distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
+ LL_COORD(b, i), UR_COORD(b, i)));
+
+ /* compute distance to zero for those dimensions in (a) absent in (b) */
+ for (i = DIM(b); i < DIM(a); i++)
+ distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
+ 0.0, 0.0));
+
+ if (swapped)
+ {
+ PG_FREE_IF_COPY(b, 0);
+ PG_FREE_IF_COPY(a, 1);
+ }
+ else
+ {
+ PG_FREE_IF_COPY(a, 0);
+ PG_FREE_IF_COPY(b, 1);
+ }
+
+ PG_RETURN_FLOAT8(distance);
+}
+
+Datum
+distance_chebyshev(PG_FUNCTION_ARGS)
+{
+ NDBOX *a = PG_GETARG_NDBOX(0),
+ *b = PG_GETARG_NDBOX(1);
+ bool swapped = false;
+ double d,
+ distance;
+ int i;
+
+ /* swap the box pointers if needed */
+ if (DIM(a) < DIM(b))
+ {
+ NDBOX *tmp = b;
+
+ b = a;
+ a = tmp;
+ swapped = true;
+ }
+
+ distance = 0.0;
+ /* compute within the dimensions of (b) */
+ for (i = 0; i < DIM(b); i++)
+ {
+ d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
+ LL_COORD(b, i), UR_COORD(b, i)));
+ if (d > distance)
+ distance = d;
+ }
+
+ /* compute distance to zero for those dimensions in (a) absent in (b) */
+ for (i = DIM(b); i < DIM(a); i++)
+ {
+ d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
+ if (d > distance)
+ distance = d;
+ }
+
+ if (swapped)
+ {
+ PG_FREE_IF_COPY(b, 0);
+ PG_FREE_IF_COPY(a, 1);
+ }
+ else
+ {
+ PG_FREE_IF_COPY(a, 0);
+ PG_FREE_IF_COPY(b, 1);
+ }
+
+ PG_RETURN_FLOAT8(distance);
+}
+
+Datum
+g_cube_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+ NDBOX *cube = DatumGetNDBOX(entry->key);
+ double retval;
+
+ if (strategy == CubeKNNDistanceCoord)
+ {
+ int coord = PG_GETARG_INT32(1);
+
+ if (IS_POINT(cube))
+ retval = cube->x[(coord - 1) % DIM(cube)];
+ else
+ retval = Min(cube->x[(coord - 1) % DIM(cube)],
+ cube->x[(coord - 1) % DIM(cube) + DIM(cube)]);
+ }
+ else
+ {
+ NDBOX *query = PG_GETARG_NDBOX(1);
+
+ switch (strategy)
+ {
+ case CubeKNNDistanceTaxicab:
+ retval = DatumGetFloat8(DirectFunctionCall2(distance_taxicab,
+ PointerGetDatum(cube), PointerGetDatum(query)));
+ break;
+ case CubeKNNDistanceEuclid:
+ retval = DatumGetFloat8(DirectFunctionCall2(cube_distance,
+ PointerGetDatum(cube), PointerGetDatum(query)));
+ break;
+ case CubeKNNDistanceChebyshev:
+ retval = DatumGetFloat8(DirectFunctionCall2(distance_chebyshev,
+ PointerGetDatum(cube), PointerGetDatum(query)));
+ break;
+ default:
+ elog(ERROR, "unrecognized cube strategy number: %d", strategy);
+ retval = 0; /* keep compiler quiet */
+ break;
+ }
+ }
+ PG_RETURN_FLOAT8(retval);
+}
+
static double
distance_1D(double a1, double a2, double b1, double b2)
{
@@ -1323,7 +1469,7 @@ Datum
cube_ll_coord(PG_FUNCTION_ARGS)
{
NDBOX *c = PG_GETARG_NDBOX(0);
- int n = PG_GETARG_INT16(1);
+ int n = PG_GETARG_INT32(1);
double result;
if (DIM(c) >= n && n > 0)
@@ -1340,7 +1486,7 @@ Datum
cube_ur_coord(PG_FUNCTION_ARGS)
{
NDBOX *c = PG_GETARG_NDBOX(0);
- int n = PG_GETARG_INT16(1);
+ int n = PG_GETARG_INT32(1);
double result;
if (DIM(c) >= n && n > 0)
@@ -1352,6 +1498,68 @@ cube_ur_coord(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(result);
}
+/*
+ * Function returns cube coordinate.
+ * Numbers from 1 to DIM denotes first corner coordinates.
+ * Numbers from DIM+1 to 2*DIM denotes second corner coordinates.
+ */
+Datum
+cube_coord(PG_FUNCTION_ARGS)
+{
+ NDBOX *cube = PG_GETARG_NDBOX(0);
+ int coord = PG_GETARG_INT32(1);
+
+ if (coord <= 0 || coord > 2 * DIM(cube))
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+ errmsg("cube index %d is out of bounds", coord)));
+
+ if (IS_POINT(cube))
+ PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
+ else
+ PG_RETURN_FLOAT8(cube->x[coord - 1]);
+}
+
+
+/*
+ * This function works like cube_coord(),
+ * but rearranges coordinates of corners to get cube representation
+ * in the form of (lower left, upper right).
+ * For historical reasons that extension allows us to create cubes in form
+ * ((2,1),(1,2)) and instead of normalizing such cube to ((1,1),(2,2)) it
+ * stores cube in original way. But to get cubes ordered by one of dimensions
+ * directly from the index without extra sort step we need some
+ * representation-independent coordinate getter. This function implements it.
+ */
+Datum
+cube_coord_llur(PG_FUNCTION_ARGS)
+{
+ NDBOX *cube = PG_GETARG_NDBOX(0);
+ int coord = PG_GETARG_INT32(1);
+
+ if (coord <= 0 || coord > 2 * DIM(cube))
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+ errmsg("cube index %d is out of bounds", coord)));
+
+ if (coord <= DIM(cube))
+ {
+ if (IS_POINT(cube))
+ PG_RETURN_FLOAT8(cube->x[coord - 1]);
+ else
+ PG_RETURN_FLOAT8(Min(cube->x[coord - 1],
+ cube->x[coord - 1 + DIM(cube)]));
+ }
+ else
+ {
+ if (IS_POINT(cube))
+ PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
+ else
+ PG_RETURN_FLOAT8(Max(cube->x[coord - 1],
+ cube->x[coord - 1 - DIM(cube)]));
+ }
+}
+
/* Increase or decrease box size by a radius in at least n dimensions. */
Datum
cube_enlarge(PG_FUNCTION_ARGS)