35#define node_degree(i) (ia[(i) + 1] - ia[(i)])
46 const int *
const ia =
D->ia;
47 const int *
const ja =
D->ja;
53 double *
const d =
D->a;
55 size_t *
const mask =
gv_calloc(
D->m,
sizeof(
size_t));
56 for (
size_t i = 0; i <
D->m; i++)
59 for (
size_t i = 0; i <
D->m; i++) {
62 for (
int j = ia[i]; j < ia[i + 1]; j++) {
67 for (
int j = ia[i]; j < ia[i + 1]; j++) {
72 for (
int l = ia[k]; l < ia[k + 1]; l++) {
84 for (
size_t i = 0; i <
D->m; i++) {
85 for (
int j = ia[i]; j < ia[i + 1]; j++) {
97 for (
size_t i = 0; i <
D->m; i++) {
98 for (
int j = ia[i]; j < ia[i + 1]; j++) {
111 double *x,
int ideal_dist_scheme) {
115 int j, k, l, *ia =
A->ia, *ja =
A->ja, *iw, *jw, *
id, *jd;
116 const size_t m =
A->m;
117 double *d, *w, *lambda;
118 double diag_d, diag_w,
dist,
s = 0, stop = 0, sbot = 0;
131 sm->
maxit_cg = floor(sqrt((
double)
A->m));
134 for (
size_t i = 0; i < m; i++)
136 size_t *
const mask =
gv_calloc(m,
sizeof(
size_t));
138 double *avg_dist =
gv_calloc(m,
sizeof(
double));
140 for (
size_t i = 0; i < m; i++) {
143 for (j = ia[i]; j < ia[i + 1]; j++) {
153 for (
size_t i = 0; i < m; i++)
157 for (
size_t i = 0; i < m; i++) {
159 for (j = ia[i]; j < ia[i + 1]; j++) {
166 for (j = ia[i]; j < ia[i + 1]; j++) {
168 for (l = ia[k]; l < ia[k + 1]; l++) {
169 if (mask[ja[l]] != i) {
193 for (
size_t i = 0; i < m; i++) {
196 for (j = ia[i]; j < ia[i + 1]; j++) {
198 if (mask[k] != i + m) {
205 dist = (avg_dist[i] + avg_dist[k]) * 0.5;
209 fprintf(stderr,
"ideal_dist_scheme value wrong");
229 d[nz] = w[nz] *
dist;
231 sbot += d[nz] *
dist;
239 for (j = ia[i]; j < ia[i + 1]; j++) {
241 for (l = ia[k]; l < ia[k + 1]; l++) {
242 if (mask[ja[l]] != i + m) {
248 dist = (avg_dist[i] + 2 * avg_dist[k] + avg_dist[ja[l]]) * 0.5;
252 fprintf(stderr,
"ideal_dist_scheme value wrong");
274 d[nz] = w[nz] *
dist;
276 sbot += d[nz] *
dist;
284 lambda[i] *= (-diag_w);
287 w[nz] = -diag_w + lambda[i];
292 assert(nz <= INT_MAX);
297 for (
size_t i = 0; i < nz; i++)
315 const size_t m =
A->m;
316 double stop = 0, sbot = 0;
321 bool has_nonzero =
false;
322 for (
size_t i = 0; i < m * (size_t)
dim; i++) {
329 for (
size_t i = 0; i < m * (size_t)
dim; i++)
333 const int *
const ia =
A->ia;
334 const int *
const ja =
A->ja;
335 const double *
const a =
A->a;
344 sm->
maxit_cg = floor(sqrt((
double)
A->m));
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 (
size_t 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 (
size_t i = 0; i < m; i++) {
420 for (j = 0; j <
dim; j++) {
421 dist += (y[(int)i *
dim + j] - x[(
int)i *
dim + j]) *
422 (y[(
int)i *
dim + j] - x[(int)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 (
size_t i = 0; i < m; i++) {
567 for (j = iw[i]; j < iw[i + 1]; j++) {
568 if ((
int)i == jw[j]) {
576 return 0.5 * res / scaling / scaling;
580 double *x,
int maxit_sm) {
582 int j, k, *
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;
591 const size_t m = Lw->
m;
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 (
size_t i = 0; i < m; i++) {
629 for (j =
id[i]; j <
id[i + 1]; j++) {
630 if ((
int)i == jd[j]) {
642 for (k = 0; k <
dim; k++)
643 x[jd[j] *
dim + k] += 0.0001 * (
drand() + .0001) * dij;
658 for (
size_t i = 0; i < m; i++) {
659 for (j = 0; j <
dim; j++) {
660 y[(int)i *
dim + j] += lambda[i] * x0[(
int)i *
dim + j];
668 for (
size_t i = 0; i < m; i++) {
669 for (j = 0; j <
dim; j++) {
670 y[(int)i *
dim + j] += x00[(
int)i *
dim + j];
681 fprintf(stderr,
"stress1 = %g\n",
690 fprintf(stderr,
"stress2 = %g\n",
698 "Outer iter = %d, cg res = %g, ||x_{k+1}-x_k||/||x_k|| = %g\n",
703 memcpy(x, y,
sizeof(
double) * m *
dim);
707 _statistics[1] += iter - 1;
712 fprintf(stderr,
"iter = %d, final stress = %f\n", iter,
743 bool use_triangularization) {
744 int j, k, *ia =
A->ia, *ja =
A->ja, *iw, *jw, jdiag, nz;
745 const size_t m =
A->m;
747 double *d, *w, diag_d, diag_w,
dist;
748 double s = 0, stop = 0, sbot = 0;
752 double *avg_dist =
gv_calloc(m,
sizeof(
double));
754 for (
size_t i = 0; i < m; i++) {
757 for (j = ia[i]; j < ia[i + 1]; j++) {
772 sm->
maxit_cg = floor(sqrt((
double)
A->m));
777 if (use_triangularization) {
790 if (!sm->
Lw || !sm->
Lwd) {
801 for (
size_t i = 0; i < m; i++) {
804 for (j = iw[i]; j < iw[i + 1]; j++) {
826 lambda[i] *= (-diag_w);
829 w[jdiag] = -diag_w + lambda[i];
834 for (
int i = 0; i < iw[m]; i++)
856 int j, k, l, *ia =
A->ia, *ja =
A->ja, *
id, *jd;
857 const size_t m =
A->m;
867 size_t *
const mask =
gv_calloc(m,
sizeof(
size_t));
869 for (
size_t i = 0; i < m; i++)
873 for (
size_t i = 0; i < m; i++) {
875 for (j = ia[i]; j < ia[i + 1]; j++) {
882 for (j = ia[i]; j < ia[i + 1]; j++) {
884 for (l = ia[k]; l < ia[k + 1]; l++) {
885 if (mask[ja[l]] != i) {
894 assert(sm->
D !=
NULL);
902 for (
size_t i = 0; i < m; i++) {
904 for (j = ia[i]; j < ia[i + 1]; j++) {
906 if (mask[k] != i + m) {
914 for (j = ia[i]; j < ia[i + 1]; j++) {
916 for (l = ia[k]; l < ia[k + 1]; l++) {
917 if (mask[ja[l]] != i + m) {
920 d[nz] = dd[j] + dd[l];
925 assert(nz <= INT_MAX);
1014 fprintf(stderr,
"post processing %f\n",
1015 ((
double)(clock() - cpu)) / CLOCKS_PER_SEC);
SparseMatrix SparseMatrix_new(size_t m, int n, size_t nz, int type, int format)
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, size_t 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)
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(size_t 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
StressMajorizationSmoother SparseStressMajorizationSmoother_new(SparseMatrix A, int dim, double *x)
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)
static double total_distance(size_t m, int dim, double *x, double *y)
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)
static UNUSED double get_stress(size_t m, int dim, int *iw, int *jw, double *w, double *d, double *x, double scaling)
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 void get_edge_label_matrix(relative_position_constraints data, size_t m, int dim, double *x, SparseMatrix *LL, double **rhs)
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)
@ 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