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