Compute the default set of or requested quantiles for a coverage.
A One-Pass Space-Efficient Algorithm for Finding Quantiles (1995) by Rakesh Agrawal, Arun Swami in Proc. 7th Intl. Conf. Management of Data (COMAD-95)
In the future, it may be worth exploring algorithms that don't require the size of the coverage
1018 {
1020 int init_quantiles = 0;
1021
1025 const uint32_t MAX_VALUES = 750;
1026
1027 uint8_t *
data = NULL;
1029 int isnodata = 0;
1030
1031 uint32_t a = 0;
1032 uint32_t i = 0;
1033 uint32_t j = 0;
1034 uint32_t k = 0;
1037 uint32_t z = 0;
1038 uint32_t idx = 0;
1039 uint32_t offset = 0;
1040 uint32_t diff = 0;
1041 uint8_t exists = 0;
1042
1043 uint32_t do_sample = 0;
1044 uint32_t sample_size = 0;
1045 uint32_t sample_per = 0;
1046 uint32_t sample_int = 0;
1047 int status;
1048
1050
1051 assert(NULL != band);
1052 assert(cov_count > 1);
1053 assert(NULL != rtn_count);
1055
1057 if (data == NULL) {
1058 rterror(
"rt_band_get_summary_stats: Cannot get band data");
1059 return NULL;
1060 }
1061
1063 exclude_nodata_value = 0;
1064 RASTER_DEBUGF(3,
"exclude_nodata_value = %d", exclude_nodata_value);
1065
1066
1067 if (NULL == *qlls) {
1068
1069 if (NULL == quantiles) {
1070
1071 if (quantiles_count < 2)
1072 quantiles_count = 5;
1073
1074 quantiles =
rtalloc(
sizeof(
double) * quantiles_count);
1075 init_quantiles = 1;
1076 if (NULL == quantiles) {
1077 rterror(
"rt_band_get_quantiles_stream: Could not allocate memory for quantile input");
1078 return NULL;
1079 }
1080
1081 quantiles_count--;
1082 for (i = 0; i <= quantiles_count; i++)
1083 quantiles[i] = ((double) i) / quantiles_count;
1084 quantiles_count++;
1085 }
1086
1087
1088 for (i = 0; i < quantiles_count; i++) {
1089 if (quantiles[i] < 0. || quantiles[i] > 1.) {
1090 rterror(
"rt_band_get_quantiles_stream: Quantile value not between 0 and 1");
1091 if (init_quantiles)
rtdealloc(quantiles);
1092 return NULL;
1093 }
1094 }
1095 quicksort(quantiles, quantiles + quantiles_count - 1);
1096
1097
1098 *qlls_count = quantiles_count * 2;
1101 if (NULL == *qlls) {
1102 rterror(
"rt_band_get_quantiles_stream: Could not allocate memory for quantile output");
1103 if (init_quantiles)
rtdealloc(quantiles);
1104 return NULL;
1105 }
1106
1107 j = (uint32_t) floor(MAX_VALUES / 100.) + 1;
1108 for (i = 0; i < *qlls_count; i++) {
1109 qll = &((*qlls)[i]);
1110 qll->
quantile = quantiles[(i * quantiles_count) / *qlls_count];
1116
1117
1119 if (NULL == qll->
index) {
1120 rterror(
"rt_band_get_quantiles_stream: Could not allocate memory for quantile output");
1121 if (init_quantiles)
rtdealloc(quantiles);
1122 return NULL;
1123 }
1126
1127
1128 if (!(i % 2)) {
1131 if (qll->
tau < 1) qll->
tau = 1;
1132 }
1133
1134 else {
1136 qll->
tau = cov_count - (*qlls)[i - 1].tau + 1;
1137 }
1138
1139 RASTER_DEBUGF(4,
"qll init: (algeq, quantile, count, tau, sum1, sum2) = (%d, %f, %d, %llu, %llu, %llu)",
1142 }
1143
1144 if (init_quantiles)
rtdealloc(quantiles);
1145 }
1146
1147
1148 if (
1149 (sample < 0 ||
FLT_EQ(sample, 0.0)) ||
1150 (sample > 1 ||
FLT_EQ(sample, 1.0))
1151 ) {
1152 do_sample = 0;
1153 sample = 1;
1154 }
1155 else
1156 do_sample = 1;
1158
1159
1160 if (!do_sample) {
1161 sample_size =
band->width *
band->height;
1162 sample_per =
band->height;
1163 }
1164
1165
1166
1167
1168
1169 else {
1170 sample_size = round((
band->width *
band->height) * sample);
1171 sample_per = round(sample_size /
band->width);
1172 sample_int = round(
band->height / sample_per);
1173 srand(time(NULL));
1174 }
1175 RASTER_DEBUGF(3,
"sampling %d of %d available pixels w/ %d per set"
1176 , sample_size, (
band->width *
band->height), sample_per);
1177
1178 for (x = 0, j = 0, k = 0;
x <
band->width;
x++) {
1180 diff = 0;
1181
1182
1184 RASTER_DEBUG(3,
"Skipping quantile calculation as band is NODATA");
1185 break;
1186 }
1187
1188 for (i = 0, z = 0; i < sample_per; i++) {
1189 if (do_sample != 1)
1191 else {
1192 offset = (rand() % sample_int) + 1;
1194 diff = sample_int - offset;
1195 }
1197 if (y >=
band->height || z > sample_per)
break;
1198
1200
1201 j++;
1202 if (status ==
ES_NONE && (!exclude_nodata_value || (exclude_nodata_value && !isnodata))) {
1203
1204
1205 for (a = 0; a < *qlls_count; a++) {
1206 qll = &((*qlls)[a]);
1207 qls = NULL;
1209 RASTER_DEBUGF(5,
"qll before: (algeq, quantile, count, tau, sum1, sum2) = (%d, %f, %d, %lld, %lld, %lld)",
1212
1213
1215 if (NULL != qll->
head) {
1216 if (value < qll->head->value)
1218 }
1219 else {
1224 }
1225
1227 continue;
1228 }
1230 if (NULL != qll->
head) {
1233 }
1234 else {
1239 }
1240
1242 continue;
1243 }
1244
1245
1246
1248 qle = NULL;
1249
1252
1253 else {
1256 }
1257
1258
1259 if (NULL != qle) {
1262
1265
1268 else
1270
1272 }
1273
1274 else if (qll->
count < MAX_VALUES) {
1276
1277
1278
1282 }
1283
1284 else
1286 if (NULL == qle) return NULL;
1290
1291
1292 if (NULL == qle->
prev)
1294
1295 if (NULL == qle->
next)
1297
1300 else
1302
1303
1305
1306 RASTER_DEBUGF(5,
"qle, prev, next, head, tail = %p, %p, %p, %p, %p", qle, qle->
prev, qle->
next, qll->
head, qll->
tail);
1307 }
1308
1309 else if (qll->
algeq) {
1311
1312 if (value < qll->head->value) {
1313
1316 }
1317 else {
1318
1319
1329
1330
1332
1336 }
1337
1338 else {
1341 }
1342 if (NULL == qle) return NULL;
1346
1347
1348 if (NULL == qle->
prev)
1350
1351 if (NULL == qle->
next)
1353
1355
1357
1359
1360 }
1361 }
1362 else {
1364 while (NULL != qle) {
1370 break;
1371 }
1372
1374 }
1375 }
1376 }
1377
1378 else {
1380
1382
1385 }
1386 else {
1387
1388
1399
1400
1402
1406 }
1407
1408 else {
1411 }
1412 if (NULL == qle) return NULL;
1416
1417
1418 if (NULL == qle->
prev)
1420
1421 if (NULL == qle->
next)
1423
1425
1427
1429
1430 }
1431 }
1432 else {
1434 while (NULL != qle) {
1440 break;
1441 }
1442
1444 }
1445 }
1446 }
1447
1450
1453
1462
1464 }
1465 else {
1472
1474 }
1475 }
1476
1477 else {
1479
1488 }
1489 else {
1496
1498 }
1499 }
1500 }
1501
1502 RASTER_DEBUGF(5,
"qll after: (algeq, quantile, count, tau, sum1, sum2) = (%d, %f, %d, %lld, %lld, %lld)",
1505 }
1506
1507 }
1508 else {
1509 RASTER_DEBUGF(5,
"skipping value at (x, y) = (%u, %lld)", x, y);
1510 }
1511
1512 z++;
1513 }
1514 }
1515
1516
1517 *rtn_count = *qlls_count / 2;
1519 if (NULL == rtn) return NULL;
1520
1522 for (i = 0, k = 0; i < *qlls_count; i++) {
1523 qll = &((*qlls)[i]);
1524
1525 exists = 0;
1526 for (x = 0;
x < k;
x++) {
1528 exists = 1;
1529 break;
1530 }
1531 }
1532 if (exists) continue;
1533
1534 RASTER_DEBUGF(5,
"qll: (algeq, quantile, count, tau, sum1, sum2) = (%d, %f, %d, %lld, %lld, %lld)",
1537
1540
1541
1542 if (qll->
head == NULL || qll->
tail == NULL)
1543 continue;
1544
1545
1548
1549 else
1551
1552 exists = 0;
1553 for (j = i + 1; j < *qlls_count; j++) {
1555
1556 RASTER_DEBUGF(5,
"qlls[%d]: (algeq, quantile, count, tau, sum1, sum2) = (%d, %f, %d, %lld, %lld, %lld)",
1557 j, (*qlls)[j].algeq, (*qlls)[j].quantile, (*qlls)[j].
count, (*qlls)[j].tau, (*qlls)[j].sum1, (*qlls)[j].sum2);
1558 RASTER_DEBUGF(5,
"qlls[%d]: (head, tail) = (%p, %p)", j, (*qlls)[j].head, (*qlls)[j].tail);
1559
1560 exists = 1;
1561 break;
1562 }
1563 }
1564
1565
1566 if (exists) {
1567 if ((*qlls)[j].algeq) {
1568 rtn[k].
value = ((qle->
value * qle->
count) + ((*qlls)[j].head->value * (*qlls)[j].head->count)) / (qle->
count + (*qlls)[j].head->count);
1569 RASTER_DEBUGF(5,
"qlls[%d].head: (value, count) = (%f, %d)", j, (*qlls)[j].head->value, (*qlls)[j].head->count);
1570 }
1571 else {
1572 rtn[k].
value = ((qle->
value * qle->
count) + ((*qlls)[j].tail->value * (*qlls)[j].tail->count)) / (qle->
count + (*qlls)[j].tail->count);
1573 RASTER_DEBUGF(5,
"qlls[%d].tail: (value, count) = (%f, %d)", j, (*qlls)[j].tail->value, (*qlls)[j].tail->count);
1574 }
1575 }
1576
1577 else {
1579 }
1582
1583 k++;
1584 }
1585
1587 return rtn;
1588}
void rterror(const char *fmt,...) __attribute__((format(printf
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
#define RASTER_DEBUG(level, msg)
#define RASTER_DEBUGF(level, msg,...)
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
void * rt_band_get_data(rt_band band)
Get pointer to raster band data.
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
void rtdealloc(void *mem)
static struct quantile_llist_element * quantile_llist_index_search(struct quantile_llist *qll, double value, uint32_t *index)
static void quantile_llist_index_update(struct quantile_llist *qll, struct quantile_llist_element *qle, uint32_t idx)
static struct quantile_llist_element * quantile_llist_insert(struct quantile_llist_element *element, double value, uint32_t *idx)
static void quantile_llist_index_delete(struct quantile_llist *qll, struct quantile_llist_element *qle)
static struct quantile_llist_element * quantile_llist_search(struct quantile_llist_element *element, double needle)
static void quicksort(double *left, double *right)
static int quantile_llist_delete(struct quantile_llist_element *element)
static void quantile_llist_index_reset(struct quantile_llist *qll)
struct quantile_llist_element * prev
struct quantile_llist_element * next
struct quantile_llist_element * head
struct quantile_llist_element * tail
struct quantile_llist_index * index