From 12b21e1d27f43deaa748419919b40b80cedd0ddd Mon Sep 17 00:00:00 2001 From: Tim Dwyer Date: Wed, 12 Jul 2006 00:55:58 +0000 Subject: Previously graph layout was done using the Kamada-Kawai layout algorithm implemented in Boost. I am replacing this with a custom implementation of a constrained stress-majorization algorithm. The stress-majorization algorithm is more robust and has better convergence characteristics than Kamada-Kawai, and also simple constraints can be placed on node position (for example, to enforce downward-pointing edges, non-overlap constraints, or cluster constraints). Another big advantage is that we no longer need Boost. I've tested the basic functionality, but I have yet to properly handle disconnected graphs or to properly scale the resulting layout. This commit also includes significant refactoring... the quadratic program solver - libvpsc (Variable Placement with Separation Constraints) has been moved to src/libvpsc and the actual graph layout algorithm is in libcola. (bzr r1394) --- src/libcola/conjugate_gradient.cpp | 113 +++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/libcola/conjugate_gradient.cpp (limited to 'src/libcola/conjugate_gradient.cpp') diff --git a/src/libcola/conjugate_gradient.cpp b/src/libcola/conjugate_gradient.cpp new file mode 100644 index 000000000..5dfb4363d --- /dev/null +++ b/src/libcola/conjugate_gradient.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include "conjugate_gradient.h" + +/* +* Authors: +* Nathan Hurst +* Tim Dwyer +* +* Copyright (C) 2006 Authors +* +* Released under GNU LGPL. +*/ + +/* lifted wholely from wikipedia. Well, apart from the bug in the wikipedia version. */ + +using std::valarray; + +static void +matrix_times_vector(valarray const &matrix, /* m * n */ + valarray const &vec, /* n */ + valarray &result) /* m */ +{ + unsigned n = vec.size(); + unsigned m = result.size(); + assert(m*n == matrix.size()); + const double* mp = &matrix[0]; + for (unsigned i = 0; i < m; i++) { + double res = 0; + for (unsigned j = 0; j < n; j++) + res += *mp++ * vec[j]; + result[i] = res; + } +} + +static double Linfty(valarray const &vec) { + return std::max(vec.max(), -vec.min()); +} + +double +inner(valarray const &x, + valarray const &y) { + double total = 0; + for(unsigned i = 0; i < x.size(); i++) + total += x[i]*y[i]; + return total;// (x*y).sum(); <- this is more concise, but ineff +} + +void +conjugate_gradient(double **A, + double *x, + double *b, + unsigned n, + double tol, + unsigned max_iterations) { + valarray vA(n*n); + valarray vx(n); + valarray vb(n); + for(unsigned i=0;i const &A, + valarray &x, + valarray const &b, + unsigned n, double tol, + unsigned max_iterations) { + valarray Ap(n), p(n), r(n); + matrix_times_vector(A,x,Ap); + r=b-Ap; + double r_r = inner(r,r); + unsigned k = 0; + tol *= tol; + while(k < max_iterations && r_r > tol) { + k++; + double r_r_new = r_r; + if(k == 1) + p = r; + else { + r_r_new = inner(r,r); + p = r + (r_r_new/r_r)*p; + } + matrix_times_vector(A, p, Ap); + double alpha_k = r_r_new / inner(p, Ap); + x += alpha_k*p; + r -= alpha_k*Ap; + r_r = r_r_new; + } + printf("njh: %d iters, Linfty = %g L2 = %g\n", k, + std::max(-r.min(), r.max()), sqrt(r_r)); + // x is solution +} +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 -- cgit v1.2.3