Code

Merge from trunk.
[inkscape.git] / src / libvpsc / solve_VPSC.cpp
1 /**
2  * \brief Solve an instance of the "Variable Placement with Separation
3  * Constraints" problem.
4  *
5  * Authors:
6  *   Tim Dwyer <tgdwyer@gmail.com>
7  *
8  * Copyright (C) 2005 Authors
9  *
10  * Released under GNU LGPL.  Read the file 'COPYING' for more information.
11  */
13 #include <cassert>
14 #include "constraint.h"
15 #include "block.h"
16 #include "blocks.h"
17 #include "solve_VPSC.h"
18 #include <math.h>
19 #include <sstream>
20 #ifdef RECTANGLE_OVERLAP_LOGGING
21 #include <fstream>
22 #endif
23 #include <map>
25 using namespace std;
27 namespace vpsc {
29 static const double ZERO_UPPERBOUND=-0.0000001;
31 IncSolver::IncSolver(const unsigned n, Variable* const vs[], const unsigned m, Constraint *cs[]) 
32         : Solver(n,vs,m,cs) {
33         inactive.assign(cs,cs+m);
34         for(ConstraintList::iterator i=inactive.begin();i!=inactive.end();++i) {
35                 (*i)->active=false;
36         }
37 }
38 Solver::Solver(const unsigned n, Variable* const vs[], const unsigned m, Constraint *cs[]) : m(m), cs(cs), n(n), vs(vs) {
39         bs=new Blocks(n, vs);
40 #ifdef RECTANGLE_OVERLAP_LOGGING
41         printBlocks();
42         //assert(!constraintGraphIsCyclic(n,vs));
43 #endif
44 }
45 Solver::~Solver() {
46         delete bs;
47 }
49 // useful in debugging
50 void Solver::printBlocks() {
51 #ifdef RECTANGLE_OVERLAP_LOGGING
52         ofstream f(LOGFILE,ios::app);
53         for(set<Block*>::iterator i=bs->begin();i!=bs->end();++i) {
54                 Block *b=*i;
55                 f<<"  "<<*b<<endl;
56         }
57         for(unsigned i=0;i<m;i++) {
58                 f<<"  "<<*cs[i]<<endl;
59         }
60 #endif
61 }
62 /**
63 * Produces a feasible - though not necessarily optimal - solution by
64 * examining blocks in the partial order defined by the directed acyclic
65 * graph of constraints. For each block (when processing left to right) we
66 * maintain the invariant that all constraints to the left of the block
67 * (incoming constraints) are satisfied. This is done by repeatedly merging
68 * blocks into bigger blocks across violated constraints (most violated
69 * first) fixing the position of variables inside blocks relative to one
70 * another so that constraints internal to the block are satisfied.
71 */
72 void Solver::satisfy() {
73         list<Variable*> *vs=bs->totalOrder();
74         for(list<Variable*>::iterator i=vs->begin();i!=vs->end();++i) {
75                 Variable *v=*i;
76                 if(!v->block->deleted) {
77                         bs->mergeLeft(v->block);
78                 }
79         }
80         bs->cleanup();
81         for(unsigned i=0;i<m;i++) {
82                 if(cs[i]->slack() < ZERO_UPPERBOUND) {
83 #ifdef RECTANGLE_OVERLAP_LOGGING
84                         ofstream f(LOGFILE,ios::app);
85                         f<<"Error: Unsatisfied constraint: "<<*cs[i]<<endl;
86 #endif
87                         //assert(cs[i]->slack()>-0.0000001);
88                         throw "Unsatisfied constraint";
89                 }
90         }
91         delete vs;
92 }
94 void Solver::refine() {
95         bool solved=false;
96         // Solve shouldn't loop indefinately
97         // ... but just to make sure we limit the number of iterations
98         unsigned maxtries=100;
99         while(!solved&&maxtries>0) {
100                 solved=true;
101                 maxtries--;
102                 for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
103                         Block *b=*i;
104                         b->setUpInConstraints();
105                         b->setUpOutConstraints();
106                 }
107                 for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
108                         Block *b=*i;
109                         Constraint *c=b->findMinLM();
110                         if(c!=NULL && c->lm<0) {
111 #ifdef RECTANGLE_OVERLAP_LOGGING
112                                 ofstream f(LOGFILE,ios::app);
113                                 f<<"Split on constraint: "<<*c<<endl;
114 #endif
115                                 // Split on c
116                                 Block *l=NULL, *r=NULL;
117                                 bs->split(b,l,r,c);
118                                 bs->cleanup();
119                                 // split alters the block set so we have to restart
120                                 solved=false;
121                                 break;
122                         }
123                 }
124         }
125         for(unsigned i=0;i<m;i++) {
126                 if(cs[i]->slack() < ZERO_UPPERBOUND) {
127                         assert(cs[i]->slack()>ZERO_UPPERBOUND);
128                         throw "Unsatisfied constraint";
129                 }
130         }
132 /**
133  * Calculate the optimal solution. After using satisfy() to produce a
134  * feasible solution, refine() examines each block to see if further
135  * refinement is possible by splitting the block. This is done repeatedly
136  * until no further improvement is possible.
137  */
138 void Solver::solve() {
139         satisfy();
140         refine();
143 void IncSolver::solve() {
144 #ifdef RECTANGLE_OVERLAP_LOGGING
145         ofstream f(LOGFILE,ios::app);
146         f<<"solve_inc()..."<<endl;
147 #endif
148         double lastcost,cost = bs->cost();
149         do {
150                 lastcost=cost;
151                 satisfy();
152                 splitBlocks();
153                 cost = bs->cost();
154 #ifdef RECTANGLE_OVERLAP_LOGGING
155         f<<"  cost="<<cost<<endl;
156 #endif
157         } while(fabs(lastcost-cost)>0.0001);
159 /**
160  * incremental version of satisfy that allows refinement after blocks are
161  * moved.
162  *
163  *  - move blocks to new positions
164  *  - repeatedly merge across most violated constraint until no more
165  *    violated constraints exist
166  *
167  * Note: there is a special case to handle when the most violated constraint
168  * is between two variables in the same block.  Then, we must split the block
169  * over an active constraint between the two variables.  We choose the 
170  * constraint with the most negative lagrangian multiplier. 
171  */
172 void IncSolver::satisfy() {
173 #ifdef RECTANGLE_OVERLAP_LOGGING
174         ofstream f(LOGFILE,ios::app);
175         f<<"satisfy_inc()..."<<endl;
176 #endif
177         splitBlocks();
178         long splitCtr = 0;
179         Constraint* v = NULL;
180         while((v=mostViolated(inactive))&&(v->equality || v->slack() < ZERO_UPPERBOUND)) {
181                 assert(!v->active);
182                 Block *lb = v->left->block, *rb = v->right->block;
183                 if(lb != rb) {
184                         lb->merge(rb,v);
185                 } else {
186                         if(lb->isActiveDirectedPathBetween(v->right,v->left)) {
187                                 // cycle found, relax the violated, cyclic constraint
188                                 v->gap = v->slack();
189                                 continue;
190                         }
191                         if(splitCtr++>10000) {
192                                 throw "Cycle Error!";
193                         }
194                         // constraint is within block, need to split first
195                         inactive.push_back(lb->splitBetween(v->left,v->right,lb,rb));
196                         lb->merge(rb,v);
197                         bs->insert(lb);
198                 }
199         }
200 #ifdef RECTANGLE_OVERLAP_LOGGING
201         f<<"  finished merges."<<endl;
202 #endif
203         bs->cleanup();
204         for(unsigned i=0;i<m;i++) {
205                 v=cs[i];
206                 if(v->slack() < ZERO_UPPERBOUND) {
207                         ostringstream s;
208                         s<<"Unsatisfied constraint: "<<*v;
209 #ifdef RECTANGLE_OVERLAP_LOGGING
210                         ofstream f(LOGFILE,ios::app);
211                         f<<s.str()<<endl;
212 #endif
213                         throw s.str().c_str();
214                 }
215         }
216 #ifdef RECTANGLE_OVERLAP_LOGGING
217         f<<"  finished cleanup."<<endl;
218         printBlocks();
219 #endif
221 void IncSolver::moveBlocks() {
222 #ifdef RECTANGLE_OVERLAP_LOGGING
223         ofstream f(LOGFILE,ios::app);
224         f<<"moveBlocks()..."<<endl;
225 #endif
226         for(set<Block*>::const_iterator i(bs->begin());i!=bs->end();++i) {
227                 Block *b = *i;
228                 b->wposn = b->desiredWeightedPosition();
229                 b->posn = b->wposn / b->weight;
230         }
231 #ifdef RECTANGLE_OVERLAP_LOGGING
232         f<<"  moved blocks."<<endl;
233 #endif
235 void IncSolver::splitBlocks() {
236 #ifdef RECTANGLE_OVERLAP_LOGGING
237         ofstream f(LOGFILE,ios::app);
238 #endif
239         moveBlocks();
240         splitCnt=0;
241         // Split each block if necessary on min LM
242         for(set<Block*>::const_iterator i(bs->begin());i!=bs->end();++i) {
243                 Block* b = *i;
244                 Constraint* v=b->findMinLM();
245                 if(v!=NULL && v->lm < ZERO_UPPERBOUND) {
246                         assert(!v->equality);
247 #ifdef RECTANGLE_OVERLAP_LOGGING
248                         f<<"    found split point: "<<*v<<" lm="<<v->lm<<endl;
249 #endif
250                         splitCnt++;
251                         Block *b = v->left->block, *l=NULL, *r=NULL;
252                         assert(v->left->block == v->right->block);
253                         double pos = b->posn;
254                         b->split(l,r,v);
255                         l->posn=r->posn=pos;
256                         l->wposn = l->posn * l->weight;
257                         r->wposn = r->posn * r->weight;
258                         bs->insert(l);
259                         bs->insert(r);
260                         b->deleted=true;
261                         inactive.push_back(v);
262 #ifdef RECTANGLE_OVERLAP_LOGGING
263                         f<<"  new blocks: "<<*l<<" and "<<*r<<endl;
264 #endif
265                 }
266         }
267 #ifdef RECTANGLE_OVERLAP_LOGGING
268         f<<"  finished splits."<<endl;
269 #endif
270         bs->cleanup();
273 /**
274  * Scan constraint list for the most violated constraint, or the first equality
275  * constraint
276  */
277 Constraint* IncSolver::mostViolated(ConstraintList &l) {
278         double minSlack = DBL_MAX;
279         Constraint* v=NULL;
280 #ifdef RECTANGLE_OVERLAP_LOGGING
281         ofstream f(LOGFILE,ios::app);
282         f<<"Looking for most violated..."<<endl;
283 #endif
284         ConstraintList::iterator end = l.end();
285         ConstraintList::iterator deletePoint = end;
286         for(ConstraintList::iterator i=l.begin();i!=end;++i) {
287                 Constraint *c=*i;
288                 double slack = c->slack();
289                 if(c->equality || slack < minSlack) {
290                         minSlack=slack; 
291                         v=c;
292                         deletePoint=i;
293                         if(c->equality) break;
294                 }
295         }
296         // Because the constraint list is not order dependent we just
297         // move the last element over the deletePoint and resize
298         // downwards.  There is always at least 1 element in the
299         // vector because of search.
300         if(deletePoint != end && (minSlack<ZERO_UPPERBOUND||v->equality)) {
301                 *deletePoint = l[l.size()-1];
302                 l.resize(l.size()-1);
303         }
304 #ifdef RECTANGLE_OVERLAP_LOGGING
305         f<<"  most violated is: "<<*v<<endl;
306 #endif
307         return v;
310 struct node {
311         set<node*> in;
312         set<node*> out;
313 };
314 // useful in debugging - cycles would be BAD
315 bool Solver::constraintGraphIsCyclic(const unsigned n, Variable* const vs[]) {
316         map<Variable*, node*> varmap;
317         vector<node*> graph;
318         for(unsigned i=0;i<n;i++) {
319                 node *u=new node;
320                 graph.push_back(u);
321                 varmap[vs[i]]=u;
322         }
323         for(unsigned i=0;i<n;i++) {
324                 for(vector<Constraint*>::iterator c=vs[i]->in.begin();c!=vs[i]->in.end();++c) {
325                         Variable *l=(*c)->left;
326                         varmap[vs[i]]->in.insert(varmap[l]);
327                 }
329                 for(vector<Constraint*>::iterator c=vs[i]->out.begin();c!=vs[i]->out.end();++c) {
330                         Variable *r=(*c)->right;
331                         varmap[vs[i]]->out.insert(varmap[r]);
332                 }
333         }
334         while(graph.size()>0) {
335                 node *u=NULL;
336                 vector<node*>::iterator i=graph.begin();
337                 for(;i!=graph.end();++i) {
338                         u=*i;
339                         if(u->in.size()==0) {
340                                 break;
341                         }
342                 }
343                 if(i==graph.end() && graph.size()>0) {
344                         //cycle found!
345                         return true;
346                 } else {
347                         graph.erase(i);
348                         for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
349                                 node *v=*j;
350                                 v->in.erase(u);
351                         }
352                         delete u;
353                 }
354         }
355         for(unsigned i=0; i<graph.size(); ++i) {
356                 delete graph[i];
357         }
358         return false;
361 // useful in debugging - cycles would be BAD
362 bool Solver::blockGraphIsCyclic() {
363         map<Block*, node*> bmap;
364         vector<node*> graph;
365         for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
366                 Block *b=*i;
367                 node *u=new node;
368                 graph.push_back(u);
369                 bmap[b]=u;
370         }
371         for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
372                 Block *b=*i;
373                 b->setUpInConstraints();
374                 Constraint *c=b->findMinInConstraint();
375                 while(c!=NULL) {
376                         Block *l=c->left->block;
377                         bmap[b]->in.insert(bmap[l]);
378                         b->deleteMinInConstraint();
379                         c=b->findMinInConstraint();
380                 }
382                 b->setUpOutConstraints();
383                 c=b->findMinOutConstraint();
384                 while(c!=NULL) {
385                         Block *r=c->right->block;
386                         bmap[b]->out.insert(bmap[r]);
387                         b->deleteMinOutConstraint();
388                         c=b->findMinOutConstraint();
389                 }
390         }
391         while(graph.size()>0) {
392                 node *u=NULL;
393                 vector<node*>::iterator i=graph.begin();
394                 for(;i!=graph.end();++i) {
395                         u=*i;
396                         if(u->in.size()==0) {
397                                 break;
398                         }
399                 }
400                 if(i==graph.end() && graph.size()>0) {
401                         //cycle found!
402                         return true;
403                 } else {
404                         graph.erase(i);
405                         for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
406                                 node *v=*j;
407                                 v->in.erase(u);
408                         }
409                         delete u;
410                 }
411         }
412         for(unsigned i=0; i<graph.size(); i++) {
413                 delete graph[i];
414         }
415         return false;