furtherest_point.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <cgraph/list.h>
  11. #include <sparse/general.h>
  12. #include <sparse/QuadTree.h>
  13. #include <edgepaint/furtherest_point.h>
  14. #include <stdbool.h>
  15. #include <stddef.h>
  16. #include <string.h>
  17. #include <util/alloc.h>
  18. #include <util/prisize_t.h>
  19. static double dist(int dim, double *x, double *y){
  20. int k;
  21. double d = 0;
  22. for (k = 0; k < dim; k++) d += (x[k] - y[k])*(x[k]-y[k]);
  23. return sqrt(d);
  24. }
  25. static double distance_to_group(int k, int dim, double *wgt, double *pts, double *center){
  26. int i;
  27. double distance = -1, dist_min = 0;
  28. if (!wgt){
  29. for (i = 0; i < k; i++){
  30. distance = dist(dim, &(pts[i*dim]), center);
  31. if (i == 0){
  32. dist_min = distance;
  33. } else {
  34. dist_min = MIN(dist_min, distance);
  35. }
  36. }
  37. } else {
  38. for (i = 0; i < k; i++){
  39. distance = dist(dim, &(pts[i*dim]), center);
  40. if (i == 0){
  41. dist_min = wgt[i]*distance;
  42. } else {
  43. dist_min = MIN(dist_min, wgt[i]*distance);
  44. }
  45. }
  46. }
  47. return dist_min;
  48. }
  49. DEFINE_LIST(qt_list, QuadTree)
  50. void furtherest_point(int k, int dim, double *wgt, double *pts, double *center, double width, int max_level, double *dist_max, double **argmax){
  51. /* Assume that in the box defined by {center, width} are feasible;
  52. find, in the, a point "furtherest_point" that is furtherest away from a group of k-points pts, using quadtree,
  53. with up to max_level. Here the distance of a point to a group of point is defined as the minimum
  54. of the distance of that point to all the points in the group,
  55. and each distance is defined by the function dist.
  56. Input:
  57. k: number of points in the group
  58. dim: dimension
  59. wgt: if not null, the weighting factor for the i-th point is wgt[i]. The color distance
  60. . of a point p to a group of points pts is min_i(wgt[i]*dist(p, pts[i])), instead of min_i(dist(p, pts[i]))
  61. pts: the i-th point is [i*k, (i+1)*k)
  62. center: the center of the root of quadtree
  63. width: the width of the root
  64. max_level: max level to go down
  65. argmax: on entry, if NULL, will be allocated, iotherwise must be an array of size >= dim which will hold the furtherest point.
  66. Return: the point (argmax) furtherest away from the group, and the distance dist_max.
  67. */
  68. QuadTree qt, qt0;
  69. double distance;
  70. int level = 0;
  71. int ii, j;
  72. double wmax = 0;
  73. if (wgt){
  74. for (int i = 0; i < k; i++) wmax = MAX(wgt[i], wmax);
  75. } else {
  76. wmax = 1.;
  77. }
  78. qt0 = qt = QuadTree_new(dim, center, width, max_level);
  79. qt->total_weight = *dist_max = distance_to_group(k, dim, wgt, pts, center);/* store distance in total_weight */
  80. if (!(*argmax)) *argmax = gv_calloc(dim, sizeof(double));
  81. memcpy(*argmax, center, sizeof(double)*dim);
  82. qt_list_t candidates = {0};
  83. qt_list_t candidates2 = {0};
  84. qt_list_append(&candidates, qt);
  85. /* idea: maintain the current best point and best (largest) distance. check the list of candidate. Subdivide each into quadrants, if any quadrant gives better distance, update, and put on the candidate
  86. list. If we can not prune a quadrant (a quadrant can be pruned if the distance of its center to the group of points pts, plus that from the center to the corner of the quadrant, is smaller than the best), we
  87. also put it down on the candidate list. We then recurse on the candidate list, unless the max level is reached. */
  88. while (level++ < max_level){
  89. if (Verbose > 10) {
  90. fprintf(stderr,"level=%d=================\n", level);
  91. }
  92. qt_list_clear(&candidates2);
  93. for (size_t i = 0; i < qt_list_size(&candidates); i++){
  94. qt = qt_list_get(&candidates, i);
  95. assert(!(qt->qts));
  96. if (Verbose > 10) {
  97. fprintf(stderr, "candidate %" PRISIZE_T " at {", i);
  98. for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->center[j]);
  99. fprintf(stderr,"}, width = %f, dist = %f\n", qt->width, qt->total_weight);
  100. }
  101. distance = qt->total_weight;/* total_weight is used to store the distance from the center to the group */
  102. if (distance + wmax*sqrt(((double) dim))*qt->width < *dist_max) continue;/* this could happen if this candidate was entered into the list earlier than a better one later in the list */
  103. qt->qts = gv_calloc((size_t)1 << dim, sizeof(QuadTree));
  104. for (ii = 0; ii < 1<<dim; ii++) {
  105. qt->qts[ii] = QuadTree_new_in_quadrant(qt->dim, qt->center, (qt->width)/2, max_level, ii);
  106. qt->qts[ii]->total_weight = distance = distance_to_group(k, dim, wgt, pts, qt->qts[ii]->center);/* store distance in total_weight */
  107. bool pruned = false;
  108. if (distance > *dist_max){
  109. *dist_max = distance;
  110. if (Verbose > 10) {
  111. fprintf(stderr,"new distmax=%f, pt={", *dist_max);
  112. for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->qts[ii]->center[j]);
  113. fprintf(stderr,"}\n");
  114. }
  115. memcpy(*argmax, qt->qts[ii]->center, sizeof(double)*dim);
  116. } else if (distance + wmax*sqrt(((double) dim))*(qt->width)/2 < *dist_max){
  117. pruned = true;
  118. }
  119. if (!pruned){
  120. qt_list_append(&candidates2, qt->qts[ii]);
  121. }
  122. }/* finish checking every of the 2^dim siblings */
  123. }/* finish checking all the candidates */
  124. /* sawp the two lists */
  125. qt_list_t ctmp = candidates;
  126. candidates = candidates2;
  127. candidates2 = ctmp;
  128. }/* continue down the quadtree */
  129. QuadTree_delete(qt0);
  130. qt_list_free(&candidates);
  131. qt_list_free(&candidates2);
  132. }
  133. void furtherest_point_in_list(int k, int dim, double *wgt, double *pts, QuadTree qt, int max_level,
  134. double *dist_max, double **argmax){
  135. /* Given a list of points in the Euclidean space contained in the quadtree qt (called the feasible points), find among them one that
  136. is closest to another list of point {dim, k, pts}.
  137. find, in the, a point "furtherest_point" that is furtherest away from a group of k-points pts, using quadtree,
  138. with up to max_level. Here the distance of a point to a group of point is defined as the minimum
  139. of the distance of that point to all the points in the group,
  140. and each distance is defined by the function dist.
  141. Input:
  142. k: number of points in the group
  143. dim: dimension
  144. wgt: if not null, the weighting factor for the i-th point is wgt[i]. The color distance
  145. . of a point p to a group of points pts is min_i(wgt[i]*dist(p, pts[i])), instead of min_i(dist(p, pts[i]))
  146. pts: the i-th point is [i*k, (i+1)*k)
  147. center: the center of the root of quadtree
  148. width: the width of the root
  149. max_level: max level to go down
  150. argmax: on entry, if NULL, will be allocated, otherwise must be an array of size >= dim which will hold the furtherest point.
  151. Return: the point (argmax) furtherest away from the group, and the distance dist_max.
  152. */
  153. double distance;
  154. int level = 0;
  155. int ii, j;
  156. double *average;
  157. double wmax = 0.;
  158. if (wgt){
  159. for (int i = 0; i < k; i++) wmax = MAX(wgt[i], wmax);
  160. } else {
  161. wmax = 1.;
  162. }
  163. average = qt->average;
  164. qt->total_weight = *dist_max = distance_to_group(k, dim, wgt, pts, average);/* store distance in total_weight */
  165. if (!(*argmax)) *argmax = gv_calloc(dim, sizeof(double));
  166. memcpy(*argmax, average, sizeof(double)*dim);
  167. qt_list_t candidates = {0};
  168. qt_list_t candidates2 = {0};
  169. qt_list_append(&candidates, qt);
  170. /* idea: maintain the current best point and best (largest) distance. check the list of candidate. Subdivide each into quadrants, if any quadrant gives better distance, update, and put on the candidate
  171. list. If we can not prune a quadrant (a quadrant can be pruned if the distance of its center to the group of points pts, plus that from the center to the corner of the quadrant, is smaller than the best), we
  172. also put it down on the candidate list. We then recurse on the candidate list, unless the max level is reached. */
  173. while (level++ < max_level){
  174. if (Verbose > 10) {
  175. fprintf(stderr,"level=%d=================\n", level);
  176. }
  177. qt_list_clear(&candidates2);
  178. for (size_t i = 0; i < qt_list_size(&candidates); i++){
  179. qt = qt_list_get(&candidates, i);
  180. if (Verbose > 10) {
  181. fprintf(stderr,"candidate %" PRISIZE_T " at {", i);
  182. for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->center[j]);
  183. fprintf(stderr,"}, width = %f, dist = %f\n", qt->width, qt->total_weight);
  184. }
  185. distance = qt->total_weight;/* total_weight is used to store the distance from average feasible points to the group */
  186. if (qt->n == 1 || distance + wmax*2*sqrt(((double) dim))*qt->width < *dist_max) continue;/* this could happen if this candidate was entered into the list earlier than a better one later in the list. Since the distance
  187. is from the average of the feasible points in the square which may not be at the center */
  188. if (!(qt->qts)) continue;
  189. for (ii = 0; ii < 1<<dim; ii++) {
  190. if (!(qt->qts[ii])) continue;
  191. qt->qts[ii]->total_weight = distance = distance_to_group(k, dim, wgt, pts, qt->qts[ii]->average);/* store distance in total_weight */
  192. bool pruned = false;
  193. if (distance > *dist_max){
  194. *dist_max = distance;
  195. if (Verbose > 10) {
  196. fprintf(stderr,"new distmax=%f, pt={", *dist_max);
  197. for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->qts[ii]->average[j]);
  198. fprintf(stderr,"}\n");
  199. }
  200. memcpy(*argmax, qt->qts[ii]->average, sizeof(double)*dim);
  201. } else if (distance + wmax*sqrt(((double) dim))*(qt->width) < *dist_max){/* average feasible point in this square is too close to the point set */
  202. pruned = true;
  203. }
  204. if (!pruned){
  205. qt_list_append(&candidates2, qt->qts[ii]);
  206. }
  207. }/* finish checking every of the 2^dim siblings */
  208. }/* finish checking all the candidates */
  209. /* sawp the two lists */
  210. qt_list_t ctmp = candidates;
  211. candidates = candidates2;
  212. candidates2 = ctmp;
  213. }/* continue down the quadtree */
  214. qt_list_free(&candidates);
  215. qt_list_free(&candidates2);
  216. }