Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
furtherest_point.c
Go to the documentation of this file.
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
11#include <cgraph/alloc.h>
12#include <cgraph/list.h>
13#include <cgraph/prisize_t.h>
14#include <sparse/general.h>
15#include <sparse/QuadTree.h>
17#include <stdbool.h>
18#include <stddef.h>
19#include <string.h>
20
21static double dist(int dim, double *x, double *y){
22 int k;
23 double d = 0;
24 for (k = 0; k < dim; k++) d += (x[k] - y[k])*(x[k]-y[k]);
25 return sqrt(d);
26}
27
28
29static double distance_to_group(int k, int dim, double *wgt, double *pts, double *center){
30 int i;
31 double distance = -1, dist_min = 0;
32 if (!wgt){
33 for (i = 0; i < k; i++){
34 distance = dist(dim, &(pts[i*dim]), center);
35 if (i == 0){
36 dist_min = distance;
37 } else {
38 dist_min = MIN(dist_min, distance);
39 }
40 }
41 } else {
42 for (i = 0; i < k; i++){
43 distance = dist(dim, &(pts[i*dim]), center);
44 if (i == 0){
45 dist_min = wgt[i]*distance;
46 } else {
47 dist_min = MIN(dist_min, wgt[i]*distance);
48 }
49 }
50 }
51 return dist_min;
52}
53
54DEFINE_LIST(qt_list, QuadTree)
55
56void furtherest_point(int k, int dim, double *wgt, double *pts, double *center, double width, int max_level, double *dist_max, double **argmax){
57 /* Assume that in the box defined by {center, width} are feasible;
58 find, in the, a point "furtherest_point" that is furtherest away from a group of k-points pts, using quadtree,
59 with up to max_level. Here the distance of a point to a group of point is defined as the minimum
60 of the distance of that point to all the points in the group,
61 and each distance is defined by the function dist.
62
63 Input:
64
65 k: number of points in the group
66 dim: dimension
67 wgt: if not null, the weighting factor for the i-th point is wgt[i]. The color distance
68 . 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]))
69 pts: the i-th point is [i*k, (i+1)*k)
70 center: the center of the root of quadtree
71 width: the width of the root
72 max_level: max level to go down
73 argmax: on entry, if NULL, will be allocated, iotherwise must be an array of size >= dim which will hold the furtherest point.
74
75 Return: the point (argmax) furtherest away from the group, and the distance dist_max.
76 */
77 QuadTree qt, qt0;
78 double distance;
79 int level = 0;
80 int ii, j;
81 double wmax = 0;
82
83 if (wgt){
84 for (int i = 0; i < k; i++) wmax = MAX(wgt[i], wmax);
85 } else {
86 wmax = 1.;
87 }
88
89 qt0 = qt = QuadTree_new(dim, center, width, max_level);
90
91 qt->total_weight = *dist_max = distance_to_group(k, dim, wgt, pts, center);/* store distance in total_weight */
92 if (!(*argmax)) *argmax = gv_calloc(dim, sizeof(double));
93 memcpy(*argmax, center, sizeof(double)*dim);
94
95 qt_list_t candidates = {0};
96 qt_list_t candidates2 = {0};
97 qt_list_append(&candidates, qt);
98
99 /* 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
100 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
101 also put it down on the candidate list. We then recurse on the candidate list, unless the max level is reached. */
102 while (level++ < max_level){
103 if (Verbose > 10) {
104 fprintf(stderr,"level=%d=================\n", level);
105 }
106 qt_list_clear(&candidates2);
107 for (size_t i = 0; i < qt_list_size(&candidates); i++){
108
109
110 qt = qt_list_get(&candidates, i);
111 assert(!(qt->qts));
112
113 if (Verbose > 10) {
114 fprintf(stderr, "candidate %" PRISIZE_T " at {", i);
115 for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->center[j]);
116 fprintf(stderr,"}, width = %f, dist = %f\n", qt->width, qt->total_weight);
117 }
118
119 distance = qt->total_weight;/* total_weight is used to store the distance from the center to the group */
120 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 */
121 qt->qts = gv_calloc((size_t)1 << dim, sizeof(QuadTree));
122 for (ii = 0; ii < 1<<dim; ii++) {
123 qt->qts[ii] = QuadTree_new_in_quadrant(qt->dim, qt->center, (qt->width)/2, max_level, ii);
124 qt->qts[ii]->total_weight = distance = distance_to_group(k, dim, wgt, pts, qt->qts[ii]->center);/* store distance in total_weight */
125 bool pruned = false;
126 if (distance > *dist_max){
127 *dist_max = distance;
128 if (Verbose > 10) {
129 fprintf(stderr,"new distmax=%f, pt={", *dist_max);
130 for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->qts[ii]->center[j]);
131 fprintf(stderr,"}\n");
132 }
133 memcpy(*argmax, qt->qts[ii]->center, sizeof(double)*dim);
134 } else if (distance + wmax*sqrt(((double) dim))*(qt->width)/2 < *dist_max){
135 pruned = true;
136 }
137 if (!pruned){
138 qt_list_append(&candidates2, qt->qts[ii]);
139 }
140 }/* finish checking every of the 2^dim siblings */
141 }/* finish checking all the candidates */
142
143 /* sawp the two lists */
144 qt_list_t ctmp = candidates;
145 candidates = candidates2;
146 candidates2 = ctmp;
147
148 }/* continue down the quadtree */
149
150 QuadTree_delete(qt0);
151
152 qt_list_free(&candidates);
153 qt_list_free(&candidates2);
154}
155
156void furtherest_point_in_list(int k, int dim, double *wgt, double *pts, QuadTree qt, int max_level,
157 double *dist_max, double **argmax){
158 /* Given a list of points in the Euclidean space contained in the quadtree qt (called the feasible points), find among them one that
159 is closest to another list of point {dim, k, pts}.
160
161
162 find, in the, a point "furtherest_point" that is furtherest away from a group of k-points pts, using quadtree,
163 with up to max_level. Here the distance of a point to a group of point is defined as the minimum
164 of the distance of that point to all the points in the group,
165 and each distance is defined by the function dist.
166
167 Input:
168
169 k: number of points in the group
170 dim: dimension
171 wgt: if not null, the weighting factor for the i-th point is wgt[i]. The color distance
172 . 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]))
173 pts: the i-th point is [i*k, (i+1)*k)
174 center: the center of the root of quadtree
175 width: the width of the root
176 max_level: max level to go down
177 argmax: on entry, if NULL, will be allocated, otherwise must be an array of size >= dim which will hold the furtherest point.
178
179 Return: the point (argmax) furtherest away from the group, and the distance dist_max.
180 */
181
182 double distance;
183 int level = 0;
184 int ii, j;
185 double *average;
186 double wmax = 0.;
187
188 if (wgt){
189 for (int i = 0; i < k; i++) wmax = MAX(wgt[i], wmax);
190 } else {
191 wmax = 1.;
192 }
193
194 average = qt->average;
195 qt->total_weight = *dist_max = distance_to_group(k, dim, wgt, pts, average);/* store distance in total_weight */
196 if (!(*argmax)) *argmax = gv_calloc(dim, sizeof(double));
197 memcpy(*argmax, average, sizeof(double)*dim);
198
199 qt_list_t candidates = {0};
200 qt_list_t candidates2 = {0};
201 qt_list_append(&candidates, qt);
202
203 /* 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
204 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
205 also put it down on the candidate list. We then recurse on the candidate list, unless the max level is reached. */
206 while (level++ < max_level){
207 if (Verbose > 10) {
208 fprintf(stderr,"level=%d=================\n", level);
209 }
210 qt_list_clear(&candidates2);
211 for (size_t i = 0; i < qt_list_size(&candidates); i++){
212 qt = qt_list_get(&candidates, i);
213
214 if (Verbose > 10) {
215 fprintf(stderr,"candidate %" PRISIZE_T " at {", i);
216 for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->center[j]);
217 fprintf(stderr,"}, width = %f, dist = %f\n", qt->width, qt->total_weight);
218 }
219
220 distance = qt->total_weight;/* total_weight is used to store the distance from average feasible points to the group */
221 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
222 is from the average of the feasible points in the square which may not be at the center */
223
224 if (!(qt->qts)) continue;
225
226 for (ii = 0; ii < 1<<dim; ii++) {
227 if (!(qt->qts[ii])) continue;
228 qt->qts[ii]->total_weight = distance = distance_to_group(k, dim, wgt, pts, qt->qts[ii]->average);/* store distance in total_weight */
229 bool pruned = false;
230 if (distance > *dist_max){
231 *dist_max = distance;
232 if (Verbose > 10) {
233 fprintf(stderr,"new distmax=%f, pt={", *dist_max);
234 for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->qts[ii]->average[j]);
235 fprintf(stderr,"}\n");
236 }
237 memcpy(*argmax, qt->qts[ii]->average, sizeof(double)*dim);
238 } else if (distance + wmax*sqrt(((double) dim))*(qt->width) < *dist_max){/* average feasible point in this square is too close to the point set */
239 pruned = true;
240 }
241 if (!pruned){
242 qt_list_append(&candidates2, qt->qts[ii]);
243 }
244 }/* finish checking every of the 2^dim siblings */
245 }/* finish checking all the candidates */
246
247 /* sawp the two lists */
248 qt_list_t ctmp = candidates;
249 candidates = candidates2;
250 candidates2 = ctmp;
251
252 }/* continue down the quadtree */
253
254 qt_list_free(&candidates);
255 qt_list_free(&candidates2);
256}
QuadTree QuadTree_new_in_quadrant(int dim, double *center, double width, int max_level, int i)
Definition QuadTree.c:412
QuadTree QuadTree_new(int dim, double *center, double width, int max_level)
Definition QuadTree.c:356
void QuadTree_delete(QuadTree q)
Definition QuadTree.c:374
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define MIN(a, b)
Definition arith.h:28
void furtherest_point_in_list(int k, int dim, double *wgt, double *pts, QuadTree qt, int max_level, double *dist_max, double **argmax)
static double dist(int dim, double *x, double *y)
static double distance_to_group(int k, int dim, double *wgt, double *pts, double *center)
void furtherest_point(int k, int dim, double *wgt, double *pts, double *center, double width, int max_level, double *dist_max, double **argmax)
double distance(double *x, int dim, int i, int j)
Definition general.c:145
static int Verbose
Definition gml2gv.c:22
#define DEFINE_LIST(name, type)
Definition list.h:26
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
double total_weight
Definition QuadTree.h:37
double * average
Definition QuadTree.h:42
QuadTree * qts
Definition QuadTree.h:43
double * center
Definition QuadTree.h:39
static point center(point vertex[], size_t n)
#define MAX(a, b)
Definition write.c:31