34#define node_degree(i) (ia[(i)+1] - ia[(i)])
40 int *ia, *ja, i, j, k, l, nz;
42 double len, di, sum, sumd;
57 for (i = 0; i <
D->m; i++) mask[i] = -1;
59 for (i = 0; i <
D->m; i++){
62 for (j = ia[i]; j < ia[i+1]; j++){
63 if (i == ja[j])
continue;
66 for (j = ia[i]; j < ia[i+1]; j++){
70 for (l = ia[k]; l < ia[k+1]; l++){
71 if (mask[ja[l]] == i)
len--;
81 for (i = 0; i <
D->m; i++){
82 for (j = ia[i]; j < ia[i+1]; j++){
83 if (i == ja[j])
continue;
89 sum /= nz; sumd /= nz;
92 for (i = 0; i <
D->m; i++){
93 for (j = ia[i]; j < ia[i+1]; j++){
94 if (i == ja[j])
continue;
105 int ideal_dist_scheme){
109 int j, k, l, m =
A->m, *ia =
A->ia, *ja =
A->ja, *iw, *jw, *
id, *jd;
110 double *d, *w, *lambda;
111 double diag_d, diag_w,
dist,
s = 0, stop = 0, sbot = 0;
126 for (
int i = 0; i < m; i++) sm->
lambda[i] = lambda0;
129 double *avg_dist =
gv_calloc(m,
sizeof(
double));
131 for (
int i = 0; i < m ;i++){
134 for (j = ia[i]; j < ia[i+1]; j++){
135 if (i == ja[j])
continue;
143 for (
int i = 0; i < m; i++) mask[i] = -1;
146 for (
int i = 0; i < m; i++){
148 for (j = ia[i]; j < ia[i+1]; j++){
155 for (j = ia[i]; j < ia[i+1]; j++){
157 for (l = ia[k]; l < ia[k+1]; l++){
158 if (mask[ja[l]] != i){
181 for (
int i = 0; i < m; i++){
184 for (j = ia[i]; j < ia[i+1]; j++){
193 dist = (avg_dist[i] + avg_dist[k])*0.5;
197 fprintf(stderr,
"ideal_dist_scheme value wrong");
226 for (j = ia[i]; j < ia[i+1]; j++){
228 for (l = ia[k]; l < ia[k+1]; l++){
229 if (mask[ja[l]] != i+m){
235 dist = (avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5;
239 fprintf(stderr,
"ideal_dist_scheme value wrong");
270 lambda[i] *= (-diag_w);
272 w[nz] = -diag_w + lambda[i];
277 assert(nz <= INT_MAX);
282 for (
size_t i = 0; i < nz; i++) d[i] *=
s;
299 double stop = 0, sbot = 0;
304 bool has_nonzero =
false;
305 for (
int i = 0; i < m *
dim; i++) {
312 for (
int i = 0; i < m*
dim; i++) x[i] = 72*
drand();
315 const int *
const ia =
A->ia;
316 const int *
const ja =
A->ja;
317 const double *
const a =
A->a;
337 int *
const iw = sm->
Lw->
ia;
338 int *
const jw = sm->
Lw->
ja;
339 int *
const id = sm->
Lwd->
ia;
340 int *
const jd = sm->
Lwd->
ja;
341 double *
const w = sm->
Lw->
a;
342 double *
const d = sm->
Lwd->
a;
346 for (
int i = 0; i < m; i++){
349 for (
int j = ia[i]; j < ia[i+1]; j++){
354 const double dist = a[j];
369 lambda[i] *= (-diag_w);
370 w[nz] = -diag_w + lambda[i];
376 assert(nz <= INT_MAX);
380 const double s = stop / sbot;
385 for (
size_t i = 0; i < nz; i++) d[i] *=
s;
396 double total = 0,
dist = 0;
399 for (i = 0; i < m; i++){
401 for (j = 0; j <
dim; j++){
426 int *ia = A_constr->
ia, *ja = A_constr->
ja, ii, jj, l, ll, i, j;
427 int *irn = data->
irn, *jcn = data->
jcn;
428 double *val = data->
val,
dist, kk, k;
450 assert((!jcn) && (!val));
452 for (i = 0; i < n_constr_nodes; i++){
453 ii = constr_nodes[i];
454 k = ia[ii+1] - ia[ii];
455 nz += (size_t)((k + 1) * (k + 1));
463 for (i = 0; i < n_constr_nodes; i++){
464 ii = constr_nodes[i];
465 jj = ja[ia[ii]]; ll = ja[ia[ii] + 1];
466 if (jj == ll)
continue;
470 k = ia[ii+1] - ia[ii];
472 irn[nz] = ii; jcn[nz] = ii; val[nz++] = constr_penalty/(
dist);
473 k = constr_penalty/(k*
dist); kk = constr_penalty/(kk*
dist);
474 for (j = ia[ii]; j < ia[ii+1]; j++){
475 irn[nz] = ii; jcn[nz] = ja[j]; val[nz++] = -k;
477 for (j = ia[ii]; j < ia[ii+1]; j++){
479 irn[nz] = jj; jcn[nz] = ii; val[nz++] = -k;
480 for (l = ia[ii]; l < ia[ii+1]; l++){
482 irn[nz] = jj; jcn[nz] = ll; val[nz++] = kk;
492 assert((!jcn) && (!val));
493 int nz = n_constr_nodes;
500 for (i = 0; i < n_constr_nodes; i++){
501 ii = constr_nodes[i];
502 jj = ja[ia[ii]]; ll = ja[ia[ii] + 1];
504 irn[nz] = ii; jcn[nz] = ii; val[nz++] = constr_penalty/(
dist);
505 for (j = ia[ii]; j < ia[ii+1]; j++){
507 for (l = 0; l <
dim; l++){
508 x00[ii*
dim+l] += x[jj*
dim+l];
511 for (l = 0; l <
dim; l++) {
512 x00[ii*
dim+l] *= constr_penalty/(
dist)/(ia[ii+1] - ia[ii]);
523 double *d,
double *x,
double scaling) {
525 double res = 0.,
dist;
528 for (i = 0; i < m; i++){
529 for (j = iw[i]; j < iw[i+1]; j++){
537 return 0.5*res/scaling/scaling;
543 int i, j, k, m, *
id, *jd, *iw, *jw, idiag, iter = 0;
544 double *w, *dd, *d, *y =
NULL, *x0 =
NULL, *x00 =
NULL, diag, diff = 1, *lambda = sm->
lambda;
548 const double tol = 0.001;
553 x0 = calloc(
dim*m,
sizeof(
double));
556 memcpy(x0, x,
sizeof(
double)*
dim*m);
557 y = calloc(
dim*m,
sizeof(
double));
560 id = Lwd->ia; jd = Lwd->ja;
564 iw = Lw->
ia; jw = Lw->
ja;
578 while (iter++ < maxit_sm && diff >
tol){
580 for (i = 0; i < m; i++){
583 for (j =
id[i]; j <
id[i+1]; j++){
596 for (k = 0; k <
dim; k++) x[jd[j]*
dim+k] += 0.0001*(
drand()+.0001)*dij;
611 for (i = 0; i < m; i++){
612 for (j = 0; j <
dim; j++){
613 y[i*
dim+j] += lambda[i]*x0[i*
dim+j];
621 for (i = 0; i < m; i++){
622 for (j = 0; j <
dim; j++){
623 y[i*
dim+j] += x00[i*
dim+j];
646 fprintf(stderr,
"Outer iter = %d, cg res = %g, ||x_{k+1}-x_k||/||x_k|| = %g\n",iter, res, diff);
651 memcpy(x, y,
sizeof(
double)*m*
dim);
655 _statistics[1] += iter-1;
659 if (
Verbose) fprintf(stderr,
"iter = %d, final stress = %f\n", iter,
get_stress(m,
dim, iw, jw, w, d, x, sm->
scaling));
686 bool use_triangularization) {
687 int i, j, k, m =
A->m, *ia =
A->ia, *ja =
A->ja, *iw, *jw, jdiag, nz;
689 double *d, *w, diag_d, diag_w,
dist;
690 double s = 0, stop = 0, sbot = 0;
694 double *avg_dist =
gv_calloc(m,
sizeof(
double));
696 for (i = 0; i < m ;i++){
699 for (j = ia[i]; j < ia[i+1]; j++){
700 if (i == ja[j])
continue;
718 if (use_triangularization){
733 if (!sm->
Lw || !sm->
Lwd) {
743 for (i = 0; i < m; i++){
746 for (j = iw[i]; j < iw[i+1]; j++){
768 lambda[i] *= (-diag_w);
771 w[jdiag] = -diag_w + lambda[i];
776 for (i = 0; i < iw[m]; i++) d[i] *=
s;
796 int j, k, l, m =
A->m, *ia =
A->ia, *ja =
A->ja, *
id, *jd;
808 double *avg_dist =
gv_calloc(m,
sizeof(
double));
810 for (
int i = 0; i < m ;i++){
813 for (j = ia[i]; j < ia[i+1]; j++){
814 if (i == ja[j])
continue;
822 for (
int i = 0; i < m; i++) mask[i] = -1;
825 for (
int i = 0; i < m; i++){
827 for (j = ia[i]; j < ia[i+1]; j++){
834 for (j = ia[i]; j < ia[i+1]; j++){
836 for (l = ia[k]; l < ia[k+1]; l++){
837 if (mask[ja[l]] != i){
846 assert(sm->
D !=
NULL);
848 id = sm->
D->
ia; jd = sm->
D->
ja;
853 for (
int i = 0; i < m; i++){
855 for (j = ia[i]; j < ia[i+1]; j++){
860 d[nz] = (avg_dist[i] + avg_dist[k])*0.5;
866 for (j = ia[i]; j < ia[i+1]; j++){
868 for (l = ia[k]; l < ia[k+1]; l++){
869 if (mask[ja[l]] != i+m){
872 d[nz] = (avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5;
878 assert(nz <= INT_MAX);
967 if (
Verbose) fprintf(stderr,
"post processing %f\n",((
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