blocks.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /**
  2. * \brief A block structure defined over the variables
  3. *
  4. * A block structure defined over the variables such that each block contains
  5. * 1 or more variables, with the invariant that all constraints inside a block
  6. * are satisfied by keeping the variables fixed relative to one another
  7. *
  8. * Authors:
  9. * Tim Dwyer <[email protected]>
  10. *
  11. * Copyright (C) 2005 Authors
  12. *
  13. * This version is released under the CPL (Common Public License) with
  14. * the Graphviz distribution.
  15. * A version is also available under the LGPL as part of the Adaptagrams
  16. * project: https://github.com/mjwybrow/adaptagrams.
  17. * If you make improvements or bug fixes to this code it would be much
  18. * appreciated if you could also contribute those changes back to the
  19. * Adaptagrams repository.
  20. */
  21. #include <vpsc/blocks.h>
  22. #include <vpsc/block.h>
  23. #include <vpsc/constraint.h>
  24. #include <fstream>
  25. using std::ios;
  26. using std::ofstream;
  27. using std::set;
  28. using std::list;
  29. #ifndef RECTANGLE_OVERLAP_LOGGING
  30. #define RECTANGLE_OVERLAP_LOGGING 0
  31. #endif
  32. long blockTimeCtr;
  33. Blocks::Blocks(const int n, Variable *vs_[]) : vs(vs_), nvs(n) {
  34. blockTimeCtr=0;
  35. for(int i=0;i<nvs;i++) {
  36. insert(new Block(vs[i]));
  37. }
  38. }
  39. Blocks::~Blocks()
  40. {
  41. blockTimeCtr=0;
  42. for (Block *b : *this) {
  43. delete b;
  44. }
  45. }
  46. /**
  47. * returns a list of variables with total ordering determined by the constraint
  48. * DAG
  49. */
  50. list<Variable*> Blocks::totalOrder() {
  51. list<Variable*> order;
  52. for(int i=0;i<nvs;i++) {
  53. vs[i]->visited=false;
  54. }
  55. for(int i=0;i<nvs;i++) {
  56. if(vs[i]->in.empty()) {
  57. dfsVisit(vs[i],order);
  58. }
  59. }
  60. return order;
  61. }
  62. // Recursive depth first search giving total order by pushing nodes in the DAG
  63. // onto the front of the list when we finish searching them
  64. void Blocks::dfsVisit(Variable *v, list<Variable*> &order) {
  65. v->visited=true;
  66. for (Constraint *c : v->out) {
  67. if(!c->right->visited) {
  68. dfsVisit(c->right, order);
  69. }
  70. }
  71. if (RECTANGLE_OVERLAP_LOGGING) {
  72. ofstream f(LOGFILE,ios::app);
  73. f<<" order="<<*v<<"\n";
  74. }
  75. order.push_front(v);
  76. }
  77. /**
  78. * Processes incoming constraints, most violated to least, merging with the
  79. * neighbouring (left) block until no more violated constraints are found
  80. */
  81. void Blocks::mergeLeft(Block *r) {
  82. if (RECTANGLE_OVERLAP_LOGGING) {
  83. ofstream f(LOGFILE,ios::app);
  84. f<<"mergeLeft called on "<<*r<<"\n";
  85. }
  86. r->timeStamp=++blockTimeCtr;
  87. r->setUpInConstraints();
  88. Constraint *c=r->findMinInConstraint();
  89. while (c != nullptr && c->slack()<0) {
  90. if (RECTANGLE_OVERLAP_LOGGING) {
  91. ofstream f(LOGFILE,ios::app);
  92. f<<"mergeLeft on constraint: "<<*c<<"\n";
  93. }
  94. r->deleteMinInConstraint();
  95. Block *l = c->left->block;
  96. if (l->in.empty()) l->setUpInConstraints();
  97. double dist = c->right->offset - c->left->offset - c->gap;
  98. if (r->vars.size() < l->vars.size()) {
  99. dist=-dist;
  100. std::swap(l, r);
  101. }
  102. blockTimeCtr++;
  103. r->merge(l, c, dist);
  104. r->mergeIn(l);
  105. r->timeStamp=blockTimeCtr;
  106. removeBlock(l);
  107. c=r->findMinInConstraint();
  108. }
  109. if (RECTANGLE_OVERLAP_LOGGING) {
  110. ofstream f(LOGFILE,ios::app);
  111. f<<"merged "<<*r<<"\n";
  112. }
  113. }
  114. /**
  115. * Symmetrical to mergeLeft
  116. */
  117. void Blocks::mergeRight(Block *l) {
  118. if (RECTANGLE_OVERLAP_LOGGING) {
  119. ofstream f(LOGFILE,ios::app);
  120. f<<"mergeRight called on "<<*l<<"\n";
  121. }
  122. l->setUpOutConstraints();
  123. Constraint *c = l->findMinOutConstraint();
  124. while (c != nullptr && c->slack()<0) {
  125. if (RECTANGLE_OVERLAP_LOGGING) {
  126. ofstream f(LOGFILE,ios::app);
  127. f<<"mergeRight on constraint: "<<*c<<"\n";
  128. }
  129. l->deleteMinOutConstraint();
  130. Block *r = c->right->block;
  131. r->setUpOutConstraints();
  132. double dist = c->left->offset + c->gap - c->right->offset;
  133. if (l->vars.size() > r->vars.size()) {
  134. dist=-dist;
  135. std::swap(l, r);
  136. }
  137. l->merge(r, c, dist);
  138. l->mergeOut(r);
  139. removeBlock(r);
  140. c=l->findMinOutConstraint();
  141. }
  142. if (RECTANGLE_OVERLAP_LOGGING) {
  143. ofstream f(LOGFILE,ios::app);
  144. f<<"merged "<<*l<<"\n";
  145. }
  146. }
  147. void Blocks::removeBlock(Block *doomed) {
  148. doomed->deleted=true;
  149. //erase(doomed);
  150. }
  151. void Blocks::cleanup() {
  152. for (auto i = begin(); i != end();) {
  153. Block *b=*i;
  154. if(b->deleted) {
  155. i = erase(i);
  156. delete b;
  157. } else {
  158. ++i;
  159. }
  160. }
  161. }
  162. /**
  163. * Splits block b across constraint c into two new blocks, l and r (c's left
  164. * and right sides respectively)
  165. */
  166. void Blocks::split(Block *b, Block *&l, Block *&r, Constraint *c) {
  167. b->split(l,r,c);
  168. if (RECTANGLE_OVERLAP_LOGGING) {
  169. ofstream f(LOGFILE,ios::app);
  170. f<<"Split left: "<<*l<<"\n";
  171. f<<"Split right: "<<*r<<"\n";
  172. }
  173. r->posn = b->posn;
  174. r->wposn = r->posn * r->weight;
  175. mergeLeft(l);
  176. // r may have been merged!
  177. r = c->right->block;
  178. r->wposn = r->desiredWeightedPosition();
  179. r->posn = r->wposn / r->weight;
  180. mergeRight(r);
  181. removeBlock(b);
  182. insert(l);
  183. insert(r);
  184. }
  185. /**
  186. * returns the cost total squared distance of variables from their desired
  187. * positions
  188. */
  189. double Blocks::cost() {
  190. double c = 0;
  191. for (Block *b : *this) {
  192. c += b->cost();
  193. }
  194. return c;
  195. }