Graphviz 13.0.0~dev.20250121.0651
Loading...
Searching...
No Matches
split.q.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 <inttypes.h>
12#include <label/index.h>
13#include <stddef.h>
14#include <stdint.h>
15#include <stdio.h>
16#include <assert.h>
17#include <label/split.q.h>
18#include <stdbool.h>
19
20/* Forward declarations */
21static void MethodZero(RTree_t * rtp);
22static void InitPVars(RTree_t * rtp);
23static void LoadNodes(RTree_t *rtp, Node_t *n, Node_t *q);
24static void Classify(RTree_t * rtp, int i, int group);
25static void PickSeeds(RTree_t * rtp);
26static void GetBranches(RTree_t * rtp, Node_t * n, Branch_t * b);
27
28/*-----------------------------------------------------------------------------
29| Split a node.
30| Divides the nodes branches and the extra one between two nodes.
31| Old node is one of the new ones, and one really new one is created.
32| Tries more than one method for choosing a partition, uses best result.
33-----------------------------------------------------------------------------*/
34void SplitNode(RTree_t * rtp, Node_t * n, Branch_t * b, Node_t ** nn)
35{
36 assert(n);
37 assert(b);
38
39#ifdef RTDEBUG
40 fprintf(stderr, "Splitting:\n");
41 PrintNode(n);
42 fprintf(stderr, "new branch:\n");
43 PrintBranch(-1, b);
44#endif
45
46 /* load all the branches into a buffer, initialize old node */
47 int level = n->level;
48 GetBranches(rtp, n, b);
49
50#ifdef RTDEBUG
51 {
52 /* Indicate that a split is about to take place */
53 for (size_t i = 0; i < NODECARD + 1; i++) {
54 PrintRect(&rtp->split.BranchBuf[i].rect);
55 }
56 PrintRect(&rtp->split.CoverSplit);
57 }
58#endif
59
60 /* find partition */
61#ifdef RTDEBUG
62 struct PartitionVars *p = &rtp->split.Partitions[0];
63#endif
64 MethodZero(rtp);
65
66 /* put branches from buffer into 2 nodes according to chosen partition */
67 *nn = RTreeNewNode();
68 (*nn)->level = n->level = level;
69 LoadNodes(rtp, n, *nn);
70 assert(n->count + (*nn)->count == NODECARD + 1);
71
72#ifdef RTDEBUG
73 PrintPVars(p);
74 fprintf(stderr, "group 0:\n");
75 PrintNode(n);
76 fprintf(stderr, "group 1:\n");
77 PrintNode(*nn);
78 fprintf(stderr, "\n");
79#endif
80
81}
82
83/*-----------------------------------------------------------------------------
84| Load branch buffer with branches from full node plus the extra branch.
85-----------------------------------------------------------------------------*/
86static void GetBranches(RTree_t * rtp, Node_t * n, Branch_t * b)
87{
88 assert(n);
89 assert(b);
90
91 /* load the branch buffer */
92 for (size_t i = 0; i < NODECARD; i++) {
93 assert(n->branch[i].child); /* node should have every entry full */
94 rtp->split.BranchBuf[i] = n->branch[i];
95 }
96 rtp->split.BranchBuf[NODECARD] = *b;
97
98 /* calculate rect containing all in the set */
99 rtp->split.CoverSplit = rtp->split.BranchBuf[0].rect;
100 for (size_t i = 1; i < NODECARD + 1; i++) {
102 &rtp->split.BranchBuf[i].rect);
103 }
105
106 InitNode(n);
107}
108
109/*-----------------------------------------------------------------------------
110| Method #0 for choosing a partition:
111| As the seeds for the two groups, pick the two rects that would waste the
112| most area if covered by a single rectangle, i.e. evidently the worst pair
113| to have in the same group.
114| Of the remaining, one at a time is chosen to be put in one of the two groups.
115| The one chosen is the one with the greatest difference in area expansion
116| depending on which group - the rect most strongly attracted to one group
117| and repelled from the other.
118| If one group gets too full (more would force other group to violate min
119| fill requirement) then other group gets the rest.
120| These last are the ones that can go in either group most easily.
121-----------------------------------------------------------------------------*/
122static void MethodZero(RTree_t * rtp)
123{
124 int group, chosen = 0, betterGroup = 0;
125
126 InitPVars(rtp);
127 PickSeeds(rtp);
128
129 while (rtp->split.Partitions[0].count[0] +
130 rtp->split.Partitions[0].count[1] < NODECARD + 1 &&
131 rtp->split.Partitions[0].count[0] < NODECARD + 1
132 && rtp->split.Partitions[0].count[1] < NODECARD + 1) {
133 bool biggestDiffSet = false;
134 uint64_t biggestDiff = 0;
135 for (int i = 0; i < NODECARD + 1; i++) {
136 if (!rtp->split.Partitions[0].taken[i]) {
137 Rect_t *r = &rtp->split.BranchBuf[i].rect;
138 Rect_t rect = CombineRect(r, &rtp->split.Partitions[0].cover[0]);
139 uint64_t growth0 = RectArea(&rect) - rtp->split.Partitions[0].area[0];
140 rect = CombineRect(r, &rtp->split.Partitions[0].cover[1]);
141 uint64_t growth1 = RectArea(&rect) - rtp->split.Partitions[0].area[1];
142 uint64_t diff;
143 if (growth1 >= growth0) {
144 diff = growth1 - growth0;
145 group = 0;
146 } else {
147 diff = growth0 - growth1;
148 group = 1;
149 }
150
151 if (!biggestDiffSet || diff > biggestDiff) {
152 biggestDiff = diff;
153 biggestDiffSet = true;
154 chosen = i;
155 betterGroup = group;
156 } else if (diff == biggestDiff &&
157 rtp->split.Partitions[0].count[group] <
158 rtp->split.Partitions[0].count[betterGroup]) {
159 chosen = i;
160 betterGroup = group;
161 }
162 }
163 }
164 Classify(rtp, chosen, betterGroup);
165 }
166
167 /* if one group too full, put remaining rects in the other */
168 if (rtp->split.Partitions[0].count[0] +
169 rtp->split.Partitions[0].count[1] < NODECARD + 1) {
170 group = 0;
171 if (rtp->split.Partitions[0].count[0] >= NODECARD + 1)
172 group = 1;
173 for (int i = 0; i < NODECARD + 1; i++) {
174 if (!rtp->split.Partitions[0].taken[i])
175 Classify(rtp, i, group);
176 }
177 }
178
179 assert(rtp->split.Partitions[0].count[0] +
180 rtp->split.Partitions[0].count[1] == NODECARD + 1);
181 assert(rtp->split.Partitions[0].count[0] >= 0
182 && rtp->split.Partitions[0].count[1] >= 0);
183}
184
185/*-----------------------------------------------------------------------------
186| Pick two rects from set to be the first elements of the two groups.
187| Pick the two that waste the most area if covered by a single rectangle.
188-----------------------------------------------------------------------------*/
189static void PickSeeds(RTree_t * rtp)
190{
191 int seed0 = 0, seed1 = 0;
192 uint64_t area[NODECARD + 1];
193
194 for (int i = 0; i < NODECARD + 1; i++)
195 area[i] = RectArea(&rtp->split.BranchBuf[i].rect);
196
197 uint64_t worst=0;
198 for (int i = 0; i < NODECARD; i++) {
199 for (int j = i + 1; j < NODECARD + 1; j++) {
200 Rect_t rect = CombineRect(&rtp->split.BranchBuf[i].rect,
201 &rtp->split.BranchBuf[j].rect);
202 uint64_t waste = RectArea(&rect) - area[i] - area[j];
203 if (waste > worst) {
204 worst = waste;
205 seed0 = i;
206 seed1 = j;
207 }
208 }
209 }
210 Classify(rtp, seed0, 0);
211 Classify(rtp, seed1, 1);
212}
213
214/*-----------------------------------------------------------------------------
215| Put a branch in one of the groups.
216-----------------------------------------------------------------------------*/
217static void Classify(RTree_t * rtp, int i, int group)
218{
219
220 assert(!rtp->split.Partitions[0].taken[i]);
221
222 rtp->split.Partitions[0].partition[i] = group;
223 rtp->split.Partitions[0].taken[i] = true;
224
225 if (rtp->split.Partitions[0].count[group] == 0)
226 rtp->split.Partitions[0].cover[group] =
227 rtp->split.BranchBuf[i].rect;
228 else
229 rtp->split.Partitions[0].cover[group] =
231 &rtp->split.Partitions[0].cover[group]);
232 rtp->split.Partitions[0].area[group] =
233 RectArea(&rtp->split.Partitions[0].cover[group]);
234 rtp->split.Partitions[0].count[group]++;
235
236# ifdef RTDEBUG
237 {
238 /* redraw entire group and its cover */
239 int j;
240 MFBSetColor(WHITE); /* cover is white */
241 PrintRect(&rtp->split.Partitions[0].cover[group]);
242 MFBSetColor(group + 3); /* group 0 green, group 1 blue */
243 for (j = 0; j < NODECARD + 1; j++) {
244 if (rtp->split.Partitions[0].taken[j] &&
245 rtp->split.Partitions[0].partition[j] == group)
246 PrintRect(&rtrtp->split.Partitions[0].BranchBuf[j].rect);
247 }
248 GraphChar();
249 }
250# endif
251}
252
253/*-----------------------------------------------------------------------------
254| Copy branches from the buffer into two nodes according to the partition.
255-----------------------------------------------------------------------------*/
256static void LoadNodes(RTree_t *rtp, Node_t *n, Node_t *q) {
257 assert(n);
258 assert(q);
259
260 for (size_t i = 0; i < NODECARD + 1; i++) {
261 assert(rtp->split.Partitions[0].partition[i] == 0 ||
262 rtp->split.Partitions[0].partition[i] == 1);
263 if (rtp->split.Partitions[0].partition[i] == 0)
264 AddBranch(rtp, &rtp->split.BranchBuf[i], n, NULL);
265 else if (rtp->split.Partitions[0].partition[i] == 1)
266 AddBranch(rtp, &rtp->split.BranchBuf[i], q, NULL);
267 }
268}
269
270/*-----------------------------------------------------------------------------
271| Initialize a PartitionVars structure.
272-----------------------------------------------------------------------------*/
273static void InitPVars(RTree_t * rtp)
274{
275 rtp->split.Partitions[0].count[0] = rtp->split.Partitions[0].count[1] =
276 0;
277 rtp->split.Partitions[0].cover[0] = rtp->split.Partitions[0].cover[1] =
278 NullRect();
279 rtp->split.Partitions[0].area[0] = rtp->split.Partitions[0].area[1] =
280 0;
281 for (size_t i = 0; i < NODECARD + 1; i++) {
282 rtp->split.Partitions[0].taken[i] = false;
283 rtp->split.Partitions[0].partition[i] = -1;
284 }
285}
286
287#ifdef RTDEBUG
288
289/*-----------------------------------------------------------------------------
290| Print out data for a partition from PartitionVars struct.
291-----------------------------------------------------------------------------*/
292PrintPVars(RTree_t * rtp)
293{
294 fprintf(stderr, "\npartition:\n");
295 for (size_t i = 0; i < NODECARD + 1; i++) {
296 fprintf(stderr, "%3zu\t", i);
297 }
298 fprintf(stderr, "\n");
299 for (size_t i = 0; i < NODECARD + 1; i++) {
300 if (rtp->split.Partitions[0].taken[i])
301 fprintf(stderr, " t\t");
302 else
303 fprintf(stderr, "\t");
304 }
305 fprintf(stderr, "\n");
306 for (size_t i = 0; i < NODECARD + 1; i++) {
307 fprintf(stderr, "%3d\t", rtp->split.Partitions[0].partition[i]);
308 }
309 fprintf(stderr, "\n");
310
311 fprintf(stderr, "count[0] = %d area = %" PRIu64 "\n",
312 rtp->split.Partitions[0].count[0],
313 rtp->split.Partitions[0].area[0]);
314 fprintf(stderr, "count[1] = %d area = %" PRIu64 "\n",
315 rtp->split.Partitions[0].count[1],
316 rtp->split.Partitions[0].area[1]);
317 if (rtp->split.Partitions[0].area[0] +
318 rtp->split.Partitions[0].area[1] > 0) {
319 fprintf(stderr, "total area = %" PRIu64 " effectiveness = %3.2f\n",
320 rtp->split.Partitions[0].area[0] +
321 rtp->split.Partitions[0].area[1],
322 (float) rtp->split.CoverSplitArea /
323 (rtp->split.Partitions[0].area[0] +
324 rtp->split.Partitions[0].area[1]));
325 }
326 fprintf(stderr, "cover[0]:\n");
327 PrintRect(&rtp->split.Partitions[0].cover[0]);
328
329 fprintf(stderr, "cover[1]:\n");
330 PrintRect(&rtp->split.Partitions[0].cover[1]);
331}
332#endif
node NULL
Definition grammar.y:163
#define NODECARD
Definition index.h:43
void InitNode(Node_t *n)
Definition node.c:32
Node_t * RTreeNewNode(void)
Definition node.c:24
int AddBranch(RTree_t *rtp, Branch_t *b, Node_t *n, Node_t **new)
Definition node.c:147
void PrintBranch(int, Branch_t *)
Rect_t NullRect(void)
Definition rectangle.c:39
Rect_t CombineRect(const Rect_t *r, const Rect_t *rr)
Definition rectangle.c:88
uint64_t RectArea(const Rect_t *r)
Definition rectangle.c:66
static void GetBranches(RTree_t *rtp, Node_t *n, Branch_t *b)
Definition split.q.c:86
static void Classify(RTree_t *rtp, int i, int group)
Definition split.q.c:217
void SplitNode(RTree_t *rtp, Node_t *n, Branch_t *b, Node_t **nn)
Definition split.q.c:34
static void MethodZero(RTree_t *rtp)
Definition split.q.c:122
static void LoadNodes(RTree_t *rtp, Node_t *n, Node_t *q)
Definition split.q.c:256
static void InitPVars(RTree_t *rtp)
Definition split.q.c:273
static void PickSeeds(RTree_t *rtp)
Definition split.q.c:189
Definition node.h:19
Rect_t rect
Definition node.h:20
struct Node * child
Definition node.h:21
Definition node.h:24
int level
Definition node.h:26
struct Branch branch[NODECARD]
Definition node.h:27
int count
Definition node.h:25
struct Rect cover[2]
Definition split.q.h:32
uint64_t area[2]
Definition split.q.h:33
int partition[NODECARD+1]
Definition split.q.h:29
int count[2]
Definition split.q.h:31
int taken[NODECARD+1]
Definition split.q.h:30
Definition index.h:65
SplitQ_t split
Definition index.h:68
struct PartitionVars Partitions[METHODS]
Definition split.q.h:40
struct Branch BranchBuf[NODECARD+1]
Definition split.q.h:37
uint64_t CoverSplitArea
Definition split.q.h:39
struct Rect CoverSplit
Definition split.q.h:38