34#define node_degree(i) (ia[(i) + 1] - ia[(i)])
45 const int *
const ia =
D->ia;
46 const int *
const ja =
D->ja;
52 double *
const d =
D->a;
55 for (
int i = 0; i <
D->m; i++)
58 for (
int i = 0; i <
D->m; i++) {
61 for (
int j = ia[i]; j < ia[i + 1]; j++) {
66 for (
int j = ia[i]; j < ia[i + 1]; j++) {
71 for (
int l = ia[k]; l < ia[k + 1]; l++) {
83 for (
int i = 0; i <
D->m; i++) {
84 for (
int j = ia[i]; j < ia[i + 1]; j++) {
96 for (
int i = 0; i <
D->m; i++) {
97 for (
int j = ia[i]; j < ia[i + 1]; j++) {
110 double *x,
int ideal_dist_scheme) {
114 int j, k, l, m =
A->m, *ia =
A->ia, *ja =
A->ja, *iw, *jw, *
id, *jd;
115 double *d, *w, *lambda;
116 double diag_d, diag_w,
dist,
s = 0, stop = 0, sbot = 0;
132 for (
int i = 0; i < m; i++)
136 double *avg_dist =
gv_calloc(m,
sizeof(
double));
138 for (
int i = 0; i < m; i++) {
141 for (j = ia[i]; j < ia[i + 1]; j++) {
151 for (
int i = 0; i < m; i++)
155 for (
int i = 0; i < m; i++) {
157 for (j = ia[i]; j < ia[i + 1]; j++) {
164 for (j = ia[i]; j < ia[i + 1]; j++) {
166 for (l = ia[k]; l < ia[k + 1]; l++) {
167 if (mask[ja[l]] != i) {
192 for (
int i = 0; i < m; i++) {
195 for (j = ia[i]; j < ia[i + 1]; j++) {
197 if (mask[k] != i + m) {
204 dist = (avg_dist[i] + avg_dist[k]) * 0.5;
208 fprintf(stderr,
"ideal_dist_scheme value wrong");
228 d[nz] = w[nz] *
dist;
230 sbot += d[nz] *
dist;
238 for (j = ia[i]; j < ia[i + 1]; j++) {
240 for (l = ia[k]; l < ia[k + 1]; l++) {
241 if (mask[ja[l]] != i + m) {
247 dist = (avg_dist[i] + 2 * avg_dist[k] + avg_dist[ja[l]]) * 0.5;
251 fprintf(stderr,
"ideal_dist_scheme value wrong");
273 d[nz] = w[nz] *
dist;
275 sbot += d[nz] *
dist;
283 lambda[i] *= (-diag_w);
286 w[nz] = -diag_w + lambda[i];
291 assert(nz <= INT_MAX);
296 for (
size_t i = 0; i < nz; i++)
315 double stop = 0, sbot = 0;
320 bool has_nonzero =
false;
321 for (
int i = 0; i < m *
dim; i++) {
328 for (
int i = 0; i < m *
dim; i++)
332 const int *
const ia =
A->ia;
333 const int *
const ja =
A->ja;
334 const double *
const a =
A->a;
355 int *
const iw = sm->
Lw->
ia;
356 int *
const jw = sm->
Lw->
ja;
357 int *
const id = sm->
Lwd->
ia;
358 int *
const jd = sm->
Lwd->
ja;
359 double *
const w = sm->
Lw->
a;
360 double *
const d = sm->
Lwd->
a;
364 for (
int i = 0; i < m; i++) {
367 for (
int j = ia[i]; j < ia[i + 1]; j++) {
372 const double dist = a[j];
376 d[nz] = w[nz] *
dist;
379 sbot += d[nz] *
dist;
387 lambda[i] *= (-diag_w);
389 w[nz] = -diag_w + lambda[i];
395 assert(nz <= INT_MAX);
399 const double s = stop / sbot;
404 for (
size_t i = 0; i < nz; i++)
415 double total = 0,
dist = 0;
418 for (i = 0; i < m; i++) {
420 for (j = 0; j <
dim; j++) {
422 (y[i *
dim + j] - x[i *
dim + j]) * (y[i *
dim + j] - x[i *
dim + j]);
436 int dim,
double *x,
int maxit_sm) {
447 int *ia = A_constr->
ia, *ja = A_constr->
ja, ii, jj, l, ll, i, j;
448 int *irn = data->
irn, *jcn = data->
jcn;
449 double *val = data->
val,
dist, kk, k;
471 assert((!jcn) && (!val));
473 for (i = 0; i < n_constr_nodes; i++) {
474 ii = constr_nodes[i];
475 k = ia[ii + 1] - ia[ii];
476 nz += (size_t)((k + 1) * (k + 1));
483 for (i = 0; i < n_constr_nodes; i++) {
484 ii = constr_nodes[i];
492 k = ia[ii + 1] - ia[ii];
496 val[nz++] = constr_penalty / (
dist);
497 k = constr_penalty / (k *
dist);
498 kk = constr_penalty / (kk *
dist);
499 for (j = ia[ii]; j < ia[ii + 1]; j++) {
504 for (j = ia[ii]; j < ia[ii + 1]; j++) {
509 for (l = ia[ii]; l < ia[ii + 1]; l++) {
527 assert((!jcn) && (!val));
528 int nz = n_constr_nodes;
535 for (i = 0; i < n_constr_nodes; i++) {
536 ii = constr_nodes[i];
542 val[nz++] = constr_penalty / (
dist);
543 for (j = ia[ii]; j < ia[ii + 1]; j++) {
545 for (l = 0; l <
dim; l++) {
546 x00[ii *
dim + l] += x[jj *
dim + l];
549 for (l = 0; l <
dim; l++) {
550 x00[ii *
dim + l] *= constr_penalty / (
dist) / (ia[ii + 1] - ia[ii]);
561 double *d,
double *x,
double scaling) {
563 double res = 0.,
dist;
566 for (i = 0; i < m; i++) {
567 for (j = iw[i]; j < iw[i + 1]; j++) {
576 return 0.5 * res / scaling / scaling;
580 double *x,
int maxit_sm) {
582 int i, j, k, m, *
id, *jd, *iw, *jw, idiag, iter = 0;
583 double *w, *dd, *d, *y =
NULL, *x0 =
NULL, *x00 =
NULL, diag, diff = 1,
588 const double tol = 0.001;
592 x0 = calloc(
dim * m,
sizeof(
double));
596 memcpy(x0, x,
sizeof(
double) *
dim * m);
597 y = calloc(
dim * m,
sizeof(
double));
611 fprintf(stderr,
"initial stress = %f\n",
624 while (iter++ < maxit_sm && diff >
tol) {
626 for (i = 0; i < m; i++) {
629 for (j =
id[i]; j <
id[i + 1]; j++) {
642 for (k = 0; k <
dim; k++)
643 x[jd[j] *
dim + k] += 0.0001 * (
drand() + .0001) * dij;
658 for (i = 0; i < m; i++) {
659 for (j = 0; j <
dim; j++) {
660 y[i *
dim + j] += lambda[i] * x0[i *
dim + j];
668 for (i = 0; i < m; i++) {
669 for (j = 0; j <
dim; j++) {
670 y[i *
dim + j] += x00[i *
dim + j];
681 fprintf(stderr,
"stress1 = %g\n",
690 fprintf(stderr,
"stress2 = %g\n",
697 "Outer iter = %d, cg res = %g, ||x_{k+1}-x_k||/||x_k|| = %g\n",
702 memcpy(x, y,
sizeof(
double) * m *
dim);
706 _statistics[1] += iter - 1;
711 fprintf(stderr,
"iter = %d, final stress = %f\n", iter,
742 bool use_triangularization) {
743 int i, j, k, m =
A->m, *ia =
A->ia, *ja =
A->ja, *iw, *jw, jdiag, nz;
745 double *d, *w, diag_d, diag_w,
dist;
746 double s = 0, stop = 0, sbot = 0;
750 double *avg_dist =
gv_calloc(m,
sizeof(
double));
752 for (i = 0; i < m; i++) {
755 for (j = ia[i]; j < ia[i + 1]; j++) {
775 if (use_triangularization) {
788 if (!sm->
Lw || !sm->
Lwd) {
799 for (i = 0; i < m; i++) {
802 for (j = iw[i]; j < iw[i + 1]; j++) {
824 lambda[i] *= (-diag_w);
827 w[jdiag] = -diag_w + lambda[i];
832 for (i = 0; i < iw[m]; i++)
854 int j, k, l, m =
A->m, *ia =
A->ia, *ja =
A->ja, *
id, *jd;
866 double *avg_dist =
gv_calloc(m,
sizeof(
double));
868 for (
int i = 0; i < m; i++) {
871 for (j = ia[i]; j < ia[i + 1]; j++) {
881 for (
int i = 0; i < m; i++)
885 for (
int i = 0; i < m; i++) {
887 for (j = ia[i]; j < ia[i + 1]; j++) {
894 for (j = ia[i]; j < ia[i + 1]; j++) {
896 for (l = ia[k]; l < ia[k + 1]; l++) {
897 if (mask[ja[l]] != i) {
906 assert(sm->
D !=
NULL);
914 for (
int i = 0; i < m; i++) {
916 for (j = ia[i]; j < ia[i + 1]; j++) {
918 if (mask[k] != i + m) {
921 d[nz] = (avg_dist[i] + avg_dist[k]) * 0.5;
927 for (j = ia[i]; j < ia[i + 1]; j++) {
929 for (l = ia[k]; l < ia[k + 1]; l++) {
930 if (mask[ja[l]] != i + m) {
933 d[nz] = (avg_dist[i] + 2 * avg_dist[k] + avg_dist[ja[l]]) * 0.5;
934 d[nz] = dd[j] + dd[l];
939 assert(nz <= INT_MAX);
1031 fprintf(stderr,
"post processing %f\n",
1032 ((
double)(clock() - cpu)) / CLOCKS_PER_SEC);
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_copy(SparseMatrix A)
SparseMatrix SparseMatrix_add(SparseMatrix A, SparseMatrix B)
SparseMatrix SparseMatrix_new(int m, int n, size_t nz, int type, int format)
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
SparseMatrix call_tri2(int n, int dim, double *xx)
SparseMatrix call_tri(int n, double *x)
static NORETURN void graphviz_exit(int status)
static double dist(int dim, double *x, double *y)
double distance(double *x, int dim, int i, int j)
double vector_product(int n, double *x, double *y)
double distance_cropped(double *x, int dim, int i, int j)
static double len(glCompPoint p)
Arithmetic helper functions.
static bool is_exactly_equal(double a, double b)
are two values precisely the same?
@ ELSCHEME_STRAIGHTLINE_PENALTY2
@ ELSCHEME_STRAIGHTLINE_PENALTY
static void get_edge_label_matrix(relative_position_constraints data, int m, int dim, double *x, SparseMatrix *LL, double **rhs)
StressMajorizationSmoother SparseStressMajorizationSmoother_new(SparseMatrix A, int dim, double *x)
static double total_distance(int m, int dim, double *x, double *y)
static SparseMatrix ideal_distance_matrix(SparseMatrix A, int dim, double *x)
void SparseStressMajorizationSmoother_delete(SparseStressMajorizationSmoother sm)
TriangleSmoother TriangleSmoother_new(SparseMatrix A, int dim, double *x, bool use_triangularization)
double StressMajorizationSmoother_smooth(StressMajorizationSmoother sm, int dim, double *x, int maxit_sm)
void SpringSmoother_delete(SpringSmoother sm)
double SparseStressMajorizationSmoother_smooth(SparseStressMajorizationSmoother sm, int dim, double *x, int maxit_sm)
void post_process_smoothing(int dim, SparseMatrix A, spring_electrical_control ctrl, double *x)
void TriangleSmoother_smooth(TriangleSmoother sm, int dim, double *x)
void StressMajorizationSmoother_delete(StressMajorizationSmoother sm)
SpringSmoother SpringSmoother_new(SparseMatrix A, int dim, spring_electrical_control ctrl, double *x)
StressMajorizationSmoother StressMajorizationSmoother2_new(SparseMatrix A, int dim, double lambda0, double *x, int ideal_dist_scheme)
static UNUSED double get_stress(int m, int dim, int *iw, int *jw, double *w, double *d, double *x, double scaling)
void TriangleSmoother_delete(TriangleSmoother sm)
void SpringSmoother_smooth(SpringSmoother sm, SparseMatrix A, int dim, double *x)
#define TriangleSmoother_struct
@ SM_SCHEME_NORMAL_ELABEL
double SparseMatrix_solve(SparseMatrix A, int dim, double *x0, double *rhs, double tol, double maxit)
void spring_electrical_spring_embedding(int dim, SparseMatrix A0, SparseMatrix D, spring_electrical_control *ctrl, double *x, int *flag)
@ SMOOTHING_STRESS_MAJORIZATION_GRAPH_DIST
@ SMOOTHING_STRESS_MAJORIZATION_POWER_DIST
@ SMOOTHING_STRESS_MAJORIZATION_AVG_DIST
size_t nz
the actual length used is nz, for CSR/CSC matrix this is the same as ia[n]
spring_electrical_control ctrl
SparseMatrix Lwd
the laplacian like matrix with offdiag = -scaling × dᵢⱼ ÷ wᵢⱼ. RHS in stress majorization = Lwd....
void(* data_deallocator)(void *)
SparseMatrix Lw
the weighted laplacian. with offdiag = -1 ÷ wᵢⱼ
bool random_start
whether to apply SE from a random layout, or from existing layout
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t
abstraction for squashing compiler warnings for unused symbols