Graphviz 14.1.3~dev.20260124.0732
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 "config.h"
12
13#include <sparse/general.h>
14#include <sparse/QuadTree.h>
16#include <stdbool.h>
17#include <stddef.h>
18#include <string.h>
19#include <util/alloc.h>
20#include <util/gv_math.h>
21#include <util/list.h>
22#include <util/prisize_t.h>
23
24static double dist(int dim, double *x, double *y){
25 int k;
26 double d = 0;
27 for (k = 0; k < dim; k++) d += (x[k] - y[k])*(x[k]-y[k]);
28 return sqrt(d);
29}
30
31
32static double distance_to_group(int k, int dim, double *wgt, double *pts, double *center){
33 int i;
34 double distance = -1, dist_min = 0;
35 if (!wgt){
36 for (i = 0; i < k; i++){
37 distance = dist(dim, &(pts[i*dim]), center);
38 if (i == 0){
39 dist_min = distance;
40 } else {
41 dist_min = MIN(dist_min, distance);
42 }
43 }
44 } else {
45 for (i = 0; i < k; i++){
46 distance = dist(dim, &(pts[i*dim]), center);
47 if (i == 0){
48 dist_min = wgt[i]*distance;
49 } else {
50 dist_min = MIN(dist_min, wgt[i]*distance);
51 }
52 }
53 }
54 return dist_min;
55}
56
57typedef LIST(QuadTree) qt_list_t;
58
59void furtherest_point(int k, int dim, double *wgt, double *pts, double *center, double width, int max_level, double *dist_max, double **argmax){
60 /* Assume that in the box defined by {center, width} are feasible;
61 find, in the, a point "furtherest_point" that is furtherest away from a group of k-points pts, using quadtree,
62 with up to max_level. Here the distance of a point to a group of point is defined as the minimum
63 of the distance of that point to all the points in the group,
64 and each distance is defined by the function dist.
65
66 Input:
67
68 k: number of points in the group
69 dim: dimension
70 wgt: if not null, the weighting factor for the i-th point is wgt[i]. The color distance
71 . 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]))
72 pts: the i-th point is [i*k, (i+1)*k)
73 center: the center of the root of quadtree
74 width: the width of the root
75 max_level: max level to go down
76 argmax: on entry, if NULL, will be allocated, iotherwise must be an array of size >= dim which will hold the furtherest point.
77
78 Return: the point (argmax) furtherest away from the group, and the distance dist_max.
79 */
80 QuadTree qt, qt0;
81 double distance;
82 int level = 0;
83 int ii, j;
84 double wmax = 0;
85
86 if (wgt){
87 for (int i = 0; i < k; i++) wmax = MAX(wgt[i], wmax);
88 } else {
89 wmax = 1.;
90 }
91
92 qt0 = qt = QuadTree_new(dim, center, width, max_level);
93
94 qt->total_weight = *dist_max = distance_to_group(k, dim, wgt, pts, center);/* store distance in total_weight */
95 if (!(*argmax)) *argmax = gv_calloc(dim, sizeof(double));
96 memcpy(*argmax, center, sizeof(double)*dim);
97
98 qt_list_t candidates = {0};
99 qt_list_t candidates2 = {0};
100 LIST_APPEND(&candidates, qt);
101
102 /* 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
103 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
104 also put it down on the candidate list. We then recurse on the candidate list, unless the max level is reached. */
105 while (level++ < max_level){
106 if (Verbose > 10) {
107 fprintf(stderr,"level=%d=================\n", level);
108 }
109 LIST_CLEAR(&candidates2);
110 for (size_t i = 0; i < LIST_SIZE(&candidates); i++){
111
112
113 qt = LIST_GET(&candidates, i);
114 assert(!(qt->qts));
115
116 if (Verbose > 10) {
117 fprintf(stderr, "candidate %" PRISIZE_T " at {", i);
118 for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->center[j]);
119 fprintf(stderr,"}, width = %f, dist = %f\n", qt->width, qt->total_weight);
120 }
121
122 distance = qt->total_weight;/* total_weight is used to store the distance from the center to the group */
123 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 */
124 qt->qts = gv_calloc((size_t)1 << dim, sizeof(QuadTree));
125 for (ii = 0; ii < 1<<dim; ii++) {
126 qt->qts[ii] = QuadTree_new_in_quadrant(qt->dim, qt->center, (qt->width)/2, max_level, ii);
127 qt->qts[ii]->total_weight = distance = distance_to_group(k, dim, wgt, pts, qt->qts[ii]->center);/* store distance in total_weight */
128 bool pruned = false;
129 if (distance > *dist_max){
130 *dist_max = distance;
131 if (Verbose > 10) {
132 fprintf(stderr,"new distmax=%f, pt={", *dist_max);
133 for (j = 0; j < dim; j++) fprintf(stderr,"%f, ", qt->qts[ii]->center[j]);
134 fprintf(stderr,"}\n");
135 }
136 memcpy(*argmax, qt->qts[ii]->center, sizeof(double)*dim);
137 } else if (distance + wmax*sqrt(((double) dim))*(qt->width)/2 < *dist_max){
138 pruned = true;
139 }
140 if (!pruned){
141 LIST_APPEND(&candidates2, qt->qts[ii]);
142 }
143 }/* finish checking every of the 2^dim siblings */
144 }/* finish checking all the candidates */
145
146 SWAP(&candidates, &candidates2);
147
148 }/* continue down the quadtree */
149
150 QuadTree_delete(qt0);
151
152 LIST_FREE(&candidates);
153 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 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 LIST_CLEAR(&candidates2);
211 for (size_t i = 0; i < LIST_SIZE(&candidates); i++){
212 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 LIST_APPEND(&candidates2, qt->qts[ii]);
243 }
244 }/* finish checking every of the 2^dim siblings */
245 }/* finish checking all the candidates */
246
247 SWAP(&candidates, &candidates2);
248
249 }/* continue down the quadtree */
250
251 LIST_FREE(&candidates);
252 LIST_FREE(&candidates2);
253}
QuadTree QuadTree_new_in_quadrant(int dim, double *center, double width, int max_level, int i)
Definition QuadTree.c:415
QuadTree QuadTree_new(int dim, double *center, double width, int max_level)
Definition QuadTree.c:359
void QuadTree_delete(QuadTree q)
Definition QuadTree.c:377
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
#define MAX(a, b)
Definition arith.h:33
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:123
static bool Verbose
Definition gml2gv.c:26
Arithmetic helper functions.
#define SWAP(a, b)
Definition gv_math.h:134
type-generic dynamically expanding list
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_CLEAR(list)
Definition list.h:240
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_GET(list, index)
Definition list.h:155
static const int dim
#define PRISIZE_T
Definition prisize_t.h:25
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)