36static const double C = 0.2;
43static const double bh = 0.6;
47static const double tol = 0.001;
49static const double cool = 0.90;
75 "NONE",
"STRESS_MAJORIZATION_GRAPH_DIST",
"STRESS_MAJORIZATION_AVG_DIST",
"STRESS_MAJORIZATION_POWER_DIST",
"SPRING",
"TRIANGLE",
"RNG"
79 "NONE",
"NORMAL",
"FAST",
"HYBRID"
83 fprintf (stderr,
"spring_electrical_control:\n");
84 fprintf (stderr,
" repulsive exponent: %.03f\n", ctrl.
p);
85 fprintf(stderr,
" random start %d seed %d\n", (
int)ctrl.
random_start,
87 fprintf (stderr,
" K : %.03f C : %.03f\n", ctrl.
K,
C);
88 fprintf (stderr,
" max levels %d\n", ctrl.
multilevels);
90 fprintf (stderr,
" Barnes-Hutt constant %.03f tolerance %.03f maxiter %d\n",
bh,
tol, ctrl.
maxiter);
91 fprintf(stderr,
" cooling %.03f step size %.03f adaptive %d\n",
cool,
93 fprintf (stderr,
" beautify_leaves %d node weights %d rotation %.03f\n",
95 fprintf (stderr,
" smoothing %s overlap %d initial_scaling %.03f do_shrinking %d\n",
139 if (opt->
work[i] < opt->
work[i+1] && opt->
i > 0){
140 opt->
i =
MAX(0, opt->
i-1);
155 int *ia =
A->ia, *ja =
A->ja, i, j, k;
158 if (ia[
A->m] == 0)
return 1;
159 for (i = 0; i <
A->m; i++){
160 for (j = ia[i]; j < ia[i+1]; j++){
162 for (k = 0; k <
dim; k++){
168 return dist/ia[
A->m];
171static double update_step(
bool adaptive_cooling,
double step,
double Fnorm,
174 if (!adaptive_cooling) {
177 if (Fnorm >= Fnorm0){
179 }
else if (Fnorm > 0.95*Fnorm0){
182 step = 0.99*step/
cool;
188#define node_degree(i) (ia[(i)+1] - ia[(i)])
196 int m =
A->m, i, j, *ia =
A->ia, *ja =
A->ja;
205 for (i = 0; i < m; i++){
206 if (ia[i+1] - ia[i] != 1)
continue;
212 LIST(
int) leaves = {0};
213 for (j = ia[p]; j < ia[p+1]; j++){
223 double ang2 = 2 *
M_PI;
224 const double pad = 0.1;
228 assert(ang2 >= ang1);
231 for (
size_t k = 0; k <
LIST_SIZE(&leaves); k++) {
244 double *x,
int *flag) {
249 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
251 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
254 double counts[4], *force =
NULL;
256 clock_t start, end, start0;
257 double qtree_cpu = 0, qtree_new_cpu = 0;
258 double total_cpu = 0;
263 if (!
A || maxiter <= 0)
return;
266 if (n <= 0 ||
dim <= 0)
return;
282 for (i = 0; i <
dim*n; i++) x[i] =
drand();
287 if (p >= 0) ctrl->
p = p = -1;
289 CRK = pow(
C, (2.-p)/3.)/K;
306 qtree_new_cpu += (double)(clock() - start) / CLOCKS_PER_SEC;
318 qtree_cpu += (double)(end - start) / CLOCKS_PER_SEC;
322 for (i = 0; i < n; i++){
324 for (j = ia[i]; j < ia[i+1]; j++){
325 if (ja[j] == i)
continue;
327 for (k = 0; k <
dim; k++){
328 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
335 for (i = 0; i < n; i++){
338 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
341 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
342 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
354 qtree_new_cpu += (double)(end - start) / CLOCKS_PER_SEC;
358 counts[0] + 0.85 * counts[1] + 3.3 * counts[2]);
362 "\r iter = %d, step = %f Fnorm = %f nz = %"
364 step, Fnorm,
A->nz, K);
368 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
369 }
while (step >
tol && iter < maxiter);
373 fprintf(stderr,
"\n iter = %d, step = %f Fnorm = %f nz = %" PRISIZE_T
374 " K = %f ", iter, step, Fnorm,
A->nz, K);
381 total_cpu += (double)(clock() - start0) / CLOCKS_PER_SEC;
382 if (
Verbose) fprintf(stderr,
"\n time for qtree = %f, qtree_force = %f, total cpu = %f\n",qtree_new_cpu, qtree_cpu, total_cpu);
395 double *x,
int *flag) {
401 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
403 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
408 clock_t start, end, start0, start2;
409 double total_cpu = 0;
413 fprintf(stderr,
"spring_electrical_embedding_slow");
414 if (!
A || maxiter <= 0)
return;
417 if (n <= 0 ||
dim <= 0)
return;
432 for (i = 0; i <
dim*n; i++) x[i] =
drand();
437 if (p >= 0) ctrl->
p = p = -1;
439 CRK = pow(
C, (2.-p)/3.)/K;
443 for (i = 0; i <
dim*n; i++) force[i] = 0;
454 for (i = 0; i < n; i++){
455 for (k = 0; k <
dim; k++) f[k] = 0.;
457 for (j = 0; j < n; j++){
458 if (j == i)
continue;
460 for (k = 0; k <
dim; k++){
461 f[k] += KP*(x[i*
dim+k] - x[j*
dim+k])/pow(
dist, 1.- p);
464 for (k = 0; k <
dim; k++) force[i*
dim+k] += f[k];
469 for (i = 0; i < n; i++){
470 for (k = 0; k <
dim; k++) f[k] = 0.;
472 for (j = ia[i]; j < ia[i+1]; j++){
473 if (ja[j] == i)
continue;
475 for (k = 0; k <
dim; k++){
476 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
479 for (k = 0; k <
dim; k++) force[i*
dim+k] += f[k];
484 for (i = 0; i < n; i++){
486 for (k = 0; k <
dim; k++) f[k] = force[i*
dim+k];
489 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
493 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
495 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
499 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
500 }
while (step >
tol && iter < maxiter);
504 fprintf(stderr,
"iter = %d, step = %f Fnorm = %f nsuper = 0 nz = %d K = %f ",iter, step, Fnorm,
A->nz,K);
511 total_cpu += (double)(clock() - start0) / CLOCKS_PER_SEC;
512 if (
Verbose) fprintf(stderr,
"time for supernode = 0, total cpu = %f\n", total_cpu);
528 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
530 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
534 int nsuper = 0, nsupermax = 10;
535 double *
center =
NULL, *supernode_wgts =
NULL, *distances =
NULL, nsuper_avg, counts = 0, counts_avg = 0;
537 clock_t start, end, start0, start2;
538 double qtree_cpu = 0;
539 double total_cpu = 0;
545 if (!
A || maxiter <= 0)
return;
548 if (n <= 0 ||
dim <= 0)
return;
554 supernode_wgts =
gv_calloc(nsupermax,
sizeof(
double));
555 distances =
gv_calloc(nsupermax,
sizeof(
double));
569 for (i = 0; i <
dim*n; i++) x[i] =
drand();
574 if (p >= 0) ctrl->
p = p = -1;
576 CRK = pow(
C, (2.-p)/3.)/K;
599 for (i = 0; i < n; i++){
600 for (k = 0; k <
dim; k++) f[k] = 0.;
602 for (j = ia[i]; j < ia[i+1]; j++){
603 if (ja[j] == i)
continue;
605 for (k = 0; k <
dim; k++){
606 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
616 &
center, &supernode_wgts, &distances, &counts);
620 qtree_cpu += (double)(end - start) / CLOCKS_PER_SEC;
622 counts_avg += counts;
623 nsuper_avg += nsuper;
624 for (j = 0; j < nsuper; j++){
626 for (k = 0; k <
dim; k++){
627 f[k] += supernode_wgts[j]*KP*(x[i*
dim+k] -
center[j*
dim+k])/pow(
dist, 1.- p);
631 for (j = 0; j < n; j++){
632 if (j == i)
continue;
634 for (k = 0; k <
dim; k++){
635 f[k] += KP*(x[i*
dim+k] - x[j*
dim+k])/pow(
dist, 1.- p);
642 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
646 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
648 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
659 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
660 }
while (step >
tol && iter < maxiter);
665 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);
667 fprintf(stderr,
"iter = %d, step = %f Fnorm = %f nsuper = %d nz = %d K = %f ",iter, step, Fnorm, (
int) nsuper_avg,
A->nz,K);
675 total_cpu += (double)(clock() - start0) / CLOCKS_PER_SEC;
676 if (
Verbose) fprintf(stderr,
"time for supernode = %f, total cpu = %f\n",qtree_cpu, total_cpu);
686 free(supernode_wgts);
692 double *x,
int *flag) {
699 double p = ctrl->
p, K = ctrl->
K, CRK, maxiter = ctrl->
maxiter, step = ctrl->
step, KP;
704 double *f =
NULL,
dist,
F, Fnorm = 0, Fnorm0;
708 int nsuper = 0, nsupermax = 10;
710 int max_qtree_level = 10;
712 if (!
A || maxiter <= 0)
return;
714 if (n <= 0 ||
dim <= 0)
return;
719 supernode_wgts =
gv_calloc(nsupermax,
sizeof(
double));
720 distances =
gv_calloc(nsupermax,
sizeof(
double));
737 for (i = 0; i <
dim*n; i++) x[i] =
drand();
742 if (p >= 0) ctrl->
p = p = -1;
744 CRK = pow(
C, (2.-p)/3.)/K;
750 memcpy(xold, x,
sizeof(
double)*
dim*n);
759 for (i = 0; i < n; i++){
760 for (k = 0; k <
dim; k++) f[k] = 0.;
763 for (j = ia[i]; j < ia[i+1]; j++){
764 if (ja[j] == i)
continue;
766 for (k = 0; k <
dim; k++){
767 f[k] -= CRK*(x[i*
dim+k] - x[ja[j]*
dim+k])*
dist;
771 for (j =
id[i]; j <
id[i+1]; j++){
772 if (jd[j] == i)
continue;
774 for (k = 0; k <
dim; k++){
787 &
center, &supernode_wgts, &distances, &counts);
788 for (j = 0; j < nsuper; j++){
790 for (k = 0; k <
dim; k++){
791 f[k] += supernode_wgts[j]*KP*(x[i*
dim+k] -
center[j*
dim+k])/pow(
dist, 1.- p);
795 for (j = 0; j < n; j++){
796 if (j == i)
continue;
798 for (k = 0; k <
dim; k++){
799 f[k] += KP*(x[i*
dim+k] - x[j*
dim+k])/pow(
dist, 1.- p);
806 for (k = 0; k <
dim; k++)
F += f[k]*f[k];
810 if (
F > 0)
for (k = 0; k <
dim; k++) f[k] /=
F;
812 for (k = 0; k <
dim; k++) x[i*
dim+k] += step*f[k];
818 step =
update_step(adaptive_cooling, step, Fnorm, Fnorm0);
819 }
while (step >
tol && iter < maxiter);
828 free(supernode_wgts);
833 int i, j, k, *ia =
A->ia, *ja =
A->ja, nz;
834 double alpha = 0.5, beta;
837 for (i = 0; i <
A->m; i++){
838 for (k = 0; k <
dim; k++) y[k] = 0;
840 for (j = ia[i]; j < ia[i+1]; j++){
841 if (ja[j] == i)
continue;
843 for (k = 0; k <
dim; k++){
844 y[k] += x[ja[j]*
dim + k];
849 for (k = 0; k <
dim; k++) x[i*
dim+k] =
alpha*x[i*
dim+k] + beta*y[k];
856 int nc, *ia, *ja, i, j, k;
863 for (i = 0; i < nc; i++){
864 for (j = ia[i]+1; j < ia[i+1]; j++){
865 for (k = 0; k <
dim; k++){
873 int m, max = 0, i, *ia =
A->ia, *ja =
A->ja, j, deg;
876 int *mask =
gv_calloc(m + 1,
sizeof(
int));
878 for (i = 0; i < m + 1; i++){
882 for (i = 0; i < m; i++){
884 for (j = ia[i]; j < ia[i+1]; j++){
885 if (i == ja[j])
continue;
889 max =
MAX(max, mask[deg]);
891 if (mask[1] > 0.8*max && mask[1] > 0.3*m) res =
true;
898 double y[4], axis[2],
center[2],
dist, x0, x1;
901 for (i = 0; i <
dim*
dim; i++) y[i] = 0;
903 for (i = 0; i < n; i++){
904 for (k = 0; k <
dim; k++){
908 for (i = 0; i <
dim; i++)
center[i] /= n;
909 for (i = 0; i < n; i++){
910 for (k = 0; k <
dim; k++){
915 for (i = 0; i < n; i++){
916 for (k = 0; k <
dim; k++){
917 for (l = 0; l <
dim; l++){
923 axis[0] = 0; axis[1] = 1;
931 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]);
934 dist = sqrt(1+axis[0]*axis[0]);
935 axis[0] = axis[0]/
dist;
936 axis[1] = axis[1]/
dist;
937 for (i = 0; i < n; i++){
938 x0 = x[
dim*i]*axis[0]+x[
dim*i+1]*axis[1];
939 x1 = -x[
dim*i]*axis[1]+x[
dim*i+1]*axis[0];
948static void rotate(
int n,
int dim,
double *x,
double angle){
950 double axis[2],
center[2], x0, x1;
951 double radian = 3.14159/180;
955 for (i = 0; i < n; i++){
956 for (k = 0; k <
dim; k++){
960 for (i = 0; i <
dim; i++)
center[i] /= n;
961 for (i = 0; i < n; i++){
962 for (k = 0; k <
dim; k++){
966 axis[0] = cos(-angle*radian);
967 axis[1] = sin(-angle*radian);
968 for (i = 0; i < n; i++){
969 x0 = x[
dim*i]*axis[0]+x[
dim*i+1]*axis[1];
970 x1 = -x[
dim*i]*axis[1]+x[
dim*i+1]*axis[0];
985 for (i = 0; i <
A->m; i++) mask[i] = 1;
986 for (i = 0; i < n_edge_label_nodes; i++) {
987 if (edge_label_nodes[i] >= 0 && edge_label_nodes[i] <
A->m) mask[edge_label_nodes[i]] = -1;
990 for (i = 0; i <
A->m; i++) {
991 if (mask[i] >= 0) mask[i] = nnodes++;
995 for (i = 0; i <
A->m; i++){
997 for (k = 0; k <
dim; k++) x[i*
dim+k] = x2[mask[i]*
dim+k];
1001 for (i = 0; i < n_edge_label_nodes; i++){
1002 ii = edge_label_nodes[i];
1003 len =
A->ia[ii+1] -
A->ia[ii];
1005 assert(mask[ii] < 0);
1006 for (k = 0; k <
dim; k++) {
1009 for (j =
A->ia[ii]; j <
A->ia[ii+1]; j++){
1010 for (k = 0; k <
dim; k++){
1011 x[ii *
dim + k] += x[
A->ja[j] *
dim + k];
1014 for (k = 0; k <
dim; k++) {
1024 int *ia =
A->
ia, *ja =
A->ja;
1028 for (
int i = 0; i <
A->m; i++) mask[i] = 1;
1030 for (
int i = 0; i < n_edge_label_nodes; i++){
1031 mask[edge_label_nodes[i]] = -1;
1034 for (
int i = 0; i <
A->m; i++) {
1035 if (mask[i] > 0) mask[i] =
id++;
1038 LIST(
int) irn = {0};
1039 LIST(
int) jcn = {0};
1040 for (
int i = 0; i <
A->m; i++){
1041 if (mask[i] < 0)
continue;
1042 for (
int j = ia[i]; j < ia[i+1]; j++){
1043 if (mask[ja[j]] >= 0) {
1048 const int ii = ja[j];
1049 for (
int jj = ia[ii]; jj < ia[ii+1]; jj++){
1050 if (ja[jj] != i && mask[ja[jj]] >= 0) {
1075 double *label_sizes,
double *x,
1076 int n_edge_label_nodes,
1077 int *edge_label_nodes,
int *flag) {
1096 if (n <= 0 ||
dim <= 0)
return;
1106 && n_edge_label_nodes > 0){
1137 if (plg) ctrl->
p = -1.8;
1145 fprintf(stderr,
"coarsest level -- %d, n = %d\n",
grid->level,
grid->n);
1147 fprintf(stderr,
"level -- %d, n = %d\n",
grid->level,
grid->n);
1155 fprintf(stderr,
"QUAD_TREE_HYBRID, size larger than %d, switch to fast quadtree",
QUAD_TREE_HYBRID_SIZE);
1177 ctrl->
K = ctrl->
K * 0.75;
1184 fprintf(stderr,
"layout time %f\n", (
double)(clock() - cpu) / CLOCKS_PER_SEC);
1190 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(size_t nz, int m, int n, int *irn, int *jcn, const void *val, 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)
Dynamically expanding string buffers.
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, 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)
type-generic dynamically expanding list
#define LIST_APPEND(list, item)
#define LIST_IS_EMPTY(list)
#define LIST_GET(list, index)
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)
void spring_electrical_embedding(int dim, SparseMatrix A0, spring_electrical_control *ctrl, double *x, int *flag)
void spring_electrical_embedding_fast(int dim, SparseMatrix A0, spring_electrical_control *ctrl, double *x, int *flag)
static char * smoothings[]
void spring_electrical_control_print(spring_electrical_control ctrl)
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 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)
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)
double average_edge_length(SparseMatrix A, int dim, double *coord)
static void oned_optimizer_train(oned_optimizer *opt, double work)
void pcp_rotate(int n, int dim, double *x)
static void rotate(int n, int dim, double *x, double angle)
void spring_electrical_spring_embedding(int dim, SparseMatrix A0, SparseMatrix D, spring_electrical_control *ctrl, double *x, int *flag)
static void set_leaves(double *x, int dim, double dist, double ang, int i, int j)
static void spring_electrical_embedding_slow(int dim, SparseMatrix A0, spring_electrical_control *ctrl, double *x, int *flag)
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 existing layout
double p
a negative real number default to -1. repulsive force = distáµ–
static point center(point vertex[], size_t n)
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t