38ConstrainedMajorizationLayout
39::ConstrainedMajorizationLayout(
40 vector<Rectangle*>&
rs,
41 const vector<Edge>&
es,
43 const double idealLength,
47 bool useNeighbourStress)
49 lap2(valarray<double>(n*n)),
50 Dij(valarray<double>(n*n)),
53 using_default_done(false),
54 preIteration(preIteration),
55 X(valarray<double>(n)), Y(valarray<double>(n)),
57 startX(valarray<double>(n)), startY(valarray<double>(n)),
58 constrainedLayout(false),
59 nonOverlappingClusters(false),
60 clusterHierarchy(clusterHierarchy),
61 gpX(nullptr), gpY(nullptr),
63 unsatisfiableX(nullptr), unsatisfiableY(nullptr),
65 straightenEdges(nullptr),
66 bendWeight(0.1), potBendWeight(0.1),
69 externalSolver(false),
85 double**
D=
new double*[
n];
86 for(
unsigned i=0;i<
n;i++) {
90 std::valarray<double> edgeLengths(eLengths.data(), eLengths.size());
92 for (
size_t i = 0; i < edgeLengths.size(); ++i)
94 if (edgeLengths[i] <= 0)
96 fprintf(stderr,
"Warning: ignoring non-positive length at index %d "
97 "in ideal edge length array.\n", (
int) i);
102 if (useNeighbourStress) {
103 for(
unsigned i=0;i<
n;i++) {
104 for(
unsigned j=0;j<
n;j++) {
105 D[i][j]=std::numeric_limits<double>::max();
108 bool haveLengths = edgeLengths.size() ==
es.size();
109 for (
unsigned i = 0; i <
es.size(); i++) {
110 unsigned source =
es[i].first;
111 unsigned target =
es[i].second;
112 D[source][target] =
D[target][source] = (haveLengths ? edgeLengths[i] : 1.0);
124 for(set<unsigned>::iterator j=
c->nodes.begin();j!=
c->nodes.end();j++) {
125 for(set<unsigned>::iterator k=
c->nodes.begin();k!=
c->nodes.end();k++) {
135 for(
unsigned i = 0; i<
n; i++) {
136 X[i]=
rs[i]->getCentreX();
137 Y[i]=
rs[i]->getCentreY();
139 for(
unsigned j=0;j<
n;j++) {
144 if(d!=0 && !std::isinf(d)) {
158 const double stickyWeight,
159 valarray<double>
const & startX,
160 valarray<double>
const & startY) {
169 for(
unsigned i = 0; i<
n; i++) {
176 valarray<double>& coords,
177 valarray<double>
const & startCoords)
179 double L_ij,dist_ij,
degree;
182 valarray<double> b(
n);
183 for (
unsigned i = 0; i <
n; i++) {
185 for (
unsigned j = 0; j <
n; j++) {
186 if (j == i)
continue;
189 if (dist_ij > 1e-30 &&
Dij[i*
n+j] > 1e-30 &&
Dij[i*
n+j] < 1e10) {
191 L_ij = 1.0 / (dist_ij *
Dij[i*
n+j]);
193 b[i] += L_ij * coords[j];
202 b[i] +=
degree * coords[i];
203 COLA_ASSERT(!std::isnan(b[i]));
216 valarray<double>& coords,
217 valarray<double>
const & startCoords)
219 COLA_UNUSED(startCoords);
222 valarray<double> b(
n);
223 valarray<double> A(
n*
n);
224 for (
unsigned i = 0; i <
n; i++) {
227 for (
unsigned j = 0; j <
n; j++) {
228 if (j == i)
continue;
229 double d =
Dij[i*
n+j];
231 double dx = coords[i]-coords[j];
232 double dy2 = l*l - dx*dx;
235 && d > 1e-30 && d < 1e10) {
236 if(d>80 && l > d)
continue;
237 b[i]+=dx*(l-d)/(l*d*d);
238 Aii-=A[i*
n+j]=(d*dy2/(l*l*l)-1)/(d*d);
266 valarray<double> x=b;
268 double numerator = 0;
269 for(
unsigned i=0;i<
n;i++) {
270 numerator+=x[i]*x[i];
272 double denominator = 0;
273 for(
unsigned i=0;i<
n;i++) {
275 for(
unsigned j=0;j<
n;j++) {
280 double stepsize=numerator/(2*denominator);
282 valarray<double> oldcoords=coords;
283 while(stepsize>0.00001) {
284 coords=oldcoords-stepsize*x;
286 printf(
" stress=%f, stepsize=%f\n",stress,stepsize);
287 if(oldstress>=stress) {
296inline double ConstrainedMajorizationLayout
297::compute_stress(valarray<double>
const &Dij) {
298 double sum = 0, d, diff;
299 for (
unsigned i = 1; i < n; i++) {
300 for (
unsigned j = 0; j < i; j++) {
302 if(!std::isinf(d)&&d!=numeric_limits<double>::max()) {
303 diff = d - euclidean_distance(i,j);
304 if(d>80&&diff<0)
continue;
305 sum += diff*diff / (d*d);
309 double l = startX[i]-X[i];
310 sum += stickyWeight*l*l;
312 sum += stickyWeight*l*l;
342 vector<straightener::Edge*> cedges;
350 unsigned id=l->getID();
420 vector<straightener::Edge*> cedges;
428 unsigned id=l->getID();
474 valarray<double>* coords;
475 valarray<double>* startCoords;
485 vector<straightener::Node*> snodes;
489 for (
unsigned i=0;i<
n;i++) {
499 vector<straightener::Cluster*> sclusters;
505 vector<SeparationConstraint*> cs;
508 for(
unsigned i=0;i<sedges.size();i++) {
510 vector<unsigned>& path=sedges[i]->path;
511 vector<unsigned>& activePath=sedges[i]->activePath;
515 double total_length=0;
516 for(
unsigned j=1;j<path.size();j++) {
517 unsigned u=path[j-1], v=path[j];
518 total_length+=snodes[u]->euclidean_distance(snodes[v]);
521 for(
unsigned j=1;j<activePath.size();j++) {
522 unsigned uj=activePath[j-1], vj=activePath[j];
523 unsigned u=path[uj], v=path[vj];
524 for(
unsigned k=uj+1;k<vj;k++) {
532 for(
unsigned j=1;j<activePath.size()-1;j++) {
533 unsigned u=path[activePath[j-1]],
534 b=path[activePath[j]],
535 v=path[activePath[j+1]];
537 *snodes[u],*snodes[v],*snodes[b],-
bendWeight));
543 for(straightener::LinearConstraints::iterator i=linearConstraints.begin();
544 i!= linearConstraints.end();i++) {
546 Q(
c->u,
c->u)+=
c->
w*
c->duu;
547 Q(
c->u,
c->v)+=
c->w*
c->duv;
548 Q(
c->u,
c->b)+=
c->w*
c->dub;
549 Q(
c->v,
c->u)+=
c->w*
c->duv;
550 Q(
c->v,
c->v)+=
c->w*
c->dvv;
551 Q(
c->v,
c->b)+=
c->w*
c->dvb;
552 Q(
c->b,
c->b)+=
c->w*
c->dbb;
553 Q(
c->b,
c->u)+=
c->w*
c->dub;
554 Q(
c->b,
c->v)+=
c->w*
c->dvb;
556 double boundaryWeight = 0.0001;
557 for(
unsigned i=0;i<sclusters.size();i++) {
561 for(
unsigned j=0;j<
c->boundary.size();j++) {
575 for(
unsigned i=0;i<snodes.size();i++) {
576 snodes[i]->pos[dim] = r[i];
578 for(
unsigned i=0;i<sedges.size();i++) {
579 sedges[i]->createRouteFromPath(snodes);
580 sedges[i]->dummyNodes.clear();
581 sedges[i]->path.clear();
583 for(
unsigned i=0;i<sclusters.size();i++) {
588 for(
unsigned i=0;i<cs.size();i++) {
591 for(
unsigned i=0;i<linearConstraints.size();i++) {
592 delete linearConstraints[i];
594 for(
unsigned i=0;i<snodes.size();i++) {
600 COLA_ASSERT(!
rs.empty());
602 double left =
rs[0]->getMinX(), right =
rs[0]->getMaxX(),
603 top =
rs[0]->getMinY(), bottom =
rs[0]->getMaxY();
605 for(
unsigned i = 1; i <
rs.size(); i++) {
606 left = min(left,
rs[i]->getMinX());
607 right = max(right,
rs[i]->getMaxX());
608 top = min(top,
rs[i]->getMinY());
609 bottom = max(bottom,
rs[i]->getMaxY());
611 return Rectangle(left, right, top, bottom);
616 if(clusterHierarchy.
nodes.size()>0 || clusterHierarchy.
clusters.size()>0) {
619 for(
unsigned i=0;i<
rs.size();i++) {
625 clusterHierarchy.generateNonOverlapConstraints(dim,
cola::Both,
rs, vars, cs);
638 for(Locks::iterator l=locks.begin();
639 l!=locks.end();l++) {
640 unsigned id=l->getID();
657 }
catch(
const char* e) {
658 cerr <<
"ERROR from solver in GraphData::removeOverlap : " << e << endl;
668 for(
unsigned i=0;i<
rs.size();i++) {
669 rs[i]->moveCentreD(dim,vars[i]->finalPosition);
671 for(Locks::iterator l=locks.begin();
672 l!=locks.end();l++) {
687 std::vector<Edge>
const &
es,
689 const double idealLength,
690 bool useNeighbourStress
693 for(
size_t i = 0; i <
es.size(); ++i) {
694 eLengths.push_back(1);
697 eLengths,
nullptr,
nullptr, useNeighbourStress);
A cluster defines a hierarchical partitioning over the nodes which should be kept disjoint by the lay...
void updateBounds(const vpsc::Dim dim)
double internalEdgeWeightFactor
std::vector< Cluster * > clusters
virtual void computeBoundingRect(const vpsc::Rectangles &rs)
std::set< unsigned > nodes
void createVars(const vpsc::Dim dim, const vpsc::Rectangles &rs, vpsc::Variables &vars)
Implements the Constrained Majorization graph layout algorithm (deprecated).
std::valarray< double > Q
std::valarray< double > X
void runOnce(bool x=true, bool y=true)
Same as run(), but only applies one iteration.
std::valarray< double > lap2
std::valarray< double > Dij
double euclidean_distance(unsigned i, unsigned j)
cola::CompoundConstraints * ccs
PreIteration * preIteration
void newton(std::valarray< double > const &Dij, GradientProjection *gp, std::valarray< double > &coords, std::valarray< double > const &startCoords)
std::valarray< double > startX
RootCluster * clusterHierarchy
vpsc::Rectangles boundingBoxes
bool nonOverlappingClusters
void straighten(std::vector< straightener::Edge * > &, vpsc::Dim)
UnsatisfiableConstraintInfos * unsatisfiableX
NonOverlapConstraintsMode avoidOverlaps
void setStickyNodes(const double stickyWeight, std::valarray< double > const &startX, std::valarray< double > const &startY)
Sticky nodes causes nodes to spring back to (startX,startY) when unconstrained.
std::valarray< double > Y
void moveBoundingBoxes()
Update position of bounding boxes.
double compute_stress(std::valarray< double > const &Dij)
void setScaling(bool scaling)
Scaling speeds up the solver by conditioning the quadratic terms matrix.
std::vector< straightener::Edge * > * straightenEdges
UnsatisfiableConstraintInfos * unsatisfiableY
std::valarray< double > startY
void run(bool x=true, bool y=true)
Implements the main layout loop, taking descent steps until stress is no-longer significantly reduced...
void majorize(std::valarray< double > const &Dij, GradientProjection *gp, std::valarray< double > &coords, std::valarray< double > const &startCoords)
void fixPos(const unsigned i, const double pos)
void straighten(cola::SparseMatrix const *Q, std::vector< SeparationConstraint * > const &ccs, std::vector< straightener::Node * > const &snodes)
unsigned getNumStaticVars() const
void unfixPos(unsigned i)
unsigned solve(std::valarray< double > const &b, std::valarray< double > &x)
std::valarray< double > const & getFullResult() const
A default functor that is called before each iteration in the main loop of the ConstrainedFDLayout::r...
Holds the cluster hierarchy specification for a diagram.
A default functor that is called after each iteration of the layout algorithm.
Incremental solver for Variable Placement with Separation Constraints problem instance.
bool solve()
Results in an optimum solution subject to the constraints.
A rectangle represents a fixed-size shape in the diagram that may be moved to prevent overlaps and sa...
static void setXBorder(double x)
A variable is comprised of an ideal position, final position and a weight.
void conjugate_gradient(valarray< double > const &A, valarray< double > &x, valarray< double > const &b, unsigned const n, double const tol, unsigned const max_iterations)
vector< vpsc::Rectangle * > rs
libcola: Force-directed network layout subject to separation constraints library.
std::vector< cola::Lock > Locks
A vector of Lock objects.
void removeClusterOverlapFast(RootCluster &clusterHierarchy, vpsc::Rectangles &rs, Locks &locks)
void removeClusterOverlap(RootCluster &clusterHierarchy, vpsc::Rectangles &rs, Locks &locks, vpsc::Dim dim)
ConstrainedMajorizationLayout * simpleCMLFactory(vpsc::Rectangles &rs, std::vector< Edge > const &es, RootCluster *clusterHierarchy, const double idealLength, bool useNeighbourStress)
std::vector< double > EdgeLengths
EdgeLengths is a vector of ideal lengths for edges corresponding to edges in the edge list.
void johnsons(unsigned const n, T **D, std::vector< Edge > const &es, std::valarray< T > const &eweights=std::valarray< T >())
find all pairs shortest paths, faster, uses dijkstra
void generateClusterBoundaries(const vpsc::Dim dim, vector< straightener::Node * > &nodes, vector< straightener::Edge * > &edges, vector< vpsc::Rectangle * > const &rs, cola::Cluster const &clusterHierarchy, vector< straightener::Cluster * > &sclusters)
set up straightener clusters.
std::vector< LinearConstraint * > LinearConstraints
void generateConstraints(const vpsc::Dim dim, vector< Node * > &nodes, vector< Edge * > const &edges, vector< cola::SeparationConstraint * > &cs, bool xSkipping=true)
Generates constraints to prevent node/edge and edge/edge intersections.
libvpsc: Variable Placement with Separation Constraints quadratic program solver library.
Dim
Indicates the x- or y-dimension.
@ HORIZONTAL
The x-dimension (0).
@ VERTICAL
The y-dimension (1).
std::vector< vpsc::Variable * > Variables
A vector of pointers to Variable objects.
std::vector< vpsc::Constraint * > Constraints
A vector of pointers to Constraint objects.
std::vector< Rectangle * > Rectangles
A vector of pointers to Rectangle objects.
double sum(const double alpha[16], const double &x, const double &y)