support.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /*
  2. * r3.stats support functions
  3. *
  4. * Copyright (C) 2004-2014 by the GRASS Development Team
  5. * Author(s): Soeren Gebbert
  6. *
  7. * This program is free software under the GNU General Public
  8. * License (>=v2). Read the file COPYING that comes with GRASS
  9. * for details.
  10. *
  11. */
  12. #include <grass/gis.h>
  13. #include "local_proto.h"
  14. /* *************************************************************** */
  15. /* ***** allocate equal_val_array structure ********************* */
  16. /* *************************************************************** */
  17. equal_val_array *alloc_equal_val_array(int count)
  18. {
  19. equal_val_array *p;
  20. int i;
  21. p = (equal_val_array *) G_calloc(1, sizeof(equal_val_array));
  22. p->count = count;
  23. p->values = (equal_val **) G_calloc(p->count, sizeof(equal_val *));
  24. for (i = 0; i < p->count; i++)
  25. p->values[i] = (equal_val *) G_calloc(1, sizeof(equal_val));
  26. return p;
  27. }
  28. /* *************************************************************** */
  29. /* ***** add an equal_val to the equal_val_array structure ******* */
  30. /* *************************************************************** */
  31. equal_val_array *add_equal_val_to_array(equal_val_array *array, double val)
  32. {
  33. equal_val_array *p = array;
  34. int count;
  35. if (p == NULL) {
  36. p = alloc_equal_val_array(1);
  37. p->values[0]->val = val;
  38. p->values[0]->count = 1;
  39. G_debug(5, "Create new equal_array with value %g\n", val);
  40. }
  41. else {
  42. /*increase the count */
  43. count = array->count;
  44. count++;
  45. /*new memory */
  46. p->values =
  47. (equal_val **) G_realloc(p->values, count * sizeof(equal_val *));
  48. p->values[count - 1] = (equal_val *) G_calloc(1, sizeof(equal_val));
  49. /*set the new value */
  50. p->values[count - 1]->val = val;
  51. p->values[count - 1]->count = 1;
  52. /*set the new counter */
  53. p->count = count;
  54. G_debug(5, "Add new value %g at position %i\n", val, p->count);
  55. }
  56. return p;
  57. }
  58. /* *************************************************************** */
  59. /* ***** check if a value exists in the equal_val_array ********* */
  60. /* *************************************************************** */
  61. int check_equal_value(equal_val_array *array, double val)
  62. {
  63. int i;
  64. /*search if the new value exists and increase the counter */
  65. if (array != NULL)
  66. for (i = 0; i < array->count; i++) {
  67. if (array->values[i]->val == val) {
  68. array->values[i]->count++;
  69. G_debug(5, "found value %g with count %i at pos %i\n", val,
  70. array->values[i]->count, i);
  71. return 1;
  72. }
  73. }
  74. /*if it does not exists, add it to the array */
  75. add_equal_val_to_array(array, val);
  76. /*return 1 if found, 0 otherwise */
  77. return 0;
  78. }
  79. /* *************************************************************** */
  80. /* ***** Release the memory of a equal_val_array structure ****** */
  81. /* *************************************************************** */
  82. void free_equal_val_array(equal_val_array *uvals)
  83. {
  84. int i;
  85. for (i = 0; i < uvals->count; i++) {
  86. G_free(uvals->values[i]);
  87. }
  88. G_free(uvals->values);
  89. G_free(uvals);
  90. uvals = NULL;
  91. return;
  92. }
  93. /* *************************************************************** */
  94. /* **** Create the structure which manages the statistical ******* */
  95. /* **** values for a value range or equal values **************** */
  96. /* *************************************************************** */
  97. stat_table *create_stat_table(int nsteps, equal_val_array *eqvals,
  98. double min, double max)
  99. {
  100. stat_table *p;
  101. int i;
  102. double step;
  103. /* Memory */
  104. p = (stat_table *) G_calloc(1, sizeof(stat_table));
  105. p->null = (stat_row *) G_calloc(nsteps, sizeof(stat_row));
  106. p->table = (stat_row **) G_calloc(nsteps, sizeof(stat_row *));
  107. for (i = 0; i < nsteps; i++)
  108. p->table[i] = (stat_row *) G_calloc(1, sizeof(stat_row));
  109. /* Some value initializing */
  110. p->null->min = 0;
  111. p->null->max = 0;
  112. p->null->vol = 0;
  113. p->null->perc = 0;
  114. p->null->count = 0;
  115. p->null->num = nsteps + 1;
  116. p->nsteps = nsteps;
  117. p->sum_count = 0;
  118. p->sum_vol = 0;
  119. p->sum_perc = 0;
  120. p->equal = 0;
  121. /*if no equal values are provided, calculate the range and the length of each step */
  122. if (!eqvals) {
  123. /*calculate the steplength */
  124. step = (max - min) / (nsteps);
  125. p->equal = 0;
  126. p->table[0]->min = min;
  127. p->table[0]->max = min + step;
  128. p->table[0]->num = 1;
  129. p->table[0]->count = 0;
  130. p->table[0]->vol = 0;
  131. p->table[0]->perc = 0;
  132. G_debug(3, "Step %i range min %.11lf max %.11lf\n", p->table[0]->num,
  133. p->table[0]->min, p->table[0]->max);
  134. for (i = 1; i < nsteps; i++) {
  135. p->table[i]->min = p->table[i - 1]->max;
  136. p->table[i]->max = p->table[i - 1]->max + step;
  137. p->table[i]->num = i + 1;
  138. p->table[i]->count = 0;
  139. p->table[i]->vol = 0;
  140. p->table[i]->perc = 0;
  141. G_debug(5, "Step %i range min %.11lf max %.11lf\n",
  142. p->table[i]->num, p->table[i]->min, p->table[i]->max);
  143. }
  144. /* the last value must be a bit larger */
  145. p->table[nsteps - 1]->max += COMPARE_PRECISION;
  146. }
  147. else { /* Create equal value statistic */
  148. p->equal = 1;
  149. for (i = 0; i < eqvals->count; i++) {
  150. p->table[i]->min = eqvals->values[i]->val; /* equal values have no range, set min and max to the same value */
  151. p->table[i]->max = eqvals->values[i]->val;
  152. p->table[i]->num = i + 1;
  153. p->table[i]->count = eqvals->values[i]->count; /* the appearance count for each equal value */
  154. p->table[i]->vol = 0;
  155. p->table[i]->perc = 0;
  156. G_debug(5, "Unique value %i = %g count %i\n", p->table[i]->num,
  157. p->table[i]->min, p->table[i]->count);
  158. }
  159. }
  160. return p;
  161. }
  162. /* *************************************************************** */
  163. /* ***** Release the memory of a stat_table structure ************ */
  164. /* *************************************************************** */
  165. void free_stat_table(stat_table *stats)
  166. {
  167. int i;
  168. for (i = 0; i < stats->nsteps; i++) {
  169. G_free(stats->table[i]);
  170. }
  171. G_free(stats->table);
  172. G_free(stats->null);
  173. G_free(stats);
  174. stats = NULL;
  175. return;
  176. }
  177. /* *************************************************************** */
  178. /* **** Compute the volume, percentage and sums ****************** */
  179. /* *************************************************************** */
  180. void update_stat_table(stat_table *stats, RASTER3D_Region *region)
  181. {
  182. int i;
  183. double vol = region->ns_res * region->ew_res * region->tb_res;
  184. int cellnum = region->rows * region->cols * region->depths;
  185. /*Calculate volume and percentage for each range or equal value and the sum stats */
  186. for (i = 0; i < stats->nsteps; i++) {
  187. stats->table[i]->vol = stats->table[i]->count * vol;
  188. stats->table[i]->perc =
  189. (double)(100.0 * (double)stats->table[i]->count /
  190. (double)cellnum);
  191. stats->sum_count += stats->table[i]->count;
  192. stats->sum_vol += stats->table[i]->vol;
  193. stats->sum_perc += stats->table[i]->perc;
  194. }
  195. /*calculate the null value stats */
  196. stats->null->vol = stats->null->count * vol;
  197. stats->null->perc =
  198. (double)(100.0 * (double)stats->null->count / (double)cellnum);
  199. return;
  200. }
  201. /* *************************************************************** */
  202. /* *************************************************************** */
  203. /* *************************************************************** */
  204. void print_stat_table(stat_table *stats, int counts_only)
  205. {
  206. int i;
  207. if (stats->equal) {
  208. /* 1234567 012345678901234567 0123456789012 0123456 0123456789 */
  209. fprintf(stdout,
  210. " num | value | volume | perc | cell count\n");
  211. for (i = 0; i < stats->nsteps; i++) {
  212. fprintf(stdout, "%7i %18.6lf %13.3lf %7.5lf %10i\n",
  213. stats->table[i]->num, stats->table[i]->min,
  214. stats->table[i]->vol, stats->table[i]->perc,
  215. stats->table[i]->count);
  216. }
  217. fprintf(stdout,
  218. "%7i * %13.3lf %7.5lf %10i\n",
  219. stats->null->num, stats->null->vol, stats->null->perc,
  220. stats->null->count);
  221. fprintf(stdout, "\nNumber of groups with equal values: %i",
  222. stats->nsteps);
  223. }
  224. else if (counts_only) {
  225. for (i = 0; i < stats->nsteps; i++) {
  226. fprintf(stdout, "%d %ld\n",
  227. stats->table[i]->num, stats->table[i]->count);
  228. }
  229. fprintf(stdout, "* %ld\n", stats->null->count);
  230. }
  231. else {
  232. /* 1234567 012345678901234567 012345678901234567 0123456789012 0123456 0123456789 */
  233. fprintf(stdout,
  234. " num | minimum <= value | value < maximum | volume | perc | cell count\n");
  235. for (i = 0; i < stats->nsteps; i++) {
  236. fprintf(stdout,
  237. "%7i %18.9lf %18.9lf %13.3lf %7.5lf %10i\n",
  238. stats->table[i]->num, stats->table[i]->min,
  239. stats->table[i]->max, stats->table[i]->vol,
  240. stats->table[i]->perc, stats->table[i]->count);
  241. }
  242. fprintf(stdout,
  243. "%7i * * %13.3lf %7.5lf %10i\n",
  244. stats->null->num, stats->null->vol, stats->null->perc,
  245. stats->null->count);
  246. }
  247. if (!counts_only) {
  248. fprintf(stdout,
  249. "\nSum of non Null cells: \n\tVolume = %13.3lf \n\tPercentage = %7.3lf \n\tCell count = %i\n",
  250. stats->sum_vol, stats->sum_perc, stats->sum_count);
  251. fprintf(stdout,
  252. "\nSum of all cells: \n\tVolume = %13.3lf \n\tPercentage = %7.3lf \n\tCell count = %i\n",
  253. stats->sum_vol + stats->null->vol,
  254. stats->sum_perc + stats->null->perc,
  255. stats->sum_count + stats->null->count);
  256. }
  257. return;
  258. }
  259. /* *************************************************************** */
  260. /* Make an entry in the statistic table based on range value check */
  261. /* *************************************************************** */
  262. void check_range_value(stat_table *stats, double value)
  263. {
  264. /* this is very expensive for large range arrays! */
  265. /*
  266. * int i;
  267. * for (i = 0; i < stats->nsteps; i++) {
  268. * if (value >= stats->table[i]->min && value < stats->table[i]->max) {
  269. * stats->table[i]->count++;
  270. * }
  271. * }
  272. */
  273. /* the much faster tree search is used */
  274. tree_search_range(stats, 0, stats->nsteps - 1, value);
  275. return;
  276. }
  277. /* *************************************************************** */
  278. /* tree search method developed by Soeren Gebbert *************** */
  279. /* *************************************************************** */
  280. /*
  281. * This is a divide and conquer tree search algorithm
  282. *
  283. * The algorithm counts how many values are located in each range.
  284. * It divides therefor the range array in smaller pices.
  285. *
  286. * e.g:
  287. * 0 1 2 3 4 5 6 7 8
  288. * [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9]]
  289. * / \
  290. * [[0,1],[1,2],[2,3],[3,4]] [[4,5],[5,6],[6,7],[7,8],[8,9]]
  291. * / \ / \
  292. * [[0,1],[1,2]] [[2,3],[3,4]] [[4,5],[5,6]] [[6,7],[7,8],[8,9]]
  293. * / \ / \ / \ / \
  294. * [[0,1]] [[1,2]] [[2,3]] [[3,4]] [[4,5]] [[5,6]] [[6,7]] [[7,8],[8,9]]
  295. * / \
  296. * [[7,8]] [[8,9]]
  297. *
  298. * Searching the value 5.5 will result in the follwoing steps:
  299. *
  300. * value 5.5 in range of
  301. * 1.) left array index = 0 - right array index = 8 -> range [0 - 9]
  302. * 2.) left array index = 4 - right array index = 8 -> range [4 - 9]
  303. * 3.) left array index = 4 - right array index = 5 -> range [4 - 6]
  304. * 4.) the value is located in range array 5 with a range of [5 - 6]
  305. * 5.) now increase the value range counter of range array with index 5
  306. *
  307. * */
  308. void tree_search_range(stat_table *stats, int left, int right, double value)
  309. {
  310. int size = right - left;
  311. G_debug(5,
  312. "Search value %g in array size %i left border index %i right border index %i\n",
  313. value, size, left, right);
  314. /*if left and right are equal */
  315. if (size == 0) {
  316. stats->table[left]->count++;
  317. return;
  318. }
  319. else if (size == 1) { /* if the size is one, check directly */
  320. if (value >= stats->table[left]->min &&
  321. value < stats->table[left]->max) {
  322. stats->table[left]->count++;
  323. }
  324. else if (value >= stats->table[right]->min &&
  325. value < stats->table[right]->max) {
  326. stats->table[right]->count++;
  327. }
  328. return;
  329. }
  330. else {
  331. if ((size % 2 == 0)) { /*even */
  332. /*left side */
  333. right = left + (size) / 2;
  334. if (value >= stats->table[left]->min &&
  335. value < stats->table[right]->max) {
  336. tree_search_range(stats, left, right, value);
  337. return;
  338. }
  339. /*right side */
  340. left += (size) / 2;
  341. right = left + (size) / 2;
  342. if (value >= stats->table[left]->min &&
  343. value < stats->table[right]->max) {
  344. tree_search_range(stats, left, right, value);
  345. return;
  346. }
  347. }
  348. else { /*odd */
  349. /*left side */
  350. right = left + (size - 1) / 2;
  351. if (value >= stats->table[left]->min &&
  352. value < stats->table[right]->max) {
  353. tree_search_range(stats, left, right, value);
  354. return;
  355. }
  356. /*right side */
  357. left += (size - 1) / 2;
  358. right = left + (size - 1) / 2 + 1; /*the right array is one col larger */
  359. if (value >= stats->table[left]->min &&
  360. value < stats->table[right]->max) {
  361. tree_search_range(stats, left, right, value);
  362. return;
  363. }
  364. }
  365. }
  366. return;
  367. }
  368. /* *************************************************************** */
  369. /* ****** heapsort for equal value arrays of size n ************** */
  370. /* ** Code based on heapsort from Sebastian Cyris **************** */
  371. /* *************************************************************** */
  372. void heapsort_eqvals(equal_val_array *e, int n)
  373. {
  374. int k;
  375. double t;
  376. int count = 0;
  377. --n;
  378. for (k = n / 2; k >= 0; k--)
  379. downheap_eqvals(e, n, k);
  380. while (n > 0) {
  381. t = e->values[0]->val;
  382. count = e->values[0]->count;
  383. e->values[0]->val = e->values[n]->val;
  384. e->values[0]->count = e->values[n]->count;
  385. e->values[n]->val = t;
  386. e->values[n]->count = count;
  387. downheap_eqvals(e, --n, 0);
  388. }
  389. return;
  390. }
  391. /* *************************************************************** */
  392. /* ** Code based on heapsort from Sebastian Cyris **************** */
  393. /* ** ************************************************************ */
  394. void downheap_eqvals(equal_val_array *e, int n, int k)
  395. {
  396. int j;
  397. double v;
  398. int count;
  399. v = e->values[k]->val;
  400. count = e->values[k]->count;
  401. while (k <= n / 2) {
  402. j = k + k;
  403. if (j < n && e->values[j]->val < e->values[j + 1]->val)
  404. j++;
  405. if (v >= e->values[j]->val)
  406. break;
  407. e->values[k]->val = e->values[j]->val;
  408. e->values[k]->count = e->values[j]->count;
  409. k = j;
  410. }
  411. e->values[k]->val = v;
  412. e->values[k]->count = count;
  413. return;
  414. }