Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
vpsc.cpp
Go to the documentation of this file.
1/*
2 * vim: ts=4 sw=4 et tw=0 wm=0
3 *
4 * libavoid - Fast, Incremental, Object-avoiding Line Router
5 *
6 * Copyright (C) 2005-2014 Monash University
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 * See the file LICENSE.LGPL distributed with the library.
13 *
14 * Licensees holding a valid commercial license may use this file in
15 * accordance with the commercial license agreement provided with the
16 * library.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 *
22 * Author(s): Tim Dwyer
23 * Michael Wybrow
24 *
25 * --------------
26 *
27 * This file contains a slightly modified version of IncSolver() from libvpsc:
28 * A solver for the problem of Variable Placement with Separation Constraints.
29 * It has the following changes from the Adaptagrams VPSC version:
30 * - The required VPSC code has been consolidated into a single file.
31 * - Unnecessary code, like the Solver() class, has been removed.
32 * - The PairingHeap code has been replaced by a STL priority_queue.
33 *
34 * Modifications: Michael Wybrow
35 *
36*/
37
38#include "libavoid/vpsc.h"
39
40#ifndef USELIBVPSC
41
42#include <iostream>
43#include <cmath>
44#include <sstream>
45#include <map>
46#include <cfloat>
47#include <cstdio>
48
49#include "libavoid/assertions.h"
50#include "libavoid/debug.h"
51
52
53using namespace std;
54
55namespace Avoid {
56
57static const double ZERO_UPPERBOUND=-1e-10;
58static const double LAGRANGIAN_TOLERANCE=-1e-4;
59
60
62 : m(cs.size()),
63 cs(cs),
64 n(vs.size()),
65 vs(vs),
66 needsScaling(false)
67{
68 for(unsigned i=0;i<n;++i) {
69 vs[i]->in.clear();
70 vs[i]->out.clear();
71
72 // Set needsScaling if any variables have a scale other than 1.
73 needsScaling |= (vs[i]->scale != 1);
74 }
75 for(unsigned i=0;i<m;++i) {
76 Constraint *c=cs[i];
77 c->left->out.push_back(c);
78 c->right->in.push_back(c);
79 c->needsScaling = needsScaling;
80 }
81 bs=new Blocks(vs);
82#ifdef LIBVPSC_LOGGING
84 //COLA_ASSERT(!constraintGraphIsCyclic(n,vs));
85#endif
86
88 for(Constraints::iterator i=inactive.begin();i!=inactive.end();++i) {
89 (*i)->active=false;
90 }
91}
93 delete bs;
94}
95
97{
98 ++m;
99 c->active = false;
100 inactive.push_back(c);
101 c->left->out.push_back(c);
102 c->right->in.push_back(c);
103 c->needsScaling = needsScaling;
104}
105
106// useful in debugging
108#ifdef LIBVPSC_LOGGING
109 ofstream f(LOGFILE,ios::app);
110 for(set<Block*>::iterator i=bs->begin();i!=bs->end();++i) {
111 Block *b=*i;
112 f<<" "<<*b<<endl;
113 }
114 for(unsigned i=0;i<m;i++) {
115 f<<" "<<*cs[i]<<endl;
116 }
117#endif
118}
119
120/*
121 * Stores the relative positions of the variables in their finalPosition
122 * field.
123 */
125 for(Variables::const_iterator i=vs.begin();i!=vs.end();++i) {
126 Variable* v=*i;
127 v->finalPosition=v->position();
128 COLA_ASSERT(v->finalPosition==v->finalPosition);
129 }
130}
131
132struct node {
133 set<node*> in;
134 set<node*> out;
135};
136// useful in debugging - cycles would be BAD
137bool IncSolver::constraintGraphIsCyclic(const unsigned n, Variable* const vs[]) {
138 map<Variable*, node*> varmap;
139 vector<node*> graph;
140 for(unsigned i=0;i<n;i++) {
141 node *u=new node;
142 graph.push_back(u);
143 varmap[vs[i]]=u;
144 }
145 for(unsigned i=0;i<n;i++) {
146 for(vector<Constraint*>::iterator c=vs[i]->in.begin();c!=vs[i]->in.end();++c) {
147 Variable *l=(*c)->left;
148 varmap[vs[i]]->in.insert(varmap[l]);
149 }
150
151 for(vector<Constraint*>::iterator c=vs[i]->out.begin();c!=vs[i]->out.end();++c) {
152 Variable *r=(*c)->right;
153 varmap[vs[i]]->out.insert(varmap[r]);
154 }
155 }
156 while(graph.size()>0) {
157 node *u=nullptr;
158 vector<node*>::iterator i=graph.begin();
159 for(;i!=graph.end();++i) {
160 u=*i;
161 if(u->in.size()==0) {
162 break;
163 }
164 }
165 if(i==graph.end() && graph.size()>0) {
166 //cycle found!
167 return true;
168 } else {
169 graph.erase(i);
170 for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
171 node *v=*j;
172 v->in.erase(u);
173 }
174 delete u;
175 }
176 }
177 for(unsigned i=0; i<graph.size(); ++i) {
178 delete graph[i];
179 }
180 return false;
181}
182
183// useful in debugging - cycles would be BAD
185 map<Block*, node*> bmap;
186 vector<node*> graph;
187 size_t length = bs->size();
188 for (size_t i = 0; i < length; ++i)
189 {
190 Block *b = bs->at(i);
191 node *u=new node;
192 graph.push_back(u);
193 bmap[b]=u;
194 }
195 for (size_t i = 0; i < length; ++i)
196 {
197 Block *b = bs->at(i);
200 while(c!=nullptr) {
201 Block *l=c->left->block;
202 bmap[b]->in.insert(bmap[l]);
205 }
206
209 while(c!=nullptr) {
210 Block *r=c->right->block;
211 bmap[b]->out.insert(bmap[r]);
214 }
215 }
216 while(graph.size()>0) {
217 node *u=nullptr;
218 vector<node*>::iterator i=graph.begin();
219 for(;i!=graph.end();++i) {
220 u=*i;
221 if(u->in.size()==0) {
222 break;
223 }
224 }
225 if(i==graph.end() && graph.size()>0) {
226 //cycle found!
227 return true;
228 } else {
229 graph.erase(i);
230 for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
231 node *v=*j;
232 v->in.erase(u);
233 }
234 delete u;
235 }
236 }
237 for(unsigned i=0; i<graph.size(); i++) {
238 delete graph[i];
239 }
240 return false;
241}
242
244#ifdef LIBVPSC_LOGGING
245 ofstream f(LOGFILE,ios::app);
246 f<<"solve_inc()..."<<endl;
247#endif
248 satisfy();
249 double lastcost = DBL_MAX, cost = bs->cost();
250 while(fabs(lastcost-cost)>0.0001) {
251 satisfy();
252 lastcost=cost;
253 cost = bs->cost();
254#ifdef LIBVPSC_LOGGING
255 f<<" bs->size="<<bs->size()<<", cost="<<cost<<endl;
256#endif
257 }
258 copyResult();
259 return bs->size()!=n;
260}
261/*
262 * incremental version of satisfy that allows refinement after blocks are
263 * moved.
264 *
265 * - move blocks to new positions
266 * - repeatedly merge across most violated constraint until no more
267 * violated constraints exist
268 *
269 * Note: there is a special case to handle when the most violated constraint
270 * is between two variables in the same block. Then, we must split the block
271 * over an active constraint between the two variables. We choose the
272 * constraint with the most negative lagrangian multiplier.
273 */
275#ifdef LIBVPSC_LOGGING
276 ofstream f(LOGFILE,ios::app);
277 f<<"satisfy_inc()..."<<endl;
278#endif
279 splitBlocks();
280 //long splitCtr = 0;
281 Constraint* v = nullptr;
282 //CBuffer buffer(inactive);
283 while ( (v = mostViolated(inactive)) &&
284 (v->equality || ((v->slack() < ZERO_UPPERBOUND) && !v->active)) )
285 {
286 COLA_ASSERT(!v->active);
287 Block *lb = v->left->block, *rb = v->right->block;
288 if(lb != rb) {
289 lb->merge(rb,v);
290 } else {
291 if(lb->isActiveDirectedPathBetween(v->right,v->left)) {
292 // cycle found, relax the violated, cyclic constraint
293 v->unsatisfiable=true;
294 continue;
295 //UnsatisfiableException e;
296 //lb->getActiveDirectedPathBetween(e.path,v->right,v->left);
297 //e.path.push_back(v);
298 //throw e;
299 }
300 //if(splitCtr++>10000) {
301 //throw "Cycle Error!";
302 //}
303 // constraint is within block, need to split first
304 try {
305 Constraint* splitConstraint
306 =lb->splitBetween(v->left,v->right,lb,rb);
307 if(splitConstraint!=nullptr) {
308 COLA_ASSERT(!splitConstraint->active);
309 inactive.push_back(splitConstraint);
310 } else {
311 v->unsatisfiable=true;
312 continue;
313 }
314 } catch(UnsatisfiableException e) {
315 e.path.push_back(v);
316 /*
317 std::cerr << "Unsatisfiable:" << std::endl;
318 for(std::vector<Constraint*>::iterator r=e.path.begin();
319 r!=e.path.end();++r)
320 {
321 std::cerr << **r <<std::endl;
322 }
323 */
324 v->unsatisfiable=true;
325 continue;
326 }
327 if(v->slack()>=0) {
328 COLA_ASSERT(!v->active);
329 // v was satisfied by the above split!
330 inactive.push_back(v);
331 bs->insert(lb);
332 bs->insert(rb);
333 } else {
334 bs->insert(lb->merge(rb,v));
335 delete ((lb->deleted) ? lb : rb);
336 }
337 }
338#ifdef LIBVPSC_LOGGING
339 f<<"...remaining blocks="<<bs->size()<<", cost="<<bs->cost()<<endl;
340#endif
341 }
342#ifdef LIBVPSC_LOGGING
343 f<<" finished merges."<<endl;
344#endif
345 bs->cleanup();
346 bool activeConstraints=false;
347 for(unsigned i=0;i<m;i++) {
348 v=cs[i];
349 if(v->active) activeConstraints=true;
350 if(v->slack() < ZERO_UPPERBOUND) {
351 ostringstream s;
352 s<<"Unsatisfied constraint: "<<*v;
353#ifdef LIBVPSC_LOGGING
354 ofstream f(LOGFILE,ios::app);
355 f<<s.str()<<endl;
356#endif
357 throw s.str().c_str();
358 }
359 }
360#ifdef LIBVPSC_LOGGING
361 f<<" finished cleanup."<<endl;
362 printBlocks();
363#endif
364 copyResult();
365 return activeConstraints;
366}
368#ifdef LIBVPSC_LOGGING
369 ofstream f(LOGFILE,ios::app);
370 f<<"moveBlocks()..."<<endl;
371#endif
372 size_t length = bs->size();
373 for (size_t i = 0; i < length; ++i)
374 {
375 Block *b = bs->at(i);
377 //b->posn = b->wposn / b->weight;
378 }
379#ifdef LIBVPSC_LOGGING
380 f<<" moved blocks."<<endl;
381#endif
382}
384#ifdef LIBVPSC_LOGGING
385 ofstream f(LOGFILE,ios::app);
386#endif
387 moveBlocks();
388 splitCnt=0;
389 // Split each block if necessary on min LM
390 size_t length = bs->size();
391 for (size_t i = 0; i < length; ++i)
392 {
393 Block *b = bs->at(i);
394 Constraint* v=b->findMinLM();
395 if(v!=nullptr && v->lm < LAGRANGIAN_TOLERANCE) {
396 COLA_ASSERT(!v->equality);
397#ifdef LIBVPSC_LOGGING
398 f<<" found split point: "<<*v<<" lm="<<v->lm<<endl;
399#endif
400 splitCnt++;
401 Block *b = v->left->block, *l=nullptr, *r=nullptr;
402 COLA_ASSERT(v->left->block == v->right->block);
403 //double pos = b->posn;
404 b->split(l,r,v);
405 //l->posn=r->posn=pos;
406 //l->wposn = l->posn * l->weight;
407 //r->wposn = r->posn * r->weight;
408 l->updateWeightedPosition();
409 r->updateWeightedPosition();
410 bs->insert(l);
411 bs->insert(r);
412 b->deleted=true;
413 COLA_ASSERT(!v->active);
414 inactive.push_back(v);
415#ifdef LIBVPSC_LOGGING
416 f<<" new blocks: "<<*l<<" and "<<*r<<endl;
417#endif
418 }
419 }
420 //if(splitCnt>0) { std::cout<<" splits: "<<splitCnt<<endl; }
421#ifdef LIBVPSC_LOGGING
422 f<<" finished splits."<<endl;
423#endif
424 bs->cleanup();
425}
426
427/*
428 * Scan constraint list for the most violated constraint, or the first equality
429 * constraint
430 */
432{
433 double slackForMostViolated = DBL_MAX;
434 Constraint* mostViolated = nullptr;
435#ifdef LIBVPSC_LOGGING
436 ofstream f(LOGFILE,ios::app);
437 f << "Looking for most violated..." << endl;
438#endif
439 size_t lSize = l.size();
440 size_t deleteIndex = lSize;
441 Constraint *constraint = nullptr;
442 double slack = 0;
443 for (size_t index = 0; index < lSize; ++index)
444 {
445 constraint = l[index];
446 slack = constraint->slack();
447 if (constraint->equality || slack < slackForMostViolated)
448 {
449 slackForMostViolated = slack;
450 mostViolated = constraint;
451 deleteIndex = index;
452 if (constraint->equality)
453 {
454 break;
455 }
456 }
457 }
458 // Because the constraint list is not order dependent we just
459 // move the last element over the deletePoint and resize
460 // downwards. There is always at least 1 element in the
461 // vector because of search.
462 if ( (deleteIndex < lSize) &&
463 (((slackForMostViolated < ZERO_UPPERBOUND) && !mostViolated->active) ||
465 {
466 l[deleteIndex] = l[lSize-1];
467 l.resize(lSize-1);
468 }
469#ifdef LIBVPSC_LOGGING
470 if (mostViolated)
471 {
472 f << " most violated is: " << *mostViolated << endl;
473 }
474 else
475 {
476 f << " non found." << endl;
477 }
478#endif
479 return mostViolated;
480}
481
482
483using std::set;
484using std::vector;
485using std::iterator;
486using std::list;
487using std::copy;
488#define __NOTNAN(p) (p)==(p)
489
490
491Blocks::Blocks(vector<Variable*> const &vs) : vs(vs),nvs(vs.size()) {
492 blockTimeCtr=0;
493 m_blocks.resize(nvs);
494 for(size_t i=0;i<nvs;i++) {
495 m_blocks[i] = new Block(this, vs[i]);
496 }
497}
499{
500 blockTimeCtr=0;
501 size_t length = m_blocks.size();
502 for (size_t i = 0; i < length; ++i)
503 {
504 delete m_blocks[i];
505 }
506 m_blocks.clear();
507}
508
509/*
510 * returns a list of variables with total ordering determined by the constraint
511 * DAG
512 */
513list<Variable*> *Blocks::totalOrder() {
514 list<Variable*> *order = new list<Variable*>;
515 for(size_t i=0;i<nvs;i++) {
516 vs[i]->visited=false;
517 }
518 for(size_t i=0;i<nvs;i++) {
519 if(vs[i]->in.size()==0) {
520 dfsVisit(vs[i],order);
521 }
522 }
523 return order;
524}
525// Recursive depth first search giving total order by pushing nodes in the DAG
526// onto the front of the list when we finish searching them
527void Blocks::dfsVisit(Variable *v, list<Variable*> *order) {
528 v->visited=true;
529 vector<Constraint*>::iterator it=v->out.begin();
530 for(;it!=v->out.end();++it) {
531 Constraint *c=*it;
532 if(!c->right->visited) {
533 dfsVisit(c->right, order);
534 }
535 }
536#ifdef LIBVPSC_LOGGING
537 ofstream f(LOGFILE,ios::app);
538 f<<" order="<<*v<<endl;
539#endif
540 order->push_front(v);
541}
542/*
543 * Processes incoming constraints, most violated to least, merging with the
544 * neighbouring (left) block until no more violated constraints are found
545 */
547#ifdef LIBVPSC_LOGGING
548 ofstream f(LOGFILE,ios::app);
549 f<<"mergeLeft called on "<<*r<<endl;
550#endif
554 while (c != nullptr && c->slack()<0) {
555#ifdef LIBVPSC_LOGGING
556 f<<"mergeLeft on constraint: "<<*c<<endl;
557#endif
559 Block *l = c->left->block;
560 if (l->in==nullptr) l->setUpInConstraints();
561 double dist = c->right->offset - c->left->offset - c->gap;
562 if (r->vars->size() < l->vars->size()) {
563 dist=-dist;
564 std::swap(l, r);
565 }
566 blockTimeCtr++;
567 r->merge(l, c, dist);
568 r->mergeIn(l);
570 removeBlock(l);
572 }
573#ifdef LIBVPSC_LOGGING
574 f<<"merged "<<*r<<endl;
575#endif
576}
577/*
578 * Symmetrical to mergeLeft
579 */
581#ifdef LIBVPSC_LOGGING
582 ofstream f(LOGFILE,ios::app);
583 f<<"mergeRight called on "<<*l<<endl;
584#endif
587 while (c != nullptr && c->slack()<0) {
588#ifdef LIBVPSC_LOGGING
589 f<<"mergeRight on constraint: "<<*c<<endl;
590#endif
592 Block *r = c->right->block;
594 double dist = c->left->offset + c->gap - c->right->offset;
595 if (l->vars->size() > r->vars->size()) {
596 dist=-dist;
597 std::swap(l, r);
598 }
599 l->merge(r, c, dist);
600 l->mergeOut(r);
601 removeBlock(r);
603 }
604#ifdef LIBVPSC_LOGGING
605 f<<"merged "<<*l<<endl;
606#endif
607}
609 doomed->deleted=true;
610 //erase(doomed);
611}
612
613// Clears up deleted blocks from the blocks list.
615{
616 // We handle removal of items in-place by doing a single linear pass over
617 // the vector. We use two indexes, j to refer to elements we've checked
618 // from the original list and i to refer to the current position we are
619 // writing in the updated list.
620 size_t i = 0;
621
622 // For all items in the current blocks list...
623 size_t length = m_blocks.size();
624 for (size_t j = 0; j < length; )
625 {
626 if (m_blocks[j]->deleted)
627 {
628 // The element is deleted, so free it and increment j.
629 delete m_blocks[j];
630 ++j;
631 }
632 else
633 {
634 // The current element is still valid.
635 if (j > i)
636 {
637 // If we've not looking at same element, then copy from j to i.
638 m_blocks[i] = m_blocks[j];
639 }
640 // Increment both indexes.
641 ++i;
642 ++j;
643 }
644 }
645 m_blocks.resize(i);
646}
647/*
648 * Splits block b across constraint c into two new blocks, l and r (c's left
649 * and right sides respectively)
650 */
652 b->split(l,r,c);
653 m_blocks.push_back(l);
654 m_blocks.push_back(r);
655#ifdef LIBVPSC_LOGGING
656 ofstream f(LOGFILE,ios::app);
657 f<<"Split left: "<<*l<<endl;
658 f<<"Split right: "<<*r<<endl;
659#endif
660 r->posn = b->posn;
661 //COLA_ASSERT(r->weight!=0);
662 //r->wposn = r->posn * r->weight;
663 mergeLeft(l);
664 // r may have been merged!
665 r = c->right->block;
667 //r->posn = r->wposn / r->weight;
668 mergeRight(r);
669 removeBlock(b);
670
671 COLA_ASSERT(__NOTNAN(l->posn));
672 COLA_ASSERT(__NOTNAN(r->posn));
673}
674/*
675 * returns the cost total squared distance of variables from their desired
676 * positions
677 */
678double Blocks::cost() {
679 double c = 0;
680 size_t length = m_blocks.size();
681 for (size_t i = 0; i < length; ++i)
682 {
683 c += m_blocks[i]->cost();
684 }
685 return c;
686}
687
689 double ai=scale/v->scale;
690 double bi=v->offset/v->scale;
691 double wi=v->weight;
692 AB+=wi*ai*bi;
693 AD+=wi*ai*v->desiredPosition;
694 A2+=wi*ai*ai;
695 /*
696#ifdef LIBVPSC_LOGGING
697 ofstream f(LOGFILE,ios::app);
698 f << "adding v[" << v->id << "], blockscale=" << scale << ", despos="
699 << v->desiredPosition << ", ai=" << ai << ", bi=" << bi
700 << ", AB=" << AB << ", AD=" << AD << ", A2=" << A2;
701#endif
702*/
703}
705 v->block=this;
706 vars->push_back(v);
707 if(ps.A2==0) ps.scale=v->scale;
708 //weight+= v->weight;
709 //wposn += v->weight * (v->desiredPosition - v->offset);
710 //posn=wposn/weight;
711 ps.addVariable(v);
712 posn=(ps.AD - ps.AB) / ps.A2;
713 COLA_ASSERT(__NOTNAN(posn));
714 /*
715#ifdef LIBVPSC_LOGGING
716 ofstream f(LOGFILE,ios::app);
717 f << ", posn=" << posn << endl;
718#endif
719*/
720}
721Block::Block(Blocks *blocks, Variable* const v)
722 : vars(new vector<Variable*>)
723 , posn(0)
724 //, weight(0)
725 //, wposn(0)
726 , deleted(false)
727 , timeStamp(0)
728 , in(nullptr)
729 , out(nullptr)
730 , blocks(blocks)
731{
732 if(v!=nullptr) {
733 v->offset=0;
734 addVariable(v);
735 }
736}
737
739 //wposn=0;
740 ps.AB=ps.AD=ps.A2=0;
741 for (Vit v=vars->begin();v!=vars->end();++v) {
742 //wposn += ((*v)->desiredPosition - (*v)->offset) * (*v)->weight;
743 ps.addVariable(*v);
744 }
745 posn=(ps.AD - ps.AB) / ps.A2;
746 COLA_ASSERT(__NOTNAN(posn));
747#ifdef LIBVPSC_LOGGING
748 ofstream f(LOGFILE,ios::app);
749 f << ", posn=" << posn << endl;
750#endif
751}
753{
754 delete vars;
755 delete in;
756 delete out;
757}
765 delete h;
766 h = new Heap();
767 for (Vit i=vars->begin();i!=vars->end();++i) {
768 Variable *v=*i;
769 vector<Constraint*> *cs=in?&(v->in):&(v->out);
770 for (Cit j=cs->begin();j!=cs->end();++j) {
771 Constraint *c=*j;
773 if ( ((c->left->block != this) && in) ||
774 ((c->right->block != this) && !in) )
775 {
776 h->push(c);
777 }
778 }
779 }
780}
782#ifdef LIBVPSC_LOGGING
783 ofstream f(LOGFILE,ios::app);
784 f<<" merging on: "<<*c<<",c->left->offset="<<c->left->offset<<",c->right->offset="<<c->right->offset<<endl;
785#endif
786 double dist = c->right->offset - c->left->offset - c->gap;
787 Block *l=c->left->block;
788 Block *r=c->right->block;
789 if (l->vars->size() < r->vars->size()) {
790 r->merge(l,c,dist);
791 } else {
792 l->merge(r,c,-dist);
793 }
794 Block* mergeBlock=b->deleted?this:b;
795#ifdef LIBVPSC_LOGGING
796 f<<" merged block="<<*mergeBlock<<endl;
797#endif
798 return mergeBlock;
799}
800/*
801 * Merges b into this block across c. Can be either a
802 * right merge or a left merge
803 * @param b block to merge into this
804 * @param c constraint being merged
805 * @param distance separation required to satisfy c
806 */
807void Block::merge(Block *b, Constraint *c, double dist) {
808#ifdef LIBVPSC_LOGGING
809 ofstream f(LOGFILE,ios::app);
810 f<<" merging: "<<*b<<"dist="<<dist<<endl;
811#endif
812 c->active=true;
813 //wposn+=b->wposn-dist*b->weight;
814 //weight+=b->weight;
815 for(Vit i=b->vars->begin();i!=b->vars->end();++i) {
816 Variable *v=*i;
817 //v->block=this;
818 //vars->push_back(v);
819 v->offset+=dist;
820 addVariable(v);
821 }
822#ifdef LIBVPSC_LOGGING
823 for(Vit i=vars->begin();i!=vars->end();++i) {
824 Variable *v=*i;
825 f<<" v["<<v->id<<"]: d="<<v->desiredPosition
826 <<" a="<<v->scale<<" o="<<v->offset
827 <<endl;
828 }
829 f<<" AD="<<ps.AD<<" AB="<<ps.AB<<" A2="<<ps.A2<<endl;
830#endif
831 //posn=wposn/weight;
832 //COLA_ASSERT(wposn==ps.AD - ps.AB);
833 posn=(ps.AD - ps.AB) / ps.A2;
834 COLA_ASSERT(__NOTNAN(posn));
835 b->deleted=true;
836}
837
839#ifdef LIBVPSC_LOGGING
840 ofstream f(LOGFILE,ios::app);
841 f<<" merging constraint heaps... "<<endl;
842#endif
843 // We check the top of the heaps to remove possible internal constraints
846 while (!b->in->empty())
847 {
848 in->push(b->in->top());
849 b->in->pop();
850 }
851#ifdef LIBVPSC_LOGGING
852 f<<" merged heap: "<<*in<<endl;
853#endif
854}
858 while (!b->out->empty())
859 {
860 out->push(b->out->top());
861 b->out->pop();
862 }
863}
865 Constraint *v = nullptr;
866 vector<Constraint*> outOfDate;
867 while (!in->empty()) {
868 v = in->top();
869 Block *lb=v->left->block;
870 Block *rb=v->right->block;
871 // rb may not be this if called between merge and mergeIn
872#ifdef LIBVPSC_LOGGING
873 ofstream f(LOGFILE,ios::app);
874 f<<" checking constraint ... "<<*v;
875 f<<" timestamps: left="<<lb->timeStamp<<" right="<<rb->timeStamp<<" constraint="<<v->timeStamp<<endl;
876#endif
877 if(lb == rb) {
878 // constraint has been merged into the same block
879#ifdef LIBVPSC_LOGGING
880 if(v->slack()<0) {
881 f<<" violated internal constraint found! "<<*v<<endl;
882 f<<" lb="<<*lb<<endl;
883 f<<" rb="<<*rb<<endl;
884 }
885#endif
886 in->pop();
887#ifdef LIBVPSC_LOGGING
888 f<<" ... skipping internal constraint"<<endl;
889#endif
890 } else if(v->timeStamp < lb->timeStamp) {
891 // block at other end of constraint has been moved since this
892 in->pop();
893 outOfDate.push_back(v);
894#ifdef LIBVPSC_LOGGING
895 f<<" reinserting out of date (reinsert later)"<<endl;
896#endif
897 } else {
898 break;
899 }
900 }
901 for(Cit i=outOfDate.begin();i!=outOfDate.end();++i) {
902 v=*i;
903 v->timeStamp=blocks->blockTimeCtr;
904 in->push(v);
905 }
906 if(in->empty()) {
907 v=nullptr;
908 } else {
909 v=in->top();
910 }
911 return v;
912}
914 if(out->empty()) return nullptr;
915 Constraint *v = out->top();
916 while (v->left->block == v->right->block) {
917 out->pop();
918 if(out->empty()) return nullptr;
919 v = out->top();
920 }
921 return v;
922}
924 in->pop();
925#ifdef LIBVPSC_LOGGING
926 ofstream f(LOGFILE,ios::app);
927 f<<"deleteMinInConstraint... "<<endl;
928 f<<" result: "<<*in<<endl;
929#endif
930}
932 out->pop();
933}
934inline bool Block::canFollowLeft(Constraint const* c, Variable const* last) const {
935 return c->left->block==this && c->active && last!=c->left;
936}
937inline bool Block::canFollowRight(Constraint const* c, Variable const* last) const {
938 return c->right->block==this && c->active && last!=c->right;
939}
940
941// computes the derivative of v and the lagrange multipliers
942// of v's out constraints (as the recursive sum of those below.
943// Does not backtrack over u.
944// also records the constraint with minimum lagrange multiplier
945// in min_lm
946double Block::compute_dfdv(Variable* const v, Variable* const u,
947 Constraint *&min_lm) {
948 double dfdv=v->dfdv();
949 for(Cit it=v->out.begin();it!=v->out.end();++it) {
950 Constraint *c=*it;
951 if(canFollowRight(c,u)) {
952 c->lm=compute_dfdv(c->right,v,min_lm);
953 dfdv+=c->lm*c->left->scale;
954 if(!c->equality&&(min_lm==nullptr||c->lm<min_lm->lm)) min_lm=c;
955 }
956 }
957 for(Cit it=v->in.begin();it!=v->in.end();++it) {
958 Constraint *c=*it;
959 if(canFollowLeft(c,u)) {
960 c->lm=-compute_dfdv(c->left,v,min_lm);
961 dfdv-=c->lm*c->right->scale;
962 if(!c->equality&&(min_lm==nullptr||c->lm<min_lm->lm)) min_lm=c;
963 }
964 }
965 return dfdv/v->scale;
966}
967double Block::compute_dfdv(Variable* const v, Variable* const u) {
968 double dfdv = v->dfdv();
969 for(Cit it = v->out.begin(); it != v->out.end(); ++it) {
970 Constraint *c = *it;
971 if(canFollowRight(c,u)) {
972 c->lm = compute_dfdv(c->right,v);
973 dfdv += c->lm * c->left->scale;
974 }
975 }
976 for(Cit it=v->in.begin();it!=v->in.end();++it) {
977 Constraint *c = *it;
978 if(canFollowLeft(c,u)) {
979 c->lm = - compute_dfdv(c->left,v);
980 dfdv -= c->lm * c->right->scale;
981 }
982 }
983 return dfdv/v->scale;
984}
985
986// The top level v and r are variables between which we want to find the
987// constraint with the smallest lm.
988// Similarly, m is initially nullptr and is only assigned a value if the next
989// variable to be visited is r or if a possible min constraint is returned from
990// a nested call (rather than nullptr).
991// Then, the search for the m with minimum lm occurs as we return from
992// the recursion (checking only constraints traversed left-to-right
993// in order to avoid creating any new violations).
994// We also do not consider equality constraints as potential split points
996 Variable* r,
997 Variable* const v,
998 Variable* const u,
999 Constraint* &m,
1000 bool desperation=false
1001 )
1002{
1003 for(Cit it(v->in.begin());it!=v->in.end();++it) {
1004 Constraint *c=*it;
1005 if(canFollowLeft(c,u)) {
1006#ifdef LIBVPSC_LOGGING
1007 ofstream f(LOGFILE,ios::app);
1008 f<<" left split path: "<<*c<<endl;
1009#endif
1010 if(c->left==r) {
1011 if(desperation&&!c->equality) m=c;
1012 return true;
1013 } else {
1014 if(split_path(r,c->left,v,m)) {
1015 if(desperation && !c->equality && (!m||c->lm<m->lm)) {
1016 m=c;
1017 }
1018 return true;
1019 }
1020 }
1021 }
1022 }
1023 for(Cit it(v->out.begin());it!=v->out.end();++it) {
1024 Constraint *c=*it;
1025 if(canFollowRight(c,u)) {
1026#ifdef LIBVPSC_LOGGING
1027 ofstream f(LOGFILE,ios::app);
1028 f<<" right split path: "<<*c<<endl;
1029#endif
1030 if(c->right==r) {
1031 if(!c->equality) m=c;
1032 return true;
1033 } else {
1034 if(split_path(r,c->right,v,m)) {
1035 if(!c->equality && (!m||c->lm<m->lm))
1036 m=c;
1037 return true;
1038 }
1039 }
1040 }
1041 }
1042 return false;
1043}
1044/*
1045Block::Pair Block::compute_dfdv_between(
1046 Variable* r, Variable* const v, Variable* const u,
1047 const Direction dir = NONE, bool changedDirection = false) {
1048 double dfdv=v->weight*(v->position() - v->desiredPosition);
1049 Constraint *m=nullptr;
1050 for(Cit it(v->in.begin());it!=v->in.end();++it) {
1051 Constraint *c=*it;
1052 if(canFollowLeft(c,u)) {
1053 if(dir==RIGHT) {
1054 changedDirection = true;
1055 }
1056 if(c->left==r) {
1057 r=nullptr;
1058 if(!c->equality) m=c;
1059 }
1060 Pair p=compute_dfdv_between(r,c->left,v,
1061 LEFT,changedDirection);
1062 dfdv -= c->lm = -p.first;
1063 if(r && p.second)
1064 m = p.second;
1065 }
1066 }
1067 for(Cit it(v->out.begin());it!=v->out.end();++it) {
1068 Constraint *c=*it;
1069 if(canFollowRight(c,u)) {
1070 if(dir==LEFT) {
1071 changedDirection = true;
1072 }
1073 if(c->right==r) {
1074 r=nullptr;
1075 if(!c->equality) m=c;
1076 }
1077 Pair p=compute_dfdv_between(r,c->right,v,
1078 RIGHT,changedDirection);
1079 dfdv += c->lm = p.first;
1080 if(r && p.second)
1081 m = changedDirection && !c->equality && c->lm < p.second->lm
1082 ? c
1083 : p.second;
1084 }
1085 }
1086 return Pair(dfdv,m);
1087}
1088*/
1089
1090// resets LMs for all active constraints to 0 by
1091// traversing active constraint tree starting from v,
1092// not back tracking over u
1093void Block::reset_active_lm(Variable* const v, Variable* const u) {
1094 for(Cit it=v->out.begin();it!=v->out.end();++it) {
1095 Constraint *c=*it;
1096 if(canFollowRight(c,u)) {
1097 c->lm=0;
1098 reset_active_lm(c->right,v);
1099 }
1100 }
1101 for(Cit it=v->in.begin();it!=v->in.end();++it) {
1102 Constraint *c=*it;
1103 if(canFollowLeft(c,u)) {
1104 c->lm=0;
1105 reset_active_lm(c->left,v);
1106 }
1107 }
1108}
1109void Block::list_active(Variable* const v, Variable* const u) {
1110 for(Cit it=v->out.begin();it!=v->out.end();++it) {
1111 Constraint *c=*it;
1112 if(canFollowRight(c,u)) {
1113#ifdef LIBVPSC_LOGGING
1114 ofstream f(LOGFILE,ios::app);
1115 f<<" "<<*c<<endl;
1116#endif
1117 list_active(c->right,v);
1118 }
1119 }
1120 for(Cit it=v->in.begin();it!=v->in.end();++it) {
1121 Constraint *c=*it;
1122 if(canFollowLeft(c,u)) {
1123#ifdef LIBVPSC_LOGGING
1124 ofstream f(LOGFILE,ios::app);
1125 f<<" "<<*c<<endl;
1126#endif
1127 list_active(c->left,v);
1128 }
1129 }
1130}
1131/*
1132 * finds the constraint with the minimum lagrange multiplier, that is, the constraint
1133 * that most wants to split
1134 */
1136 Constraint *min_lm=nullptr;
1137 reset_active_lm(vars->front(),nullptr);
1138 compute_dfdv(vars->front(),nullptr,min_lm);
1139#ifdef LIBVPSC_LOGGING
1140 ofstream f(LOGFILE,ios::app);
1141 f<<" langrangians: "<<endl;
1142 list_active(vars->front(),nullptr);
1143#endif
1144 return min_lm;
1145}
1147 reset_active_lm(vars->front(),nullptr);
1148 compute_dfdv(vars->front(),nullptr);
1149 Constraint *min_lm=nullptr;
1150 split_path(rv,lv,nullptr,min_lm);
1151#if 0
1152 if(min_lm==nullptr) {
1153 split_path(rv,lv,nullptr,min_lm,true);
1154 }
1155#else
1156 if(min_lm==nullptr) {
1157 //err_printf("Couldn't find split point!\n");
1159 getActivePathBetween(e.path,lv,rv,nullptr);
1160 throw e;
1161 }
1162 COLA_ASSERT(min_lm!=nullptr);
1163#endif
1164 return min_lm;
1165}
1166
1167// populates block b by traversing the active constraint tree adding variables as they're
1168// visited. Starts from variable v and does not backtrack over variable u.
1170 b->addVariable(v);
1171 for (Cit c=v->in.begin();c!=v->in.end();++c) {
1172 if (canFollowLeft(*c,u))
1173 populateSplitBlock(b, (*c)->left, v);
1174 }
1175 for (Cit c=v->out.begin();c!=v->out.end();++c) {
1176 if (canFollowRight(*c,u))
1177 populateSplitBlock(b, (*c)->right, v);
1178 }
1179}
1180/*
1181 * Returns the active path between variables u and v... not back tracking over w
1182 */
1184 Variable const* v, Variable const *w) const {
1185 if(u==v) return true;
1186 for (Cit_const c=u->in.begin();c!=u->in.end();++c) {
1187 if (canFollowLeft(*c,w)) {
1188 if(getActivePathBetween(path, (*c)->left, v, u)) {
1189 path.push_back(*c);
1190 return true;
1191 }
1192 }
1193 }
1194 for (Cit_const c=u->out.begin();c!=u->out.end();++c) {
1195 if (canFollowRight(*c,w)) {
1196 if(getActivePathBetween(path, (*c)->right, v, u)) {
1197 path.push_back(*c);
1198 return true;
1199 }
1200 }
1201 }
1202 return false;
1203}
1204// Search active constraint tree from u to see if there is a directed path to v.
1205// Returns true if path is found with all constraints in path having their visited flag
1206// set true.
1208 if(u==v) return true;
1209 for (Cit_const c=u->out.begin();c!=u->out.end();++c) {
1210 if(canFollowRight(*c,nullptr)) {
1211 if(isActiveDirectedPathBetween((*c)->right,v)) {
1212 return true;
1213 }
1214 }
1215 }
1216 return false;
1217}
1219 Constraints& path, Variable const* u, Variable const* v) const {
1220 if(u==v) return true;
1221 for (Cit_const c=u->out.begin();c!=u->out.end();++c) {
1222 if(canFollowRight(*c,nullptr)) {
1223 if(getActiveDirectedPathBetween(path,(*c)->right,v)) {
1224 path.push_back(*c);
1225 return true;
1226 }
1227 }
1228 }
1229 return false;
1230}
1231/*
1232 * Block needs to be split because of a violated constraint between vl and vr.
1233 * We need to search the active constraint tree between l and r and find the constraint
1234 * with min lagrangrian multiplier and split at that point.
1235 * Returns the split constraint
1236 */
1238 Block* &lb, Block* &rb) {
1239#ifdef LIBVPSC_LOGGING
1240 ofstream f(LOGFILE,ios::app);
1241 f<<" need to split between: "<<*vl<<" and "<<*vr<<endl;
1242#endif
1243 Constraint *c=findMinLMBetween(vl, vr);
1244#ifdef LIBVPSC_LOGGING
1245 f<<" going to split on: "<<*c<<endl;
1246#endif
1247 if(c!=nullptr) {
1248 split(lb,rb,c);
1249 deleted = true;
1250 }
1251 return c;
1252}
1253
1254/*
1255 * Creates two new blocks, l and r, and splits this block across constraint c,
1256 * placing the left subtree of constraints (and associated variables) into l
1257 * and the right into r.
1258 */
1260 c->active=false;
1261 l=new Block(blocks);
1262 populateSplitBlock(l,c->left,c->right);
1263 //COLA_ASSERT(l->weight>0);
1264 r=new Block(blocks);
1265 populateSplitBlock(r,c->right,c->left);
1266 //COLA_ASSERT(r->weight>0);
1267}
1268
1269/*
1270 * Computes the cost (squared euclidean distance from desired positions) of the
1271 * current positions for variables in this block
1272 */
1273double Block::cost() {
1274 double c = 0;
1275 for (Vit v=vars->begin();v!=vars->end();++v) {
1276 double diff = (*v)->position() - (*v)->desiredPosition;
1277 c += (*v)->weight * diff * diff;
1278 }
1279 return c;
1280}
1281ostream& operator <<(ostream &os, const Block& b)
1282{
1283 os<<"Block(posn="<<b.posn<<"):";
1284 for(Block::Vit v=b.vars->begin();v!=b.vars->end();++v) {
1285 os<<" "<<**v;
1286 }
1287 if(b.deleted) {
1288 os<<" Deleted!";
1289 }
1290 return os;
1291}
1292
1293Constraint::Constraint(Variable *left, Variable *right, double gap, bool equality)
1294: left(left),
1295 right(right),
1296 gap(gap),
1297 timeStamp(0),
1298 active(false),
1299 equality(equality),
1300 unsatisfiable(false),
1301 needsScaling(true),
1302 creator(nullptr)
1303{
1304 // In hindsight I think it's probably better to build the constraint DAG
1305 // (by creating variable in/out lists) when needed, rather than in advance
1306 //left->out.push_back(this);
1307 //right->in.push_back(this);
1308}
1310 // see constructor: the following is just way too slow.
1311 // Better to create a
1312 // new DAG on demand than maintain the lists dynamically.
1313 //Constraints::iterator i;
1314 //for(i=left->out.begin(); i!=left->out.end(); i++) {
1315 //if(*i==this) break;
1316 //}
1317 //left->out.erase(i);
1318 //for(i=right->in.begin(); i!=right->in.end(); i++) {
1319 //if(*i==this) break;
1320 //}
1321 //right->in.erase(i);
1322}
1323std::string Constraint::toString(void) const
1324{
1325 std::stringstream stream;
1326 stream << "Constraint: var(" << left->id << ") ";
1327 if (gap < 0)
1328 {
1329 stream << "- " << -gap << " ";
1330 }
1331 else
1332 {
1333 stream << "+ " << gap << " ";
1334 }
1335 stream << ((equality) ? "==" : "<=");
1336 stream << " var(" << right->id << ") ";
1337 return stream.str();
1338}
1339
1340std::ostream& operator <<(std::ostream &os, const Constraint &c)
1341{
1342 const char *type = c.equality ? "=" : "<=";
1343 std::ostringstream lscale, rscale;
1344 if (c.left->scale != 1)
1345 {
1346 lscale << c.left->scale << "*";
1347 }
1348 if (c.right->scale != 1)
1349 {
1350 rscale << c.right->scale << "*";
1351 }
1352 os << lscale.str() << *c.left << "+" << c.gap << type <<
1353 rscale.str() << *c.right;
1354 if (c.left->block && c.right->block)
1355 {
1356 os << "(" << c.slack() << ")" << (c.active ? "-active" : "") <<
1357 "(lm=" << c.lm << ")";
1358 }
1359 else
1360 {
1361 os << "(vars have no position)";
1362 }
1363 return os;
1364}
1365
1367 Constraint *const &l, Constraint *const &r
1368) const {
1369 double const sl =
1370 l->left->block->timeStamp > l->timeStamp
1371 ||l->left->block==l->right->block
1372 ?-DBL_MAX:l->slack();
1373 double const sr =
1374 r->left->block->timeStamp > r->timeStamp
1375 ||r->left->block==r->right->block
1376 ?-DBL_MAX:r->slack();
1377 if(sl==sr) {
1378 // arbitrary choice based on id
1379 if(l->left->id==r->left->id) {
1380 if(l->right->id<r->right->id) return true;
1381 return false;
1382 }
1383 if(l->left->id<r->left->id) return true;
1384 return false;
1385 }
1386 return sl > sr;
1387}
1388
1389std::ostream& operator <<(std::ostream &os, const Variable &v) {
1390 if(v.block)
1391 os << "(" << v.id << "=" << v.position() << ")";
1392 else
1393 os << "(" << v.id << "=" << v.desiredPosition << ")";
1394 return os;
1395}
1396
1397typedef std::list<std::map<Variable *, double> > VarOffsetMapList;
1398
1399class EqualityConstraintSet
1400{
1401 public:
1402 EqualityConstraintSet(Variables vs)
1403 {
1404 for (size_t i = 0; i < vs.size(); ++i)
1405 {
1406 std::map<Variable *, double> varSet;
1407 varSet[vs[i]] = 0;
1408 variableGroups.push_back(varSet);
1409 }
1410 }
1411 bool isRedundant(Variable *lhs, Variable *rhs, double sep)
1412 {
1413 VarOffsetMapList::iterator lhsSet = setForVar(lhs);
1414 VarOffsetMapList::iterator rhsSet = setForVar(rhs);
1415 if (lhsSet == rhsSet)
1416 {
1417 // Check if this is a redundant constraint.
1418 if (fabs(((*lhsSet)[lhs] + sep) - (*rhsSet)[rhs]) < 0.0001)
1419 {
1420 // If so, return true.
1421 return true;
1422 }
1423 }
1424 return false;
1425 }
1426 void mergeSets(Variable *lhs, Variable *rhs, double sep)
1427 {
1428 VarOffsetMapList::iterator lhsSet = setForVar(lhs);
1429 VarOffsetMapList::iterator rhsSet = setForVar(rhs);
1430 if (lhsSet == rhsSet)
1431 {
1432 return;
1433 }
1434
1435 double rhsOldOffset = (*rhsSet)[rhs];
1436 double rhsNewOffset = (*lhsSet)[lhs] + sep;
1437 double offset = rhsNewOffset - rhsOldOffset;
1438
1439 // Update offsets
1440 for (std::map<Variable *, double>::iterator it = rhsSet->begin();
1441 it != rhsSet->end(); ++it)
1442 {
1443 it->second += offset;
1444 }
1445
1446 // Merge rhsSet into lhsSet
1447 lhsSet->insert(rhsSet->begin(), rhsSet->end());
1448 variableGroups.erase(rhsSet);
1449 }
1450
1451 private:
1452 VarOffsetMapList::iterator setForVar(Variable *var)
1453 {
1454 for (VarOffsetMapList::iterator it = variableGroups.begin();
1455 it != variableGroups.end(); ++it)
1456 {
1457 if (it->find(var) != it->end())
1458 {
1459 return it;
1460 }
1461 }
1462 return variableGroups.end();
1463 }
1464
1465 VarOffsetMapList variableGroups;
1466};
1467
1469 Constraints const &constraints)
1470{
1471 EqualityConstraintSet equalitySets(vars);
1472 Constraints cs = Constraints(constraints.size());
1473 int csSize = 0;
1474
1475 for (unsigned i = 0; i < constraints.size(); ++i)
1476 {
1477 Constraint *c = constraints[i];
1478 if (c->equality)
1479 {
1480 if (!equalitySets.isRedundant(c->left, c->right, c->gap))
1481 {
1482 // Only add non-redundant equalities
1483 equalitySets.mergeSets(c->left, c->right, c->gap);
1484 cs[csSize++] = c;
1485 }
1486 }
1487 else
1488 {
1489 // Add all non-equalities
1490 cs[csSize++] = c;
1491 }
1492 }
1493 cs.resize(csSize);
1494 return cs;
1495}
1496
1497
1498}
1499
1500#endif
void split(Block *&l, Block *&r, Constraint *c)
Definition vpsc.cpp:1259
double posn
Definition vpsc.h:109
Constraint * splitBetween(Variable *vl, Variable *vr, Block *&lb, Block *&rb)
Definition vpsc.cpp:1237
Blocks * blocks
Definition vpsc.h:156
bool canFollowLeft(Constraint const *c, Variable const *last) const
Definition vpsc.cpp:934
bool deleted
Definition vpsc.h:131
Constraint * findMinInConstraint()
Definition vpsc.cpp:864
bool canFollowRight(Constraint const *c, Variable const *last) const
Definition vpsc.cpp:937
bool getActivePathBetween(Constraints &path, Variable const *u, Variable const *v, Variable const *w) const
Definition vpsc.cpp:1183
void setUpInConstraints()
Definition vpsc.cpp:758
void reset_active_lm(Variable *const v, Variable *const u)
Definition vpsc.cpp:1093
long timeStamp
Definition vpsc.h:132
~Block(void)
Definition vpsc.cpp:752
void list_active(Variable *const v, Variable *const u)
Definition vpsc.cpp:1109
Heap * out
Definition vpsc.h:134
Block(Blocks *blocks, Variable *const v=nullptr)
Definition vpsc.cpp:721
void mergeOut(Block *b)
Definition vpsc.cpp:855
void merge(Block *b, Constraint *c, double dist)
Definition vpsc.cpp:807
Variables * vars
Definition vpsc.h:108
double cost()
Definition vpsc.cpp:1273
Variables::iterator Vit
Definition vpsc.h:102
Constraint * findMinLMBetween(Variable *const lv, Variable *const rv)
Definition vpsc.cpp:1146
void populateSplitBlock(Block *b, Variable *v, Variable const *u)
Definition vpsc.cpp:1169
void updateWeightedPosition()
Definition vpsc.cpp:738
Constraints::iterator Cit
Definition vpsc.h:103
void mergeIn(Block *b)
Definition vpsc.cpp:838
bool getActiveDirectedPathBetween(Constraints &path, Variable const *u, Variable const *v) const
Definition vpsc.cpp:1218
Constraints::const_iterator Cit_const
Definition vpsc.h:104
bool isActiveDirectedPathBetween(Variable const *u, Variable const *v) const
Definition vpsc.cpp:1207
void deleteMinInConstraint()
Definition vpsc.cpp:923
void setUpOutConstraints()
Definition vpsc.cpp:761
bool split_path(Variable *, Variable *const, Variable *const, Constraint *&min_lm, bool desperation)
Definition vpsc.cpp:995
Heap * in
Definition vpsc.h:133
Constraint * findMinOutConstraint()
Definition vpsc.cpp:913
double compute_dfdv(Variable *const v, Variable *const u)
Definition vpsc.cpp:967
void addVariable(Variable *v)
Definition vpsc.cpp:704
void deleteMinOutConstraint()
Definition vpsc.cpp:931
void setUpConstraintHeap(Heap *&h, bool in)
Definition vpsc.cpp:764
PositionStats ps
Definition vpsc.h:112
Constraint * findMinLM()
Definition vpsc.cpp:1135
long blockTimeCtr
Definition vpsc.h:263
size_t size() const
Definition vpsc.h:273
void dfsVisit(Variable *v, std::list< Variable * > *order)
Definition vpsc.cpp:527
void mergeLeft(Block *r)
Definition vpsc.cpp:546
void cleanup()
Definition vpsc.cpp:614
Blocks(Variables const &vs)
void split(Block *b, Block *&l, Block *&r, Constraint *c)
Definition vpsc.cpp:651
~Blocks(void)
Definition vpsc.cpp:498
double cost()
Definition vpsc.cpp:678
std::vector< Block * > m_blocks
Definition vpsc.h:268
void mergeRight(Block *l)
Definition vpsc.cpp:580
size_t nvs
Definition vpsc.h:270
Variables const & vs
Definition vpsc.h:269
void removeBlock(Block *doomed)
Definition vpsc.cpp:608
std::list< Variable * > * totalOrder()
Definition vpsc.cpp:513
void insert(Block *block)
Definition vpsc.h:283
Block * at(size_t index) const
Definition vpsc.h:278
bool operator()(Constraint *const &l, Constraint *const &r) const
Definition vpsc.cpp:1366
Variable * right
Definition vpsc.h:232
Constraint(Variable *left, Variable *right, double gap, bool equality=false)
Definition vpsc.cpp:1293
double slack(void) const
Definition vpsc.h:213
Variable * left
Definition vpsc.h:231
std::string toString(void) const
Definition vpsc.cpp:1323
const bool equality
Definition vpsc.h:237
void moveBlocks()
Definition vpsc.cpp:367
void copyResult()
Definition vpsc.cpp:124
unsigned splitCnt
Definition vpsc.h:300
void addConstraint(Constraint *constraint)
Definition vpsc.cpp:96
bool needsScaling
Definition vpsc.h:316
bool constraintGraphIsCyclic(const unsigned n, Variable *const vs[])
Definition vpsc.cpp:137
bool satisfy()
Definition vpsc.cpp:274
Variables const & vs
Definition vpsc.h:315
Constraints const & cs
Definition vpsc.h:313
void printBlocks()
Definition vpsc.cpp:107
IncSolver(Variables const &vs, Constraints const &cs)
Definition vpsc.cpp:61
bool blockGraphIsCyclic()
Definition vpsc.cpp:184
Constraint * mostViolated(Constraints &l)
Definition vpsc.cpp:431
Constraints inactive
Definition vpsc.h:323
void splitBlocks()
Definition vpsc.cpp:383
Blocks * bs
Definition vpsc.h:311
Constraints in
Definition vpsc.h:179
Constraints out
Definition vpsc.h:180
Block * block
Definition vpsc.h:176
iterator begin()
Iterator over children.
Definition node.h:557
const double w
Definition conic-4.cpp:19
Geom::IntPoint size
double c[8][4]
const unsigned order
Inkscape::XML::Node * node
double offset
libavoid: Object-avoiding orthogonal and polyline connector routing library.
static const double LAGRANGIAN_TOLERANCE
Definition vpsc.cpp:58
static double cost(ConnRef *lineRef, const double dist, VertInf *inf2, VertInf *inf3, ANode *inf1Node)
Definition makepath.cpp:308
Constraints constraintsRemovingRedundantEqualities(Variables const &vars, Constraints const &constraints)
Definition vpsc.cpp:1468
std::vector< Variable * > Variables
Definition vpsc.h:82
std::list< std::map< Variable *, double > > VarOffsetMapList
Definition vpsc.cpp:1397
std::vector< Constraint * > Constraints
Definition vpsc.h:83
std::priority_queue< Constraint *, std::vector< Constraint * >, CompareConstraints > Heap
Definition vpsc.h:98
static const double ZERO_UPPERBOUND
Definition vpsc.cpp:57
double dist(const Point &a, const Point &b)
Definition geometry.cpp:310
STL namespace.
void addVariable(Variable *const v)
Definition vpsc.cpp:688
int index