src/apps/testapps/testGridDisk.c (332 lines of code) (raw):
/*
* Copyright 2017-2018, 2020-2021 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file
* @brief tests H3 function `gridDisk` and `gridDiskDistances`
*
* usage: `testGridDisk`
*/
#include <stdlib.h>
#include "algos.h"
#include "baseCells.h"
#include "h3Index.h"
#include "test.h"
#include "utility.h"
static void gridDisk_equals_gridDiskDistancesSafe_assertions(H3Index h3) {
for (int k = 0; k < 3; k++) {
int64_t kSz;
t_assertSuccess(H3_EXPORT(maxGridDiskSize)(k, &kSz));
H3Index *neighbors = calloc(kSz, sizeof(H3Index));
int *distances = calloc(kSz, sizeof(int));
t_assertSuccess(
H3_EXPORT(gridDiskDistances)(h3, k, neighbors, distances));
H3Index *internalNeighbors = calloc(kSz, sizeof(H3Index));
int *internalDistances = calloc(kSz, sizeof(int));
t_assertSuccess(H3_EXPORT(gridDiskDistancesSafe)(
h3, k, internalNeighbors, internalDistances));
int found = 0;
int internalFound = 0;
for (int64_t iNeighbor = 0; iNeighbor < kSz; iNeighbor++) {
if (neighbors[iNeighbor] != 0) {
found++;
for (int64_t iInternal = 0; iInternal < kSz; iInternal++) {
if (internalNeighbors[iInternal] == neighbors[iNeighbor]) {
internalFound++;
t_assert(distances[iNeighbor] ==
internalDistances[iInternal],
"External and internal agree on "
"distance");
break;
}
}
t_assert(found == internalFound,
"External and internal implementations "
"produce same output");
}
}
free(internalDistances);
free(internalNeighbors);
free(distances);
free(neighbors);
}
}
SUITE(gridDisk) {
TEST(gridDisk0) {
LatLng sf = {0.659966917655, 2 * 3.14159 - 2.1364398519396};
H3Index sfHex0;
t_assertSuccess(H3_EXPORT(latLngToCell)(&sf, 0, &sfHex0));
H3Index k1[] = {0, 0, 0, 0, 0, 0, 0};
int k1Dist[] = {0, 0, 0, 0, 0, 0, 0};
H3Index expectedK1[] = {0x8029fffffffffff, 0x801dfffffffffff,
0x8013fffffffffff, 0x8027fffffffffff,
0x8049fffffffffff, 0x8051fffffffffff,
0x8037fffffffffff};
t_assertSuccess(H3_EXPORT(gridDiskDistances)(sfHex0, 1, k1, k1Dist));
for (int i = 0; i < 7; i++) {
t_assert(k1[i] != 0, "index is populated");
int inList = 0;
for (int j = 0; j < 7; j++) {
if (k1[i] == expectedK1[j]) {
t_assert(k1Dist[i] == (k1[i] == sfHex0 ? 0 : 1),
"distance is as expected");
inList++;
}
}
t_assert(inList == 1, "index found in expected set");
}
}
TEST(gridDisk0_PolarPentagon) {
H3Index polar;
setH3Index(&polar, 0, 4, 0);
H3Index k2[] = {0, 0, 0, 0, 0, 0, 0};
int k2Dist[] = {0, 0, 0, 0, 0, 0, 0};
H3Index expectedK2[] = {0x8009fffffffffff,
0x8007fffffffffff,
0x8001fffffffffff,
0x8011fffffffffff,
0x801ffffffffffff,
0x8019fffffffffff,
0};
t_assertSuccess(H3_EXPORT(gridDiskDistances)(polar, 1, k2, k2Dist));
int k2present = 0;
for (int i = 0; i < 7; i++) {
if (k2[i] != 0) {
k2present++;
int inList = 0;
for (int j = 0; j < 7; j++) {
if (k2[i] == expectedK2[j]) {
t_assert(k2Dist[i] == (k2[i] == polar ? 0 : 1),
"distance is as expected");
inList++;
}
}
t_assert(inList == 1, "index found in expected set");
}
}
t_assert(k2present == 6, "pentagon has 5 neighbors");
}
TEST(gridDisk1_PolarPentagon) {
H3Index polar;
setH3Index(&polar, 1, 4, 0);
H3Index k2[] = {0, 0, 0, 0, 0, 0, 0};
int k2Dist[] = {0, 0, 0, 0, 0, 0, 0};
H3Index expectedK2[] = {0x81083ffffffffff,
0x81093ffffffffff,
0x81097ffffffffff,
0x8108fffffffffff,
0x8108bffffffffff,
0x8109bffffffffff,
0};
t_assertSuccess(H3_EXPORT(gridDiskDistances)(polar, 1, k2, k2Dist));
int k2present = 0;
for (int i = 0; i < 7; i++) {
if (k2[i] != 0) {
k2present++;
int inList = 0;
for (int j = 0; j < 7; j++) {
if (k2[i] == expectedK2[j]) {
t_assert(k2Dist[i] == (k2[i] == polar ? 0 : 1),
"distance is as expected");
inList++;
}
}
t_assert(inList == 1, "index found in expected set");
}
}
t_assert(k2present == 6, "pentagon has 5 neighbors");
}
TEST(gridDisk1_PolarPentagon_k3) {
H3Index polar;
setH3Index(&polar, 1, 4, 0);
H3Index k2[37] = {0};
int k2Dist[37] = {0};
H3Index expectedK2[37] = {0x81013ffffffffff,
0x811fbffffffffff,
0x81193ffffffffff,
0x81097ffffffffff,
0x81003ffffffffff,
0x81183ffffffffff,
0x8111bffffffffff,
0x81077ffffffffff,
0x811f7ffffffffff,
0x81067ffffffffff,
0x81093ffffffffff,
0x811e7ffffffffff,
0x81083ffffffffff,
0x81117ffffffffff,
0x8101bffffffffff,
0x81107ffffffffff,
0x81073ffffffffff,
0x811f3ffffffffff,
0x81063ffffffffff,
0x8108fffffffffff,
0x811e3ffffffffff,
0x8119bffffffffff,
0x81113ffffffffff,
0x81017ffffffffff,
0x81103ffffffffff,
0x8109bffffffffff,
0x81197ffffffffff,
0x81007ffffffffff,
0x8108bffffffffff,
0x81187ffffffffff,
0x8107bffffffffff,
0,
0,
0,
0,
0,
0};
int expectedK2Dist[37] = {2, 3, 2, 1, 3, 3, 3, 2, 2, 3, 1, 3, 0,
2, 3, 3, 2, 2, 3, 1, 3, 3, 2, 2, 3, 1,
2, 3, 1, 3, 3, 0, 0, 0, 0, 0, 0};
t_assertSuccess(H3_EXPORT(gridDiskDistances)(polar, 3, k2, k2Dist));
int k2present = 0;
for (int i = 0; i < 37; i++) {
if (k2[i] != 0) {
k2present++;
int inList = 0;
for (int j = 0; j < 37; j++) {
if (k2[i] == expectedK2[j]) {
t_assert(k2Dist[i] == expectedK2Dist[j],
"distance is as expected");
inList++;
}
}
t_assert(inList == 1, "index found in expected set");
}
}
t_assert(k2present == 31, "pentagon has 30 neighbors");
}
TEST(gridDisk1_Pentagon_k4) {
H3Index pent;
setH3Index(&pent, 1, 14, 0);
H3Index k2[61] = {0};
int k2Dist[61] = {0};
H3Index expectedK2[61] = {0x811d7ffffffffff,
0x810c7ffffffffff,
0x81227ffffffffff,
0x81293ffffffffff,
0x81133ffffffffff,
0x8136bffffffffff,
0x81167ffffffffff,
0x811d3ffffffffff,
0x810c3ffffffffff,
0x81223ffffffffff,
0x81477ffffffffff,
0x8128fffffffffff,
0x81367ffffffffff,
0x8112fffffffffff,
0x811cfffffffffff,
0x8123bffffffffff,
0x810dbffffffffff,
0x8112bffffffffff,
0x81473ffffffffff,
0x8128bffffffffff,
0x81363ffffffffff,
0x811cbffffffffff,
0x81237ffffffffff,
0x810d7ffffffffff,
0x81127ffffffffff,
0x8137bffffffffff,
0x81287ffffffffff,
0x8126bffffffffff,
0x81177ffffffffff,
0x810d3ffffffffff,
0x81233ffffffffff,
0x8150fffffffffff,
0x81123ffffffffff,
0x81377ffffffffff,
0x81283ffffffffff,
0x8102fffffffffff,
0x811c3ffffffffff,
0x810cfffffffffff,
0x8122fffffffffff,
0x8113bffffffffff,
0x81373ffffffffff,
0x8129bffffffffff,
0x8102bffffffffff,
0x811dbffffffffff,
0x810cbffffffffff,
0x8122bffffffffff,
0x81297ffffffffff,
0x81507ffffffffff,
0x8136fffffffffff,
0x8127bffffffffff,
0x81137ffffffffff,
0,
0};
t_assertSuccess(H3_EXPORT(gridDiskDistances)(pent, 4, k2, k2Dist));
int k2present = 0;
for (int i = 0; i < 61; i++) {
if (k2[i] != 0) {
k2present++;
int inList = 0;
for (int j = 0; j < 61; j++) {
if (k2[i] == expectedK2[j]) {
inList++;
}
}
t_assert(inList == 1, "index found in expected set");
}
}
t_assert(k2present == 51, "pentagon has 50 neighbors");
}
TEST(gridDisk_equals_gridDiskDistancesSafe) {
// Check that gridDiskDistances output matches gridDiskDistancesSafe,
// since gridDiskDistances will sometimes use a different
// implementation.
for (int res = 0; res < 2; res++) {
iterateAllIndexesAtRes(
res, gridDisk_equals_gridDiskDistancesSafe_assertions);
}
}
TEST(gridDiskInvalid) {
int k = 1000;
int64_t kSz;
t_assertSuccess(H3_EXPORT(maxGridDiskSize)(k, &kSz));
H3Index *neighbors = calloc(kSz, sizeof(H3Index));
t_assert(H3_EXPORT(gridDisk)(0x7fffffffffffffff, k, neighbors) ==
E_CELL_INVALID,
"gridDisk returns error for invalid input");
free(neighbors);
}
TEST(gridDiskInvalidDigit) {
int k = 2;
int64_t kSz;
t_assertSuccess(H3_EXPORT(maxGridDiskSize)(k, &kSz));
H3Index *neighbors = calloc(kSz, sizeof(H3Index));
t_assert(H3_EXPORT(gridDisk)(0x4d4b00fe5c5c3030, k, neighbors) ==
E_CELL_INVALID,
"gridDisk returns error for invalid input");
free(neighbors);
}
TEST(gridDiskDistances_invalidK) {
H3Index index = 0x811d7ffffffffff;
t_assert(
H3_EXPORT(gridDiskDistances)(index, -1, NULL, NULL) == E_DOMAIN,
"gridDiskDistances invalid k");
t_assert(H3_EXPORT(gridDiskDistancesUnsafe)(index, -1, NULL, NULL) ==
E_DOMAIN,
"gridDiskDistancesUnsafe invalid k");
t_assert(
H3_EXPORT(gridDiskDistancesSafe)(index, -1, NULL, NULL) == E_DOMAIN,
"gridDiskDistancesSafe invalid k");
}
TEST(maxGridDiskSize_invalid) {
int64_t sz;
t_assert(H3_EXPORT(maxGridDiskSize)(-1, &sz) == E_DOMAIN,
"negative k is invalid");
}
TEST(maxGridDiskSize_large) {
int64_t sz;
t_assertSuccess(H3_EXPORT(maxGridDiskSize)(26755, &sz));
t_assert(sz == 2147570341, "large (> 32 bit signed int) k works");
}
TEST(maxGridDiskSize_numCells) {
int64_t sz;
int64_t prev = 0;
int64_t max;
t_assertSuccess(H3_EXPORT(getNumCells)(15, &max));
// 13780510 will produce values above max
for (int k = 13780510 - 100; k < 13780510 + 100; k++) {
t_assertSuccess(H3_EXPORT(maxGridDiskSize)(k, &sz));
t_assert(sz <= max,
"maxGridDiskSize does not produce estimates above the "
"number of grid cells");
t_assert(prev <= sz, "maxGridDiskSize is monotonically increasing");
prev = sz;
}
t_assertSuccess(H3_EXPORT(maxGridDiskSize)(INT32_MAX, &sz));
t_assert(sz == max,
"maxGridDiskSize of INT32_MAX produces valid result");
}
}