33static const double C = 0.2;
40static const double bh = 0.6;
44static const double tol = 0.001;
46static const double cool = 0.90;
77 "NONE",
"STRESS_MAJORIZATION_GRAPH_DIST",
"STRESS_MAJORIZATION_AVG_DIST",
"STRESS_MAJORIZATION_POWER_DIST",
"SPRING",
"TRIANGLE",
"RNG"
81 "NONE",
"NORMAL",
"FAST",
"HYBRID"
85 fprintf (stderr,
"spring_electrical_control:\n");
86 fprintf (stderr,
" repulsive exponent: %.03f\n", ctrl->
p);
87 fprintf(stderr,
" random start %d seed %d\n", (
int)ctrl->
random_start,
89 fprintf (stderr,
" K : %.03f C : %.03f\n", ctrl->
K,
C);
90 fprintf (stderr,
" max levels %d\n", ctrl->
multilevels);
92 fprintf (stderr,
" Barnes-Hutt constant %.03f tolerance %.03f maxiter %d\n",
bh,
tol, ctrl->
maxiter);
93 fprintf(stderr,
" cooling %.03f step size %.03f adaptive %d\n",
cool,
95 fprintf (stderr,
" beautify_leaves %d node weights %d rotation %.03f\n",
97 fprintf (stderr,
" smoothing %s overlap %d initial_scaling %.03f do_shrinking %d\n",
141 if (opt->
work[i] < opt->
work[i+1] && opt->
i > 0){
142 opt->
i =
MAX(0, opt->
i-1);
157 int *ia =
A->ia, *ja =
A->ja, i, j, k;
160 if (ia[
A->m] == 0)
return 1;
161 for (i = 0; i <
A->m; i++){
162 for (j = ia[i]; j < ia[i+1]; j++){
164 for (k = 0; k <
dim; k++){
170 return dist/ia[
A->m];
173static double update_step(
bool adaptive_cooling,
double step,
double Fnorm,
176 if (!adaptive_cooling) {
179 if (Fnorm >= Fnorm0){
181 }
else if (Fnorm > 0.95*Fnorm0){
184 step = 0.99*step/
cool;
190#define node_degree(i) (ia[(i)+1] - ia[(i)])
200 int m =
A->m, i, j, *ia =
A->ia, *ja =
A->ja;
209 for (i = 0; i < m; i++){
210 if (ia[i+1] - ia[i] != 1)
continue;
217 for (j = ia[p]; j < ia[p+1]; j++){
221 ints_append(&leaves, ja[j]);
224 assert(!ints_is_empty(&leaves));
225 dist /= (double)ints_size(&leaves);
227 double ang2 = 2 *
M_PI;
228 const double pad = 0.1;
232 assert(ang2 >= ang1);
234 if (ints_size(&leaves) > 1) step = (ang2 - ang1) / (
double)ints_size(&leaves);
235 for (
size_t k = 0; k < ints_size(&leaves); k++) {
251 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
253 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
256 double counts[4], *force =
NULL;
258 clock_t start, end, start0;
259 double qtree_cpu = 0, qtree_new_cpu = 0;
260 double total_cpu = 0;
265 if (!
A || maxiter <= 0)
return;
268 if (n <= 0 ||
dim <= 0)
return;
284 for (i = 0; i <
dim*n; i++) x[i] =
drand();
289 if (p >= 0) ctrl->
p = p = -1;
291 CRK = pow(
C, (2.-p)/3.)/K;
308 qtree_new_cpu += ((double) (clock() - start))/CLOCKS_PER_SEC;
320 qtree_cpu += ((double) (end - start)) / CLOCKS_PER_SEC;
324 for (i = 0; i < n; i++){
326 for (j = ia[i]; j < ia[i+1]; j++){
327 if (ja[j] == i)
continue;
329 for (k = 0; k <
dim; k++){
330 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
337 for (i = 0; i < n; i++){
340 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
343 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
344 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
356 qtree_new_cpu += ((double) (end - start)) / CLOCKS_PER_SEC;
360 counts[0] + 0.85 * counts[1] + 3.3 * counts[2]);
363 fprintf(stderr,
"\r iter = %d, step = %f Fnorm = %f nz = %d K = %f ",iter, step, Fnorm,
A->nz,K);
367 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
368 }
while (step >
tol && iter < maxiter);
372 fprintf(stderr,
"\n iter = %d, step = %f Fnorm = %f nz = %d K = %f ",iter, step, Fnorm,
A->nz, K);
379 total_cpu += ((double) (clock() - start0)) / CLOCKS_PER_SEC;
380 if (
Verbose) fprintf(stderr,
"\n time for qtree = %f, qtree_force = %f, total cpu = %f\n",qtree_new_cpu, qtree_cpu, total_cpu);
397 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
399 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
404 clock_t start, end, start0, start2;
405 double total_cpu = 0;
409 fprintf(stderr,
"spring_electrical_embedding_slow");
410 if (!
A || maxiter <= 0)
return;
413 if (n <= 0 ||
dim <= 0)
return;
428 for (i = 0; i <
dim*n; i++) x[i] =
drand();
433 if (p >= 0) ctrl->
p = p = -1;
435 CRK = pow(
C, (2.-p)/3.)/K;
439 for (i = 0; i <
dim*n; i++) force[i] = 0;
450 for (i = 0; i < n; i++){
451 for (k = 0; k <
dim; k++) f[k] = 0.;
453 for (j = 0; j < n; j++){
454 if (j == i)
continue;
456 for (k = 0; k <
dim; k++){
457 f[k] += KP*(x[i*
dim+k] - x[j*
dim+k])/pow(
dist, 1.- p);
460 for (k = 0; k <
dim; k++) force[i*
dim+k] += f[k];
465 for (i = 0; i < n; i++){
466 for (k = 0; k <
dim; k++) f[k] = 0.;
468 for (j = ia[i]; j < ia[i+1]; j++){
469 if (ja[j] == i)
continue;
471 for (k = 0; k <
dim; k++){
472 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
475 for (k = 0; k <
dim; k++) force[i*
dim+k] += f[k];
480 for (i = 0; i < n; i++){
482 for (k = 0; k <
dim; k++) f[k] = force[i*
dim+k];
485 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
489 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
491 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
495 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
496 }
while (step >
tol && iter < maxiter);
500 fprintf(stderr,
"iter = %d, step = %f Fnorm = %f nsuper = 0 nz = %d K = %f ",iter, step, Fnorm,
A->nz,K);
507 total_cpu += ((double) (clock() - start0)) / CLOCKS_PER_SEC;
508 if (
Verbose) fprintf(stderr,
"time for supernode = 0, total cpu = %f\n", total_cpu);
524 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
526 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
530 int nsuper = 0, nsupermax = 10;
531 double *
center =
NULL, *supernode_wgts =
NULL, *distances =
NULL, nsuper_avg, counts = 0, counts_avg = 0;
533 clock_t start, end, start0, start2;
534 double qtree_cpu = 0;
535 double total_cpu = 0;
541 if (!
A || maxiter <= 0)
return;
544 if (n <= 0 ||
dim <= 0)
return;
550 supernode_wgts =
gv_calloc(nsupermax,
sizeof(
double));
551 distances =
gv_calloc(nsupermax,
sizeof(
double));
565 for (i = 0; i <
dim*n; i++) x[i] =
drand();
570 if (p >= 0) ctrl->
p = p = -1;
572 CRK = pow(
C, (2.-p)/3.)/K;
595 for (i = 0; i < n; i++){
596 for (k = 0; k <
dim; k++) f[k] = 0.;
598 for (j = ia[i]; j < ia[i+1]; j++){
599 if (ja[j] == i)
continue;
601 for (k = 0; k <
dim; k++){
602 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
612 &
center, &supernode_wgts, &distances, &counts);
616 qtree_cpu += ((double) (end - start)) / CLOCKS_PER_SEC;
618 counts_avg += counts;
619 nsuper_avg += nsuper;
620 for (j = 0; j < nsuper; j++){
622 for (k = 0; k <
dim; k++){
623 f[k] += supernode_wgts[j]*KP*(x[i*
dim+k] -
center[j*
dim+k])/pow(
dist, 1.- p);
627 for (j = 0; j < n; j++){
628 if (j == i)
continue;
630 for (k = 0; k <
dim; k++){
631 f[k] += KP*(x[i*
dim+k] - x[j*
dim+k])/pow(
dist, 1.- p);
638 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
642 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
644 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
655 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
656 }
while (step >
tol && iter < maxiter);
661 fprintf(stderr,
"iter = %d, step = %f Fnorm = %f qt_level = %d nsuper = %d nz = %d K = %f ",iter, step, Fnorm, max_qtree_level, (
int) nsuper_avg,
A->nz,K);
663 fprintf(stderr,
"iter = %d, step = %f Fnorm = %f nsuper = %d nz = %d K = %f ",iter, step, Fnorm, (
int) nsuper_avg,
A->nz,K);
671 total_cpu += ((double) (clock() - start0)) / CLOCKS_PER_SEC;
672 if (
Verbose) fprintf(stderr,
"time for supernode = %f, total cpu = %f\n",qtree_cpu, total_cpu);
682 free(supernode_wgts);
693 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
698 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
702 int nsuper = 0, nsupermax = 10;
704 int max_qtree_level = 10;
706 if (!
A || maxiter <= 0)
return;
708 if (n <= 0 ||
dim <= 0)
return;
713 supernode_wgts =
gv_calloc(nsupermax,
sizeof(
double));
714 distances =
gv_calloc(nsupermax,
sizeof(
double));
731 for (i = 0; i <
dim*n; i++) x[i] =
drand();
736 if (p >= 0) ctrl->
p = p = -1;
738 CRK = pow(
C, (2.-p)/3.)/K;
744 memcpy(xold, x,
sizeof(
double)*
dim*n);
753 for (i = 0; i < n; i++){
754 for (k = 0; k <
dim; k++) f[k] = 0.;
757 for (j = ia[i]; j < ia[i+1]; j++){
758 if (ja[j] == i)
continue;
760 for (k = 0; k <
dim; k++){
761 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
765 for (j =
id[i]; j <
id[i+1]; j++){
766 if (jd[j] == i)
continue;
768 for (k = 0; k <
dim; k++){
781 &
center, &supernode_wgts, &distances, &counts);
782 for (j = 0; j < nsuper; j++){
784 for (k = 0; k <
dim; k++){
785 f[k] += supernode_wgts[j]*KP*(x[i*
dim+k] -
center[j*
dim+k])/pow(
dist, 1.- p);
789 for (j = 0; j < n; j++){
790 if (j == i)
continue;
792 for (k = 0; k <
dim; k++){
793 f[k] += KP*(x[i*
dim+k] - x[j*
dim+k])/pow(
dist, 1.- p);
800 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
804 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
806 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
812 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
813 }
while (step >
tol && iter < maxiter);
822 free(supernode_wgts);
827 int i, j, k, *ia =
A->ia, *ja =
A->ja, nz;
828 double alpha = 0.5, beta;
831 for (i = 0; i <
A->m; i++){
832 for (k = 0; k <
dim; k++) y[k] = 0;
834 for (j = ia[i]; j < ia[i+1]; j++){
835 if (ja[j] == i)
continue;
837 for (k = 0; k <
dim; k++){
838 y[k] += x[ja[j]*
dim + k];
843 for (k = 0; k <
dim; k++) x[i*
dim+k] =
alpha*x[i*
dim+k] + beta*y[k];
850 int nc, *ia, *ja, i, j, k;
857 for (i = 0; i < nc; i++){
858 for (j = ia[i]+1; j < ia[i+1]; j++){
859 for (k = 0; k <
dim; k++){
867 int m, max = 0, i, *ia =
A->ia, *ja =
A->ja, j, deg;
870 int *mask =
gv_calloc(m + 1,
sizeof(
int));
872 for (i = 0; i < m + 1; i++){
876 for (i = 0; i < m; i++){
878 for (j = ia[i]; j < ia[i+1]; j++){
879 if (i == ja[j])
continue;
883 max =
MAX(max, mask[deg]);
885 if (mask[1] > 0.8*max && mask[1] > 0.3*m) res =
true;
892 double y[4], axis[2],
center[2],
dist, x0, x1;
895 for (i = 0; i <
dim*
dim; i++) y[i] = 0;
897 for (i = 0; i < n; i++){
898 for (k = 0; k <
dim; k++){
902 for (i = 0; i <
dim; i++)
center[i] /= n;
903 for (i = 0; i < n; i++){
904 for (k = 0; k <
dim; k++){
909 for (i = 0; i < n; i++){
910 for (k = 0; k <
dim; k++){
911 for (l = 0; l <
dim; l++){
917 axis[0] = 0; axis[1] = 1;
925 axis[0] = -(-y[0] + y[3] - sqrt(y[0]*y[0]+4*y[1]*y[1]-2*y[0]*y[3]+y[3]*y[3]))/(2*y[1]);
928 dist = sqrt(1+axis[0]*axis[0]);
929 axis[0] = axis[0]/
dist;
930 axis[1] = axis[1]/
dist;
931 for (i = 0; i < n; i++){
932 x0 = x[
dim*i]*axis[0]+x[
dim*i+1]*axis[1];
933 x1 = -x[
dim*i]*axis[1]+x[
dim*i+1]*axis[0];
942static void rotate(
int n,
int dim,
double *x,
double angle){
944 double axis[2],
center[2], x0, x1;
945 double radian = 3.14159/180;
949 for (i = 0; i < n; i++){
950 for (k = 0; k <
dim; k++){
954 for (i = 0; i <
dim; i++)
center[i] /= n;
955 for (i = 0; i < n; i++){
956 for (k = 0; k <
dim; k++){
960 axis[0] = cos(-angle*radian);
961 axis[1] = sin(-angle*radian);
962 for (i = 0; i < n; i++){
963 x0 = x[
dim*i]*axis[0]+x[
dim*i+1]*axis[1];
964 x1 = -x[
dim*i]*axis[1]+x[
dim*i+1]*axis[0];
979 for (i = 0; i <
A->m; i++) mask[i] = 1;
980 for (i = 0; i < n_edge_label_nodes; i++) {
981 if (edge_label_nodes[i] >= 0 && edge_label_nodes[i] <
A->m) mask[edge_label_nodes[i]] = -1;
984 for (i = 0; i <
A->m; i++) {
985 if (mask[i] >= 0) mask[i] = nnodes++;
989 for (i = 0; i <
A->m; i++){
991 for (k = 0; k <
dim; k++) x[i*
dim+k] = x2[mask[i]*
dim+k];
995 for (i = 0; i < n_edge_label_nodes; i++){
996 ii = edge_label_nodes[i];
997 len =
A->ia[ii+1] -
A->ia[ii];
999 assert(mask[ii] < 0);
1000 for (k = 0; k <
dim; k++) {
1003 for (j =
A->ia[ii]; j <
A->ia[ii+1]; j++){
1004 for (k = 0; k <
dim; k++){
1005 x[ii*
dim+k] += x[(
A->ja[j])*
dim+k];
1008 for (k = 0; k <
dim; k++) {
1017 int i,
id = 0, nz, j, jj, ii;
1018 int *ia =
A->
ia, *ja =
A->ja, *irn =
NULL, *jcn =
NULL;
1023 for (i = 0; i <
A->m; i++) mask[i] = 1;
1025 for (i = 0; i < n_edge_label_nodes; i++){
1026 mask[edge_label_nodes[i]] = -1;
1029 for (i = 0; i <
A->m; i++) {
1030 if (mask[i] > 0) mask[i] =
id++;
1034 for (i = 0; i <
A->m; i++){
1035 if (mask[i] < 0)
continue;
1036 for (j = ia[i]; j < ia[i+1]; j++){
1037 if (mask[ja[j]] >= 0) {
1042 for (jj = ia[ii]; jj < ia[ii+1]; jj++){
1043 if (ja[jj] != i && mask[ja[jj]] >= 0) nz++;
1054 for (i = 0; i <
A->m; i++){
1055 if (mask[i] < 0)
continue;
1056 for (j = ia[i]; j < ia[i+1]; j++){
1057 if (mask[ja[j]] >= 0) {
1059 jcn[nz++] = mask[ja[j]];
1063 for (jj = ia[ii]; jj < ia[ii+1]; jj++){
1064 if (ja[jj] != i && mask[ja[jj]] >= 0) {
1066 jcn[nz++] = mask[ja[jj]];
1083 double *label_sizes,
double *x,
1084 int n_edge_label_nodes,
1085 int *edge_label_nodes,
int *flag) {
1105 if (n <= 0 ||
dim <= 0)
return;
1115 && n_edge_label_nodes > 0){
1146 if (plg) ctrl->
p = -1.8;
1154 fprintf(stderr,
"coarsest level -- %d, n = %d\n",
grid->level,
grid->n);
1156 fprintf(stderr,
"level -- %d, n = %d\n",
grid->level,
grid->n);
1164 fprintf(stderr,
"QUAD_TREE_HYBRID, size larger than %d, switch to fast quadtree",
QUAD_TREE_HYBRID_SIZE);
1186 ctrl->
K = ctrl->
K * 0.75;
1193 fprintf(stderr,
"layout time %f\n",((
double) (clock() - cpu)) / CLOCKS_PER_SEC);
1199 if (
Verbose) fprintf(stderr,
"ctrl->overlap=%d\n",ctrl->
overlap);
void print_padding(int n)
Multilevel Multilevel_get_coarsest(Multilevel grid)
void Multilevel_delete(Multilevel grid)
Multilevel Multilevel_new(SparseMatrix A0, const Multilevel_control ctrl)
#define Multilevel_is_coarsest(grid)
#define Multilevel_is_finest(grid)
void QuadTree_get_repulsive_force(QuadTree qt, double *force, double *x, double bh, double p, double KP, double *counts)
QuadTree QuadTree_new_from_point_list(int dim, int n, int max_level, double *coord)
void QuadTree_delete(QuadTree q)
void QuadTree_get_supernodes(QuadTree qt, double bh, double *pt, int nodeid, int *nsuper, int *nsupermax, double **center, double **supernode_wgts, double **distances, double *counts)
SparseMatrix SparseMatrix_symmetrize(SparseMatrix A, bool pattern_symmetric_only)
void SparseMatrix_multiply_dense(SparseMatrix A, const double *v, double *res, int dim)
bool SparseMatrix_is_symmetric(SparseMatrix A, bool test_pattern_symmetry_only)
SparseMatrix SparseMatrix_from_coordinate_arrays(int nz, int m, int n, int *irn, int *jcn, void *val0, int type, size_t sz)
void SparseMatrix_delete(SparseMatrix A)
SparseMatrix SparseMatrix_get_real_adjacency_matrix_symmetrized(SparseMatrix A)
bool SparseMatrix_has_diagonal(SparseMatrix A)
SparseMatrix SparseMatrix_remove_diagonal(SparseMatrix A)
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
API for compacted arrays of booleans.
static bitarray_t bitarray_new(size_t size_bits)
create an array of the given element length
static bool bitarray_get(bitarray_t self, size_t index)
get the value of the given element
static void bitarray_set(bitarray_t *self, size_t index, bool value)
set or clear the value of the given element
static void bitarray_reset(bitarray_t *self)
free underlying resources and leave a bit array empty
static double dist(int dim, double *x, double *y)
double distance(double *x, int dim, int i, int j)
double distance_cropped(double *x, int dim, int i, int j)
static double len(glCompPoint p)
static double drand(void)
#define DEFINE_LIST(name, type)
void remove_overlap(int dim, SparseMatrix A, double *x, double *label_sizes, int ntry, double initial_scaling, int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, bool do_shrinking)
@ ELSCHEME_STRAIGHTLINE_PENALTY2
@ ELSCHEME_STRAIGHTLINE_PENALTY
void post_process_smoothing(int dim, SparseMatrix A, spring_electrical_control ctrl, double *x)
static bool power_law_graph(SparseMatrix A)
static char * smoothings[]
void spring_electrical_control_print(spring_electrical_control ctrl)
static double update_step(bool adaptive_cooling, double step, double Fnorm, double Fnorm0)
spring_electrical_control spring_electrical_control_new(void)
static const int quadtree_size
cut off size above which quadtree approximation is used
static SparseMatrix shorting_edge_label_nodes(SparseMatrix A, int n_edge_label_nodes, int *edge_label_nodes)
static int oned_optimizer_get(const oned_optimizer opt)
static void prolongate(int dim, SparseMatrix A, SparseMatrix P, SparseMatrix R, double *x, double *y, double delta)
void spring_electrical_embedding_fast(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *x, int *flag)
static void beautify_leaves(int dim, SparseMatrix A, double *x)
static oned_optimizer oned_optimizer_new(int i)
static void attach_edge_label_coordinates(int dim, SparseMatrix A, int n_edge_label_nodes, int *edge_label_nodes, double *x, double *x2)
static void spring_electrical_embedding_slow(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *x, int *flag)
double average_edge_length(SparseMatrix A, int dim, double *coord)
void spring_electrical_spring_embedding(int dim, SparseMatrix A0, SparseMatrix D, spring_electrical_control ctrl, double *x, int *flag)
void multilevel_spring_electrical_embedding(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *label_sizes, double *x, int n_edge_label_nodes, int *edge_label_nodes, int *flag)
static void oned_optimizer_train(oned_optimizer *opt, double work)
void spring_electrical_control_delete(spring_electrical_control ctrl)
void pcp_rotate(int n, int dim, double *x)
void spring_electrical_embedding(int dim, SparseMatrix A0, spring_electrical_control ctrl, double *x, int *flag)
static void rotate(int n, int dim, double *x, double angle)
static void set_leaves(double *x, int dim, double dist, double ang, int i, int j)
static void interpolate_coord(int dim, SparseMatrix A, double *x)
@ ERROR_NOT_SQUARE_MATRIX
bool random_start
whether to apply SE from a random layout, or from exisiting layout
static point center(point vertex[], size_t n)
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t