summaryrefslogtreecommitdiffstats
path: root/src/libavoid/vpsc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libavoid/vpsc.cpp')
-rw-r--r--src/libavoid/vpsc.cpp1500
1 files changed, 0 insertions, 1500 deletions
diff --git a/src/libavoid/vpsc.cpp b/src/libavoid/vpsc.cpp
deleted file mode 100644
index 294100c91..000000000
--- a/src/libavoid/vpsc.cpp
+++ /dev/null
@@ -1,1500 +0,0 @@
-/*
- * vim: ts=4 sw=4 et tw=0 wm=0
- *
- * libavoid - Fast, Incremental, Object-avoiding Line Router
- *
- * Copyright (C) 2005-2014 Monash University
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * See the file LICENSE.LGPL distributed with the library.
- *
- * Licensees holding a valid commercial license may use this file in
- * accordance with the commercial license agreement provided with the
- * library.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Author(s): Tim Dwyer
- * Michael Wybrow
- *
- * --------------
- *
- * This file contains a slightly modified version of IncSolver() from libvpsc:
- * A solver for the problem of Variable Placement with Separation Constraints.
- * It has the following changes from the Adaptagrams VPSC version:
- * - The required VPSC code has been consolidated into a single file.
- * - Unnecessary code, like the Solver() class, has been removed.
- * - The PairingHeap code has been replaced by a STL priority_queue.
- *
- * Modifications: Michael Wybrow
- *
-*/
-
-#include "libavoid/vpsc.h"
-
-#ifndef USELIBVPSC
-
-#include <iostream>
-#include <cmath>
-#include <sstream>
-#include <map>
-#include <cfloat>
-#include <cstdio>
-
-#include "libavoid/assertions.h"
-#include "libavoid/debug.h"
-
-
-using namespace std;
-
-namespace Avoid {
-
-static const double ZERO_UPPERBOUND=-1e-10;
-static const double LAGRANGIAN_TOLERANCE=-1e-4;
-
-
-IncSolver::IncSolver(Variables const &vs, Constraints const &cs)
- : m(cs.size()),
- cs(cs),
- n(vs.size()),
- vs(vs),
- needsScaling(false)
-{
- for(unsigned i=0;i<n;++i) {
- vs[i]->in.clear();
- vs[i]->out.clear();
-
- // Set needsScaling if any variables have a scale other than 1.
- needsScaling |= (vs[i]->scale != 1);
- }
- for(unsigned i=0;i<m;++i) {
- Constraint *c=cs[i];
- c->left->out.push_back(c);
- c->right->in.push_back(c);
- c->needsScaling = needsScaling;
- }
- bs=new Blocks(vs);
-#ifdef LIBVPSC_LOGGING
- printBlocks();
- //COLA_ASSERT(!constraintGraphIsCyclic(n,vs));
-#endif
-
- inactive=cs;
- for(Constraints::iterator i=inactive.begin();i!=inactive.end();++i) {
- (*i)->active=false;
- }
-}
-IncSolver::~IncSolver() {
- delete bs;
-}
-
-void IncSolver::addConstraint(Constraint *c)
-{
- ++m;
- c->active = false;
- inactive.push_back(c);
- c->left->out.push_back(c);
- c->right->in.push_back(c);
- c->needsScaling = needsScaling;
-}
-
-// useful in debugging
-void IncSolver::printBlocks() {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- for(set<Block*>::iterator i=bs->begin();i!=bs->end();++i) {
- Block *b=*i;
- f<<" "<<*b<<endl;
- }
- for(unsigned i=0;i<m;i++) {
- f<<" "<<*cs[i]<<endl;
- }
-#endif
-}
-
-/*
- * Stores the relative positions of the variables in their finalPosition
- * field.
- */
-void IncSolver::copyResult() {
- for(Variables::const_iterator i=vs.begin();i!=vs.end();++i) {
- Variable* v=*i;
- v->finalPosition=v->position();
- COLA_ASSERT(v->finalPosition==v->finalPosition);
- }
-}
-
-struct node {
- set<node*> in;
- set<node*> out;
-};
-// useful in debugging - cycles would be BAD
-bool IncSolver::constraintGraphIsCyclic(const unsigned n, Variable* const vs[]) {
- map<Variable*, node*> varmap;
- vector<node*> graph;
- for(unsigned i=0;i<n;i++) {
- node *u=new node;
- graph.push_back(u);
- varmap[vs[i]]=u;
- }
- for(unsigned i=0;i<n;i++) {
- for(vector<Constraint*>::iterator c=vs[i]->in.begin();c!=vs[i]->in.end();++c) {
- Variable *l=(*c)->left;
- varmap[vs[i]]->in.insert(varmap[l]);
- }
-
- for(vector<Constraint*>::iterator c=vs[i]->out.begin();c!=vs[i]->out.end();++c) {
- Variable *r=(*c)->right;
- varmap[vs[i]]->out.insert(varmap[r]);
- }
- }
- while(graph.size()>0) {
- node *u=NULL;
- vector<node*>::iterator i=graph.begin();
- for(;i!=graph.end();++i) {
- u=*i;
- if(u->in.size()==0) {
- break;
- }
- }
- if(i==graph.end() && graph.size()>0) {
- //cycle found!
- return true;
- } else {
- graph.erase(i);
- for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
- node *v=*j;
- v->in.erase(u);
- }
- delete u;
- }
- }
- for(unsigned i=0; i<graph.size(); ++i) {
- delete graph[i];
- }
- return false;
-}
-
-// useful in debugging - cycles would be BAD
-bool IncSolver::blockGraphIsCyclic() {
- map<Block*, node*> bmap;
- vector<node*> graph;
- size_t length = bs->size();
- for (size_t i = 0; i < length; ++i)
- {
- Block *b = bs->at(i);
- node *u=new node;
- graph.push_back(u);
- bmap[b]=u;
- }
- for (size_t i = 0; i < length; ++i)
- {
- Block *b = bs->at(i);
- b->setUpInConstraints();
- Constraint *c=b->findMinInConstraint();
- while(c!=NULL) {
- Block *l=c->left->block;
- bmap[b]->in.insert(bmap[l]);
- b->deleteMinInConstraint();
- c=b->findMinInConstraint();
- }
-
- b->setUpOutConstraints();
- c=b->findMinOutConstraint();
- while(c!=NULL) {
- Block *r=c->right->block;
- bmap[b]->out.insert(bmap[r]);
- b->deleteMinOutConstraint();
- c=b->findMinOutConstraint();
- }
- }
- while(graph.size()>0) {
- node *u=NULL;
- vector<node*>::iterator i=graph.begin();
- for(;i!=graph.end();++i) {
- u=*i;
- if(u->in.size()==0) {
- break;
- }
- }
- if(i==graph.end() && graph.size()>0) {
- //cycle found!
- return true;
- } else {
- graph.erase(i);
- for(set<node*>::iterator j=u->out.begin();j!=u->out.end();++j) {
- node *v=*j;
- v->in.erase(u);
- }
- delete u;
- }
- }
- for(unsigned i=0; i<graph.size(); i++) {
- delete graph[i];
- }
- return false;
-}
-
-bool IncSolver::solve() {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"solve_inc()..."<<endl;
-#endif
- satisfy();
- double lastcost = DBL_MAX, cost = bs->cost();
- while(fabs(lastcost-cost)>0.0001) {
- satisfy();
- lastcost=cost;
- cost = bs->cost();
-#ifdef LIBVPSC_LOGGING
- f<<" bs->size="<<bs->size()<<", cost="<<cost<<endl;
-#endif
- }
- copyResult();
- return bs->size()!=n;
-}
-/*
- * incremental version of satisfy that allows refinement after blocks are
- * moved.
- *
- * - move blocks to new positions
- * - repeatedly merge across most violated constraint until no more
- * violated constraints exist
- *
- * Note: there is a special case to handle when the most violated constraint
- * is between two variables in the same block. Then, we must split the block
- * over an active constraint between the two variables. We choose the
- * constraint with the most negative lagrangian multiplier.
- */
-bool IncSolver::satisfy() {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"satisfy_inc()..."<<endl;
-#endif
- splitBlocks();
- //long splitCtr = 0;
- Constraint* v = NULL;
- //CBuffer buffer(inactive);
- while ( (v = mostViolated(inactive)) &&
- (v->equality || ((v->slack() < ZERO_UPPERBOUND) && !v->active)) )
- {
- COLA_ASSERT(!v->active);
- Block *lb = v->left->block, *rb = v->right->block;
- if(lb != rb) {
- lb->merge(rb,v);
- } else {
- if(lb->isActiveDirectedPathBetween(v->right,v->left)) {
- // cycle found, relax the violated, cyclic constraint
- v->unsatisfiable=true;
- continue;
- //UnsatisfiableException e;
- //lb->getActiveDirectedPathBetween(e.path,v->right,v->left);
- //e.path.push_back(v);
- //throw e;
- }
- //if(splitCtr++>10000) {
- //throw "Cycle Error!";
- //}
- // constraint is within block, need to split first
- try {
- Constraint* splitConstraint
- =lb->splitBetween(v->left,v->right,lb,rb);
- if(splitConstraint!=NULL) {
- COLA_ASSERT(!splitConstraint->active);
- inactive.push_back(splitConstraint);
- } else {
- v->unsatisfiable=true;
- continue;
- }
- } catch(UnsatisfiableException e) {
- e.path.push_back(v);
- /*
- std::cerr << "Unsatisfiable:" << std::endl;
- for(std::vector<Constraint*>::iterator r=e.path.begin();
- r!=e.path.end();++r)
- {
- std::cerr << **r <<std::endl;
- }
- */
- v->unsatisfiable=true;
- continue;
- }
- if(v->slack()>=0) {
- COLA_ASSERT(!v->active);
- // v was satisfied by the above split!
- inactive.push_back(v);
- bs->insert(lb);
- bs->insert(rb);
- } else {
- bs->insert(lb->merge(rb,v));
- delete ((lb->deleted) ? lb : rb);
- }
- }
-#ifdef LIBVPSC_LOGGING
- f<<"...remaining blocks="<<bs->size()<<", cost="<<bs->cost()<<endl;
-#endif
- }
-#ifdef LIBVPSC_LOGGING
- f<<" finished merges."<<endl;
-#endif
- bs->cleanup();
- bool activeConstraints=false;
- for(unsigned i=0;i<m;i++) {
- v=cs[i];
- if(v->active) activeConstraints=true;
- if(v->slack() < ZERO_UPPERBOUND) {
- ostringstream s;
- s<<"Unsatisfied constraint: "<<*v;
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<s.str()<<endl;
-#endif
- throw s.str().c_str();
- }
- }
-#ifdef LIBVPSC_LOGGING
- f<<" finished cleanup."<<endl;
- printBlocks();
-#endif
- copyResult();
- return activeConstraints;
-}
-void IncSolver::moveBlocks() {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"moveBlocks()..."<<endl;
-#endif
- size_t length = bs->size();
- for (size_t i = 0; i < length; ++i)
- {
- Block *b = bs->at(i);
- b->updateWeightedPosition();
- //b->posn = b->wposn / b->weight;
- }
-#ifdef LIBVPSC_LOGGING
- f<<" moved blocks."<<endl;
-#endif
-}
-void IncSolver::splitBlocks() {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
-#endif
- moveBlocks();
- splitCnt=0;
- // Split each block if necessary on min LM
- size_t length = bs->size();
- for (size_t i = 0; i < length; ++i)
- {
- Block *b = bs->at(i);
- Constraint* v=b->findMinLM();
- if(v!=NULL && v->lm < LAGRANGIAN_TOLERANCE) {
- COLA_ASSERT(!v->equality);
-#ifdef LIBVPSC_LOGGING
- f<<" found split point: "<<*v<<" lm="<<v->lm<<endl;
-#endif
- splitCnt++;
- Block *b = v->left->block, *l=NULL, *r=NULL;
- COLA_ASSERT(v->left->block == v->right->block);
- //double pos = b->posn;
- b->split(l,r,v);
- //l->posn=r->posn=pos;
- //l->wposn = l->posn * l->weight;
- //r->wposn = r->posn * r->weight;
- l->updateWeightedPosition();
- r->updateWeightedPosition();
- bs->insert(l);
- bs->insert(r);
- b->deleted=true;
- COLA_ASSERT(!v->active);
- inactive.push_back(v);
-#ifdef LIBVPSC_LOGGING
- f<<" new blocks: "<<*l<<" and "<<*r<<endl;
-#endif
- }
- }
- //if(splitCnt>0) { std::cout<<" splits: "<<splitCnt<<endl; }
-#ifdef LIBVPSC_LOGGING
- f<<" finished splits."<<endl;
-#endif
- bs->cleanup();
-}
-
-/*
- * Scan constraint list for the most violated constraint, or the first equality
- * constraint
- */
-Constraint* IncSolver::mostViolated(Constraints &l)
-{
- double slackForMostViolated = DBL_MAX;
- Constraint* mostViolated = NULL;
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f << "Looking for most violated..." << endl;
-#endif
- size_t lSize = l.size();
- size_t deleteIndex = lSize;
- Constraint *constraint = NULL;
- double slack = 0;
- for (size_t index = 0; index < lSize; ++index)
- {
- constraint = l[index];
- slack = constraint->slack();
- if (constraint->equality || slack < slackForMostViolated)
- {
- slackForMostViolated = slack;
- mostViolated = constraint;
- deleteIndex = index;
- if (constraint->equality)
- {
- break;
- }
- }
- }
- // Because the constraint list is not order dependent we just
- // move the last element over the deletePoint and resize
- // downwards. There is always at least 1 element in the
- // vector because of search.
- if ( (deleteIndex < lSize) &&
- (((slackForMostViolated < ZERO_UPPERBOUND) && !mostViolated->active) ||
- mostViolated->equality) )
- {
- l[deleteIndex] = l[lSize-1];
- l.resize(lSize-1);
- }
-#ifdef LIBVPSC_LOGGING
- if (mostViolated)
- {
- f << " most violated is: " << *mostViolated << endl;
- }
- else
- {
- f << " non found." << endl;
- }
-#endif
- return mostViolated;
-}
-
-
-using std::set;
-using std::vector;
-using std::iterator;
-using std::list;
-using std::copy;
-#define __NOTNAN(p) (p)==(p)
-
-
-Blocks::Blocks(vector<Variable*> const &vs) : vs(vs),nvs(vs.size()) {
- blockTimeCtr=0;
- m_blocks.resize(nvs);
- for(size_t i=0;i<nvs;i++) {
- m_blocks[i] = new Block(this, vs[i]);
- }
-}
-Blocks::~Blocks(void)
-{
- blockTimeCtr=0;
- size_t length = m_blocks.size();
- for (size_t i = 0; i < length; ++i)
- {
- delete m_blocks[i];
- }
- m_blocks.clear();
-}
-
-/*
- * returns a list of variables with total ordering determined by the constraint
- * DAG
- */
-list<Variable*> *Blocks::totalOrder() {
- list<Variable*> *order = new list<Variable*>;
- for(size_t i=0;i<nvs;i++) {
- vs[i]->visited=false;
- }
- for(size_t i=0;i<nvs;i++) {
- if(vs[i]->in.size()==0) {
- dfsVisit(vs[i],order);
- }
- }
- return order;
-}
-// Recursive depth first search giving total order by pushing nodes in the DAG
-// onto the front of the list when we finish searching them
-void Blocks::dfsVisit(Variable *v, list<Variable*> *order) {
- v->visited=true;
- vector<Constraint*>::iterator it=v->out.begin();
- for(;it!=v->out.end();++it) {
- Constraint *c=*it;
- if(!c->right->visited) {
- dfsVisit(c->right, order);
- }
- }
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" order="<<*v<<endl;
-#endif
- order->push_front(v);
-}
-/*
- * Processes incoming constraints, most violated to least, merging with the
- * neighbouring (left) block until no more violated constraints are found
- */
-void Blocks::mergeLeft(Block *r) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"mergeLeft called on "<<*r<<endl;
-#endif
- r->timeStamp=++blockTimeCtr;
- r->setUpInConstraints();
- Constraint *c=r->findMinInConstraint();
- while (c != NULL && c->slack()<0) {
-#ifdef LIBVPSC_LOGGING
- f<<"mergeLeft on constraint: "<<*c<<endl;
-#endif
- r->deleteMinInConstraint();
- Block *l = c->left->block;
- if (l->in==NULL) l->setUpInConstraints();
- double dist = c->right->offset - c->left->offset - c->gap;
- if (r->vars->size() < l->vars->size()) {
- dist=-dist;
- std::swap(l, r);
- }
- blockTimeCtr++;
- r->merge(l, c, dist);
- r->mergeIn(l);
- r->timeStamp=blockTimeCtr;
- removeBlock(l);
- c=r->findMinInConstraint();
- }
-#ifdef LIBVPSC_LOGGING
- f<<"merged "<<*r<<endl;
-#endif
-}
-/*
- * Symmetrical to mergeLeft
- */
-void Blocks::mergeRight(Block *l) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"mergeRight called on "<<*l<<endl;
-#endif
- l->setUpOutConstraints();
- Constraint *c = l->findMinOutConstraint();
- while (c != NULL && c->slack()<0) {
-#ifdef LIBVPSC_LOGGING
- f<<"mergeRight on constraint: "<<*c<<endl;
-#endif
- l->deleteMinOutConstraint();
- Block *r = c->right->block;
- r->setUpOutConstraints();
- double dist = c->left->offset + c->gap - c->right->offset;
- if (l->vars->size() > r->vars->size()) {
- dist=-dist;
- std::swap(l, r);
- }
- l->merge(r, c, dist);
- l->mergeOut(r);
- removeBlock(r);
- c=l->findMinOutConstraint();
- }
-#ifdef LIBVPSC_LOGGING
- f<<"merged "<<*l<<endl;
-#endif
-}
-void Blocks::removeBlock(Block *doomed) {
- doomed->deleted=true;
- //erase(doomed);
-}
-
-// Clears up deleted blocks from the blocks list.
-void Blocks::cleanup(void)
-{
- // We handle removal of items in-place by doing a single linear pass over
- // the vector. We use two indexes, j to refer to elements we've checked
- // from the original list and i to refer to the current position we are
- // writing in the updated list.
- size_t i = 0;
-
- // For all items in the current blocks list...
- size_t length = m_blocks.size();
- for (size_t j = 0; j < length; )
- {
- if (m_blocks[j]->deleted)
- {
- // The element is deleted, so free it and increment j.
- delete m_blocks[j];
- ++j;
- }
- else
- {
- // The current element is still valid.
- if (j > i)
- {
- // If we've not looking at same element, then copy from j to i.
- m_blocks[i] = m_blocks[j];
- }
- // Increment both indexes.
- ++i;
- ++j;
- }
- }
- m_blocks.resize(i);
-}
-/*
- * Splits block b across constraint c into two new blocks, l and r (c's left
- * and right sides respectively)
- */
-void Blocks::split(Block *b, Block *&l, Block *&r, Constraint *c) {
- b->split(l,r,c);
- m_blocks.push_back(l);
- m_blocks.push_back(r);
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"Split left: "<<*l<<endl;
- f<<"Split right: "<<*r<<endl;
-#endif
- r->posn = b->posn;
- //COLA_ASSERT(r->weight!=0);
- //r->wposn = r->posn * r->weight;
- mergeLeft(l);
- // r may have been merged!
- r = c->right->block;
- r->updateWeightedPosition();
- //r->posn = r->wposn / r->weight;
- mergeRight(r);
- removeBlock(b);
-
- COLA_ASSERT(__NOTNAN(l->posn));
- COLA_ASSERT(__NOTNAN(r->posn));
-}
-/*
- * returns the cost total squared distance of variables from their desired
- * positions
- */
-double Blocks::cost() {
- double c = 0;
- size_t length = m_blocks.size();
- for (size_t i = 0; i < length; ++i)
- {
- c += m_blocks[i]->cost();
- }
- return c;
-}
-
-void PositionStats::addVariable(Variable* v) {
- double ai=scale/v->scale;
- double bi=v->offset/v->scale;
- double wi=v->weight;
- AB+=wi*ai*bi;
- AD+=wi*ai*v->desiredPosition;
- A2+=wi*ai*ai;
- /*
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f << "adding v[" << v->id << "], blockscale=" << scale << ", despos="
- << v->desiredPosition << ", ai=" << ai << ", bi=" << bi
- << ", AB=" << AB << ", AD=" << AD << ", A2=" << A2;
-#endif
-*/
-}
-void Block::addVariable(Variable* v) {
- v->block=this;
- vars->push_back(v);
- if(ps.A2==0) ps.scale=v->scale;
- //weight+= v->weight;
- //wposn += v->weight * (v->desiredPosition - v->offset);
- //posn=wposn/weight;
- ps.addVariable(v);
- posn=(ps.AD - ps.AB) / ps.A2;
- COLA_ASSERT(__NOTNAN(posn));
- /*
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f << ", posn=" << posn << endl;
-#endif
-*/
-}
-Block::Block(Blocks *blocks, Variable* const v)
- : vars(new vector<Variable*>)
- , posn(0)
- //, weight(0)
- //, wposn(0)
- , deleted(false)
- , timeStamp(0)
- , in(NULL)
- , out(NULL)
- , blocks(blocks)
-{
- if(v!=NULL) {
- v->offset=0;
- addVariable(v);
- }
-}
-
-void Block::updateWeightedPosition() {
- //wposn=0;
- ps.AB=ps.AD=ps.A2=0;
- for (Vit v=vars->begin();v!=vars->end();++v) {
- //wposn += ((*v)->desiredPosition - (*v)->offset) * (*v)->weight;
- ps.addVariable(*v);
- }
- posn=(ps.AD - ps.AB) / ps.A2;
- COLA_ASSERT(__NOTNAN(posn));
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f << ", posn=" << posn << endl;
-#endif
-}
-Block::~Block(void)
-{
- delete vars;
- delete in;
- delete out;
-}
-void Block::setUpInConstraints() {
- setUpConstraintHeap(in,true);
-}
-void Block::setUpOutConstraints() {
- setUpConstraintHeap(out,false);
-}
-void Block::setUpConstraintHeap(Heap* &h,bool in) {
- delete h;
- h = new Heap();
- for (Vit i=vars->begin();i!=vars->end();++i) {
- Variable *v=*i;
- vector<Constraint*> *cs=in?&(v->in):&(v->out);
- for (Cit j=cs->begin();j!=cs->end();++j) {
- Constraint *c=*j;
- c->timeStamp=blocks->blockTimeCtr;
- if ( ((c->left->block != this) && in) ||
- ((c->right->block != this) && !in) )
- {
- h->push(c);
- }
- }
- }
-}
-Block* Block::merge(Block* b, Constraint* c) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" merging on: "<<*c<<",c->left->offset="<<c->left->offset<<",c->right->offset="<<c->right->offset<<endl;
-#endif
- double dist = c->right->offset - c->left->offset - c->gap;
- Block *l=c->left->block;
- Block *r=c->right->block;
- if (l->vars->size() < r->vars->size()) {
- r->merge(l,c,dist);
- } else {
- l->merge(r,c,-dist);
- }
- Block* mergeBlock=b->deleted?this:b;
-#ifdef LIBVPSC_LOGGING
- f<<" merged block="<<*mergeBlock<<endl;
-#endif
- return mergeBlock;
-}
-/*
- * Merges b into this block across c. Can be either a
- * right merge or a left merge
- * @param b block to merge into this
- * @param c constraint being merged
- * @param distance separation required to satisfy c
- */
-void Block::merge(Block *b, Constraint *c, double dist) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" merging: "<<*b<<"dist="<<dist<<endl;
-#endif
- c->active=true;
- //wposn+=b->wposn-dist*b->weight;
- //weight+=b->weight;
- for(Vit i=b->vars->begin();i!=b->vars->end();++i) {
- Variable *v=*i;
- //v->block=this;
- //vars->push_back(v);
- v->offset+=dist;
- addVariable(v);
- }
-#ifdef LIBVPSC_LOGGING
- for(Vit i=vars->begin();i!=vars->end();++i) {
- Variable *v=*i;
- f<<" v["<<v->id<<"]: d="<<v->desiredPosition
- <<" a="<<v->scale<<" o="<<v->offset
- <<endl;
- }
- f<<" AD="<<ps.AD<<" AB="<<ps.AB<<" A2="<<ps.A2<<endl;
-#endif
- //posn=wposn/weight;
- //COLA_ASSERT(wposn==ps.AD - ps.AB);
- posn=(ps.AD - ps.AB) / ps.A2;
- COLA_ASSERT(__NOTNAN(posn));
- b->deleted=true;
-}
-
-void Block::mergeIn(Block *b) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" merging constraint heaps... "<<endl;
-#endif
- // We check the top of the heaps to remove possible internal constraints
- findMinInConstraint();
- b->findMinInConstraint();
- while (!b->in->empty())
- {
- in->push(b->in->top());
- b->in->pop();
- }
-#ifdef LIBVPSC_LOGGING
- f<<" merged heap: "<<*in<<endl;
-#endif
-}
-void Block::mergeOut(Block *b) {
- findMinOutConstraint();
- b->findMinOutConstraint();
- while (!b->out->empty())
- {
- out->push(b->out->top());
- b->out->pop();
- }
-}
-Constraint *Block::findMinInConstraint() {
- Constraint *v = NULL;
- vector<Constraint*> outOfDate;
- while (!in->empty()) {
- v = in->top();
- Block *lb=v->left->block;
- Block *rb=v->right->block;
- // rb may not be this if called between merge and mergeIn
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" checking constraint ... "<<*v;
- f<<" timestamps: left="<<lb->timeStamp<<" right="<<rb->timeStamp<<" constraint="<<v->timeStamp<<endl;
-#endif
- if(lb == rb) {
- // constraint has been merged into the same block
-#ifdef LIBVPSC_LOGGING
- if(v->slack()<0) {
- f<<" violated internal constraint found! "<<*v<<endl;
- f<<" lb="<<*lb<<endl;
- f<<" rb="<<*rb<<endl;
- }
-#endif
- in->pop();
-#ifdef LIBVPSC_LOGGING
- f<<" ... skipping internal constraint"<<endl;
-#endif
- } else if(v->timeStamp < lb->timeStamp) {
- // block at other end of constraint has been moved since this
- in->pop();
- outOfDate.push_back(v);
-#ifdef LIBVPSC_LOGGING
- f<<" reinserting out of date (reinsert later)"<<endl;
-#endif
- } else {
- break;
- }
- }
- for(Cit i=outOfDate.begin();i!=outOfDate.end();++i) {
- v=*i;
- v->timeStamp=blocks->blockTimeCtr;
- in->push(v);
- }
- if(in->empty()) {
- v=NULL;
- } else {
- v=in->top();
- }
- return v;
-}
-Constraint *Block::findMinOutConstraint() {
- if(out->empty()) return NULL;
- Constraint *v = out->top();
- while (v->left->block == v->right->block) {
- out->pop();
- if(out->empty()) return NULL;
- v = out->top();
- }
- return v;
-}
-void Block::deleteMinInConstraint() {
- in->pop();
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<"deleteMinInConstraint... "<<endl;
- f<<" result: "<<*in<<endl;
-#endif
-}
-void Block::deleteMinOutConstraint() {
- out->pop();
-}
-inline bool Block::canFollowLeft(Constraint const* c, Variable const* last) const {
- return c->left->block==this && c->active && last!=c->left;
-}
-inline bool Block::canFollowRight(Constraint const* c, Variable const* last) const {
- return c->right->block==this && c->active && last!=c->right;
-}
-
-// computes the derivative of v and the lagrange multipliers
-// of v's out constraints (as the recursive sum of those below.
-// Does not backtrack over u.
-// also records the constraint with minimum lagrange multiplier
-// in min_lm
-double Block::compute_dfdv(Variable* const v, Variable* const u,
- Constraint *&min_lm) {
- double dfdv=v->dfdv();
- for(Cit it=v->out.begin();it!=v->out.end();++it) {
- Constraint *c=*it;
- if(canFollowRight(c,u)) {
- c->lm=compute_dfdv(c->right,v,min_lm);
- dfdv+=c->lm*c->left->scale;
- if(!c->equality&&(min_lm==NULL||c->lm<min_lm->lm)) min_lm=c;
- }
- }
- for(Cit it=v->in.begin();it!=v->in.end();++it) {
- Constraint *c=*it;
- if(canFollowLeft(c,u)) {
- c->lm=-compute_dfdv(c->left,v,min_lm);
- dfdv-=c->lm*c->right->scale;
- if(!c->equality&&(min_lm==NULL||c->lm<min_lm->lm)) min_lm=c;
- }
- }
- return dfdv/v->scale;
-}
-double Block::compute_dfdv(Variable* const v, Variable* const u) {
- double dfdv = v->dfdv();
- for(Cit it = v->out.begin(); it != v->out.end(); ++it) {
- Constraint *c = *it;
- if(canFollowRight(c,u)) {
- c->lm = compute_dfdv(c->right,v);
- dfdv += c->lm * c->left->scale;
- }
- }
- for(Cit it=v->in.begin();it!=v->in.end();++it) {
- Constraint *c = *it;
- if(canFollowLeft(c,u)) {
- c->lm = - compute_dfdv(c->left,v);
- dfdv -= c->lm * c->right->scale;
- }
- }
- return dfdv/v->scale;
-}
-
-// The top level v and r are variables between which we want to find the
-// constraint with the smallest lm.
-// Similarly, m is initially NULL and is only assigned a value if the next
-// variable to be visited is r or if a possible min constraint is returned from
-// a nested call (rather than NULL).
-// Then, the search for the m with minimum lm occurs as we return from
-// the recursion (checking only constraints traversed left-to-right
-// in order to avoid creating any new violations).
-// We also do not consider equality constraints as potential split points
-bool Block::split_path(
- Variable* r,
- Variable* const v,
- Variable* const u,
- Constraint* &m,
- bool desperation=false
- )
-{
- for(Cit it(v->in.begin());it!=v->in.end();++it) {
- Constraint *c=*it;
- if(canFollowLeft(c,u)) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" left split path: "<<*c<<endl;
-#endif
- if(c->left==r) {
- if(desperation&&!c->equality) m=c;
- return true;
- } else {
- if(split_path(r,c->left,v,m)) {
- if(desperation && !c->equality && (!m||c->lm<m->lm)) {
- m=c;
- }
- return true;
- }
- }
- }
- }
- for(Cit it(v->out.begin());it!=v->out.end();++it) {
- Constraint *c=*it;
- if(canFollowRight(c,u)) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" right split path: "<<*c<<endl;
-#endif
- if(c->right==r) {
- if(!c->equality) m=c;
- return true;
- } else {
- if(split_path(r,c->right,v,m)) {
- if(!c->equality && (!m||c->lm<m->lm))
- m=c;
- return true;
- }
- }
- }
- }
- return false;
-}
-/*
-Block::Pair Block::compute_dfdv_between(
- Variable* r, Variable* const v, Variable* const u,
- const Direction dir = NONE, bool changedDirection = false) {
- double dfdv=v->weight*(v->position() - v->desiredPosition);
- Constraint *m=NULL;
- for(Cit it(v->in.begin());it!=v->in.end();++it) {
- Constraint *c=*it;
- if(canFollowLeft(c,u)) {
- if(dir==RIGHT) {
- changedDirection = true;
- }
- if(c->left==r) {
- r=NULL;
- if(!c->equality) m=c;
- }
- Pair p=compute_dfdv_between(r,c->left,v,
- LEFT,changedDirection);
- dfdv -= c->lm = -p.first;
- if(r && p.second)
- m = p.second;
- }
- }
- for(Cit it(v->out.begin());it!=v->out.end();++it) {
- Constraint *c=*it;
- if(canFollowRight(c,u)) {
- if(dir==LEFT) {
- changedDirection = true;
- }
- if(c->right==r) {
- r=NULL;
- if(!c->equality) m=c;
- }
- Pair p=compute_dfdv_between(r,c->right,v,
- RIGHT,changedDirection);
- dfdv += c->lm = p.first;
- if(r && p.second)
- m = changedDirection && !c->equality && c->lm < p.second->lm
- ? c
- : p.second;
- }
- }
- return Pair(dfdv,m);
-}
-*/
-
-// resets LMs for all active constraints to 0 by
-// traversing active constraint tree starting from v,
-// not back tracking over u
-void Block::reset_active_lm(Variable* const v, Variable* const u) {
- for(Cit it=v->out.begin();it!=v->out.end();++it) {
- Constraint *c=*it;
- if(canFollowRight(c,u)) {
- c->lm=0;
- reset_active_lm(c->right,v);
- }
- }
- for(Cit it=v->in.begin();it!=v->in.end();++it) {
- Constraint *c=*it;
- if(canFollowLeft(c,u)) {
- c->lm=0;
- reset_active_lm(c->left,v);
- }
- }
-}
-void Block::list_active(Variable* const v, Variable* const u) {
- for(Cit it=v->out.begin();it!=v->out.end();++it) {
- Constraint *c=*it;
- if(canFollowRight(c,u)) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" "<<*c<<endl;
-#endif
- list_active(c->right,v);
- }
- }
- for(Cit it=v->in.begin();it!=v->in.end();++it) {
- Constraint *c=*it;
- if(canFollowLeft(c,u)) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" "<<*c<<endl;
-#endif
- list_active(c->left,v);
- }
- }
-}
-/*
- * finds the constraint with the minimum lagrange multiplier, that is, the constraint
- * that most wants to split
- */
-Constraint *Block::findMinLM() {
- Constraint *min_lm=NULL;
- reset_active_lm(vars->front(),NULL);
- compute_dfdv(vars->front(),NULL,min_lm);
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" langrangians: "<<endl;
- list_active(vars->front(),NULL);
-#endif
- return min_lm;
-}
-Constraint *Block::findMinLMBetween(Variable* const lv, Variable* const rv) {
- reset_active_lm(vars->front(),NULL);
- compute_dfdv(vars->front(),NULL);
- Constraint *min_lm=NULL;
- split_path(rv,lv,NULL,min_lm);
-#if 0
- if(min_lm==NULL) {
- split_path(rv,lv,NULL,min_lm,true);
- }
-#else
- if(min_lm==NULL) {
- //err_printf("Couldn't find split point!\n");
- UnsatisfiableException e;
- getActivePathBetween(e.path,lv,rv,NULL);
- throw e;
- }
- COLA_ASSERT(min_lm!=NULL);
-#endif
- return min_lm;
-}
-
-// populates block b by traversing the active constraint tree adding variables as they're
-// visited. Starts from variable v and does not backtrack over variable u.
-void Block::populateSplitBlock(Block *b, Variable* v, Variable const* u) {
- b->addVariable(v);
- for (Cit c=v->in.begin();c!=v->in.end();++c) {
- if (canFollowLeft(*c,u))
- populateSplitBlock(b, (*c)->left, v);
- }
- for (Cit c=v->out.begin();c!=v->out.end();++c) {
- if (canFollowRight(*c,u))
- populateSplitBlock(b, (*c)->right, v);
- }
-}
-/*
- * Returns the active path between variables u and v... not back tracking over w
- */
-bool Block::getActivePathBetween(Constraints& path, Variable const* u,
- Variable const* v, Variable const *w) const {
- if(u==v) return true;
- for (Cit_const c=u->in.begin();c!=u->in.end();++c) {
- if (canFollowLeft(*c,w)) {
- if(getActivePathBetween(path, (*c)->left, v, u)) {
- path.push_back(*c);
- return true;
- }
- }
- }
- for (Cit_const c=u->out.begin();c!=u->out.end();++c) {
- if (canFollowRight(*c,w)) {
- if(getActivePathBetween(path, (*c)->right, v, u)) {
- path.push_back(*c);
- return true;
- }
- }
- }
- return false;
-}
-// Search active constraint tree from u to see if there is a directed path to v.
-// Returns true if path is found with all constraints in path having their visited flag
-// set true.
-bool Block::isActiveDirectedPathBetween(Variable const* u, Variable const* v) const {
- if(u==v) return true;
- for (Cit_const c=u->out.begin();c!=u->out.end();++c) {
- if(canFollowRight(*c,NULL)) {
- if(isActiveDirectedPathBetween((*c)->right,v)) {
- return true;
- }
- }
- }
- return false;
-}
-bool Block::getActiveDirectedPathBetween(
- Constraints& path, Variable const* u, Variable const* v) const {
- if(u==v) return true;
- for (Cit_const c=u->out.begin();c!=u->out.end();++c) {
- if(canFollowRight(*c,NULL)) {
- if(getActiveDirectedPathBetween(path,(*c)->right,v)) {
- path.push_back(*c);
- return true;
- }
- }
- }
- return false;
-}
-/*
- * Block needs to be split because of a violated constraint between vl and vr.
- * We need to search the active constraint tree between l and r and find the constraint
- * with min lagrangrian multiplier and split at that point.
- * Returns the split constraint
- */
-Constraint* Block::splitBetween(Variable* const vl, Variable* const vr,
- Block* &lb, Block* &rb) {
-#ifdef LIBVPSC_LOGGING
- ofstream f(LOGFILE,ios::app);
- f<<" need to split between: "<<*vl<<" and "<<*vr<<endl;
-#endif
- Constraint *c=findMinLMBetween(vl, vr);
-#ifdef LIBVPSC_LOGGING
- f<<" going to split on: "<<*c<<endl;
-#endif
- if(c!=NULL) {
- split(lb,rb,c);
- deleted = true;
- }
- return c;
-}
-
-/*
- * Creates two new blocks, l and r, and splits this block across constraint c,
- * placing the left subtree of constraints (and associated variables) into l
- * and the right into r.
- */
-void Block::split(Block* &l, Block* &r, Constraint* c) {
- c->active=false;
- l=new Block(blocks);
- populateSplitBlock(l,c->left,c->right);
- //COLA_ASSERT(l->weight>0);
- r=new Block(blocks);
- populateSplitBlock(r,c->right,c->left);
- //COLA_ASSERT(r->weight>0);
-}
-
-/*
- * Computes the cost (squared euclidean distance from desired positions) of the
- * current positions for variables in this block
- */
-double Block::cost() {
- double c = 0;
- for (Vit v=vars->begin();v!=vars->end();++v) {
- double diff = (*v)->position() - (*v)->desiredPosition;
- c += (*v)->weight * diff * diff;
- }
- return c;
-}
-ostream& operator <<(ostream &os, const Block& b)
-{
- os<<"Block(posn="<<b.posn<<"):";
- for(Block::Vit v=b.vars->begin();v!=b.vars->end();++v) {
- os<<" "<<**v;
- }
- if(b.deleted) {
- os<<" Deleted!";
- }
- return os;
-}
-
-Constraint::Constraint(Variable *left, Variable *right, double gap, bool equality)
-: left(left),
- right(right),
- gap(gap),
- timeStamp(0),
- active(false),
- equality(equality),
- unsatisfiable(false),
- needsScaling(true),
- creator(NULL)
-{
- // In hindsight I think it's probably better to build the constraint DAG
- // (by creating variable in/out lists) when needed, rather than in advance
- //left->out.push_back(this);
- //right->in.push_back(this);
-}
-Constraint::~Constraint() {
- // see constructor: the following is just way too slow.
- // Better to create a
- // new DAG on demand than maintain the lists dynamically.
- //Constraints::iterator i;
- //for(i=left->out.begin(); i!=left->out.end(); i++) {
- //if(*i==this) break;
- //}
- //left->out.erase(i);
- //for(i=right->in.begin(); i!=right->in.end(); i++) {
- //if(*i==this) break;
- //}
- //right->in.erase(i);
-}
-std::string Constraint::toString(void) const
-{
- std::stringstream stream;
- stream << "Constraint: var(" << left->id << ") ";
- if (gap < 0)
- {
- stream << "- " << -gap << " ";
- }
- else
- {
- stream << "+ " << gap << " ";
- }
- stream << ((equality) ? "==" : "<=");
- stream << " var(" << right->id << ") ";
- return stream.str();
-}
-
-std::ostream& operator <<(std::ostream &os, const Constraint &c)
-{
- const char *type = c.equality ? "=" : "<=";
- std::ostringstream lscale, rscale;
- if (c.left->scale != 1)
- {
- lscale << c.left->scale << "*";
- }
- if (c.right->scale != 1)
- {
- rscale << c.right->scale << "*";
- }
- os << lscale.str() << *c.left << "+" << c.gap << type <<
- rscale.str() << *c.right;
- if (c.left->block && c.right->block)
- {
- os << "(" << c.slack() << ")" << (c.active ? "-active" : "") <<
- "(lm=" << c.lm << ")";
- }
- else
- {
- os << "(vars have no position)";
- }
- return os;
-}
-
-bool CompareConstraints::operator() (
- Constraint *const &l, Constraint *const &r
-) const {
- double const sl =
- l->left->block->timeStamp > l->timeStamp
- ||l->left->block==l->right->block
- ?-DBL_MAX:l->slack();
- double const sr =
- r->left->block->timeStamp > r->timeStamp
- ||r->left->block==r->right->block
- ?-DBL_MAX:r->slack();
- if(sl==sr) {
- // arbitrary choice based on id
- if(l->left->id==r->left->id) {
- if(l->right->id<r->right->id) return true;
- return false;
- }
- if(l->left->id<r->left->id) return true;
- return false;
- }
- return sl > sr;
-}
-
-std::ostream& operator <<(std::ostream &os, const Variable &v) {
- if(v.block)
- os << "(" << v.id << "=" << v.position() << ")";
- else
- os << "(" << v.id << "=" << v.desiredPosition << ")";
- return os;
-}
-
-typedef std::list<std::map<Variable *, double> > VarOffsetMapList;
-
-class EqualityConstraintSet
-{
- public:
- EqualityConstraintSet(Variables vs)
- {
- for (size_t i = 0; i < vs.size(); ++i)
- {
- std::map<Variable *, double> varSet;
- varSet[vs[i]] = 0;
- variableGroups.push_back(varSet);
- }
- }
- bool isRedundant(Variable *lhs, Variable *rhs, double sep)
- {
- VarOffsetMapList::iterator lhsSet = setForVar(lhs);
- VarOffsetMapList::iterator rhsSet = setForVar(rhs);
- if (lhsSet == rhsSet)
- {
- // Check if this is a redundant constraint.
- if (fabs(((*lhsSet)[lhs] + sep) - (*rhsSet)[rhs]) < 0.0001)
- {
- // If so, return true.
- return true;
- }
- }
- return false;
- }
- void mergeSets(Variable *lhs, Variable *rhs, double sep)
- {
- VarOffsetMapList::iterator lhsSet = setForVar(lhs);
- VarOffsetMapList::iterator rhsSet = setForVar(rhs);
- if (lhsSet == rhsSet)
- {
- return;
- }
-
- double rhsOldOffset = (*rhsSet)[rhs];
- double rhsNewOffset = (*lhsSet)[lhs] + sep;
- double offset = rhsNewOffset - rhsOldOffset;
-
- // Update offsets
- for (std::map<Variable *, double>::iterator it = rhsSet->begin();
- it != rhsSet->end(); ++it)
- {
- it->second += offset;
- }
-
- // Merge rhsSet into lhsSet
- lhsSet->insert(rhsSet->begin(), rhsSet->end());
- variableGroups.erase(rhsSet);
- }
-
- private:
- VarOffsetMapList::iterator setForVar(Variable *var)
- {
- for (VarOffsetMapList::iterator it = variableGroups.begin();
- it != variableGroups.end(); ++it)
- {
- if (it->find(var) != it->end())
- {
- return it;
- }
- }
- return variableGroups.end();
- }
-
- VarOffsetMapList variableGroups;
-};
-
-Constraints constraintsRemovingRedundantEqualities(Variables const &vars,
- Constraints const &constraints)
-{
- EqualityConstraintSet equalitySets(vars);
- Constraints cs = Constraints(constraints.size());
- int csSize = 0;
-
- for (unsigned i = 0; i < constraints.size(); ++i)
- {
- Constraint *c = constraints[i];
- if (c->equality)
- {
- if (!equalitySets.isRedundant(c->left, c->right, c->gap))
- {
- // Only add non-redundant equalities
- equalitySets.mergeSets(c->left, c->right, c->gap);
- cs[csSize++] = c;
- }
- }
- else
- {
- // Add all non-equalities
- cs[csSize++] = c;
- }
- }
- cs.resize(csSize);
- return cs;
-}
-
-
-}
-
-#endif