2
* \brief Solve an instance of the "Variable Placement with Separation
3
* Constraints" problem.
6
* Tim Dwyer <tgdwyer@gmail.com>
8
* Copyright (C) 2005 Authors
10
* Released under GNU LGPL. Read the file 'COPYING' for more information.
14
#include "constraint.h"
17
#include "solve_VPSC.h"
20
#ifdef RECTANGLE_OVERLAP_LOGGING
27
using std::ostringstream;
31
IncVPSC::IncVPSC(const unsigned n, Variable *vs[], const unsigned m, Constraint *cs[])
33
inactive.assign(cs,cs+m);
34
for(ConstraintList::iterator i=inactive.begin();i!=inactive.end();++i) {
38
VPSC::VPSC(const unsigned n, Variable *vs[], const unsigned m, Constraint *cs[]) : cs(cs), m(m), vs(vs) {
40
#ifdef RECTANGLE_OVERLAP_LOGGING
42
assert(!constraintGraphIsCyclic(n,vs));
49
// useful in debugging
50
void VPSC::printBlocks() {
51
#ifdef RECTANGLE_OVERLAP_LOGGING
52
ofstream f(LOGFILE,ios::app);
53
for(set<Block*>::iterator i=bs->begin();i!=bs->end();++i) {
57
for(unsigned i=0;i<m;i++) {
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.
72
void VPSC::satisfy() {
73
list<Variable*> *vs=bs->totalOrder();
74
for(list<Variable*>::iterator i=vs->begin();i!=vs->end();++i) {
76
if(!v->block->deleted) {
77
bs->mergeLeft(v->block);
81
for(unsigned i=0;i<m;i++) {
82
if(cs[i]->slack()<-0.0000001) {
83
#ifdef RECTANGLE_OVERLAP_LOGGING
84
ofstream f(LOGFILE,ios::app);
85
f<<"Error: Unsatisfied constraint: "<<*cs[i]<<endl;
87
//assert(cs[i]->slack()>-0.0000001);
88
throw "Unsatisfied constraint";
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) {
102
for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
104
b->setUpInConstraints();
105
b->setUpOutConstraints();
107
for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++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;
116
Block *l=NULL, *r=NULL;
119
// split alters the block set so we have to restart
125
for(unsigned i=0;i<m;i++) {
126
if(cs[i]->slack()<-0.0000001) {
127
assert(cs[i]->slack()>-0.0000001);
128
throw "Unsatisfied constraint";
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.
143
void IncVPSC::solve() {
144
#ifdef RECTANGLE_OVERLAP_LOGGING
145
ofstream f(LOGFILE,ios::app);
146
f<<"solve_inc()..."<<endl;
148
double lastcost,cost = bs->cost();
154
#ifdef RECTANGLE_OVERLAP_LOGGING
155
f<<" cost="<<cost<<endl;
157
} while(fabs(lastcost-cost)>0.0001);
160
* incremental version of satisfy that allows refinement after blocks are
163
* - move blocks to new positions
164
* - repeatedly merge across most violated constraint until no more
165
* violated constraints exist
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.
172
void IncVPSC::satisfy() {
173
#ifdef RECTANGLE_OVERLAP_LOGGING
174
ofstream f(LOGFILE,ios::app);
175
f<<"satisfy_inc()..."<<endl;
179
Constraint* v = NULL;
180
while((v=mostViolated(inactive))&&(v->equality || v->slack()<-0.000001)) {
182
Block *lb = v->left->block, *rb = v->right->block;
186
if(splitCtr++>10000) {
187
throw "Cycle Error!";
189
// constraint is within block, need to split first
190
inactive.push_back(lb->splitBetween(v->left,v->right,lb,rb));
195
#ifdef RECTANGLE_OVERLAP_LOGGING
196
f<<" finished merges."<<endl;
199
for(unsigned i=0;i<m;i++) {
201
if(v->slack()<-0.0000001) {
202
//assert(cs[i]->slack()>-0.0000001);
204
s<<"Unsatisfied constraint: "<<*v;
205
throw s.str().c_str();
208
#ifdef RECTANGLE_OVERLAP_LOGGING
209
f<<" finished cleanup."<<endl;
213
void IncVPSC::moveBlocks() {
214
#ifdef RECTANGLE_OVERLAP_LOGGING
215
ofstream f(LOGFILE,ios::app);
216
f<<"moveBlocks()..."<<endl;
218
for(set<Block*>::const_iterator i(bs->begin());i!=bs->end();++i) {
220
b->wposn = b->desiredWeightedPosition();
221
b->posn = b->wposn / b->weight;
223
#ifdef RECTANGLE_OVERLAP_LOGGING
224
f<<" moved blocks."<<endl;
227
void IncVPSC::splitBlocks() {
228
#ifdef RECTANGLE_OVERLAP_LOGGING
229
ofstream f(LOGFILE,ios::app);
233
// Split each block if necessary on min LM
234
for(set<Block*>::const_iterator i(bs->begin());i!=bs->end();++i) {
236
Constraint* v=b->findMinLM();
237
if(v!=NULL && v->lm < -0.0000001) {
238
assert(!v->equality);
239
#ifdef RECTANGLE_OVERLAP_LOGGING
240
f<<" found split point: "<<*v<<" lm="<<v->lm<<endl;
243
Block *b = v->left->block, *l=NULL, *r=NULL;
244
assert(v->left->block == v->right->block);
245
double pos = b->posn;
248
l->wposn = l->posn * l->weight;
249
r->wposn = r->posn * r->weight;
253
inactive.push_back(v);
254
#ifdef RECTANGLE_OVERLAP_LOGGING
255
f<<" new blocks: "<<*l<<" and "<<*r<<endl;
259
#ifdef RECTANGLE_OVERLAP_LOGGING
260
f<<" finished splits."<<endl;
266
* Scan constraint list for the most violated constraint, or the first equality
269
Constraint* IncVPSC::mostViolated(ConstraintList &l) {
270
double minSlack = DBL_MAX;
272
#ifdef RECTANGLE_OVERLAP_LOGGING
273
ofstream f(LOGFILE,ios::app);
274
f<<"Looking for most violated..."<<endl;
276
ConstraintList::iterator end = l.end();
277
ConstraintList::iterator deletePoint = end;
278
for(ConstraintList::iterator i=l.begin();i!=end;++i) {
280
double slack = c->slack();
281
if(c->equality || slack < minSlack) {
285
if(c->equality) break;
288
// Because the constraint list is not order dependent we just
289
// move the last element over the deletePoint and resize
290
// downwards. There is always at least 1 element in the
291
// vector because of search.
292
if(deletePoint != end && (minSlack<-0.0000001||v->equality)) {
293
*deletePoint = l[l.size()-1];
294
l.resize(l.size()-1);
296
#ifdef RECTANGLE_OVERLAP_LOGGING
297
f<<" most violated is: "<<*v<<endl;
309
// useful in debugging - cycles would be BAD
310
bool VPSC::constraintGraphIsCyclic(const unsigned n, Variable *vs[]) {
311
map<Variable*, node*> varmap;
313
for(unsigned i=0;i<n;i++) {
318
for(unsigned i=0;i<n;i++) {
319
for(vector<Constraint*>::iterator c=vs[i]->in.begin();c!=vs[i]->in.end();++c) {
320
Variable *l=(*c)->left;
321
varmap[vs[i]]->in.insert(varmap[l]);
324
for(vector<Constraint*>::iterator c=vs[i]->out.begin();c!=vs[i]->out.end();++c) {
325
Variable *r=(*c)->right;
326
varmap[vs[i]]->out.insert(varmap[r]);
329
while(graph.size()>0) {
331
vector<node*>::iterator i=graph.begin();
332
for(;i!=graph.end();++i) {
334
if(u->in.size()==0) {
338
if(i==graph.end() && graph.size()>0) {
343
for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
350
for(unsigned i=0; i<graph.size(); ++i) {
356
// useful in debugging - cycles would be BAD
357
bool VPSC::blockGraphIsCyclic() {
358
map<Block*, node*> bmap;
360
for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
366
for(set<Block*>::const_iterator i=bs->begin();i!=bs->end();++i) {
368
b->setUpInConstraints();
369
Constraint *c=b->findMinInConstraint();
371
Block *l=c->left->block;
372
bmap[b]->in.insert(bmap[l]);
373
b->deleteMinInConstraint();
374
c=b->findMinInConstraint();
377
b->setUpOutConstraints();
378
c=b->findMinOutConstraint();
380
Block *r=c->right->block;
381
bmap[b]->out.insert(bmap[r]);
382
b->deleteMinOutConstraint();
383
c=b->findMinOutConstraint();
386
while(graph.size()>0) {
388
vector<node*>::iterator i=graph.begin();
389
for(;i!=graph.end();++i) {
391
if(u->in.size()==0) {
395
if(i==graph.end() && graph.size()>0) {
400
for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
407
for(unsigned i=0; i<graph.size(); i++) {