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