Graphviz 14.1.3~dev.20260206.1255
Loading...
Searching...
No Matches
block.cpp
Go to the documentation of this file.
1
20#include "config.h"
21
22#include <algorithm>
23#include <cassert>
24#include <ostream>
25#include <vector>
26#include <vpsc/constraint.h>
27#include <vpsc/block.h>
28#include <vpsc/blocks.h>
29#include <fstream>
30using std::ios;
31using std::ofstream;
32using std::vector;
33
34#ifndef RECTANGLE_OVERLAP_LOGGING
35 #define RECTANGLE_OVERLAP_LOGGING 0
36#endif
37
39static bool gt(const Constraint *const lhs, const Constraint *const rhs) {
40 return compareConstraints(rhs, lhs);
41}
42
47static void make_heap(std::vector<Constraint *> &heap) {
48 std::make_heap(heap.begin(), heap.end(), gt);
49}
50
52static void merge_heaps(std::vector<Constraint *> &heap1,
53 const std::vector<Constraint *> &heap2) {
54 heap1.insert(heap1.end(), heap2.begin(), heap2.end());
55 make_heap(heap1);
56}
57
59static Constraint *findMin(std::vector<Constraint *> &heap) {
60 assert(std::is_heap(heap.begin(), heap.end(), gt));
61 return heap.front();
62}
63
65static void deleteMin(std::vector<Constraint *> &heap) {
66 assert(std::is_heap(heap.begin(), heap.end(), gt));
67 std::pop_heap(heap.begin(), heap.end(), gt);
68 heap.pop_back();
69}
70
72static void insert(std::vector<Constraint *> &heap, Constraint *c) {
73 assert(std::is_heap(heap.begin(), heap.end(), gt));
74 heap.push_back(c);
75 std::push_heap(heap.begin(), heap.end(), gt);
76}
77
78void Block::addVariable(Variable *v) {
79 v->block=this;
80 vars.push_back(v);
81 weight+=v->weight;
82 wposn += v->weight * (v->desiredPosition - v->offset);
84}
86 timeStamp=0;
88 deleted=false;
89 if(v!=nullptr) {
90 v->offset=0;
91 addVariable(v);
92 }
93}
94
96 double wp = 0;
97 for (const Variable *v : vars) {
98 wp += (v->desiredPosition - v->offset) * v->weight;
99 }
100 return wp;
101}
103 in = setUpConstraintHeap(true);
104}
106 out = setUpConstraintHeap(false);
107}
108
109std::vector<Constraint *> Block::setUpConstraintHeap(bool use_in) {
110 std::vector<Constraint *> h;
111 for (Variable *v : vars) {
112 vector<Constraint*> *cs= use_in ? &v->in : &v->out;
113 for (Constraint *c : *cs) {
114 c->timeStamp=blockTimeCtr;
115 if ((c->left->block != this && use_in) || (c->right->block != this && !use_in)) {
116 h.push_back(c);
117 }
118 }
119 }
120 make_heap(h);
121 return h;
122}
125 ofstream f(LOGFILE,ios::app);
126 f<<" merging on: "<<*c<<",c->left->offset="<<c->left->offset<<",c->right->offset="<<c->right->offset<<"\n";
127 }
128 const double dist = c->right->offset - c->left->offset - c->gap;
129 Block *l=c->left->block;
130 Block *r=c->right->block;
131 if (vars.size() < b->vars.size()) {
132 r->merge(l,c,dist);
133 } else {
134 l->merge(r,c,-dist);
135 }
137 ofstream f(LOGFILE,ios::app);
138 f<<" merged block="<<(b->deleted?*this:*b)<<"\n";
139 }
140}
148void Block::merge(Block *b, Constraint *c, double dist) {
150 ofstream f(LOGFILE,ios::app);
151 f<<" merging: "<<*b<<"dist="<<dist<<"\n";
152 }
153 c->active=true;
154 wposn+=b->wposn-dist*b->weight;
155 weight+=b->weight;
157 for (Variable *v : b->vars) {
158 v->block=this;
159 v->offset+=dist;
160 vars.push_back(v);
161 }
162 b->deleted=true;
163}
164
167 ofstream f(LOGFILE,ios::app);
168 f<<" merging constraint heaps... \n";
169 }
170 // We check the top of the heaps to remove possible internal constraints
173 merge_heaps(in, b->in);
174}
181 Constraint *v = nullptr;
182 vector<Constraint*> outOfDate;
183 while (!in.empty()) {
184 v = findMin(in);
185 const Block *lb = v->left->block;
186 const Block *rb = v->right->block;
187 // rb may not be this if called between merge and mergeIn
189 ofstream f(LOGFILE,ios::app);
190 f<<" checking constraint ... "<<*v;
191 f<<" timestamps: left="<<lb->timeStamp<<" right="<<rb->timeStamp<<" constraint="<<v->timeStamp<<"\n";
192 }
193 if(lb == rb) {
194 // constraint has been merged into the same block
195 if(RECTANGLE_OVERLAP_LOGGING && v->slack()<0) {
196 ofstream f(LOGFILE,ios::app);
197 f<<" violated internal constraint found! "<<*v<<"\n";
198 f<<" lb="<<*lb<<"\n";
199 f<<" rb="<<*rb<<"\n";
200 }
201 deleteMin(in);
203 ofstream f(LOGFILE,ios::app);
204 f<<" ... skipping internal constraint\n";
205 }
206 } else if(v->timeStamp < lb->timeStamp) {
207 // block at other end of constraint has been moved since this
208 deleteMin(in);
209 outOfDate.push_back(v);
211 ofstream f(LOGFILE,ios::app);
212 f<<" reinserting out of date (reinsert later)\n";
213 }
214 } else {
215 break;
216 }
217 }
218 for (Constraint *c : outOfDate) {
219 c->timeStamp=blockTimeCtr;
220 insert(in, c);
221 }
222 if(in.empty()) {
223 v=nullptr;
224 } else {
225 v = findMin(in);
226 }
227 return v;
228}
230 if(out.empty()) return nullptr;
231 Constraint *v = findMin(out);
232 while (v->left->block == v->right->block) {
233 deleteMin(out);
234 if(out.empty()) return nullptr;
235 v = findMin(out);
236 }
237 return v;
238}
245inline bool Block::canFollowLeft(const Constraint *c, const Variable *last) {
246 return c->left->block==this && c->active && last!=c->left;
247}
248inline bool Block::canFollowRight(const Constraint *c, const Variable *last) {
249 return c->right->block==this && c->active && last!=c->right;
250}
251
252// computes the derivative of v and the lagrange multipliers
253// of v's out constraints (as the recursive sum of those below.
254// Does not backtrack over u.
255// also records the constraint with minimum lagrange multiplier
256// in min_lm
257double Block::compute_dfdv(Variable *v, Variable *u, Constraint *&min_lm) {
258 double dfdv=v->weight*(v->position() - v->desiredPosition);
259 for (Constraint *c : v->out) {
260 if(canFollowRight(c,u)) {
261 dfdv+=c->lm=compute_dfdv(c->right,v,min_lm);
262 if(min_lm==nullptr||c->lm<min_lm->lm) min_lm=c;
263 }
264 }
265 for (Constraint *c : v->in) {
266 if(canFollowLeft(c,u)) {
267 dfdv-=c->lm=-compute_dfdv(c->left,v,min_lm);
268 if(min_lm==nullptr||c->lm<min_lm->lm) min_lm=c;
269 }
270 }
271 return dfdv;
272}
273
274
275// computes dfdv for each variable and uses the sum of dfdv on either side of
276// the constraint c to compute the lagrangian multiplier lm_c.
277// The top level v and r are variables between which we want to find the
278// constraint with the smallest lm.
279// When we find r we pass nullptr to subsequent recursive calls,
280// thus r=nullptr indicates constraints are not on the shortest path.
281// Similarly, m is initially nullptr and is only assigned a value if the next
282// variable to be visited is r or if a possible min constraint is returned from
283// a nested call (rather than nullptr).
284// Then, the search for the m with minimum lm occurs as we return from
285// the recursion (checking only constraints traversed left-to-right
286// in order to avoid creating any new violations).
287Block::Pair Block::compute_dfdv_between(Variable* r, Variable* v, Variable* u,
288 Direction dir = NONE, bool changedDirection = false) {
289 double dfdv=v->weight*(v->position() - v->desiredPosition);
290 Constraint *m=nullptr;
291 for (Constraint *c : v->in) {
292 if(canFollowLeft(c,u)) {
293 if(dir==RIGHT) {
294 changedDirection = true;
295 }
296 if(c->left==r) {
297 r=nullptr; m=c;
298 }
299 Pair p=compute_dfdv_between(r,c->left,v,
300 LEFT,changedDirection);
301 dfdv -= c->lm = -p.first;
302 if(r && p.second)
303 m = p.second;
304 }
305 }
306 for (Constraint *c : v->out) {
307 if(canFollowRight(c,u)) {
308 if(dir==LEFT) {
309 changedDirection = true;
310 }
311 if(c->right==r) {
312 r=nullptr; m=c;
313 }
314 Pair p=compute_dfdv_between(r,c->right,v,
315 RIGHT,changedDirection);
316 dfdv += c->lm = p.first;
317 if(r && p.second)
318 m = changedDirection && c->lm < p.second->lm
319 ? c
320 : p.second;
321 }
322 }
323 return Pair(dfdv,m);
324}
325
326// resets LMs for all active constraints to 0 by
327// traversing active constraint tree starting from v,
328// not back tracking over u
329void Block::reset_active_lm(Variable *v, Variable *u) {
330 for (Constraint *c : v->out) {
331 if(canFollowRight(c,u)) {
332 c->lm=0;
333 reset_active_lm(c->right,v);
334 }
335 }
336 for (Constraint *c : v->in) {
337 if(canFollowLeft(c,u)) {
338 c->lm=0;
339 reset_active_lm(c->left,v);
340 }
341 }
342}
348 Constraint *min_lm=nullptr;
349 reset_active_lm(vars.front(),nullptr);
350 compute_dfdv(vars.front(),nullptr,min_lm);
351 return min_lm;
352}
354 Constraint *min_lm=nullptr;
355 reset_active_lm(vars.front(),nullptr);
356 min_lm=compute_dfdv_between(rv,lv,nullptr).second;
357 return min_lm;
358}
359
360// populates block b by traversing the active constraint tree adding variables as they're
361// visited. Starts from variable v and does not backtrack over variable u.
362void Block::populateSplitBlock(Block *b, Variable *v, Variable *u) {
363 b->addVariable(v);
364 for (Constraint *c : v->in) {
365 if (canFollowLeft(c,u))
366 populateSplitBlock(b, c->left, v);
367 }
368 for (Constraint *c : v->out) {
369 if (canFollowRight(c,u))
370 populateSplitBlock(b, c->right, v);
371 }
372}
381 ofstream f(LOGFILE,ios::app);
382 f<<" need to split between: "<<*vl<<" and "<<*vr<<"\n";
383 }
384 Constraint *c=findMinLMBetween(vl, vr);
386 ofstream f(LOGFILE,ios::app);
387 f<<" going to split on: "<<*c<<"\n";
388 }
389 split(lb,rb,c);
390 deleted = true;
391 return c;
392}
398void Block::split(Block* &l, Block* &r, Constraint* c) {
399 c->active=false;
400 l=new Block();
401 populateSplitBlock(l,c->left,c->right);
402 r=new Block();
403 populateSplitBlock(r,c->right,c->left);
404}
405
410double Block::cost() {
411 double c = 0;
412 for (const Variable *v : vars) {
413 const double diff = v->position() - v->desiredPosition;
414 c += v->weight * diff * diff;
415 }
416 return c;
417}
418
419std::ostream& operator <<(std::ostream &os, const Block &b) {
420 os<<"Block:";
421 for(const Variable *v : b.vars) {
422 os<<" "<<*v;
423 }
424 if(b.deleted) {
425 os<<" Deleted!";
426 }
427 return os;
428}
static agxbuf last
last message
Definition agerror.c:31
std::ostream & operator<<(std::ostream &os, const Block &b)
Definition block.cpp:419
static Constraint * findMin(std::vector< Constraint * > &heap)
get the minimum heap element
Definition block.cpp:59
static void make_heap(std::vector< Constraint * > &heap)
Definition block.cpp:47
#define RECTANGLE_OVERLAP_LOGGING
Definition block.cpp:35
static void insert(std::vector< Constraint * > &heap, Constraint *c)
add an item to a heap
Definition block.cpp:72
static void deleteMin(std::vector< Constraint * > &heap)
remove the minimum heap element
Definition block.cpp:65
static void merge_heaps(std::vector< Constraint * > &heap1, const std::vector< Constraint * > &heap2)
add all elements from heap2 into the heap heap1
Definition block.cpp:52
static bool gt(const Constraint *const lhs, const Constraint *const rhs)
> comparator for constraints
Definition block.cpp:39
long blockTimeCtr
Definition blocks.cpp:37
#define LOGFILE
A block structure defined over the variables.
Definition blocks.h:24
Definition block.h:28
std::vector< Constraint * > out
Definition block.h:56
bool deleted
Definition block.h:53
Constraint * findMinInConstraint()
Definition block.cpp:180
std::vector< Variable * > vars
Definition block.h:31
void split(Block *&l, Block *&r, Constraint *c)
Definition block.cpp:398
double posn
Definition block.h:32
Constraint * findMinLM()
Definition block.cpp:347
Constraint * splitBetween(Variable *vl, Variable *vr, Block *&lb, Block *&rb)
Definition block.cpp:379
void deleteMinOutConstraint()
Definition block.cpp:242
Block(Variable *v=nullptr)
Definition block.cpp:85
void mergeIn(Block *b)
Definition block.cpp:165
void mergeOut(Block *b)
Definition block.cpp:175
std::vector< Constraint * > in
Definition block.h:55
void setUpOutConstraints()
Definition block.cpp:105
double wposn
Definition block.h:34
void setUpInConstraints()
Definition block.cpp:102
double cost()
Definition block.cpp:410
double desiredWeightedPosition()
Definition block.cpp:95
double weight
Definition block.h:33
Constraint * findMinOutConstraint()
Definition block.cpp:229
void merge(Block *b, Constraint *c, double dist)
Definition block.cpp:148
void deleteMinInConstraint()
Definition block.cpp:239
Constraint * findMinLMBetween(Variable *lv, Variable *rv)
Definition block.cpp:353
long timeStamp
Definition block.h:54
static void insert(PairHeap *h, Pair edge)
Definition closest.c:134
static void split(void)
Definition ccomps.c:101
#define NONE
Definition const.h:123
static bool compareConstraints(const Constraint *const l, const Constraint *const r)
Definition constraint.h:41
static double dist(int dim, double *x, double *y)
A constraint determines a minimum or exact spacing required between two variables.
Definition constraint.h:25
Variable * right
Definition constraint.h:29
double lm
Definition constraint.h:31
long timeStamp
Definition constraint.h:35
double gap
Definition constraint.h:30
Variable * left
Definition constraint.h:28
bool active
Definition constraint.h:36
double slack() const
Definition constraint.h:34
Definition closest.c:32
double desiredPosition
Definition variable.h:30
Constraints out
Definition variable.h:36
const double weight
Definition variable.h:31
Block * block
Definition variable.h:33
double offset
Definition variable.h:32
Constraints in
Definition variable.h:35
double position() const
Definition variable.h:46