split.q.c 11 KB

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