OverlapSmoother OverlapSmoother_new(SparseMatrix A, int m, int dim, real lambda0, real *x, real *width, int include_original_graph, int neighborhood_only, real *max_overlap, real *min_overlap, int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int shrink ){ OverlapSmoother sm; int i, j, k, *iw, *jw, jdiag; SparseMatrix B; real *lambda, *d, *w, diag_d, diag_w, dist; assert((!A) || SparseMatrix_is_symmetric(A, FALSE)); sm = GNEW(struct OverlapSmoother_struct); sm->scheme = SM_SCHEME_NORMAL; if (constr_nodes && n_constr_nodes > 0 && edge_labeling_scheme != ELSCHEME_NONE){ sm->scheme = SM_SCHEME_NORMAL_ELABEL; sm->data = relative_position_constraints_new(A_constr, edge_labeling_scheme, n_constr_nodes, constr_nodes); sm->data_deallocator = relative_position_constraints_delete; } else { sm->data = NULL; } sm->tol_cg = 0.01; sm->maxit_cg = sqrt((double) A->m); lambda = sm->lambda = N_GNEW(m,real); for (i = 0; i < m; i++) sm->lambda[i] = lambda0; B= call_tri(m, dim, x); if (!neighborhood_only){ SparseMatrix C, D; C = get_overlap_graph(dim, m, x, width, 0); D = SparseMatrix_add(B, C); SparseMatrix_delete(B); SparseMatrix_delete(C); B = D; } if (include_original_graph){ sm->Lw = SparseMatrix_add(A, B); SparseMatrix_delete(B); } else { sm->Lw = B; } sm->Lwd = SparseMatrix_copy(sm->Lw); #ifdef DEBUG { FILE *fp; fp = fopen("/tmp/111","w"); export_embedding(fp, dim, sm->Lwd, x, NULL); fclose(fp); } #endif if (!(sm->Lw) || !(sm->Lwd)) { OverlapSmoother_delete(sm); return NULL; } assert((sm->Lwd)->type == MATRIX_TYPE_REAL); ideal_distance_avoid_overlap(dim, sm->Lwd, x, width, (real*) (sm->Lwd->a), max_overlap, min_overlap); /* no overlap at all! */ if (*max_overlap < 1 && shrink){ real scale_sta = MIN(1, *max_overlap*1.0001), scale_sto = 1; if (Verbose) fprintf(stderr," no overlap (overlap = %f), rescale to shrink\n", *max_overlap - 1); scale_sta = overlap_scaling(dim, m, x, width, scale_sta, scale_sto, 0.0001, 15); *max_overlap = 1; goto RETURN; } iw = sm->Lw->ia; jw = sm->Lw->ja; w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a; for (i = 0; i < m; i++){ diag_d = diag_w = 0; jdiag = -1; for (j = iw[i]; j < iw[i+1]; j++){ k = jw[j]; if (k == i){ jdiag = j; continue; } if (d[j] > 0){/* those edges that needs expansion */ w[j] = -100/d[j]/d[j]; /*w[j] = 100/d[j]/d[j];*/ } else {/* those that needs shrinking is set to negative in ideal_distance_avoid_overlap */ /*w[j] = 1/d[j]/d[j];*/ w[j] = -1/d[j]/d[j]; d[j] = -d[j]; } dist = d[j]; diag_w += w[j]; d[j] = w[j]*dist; diag_d += d[j]; } lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */ assert(jdiag >= 0); w[jdiag] = -diag_w + lambda[i]; d[jdiag] = -diag_d; } RETURN: return sm; }
TriangleSmoother TriangleSmoother_new(SparseMatrix A, int dim, real lambda0, real *x, int use_triangularization){ TriangleSmoother sm; int i, j, k, m = A->m, *ia = A->ia, *ja = A->ja, *iw, *jw, jdiag, nz; SparseMatrix B; real *avg_dist, *lambda, *d, *w, diag_d, diag_w, dist; real s = 0, stop = 0, sbot = 0; assert(SparseMatrix_is_symmetric(A, FALSE)); avg_dist = N_GNEW(m,real); for (i = 0; i < m ;i++){ avg_dist[i] = 0; nz = 0; for (j = ia[i]; j < ia[i+1]; j++){ if (i == ja[j]) continue; avg_dist[i] += distance(x, dim, i, ja[j]); nz++; } assert(nz > 0); avg_dist[i] /= nz; } sm = N_GNEW(1,struct TriangleSmoother_struct); sm->scaling = 1; sm->data = NULL; sm->scheme = SM_SCHEME_NORMAL; sm->tol_cg = 0.01; sm->maxit_cg = sqrt((double) A->m); lambda = sm->lambda = N_GNEW(m,real); for (i = 0; i < m; i++) sm->lambda[i] = lambda0; if (m > 2){ if (use_triangularization){ B= call_tri(m, dim, x); } else { B= call_tri2(m, dim, x); } } else { B = SparseMatrix_copy(A); } sm->Lw = SparseMatrix_add(A, B); SparseMatrix_delete(B); sm->Lwd = SparseMatrix_copy(sm->Lw); if (!(sm->Lw) || !(sm->Lwd)) { TriangleSmoother_delete(sm); return NULL; } iw = sm->Lw->ia; jw = sm->Lw->ja; w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a; for (i = 0; i < m; i++){ diag_d = diag_w = 0; jdiag = -1; for (j = iw[i]; j < iw[i+1]; j++){ k = jw[j]; if (k == i){ jdiag = j; continue; } /* w[j] = -1./(ia[i+1]-ia[i]+ia[ja[j]+1]-ia[ja[j]]); w[j] = -2./(avg_dist[i]+avg_dist[k]); w[j] = -1.*/;/* use unit weight for now, later can try 1/(deg(i)+deg(k)) */ dist = pow(distance_cropped(x,dim,i,k),0.6); w[j] = 1/(dist*dist); diag_w += w[j]; /* d[j] = w[j]*distance(x,dim,i,k); d[j] = w[j]*(avg_dist[i] + avg_dist[k])*0.5;*/ d[j] = w[j]*dist; stop += d[j]*distance(x,dim,i,k); sbot += d[j]*dist; diag_d += d[j]; } lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */ assert(jdiag >= 0); w[jdiag] = -diag_w + lambda[i]; d[jdiag] = -diag_d; } s = stop/sbot; for (i = 0; i < iw[m]; i++) d[i] *= s; sm->scaling = s; FREE(avg_dist); return sm; }
real StressMajorizationSmoother_smooth(StressMajorizationSmoother sm, int dim, real *x, int maxit_sm, real tol) { SparseMatrix Lw = sm->Lw, Lwd = sm->Lwd, Lwdd = NULL; int i, j, k, m, *id, *jd, *iw, *jw, idiag, flag = 0, iter = 0; real *w, *dd, *d, *y = NULL, *x0 = NULL, *x00 = NULL, diag, diff = 1, *lambda = sm->lambda, res, alpha = 0., M = 0.; SparseMatrix Lc = NULL; real dij, dist; Lwdd = SparseMatrix_copy(Lwd); m = Lw->m; x0 = N_GNEW(dim*m,real); if (!x0) goto RETURN; x0 = MEMCPY(x0, x, sizeof(real)*dim*m); y = N_GNEW(dim*m,real); if (!y) goto RETURN; id = Lwd->ia; jd = Lwd->ja; d = (real*) Lwd->a; dd = (real*) Lwdd->a; w = (real*) Lw->a; iw = Lw->ia; jw = Lw->ja; #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "initial stress = %f\n", get_stress(m, dim, iw, jw, w, d, x, sm->scaling, sm->data, 1)); #endif /* for the additional matrix L due to the position constraints */ if (sm->scheme == SM_SCHEME_NORMAL_ELABEL){ get_edge_label_matrix(sm->data, m, dim, x, &Lc, &x00); if (Lc) Lw = SparseMatrix_add(Lw, Lc); } else if (sm->scheme == SM_SCHEME_UNIFORM_STRESS){ alpha = ((real*) (sm->data))[0]; M = ((real*) (sm->data))[1]; } while (iter++ < maxit_sm && diff > tol){ #ifdef GVIEWER if (Gviewer) { drawScene(); if (iter%2 == 0) gviewer_dump_current_frame(); } #endif if (sm->scheme != SM_SCHEME_STRESS_APPROX){ for (i = 0; i < m; i++){ idiag = -1; diag = 0.; for (j = id[i]; j < id[i+1]; j++){ if (i == jd[j]) { idiag = j; continue; } dist = distance(x, dim, i, jd[j]); //if (d[j] >= -0.0001*dist){ // /* sometimes d[j] = 0 and ||x_i-x_j||=0*/ // dd[j] = d[j]/MAX(0.0001, dist); if (d[j] == 0){ dd[j] = 0; } else { if (dist == 0){ dij = d[j]/w[j];/* the ideal distance */ /* perturb so points do not sit at the same place */ for (k = 0; k < dim; k++) x[jd[j]*dim+k] += 0.0001*(drand()+.0001)*dij; dist = distance(x, dim, i, jd[j]); } dd[j] = d[j]/dist; #if 0 /* if two points are at the same place, we do not want a huge entry, as this cause problem with CG./ In any case, at thw limit d[j] == ||x[i] - x[jd[j]]||, or close. */ if (dist < -d[j]*0.0000001){ dd[j] = -10000.; } else { dd[j] = d[j]/dist; } #endif } diag += dd[j]; } assert(idiag >= 0); dd[idiag] = -diag; } /* solve (Lw+lambda*I) x = Lwdd y + lambda x0 */ SparseMatrix_multiply_dense(Lwdd, FALSE, x, FALSE, &y, FALSE, dim); } else { for (i = 0; i < m; i++){ for (j = 0; j < dim; j++){ y[i*dim+j] = 0;/* for stress_approx scheme, the whole rhs is calculated in stress_maxent_augment_rhs */ } } } if (lambda){/* is there a penalty term? */ for (i = 0; i < m; i++){ for (j = 0; j < dim; j++){ y[i*dim+j] += lambda[i]*x0[i*dim+j]; } } } /* additional term added to the rhs */ switch (sm->scheme){ case SM_SCHEME_NORMAL_ELABEL: { for (i = 0; i < m; i++){ for (j = 0; j < dim; j++){ y[i*dim+j] += x00[i*dim+j]; } } break; } case SM_SCHEME_UNIFORM_STRESS:{/* this part can be done more efficiently using octree approximation */ uniform_stress_augment_rhs(m, dim, x, y, alpha, M); break; } #if UNIMPEMENTED case SM_SCHEME_MAXENT:{ #ifdef GVIEWER if (Gviewer){ char *lab; lab = MALLOC(sizeof(char)*100); sprintf(lab,"maxent. alpha=%10.2g, iter=%d",stress_maxent_data_get_alpha(sm->data), iter); gviewer_set_label(lab); FREE(lab); } #endif stress_maxent_augment_rhs_fast(sm, dim, x, y, &flag); if (flag) goto RETURN; break; } case SM_SCHEME_STRESS_APPROX:{ stress_approx_augment_rhs(sm, dim, x, y, &flag); if (flag) goto RETURN; break; } case SM_SCHEME_STRESS:{ #ifdef GVIEWER if (Gviewer){ char *lab; lab = MALLOC(sizeof(char)*100); sprintf(lab,"pmds(k), iter=%d", iter); gviewer_set_label(lab); FREE(lab); } #endif } #endif /* UNIMPEMENTED */ default: break; } #ifdef DEBUG_PRINT if (Verbose) { fprintf(stderr, "stress1 = %g\n",get_stress(m, dim, iw, jw, w, d, x, sm->scaling, sm->data, 1)); } #endif if (sm->scheme == SM_SCHEME_UNIFORM_STRESS){ res = uniform_stress_solve(Lw, alpha, dim, x, y, sm->tol_cg, sm->maxit_cg, &flag); } else { res = SparseMatrix_solve(Lw, dim, x, y, sm->tol_cg, sm->maxit_cg, SOLVE_METHOD_CG, &flag); //res = SparseMatrix_solve(Lw, dim, x, y, sm->tol_cg, 1, SOLVE_METHOD_JACOBI, &flag); } if (flag) goto RETURN; #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "stress2 = %g\n",get_stress(m, dim, iw, jw, w, d, y, sm->scaling, sm->data, 1)); #endif diff = total_distance(m, dim, x, y)/sqrt(vector_product(m*dim, x, x)); #ifdef DEBUG_PRINT if (Verbose){ fprintf(stderr, "Outer iter = %d, cg res = %g, ||x_{k+1}-x_k||/||x_k|| = %g\n",iter, res, diff); } #endif MEMCPY(x, y, sizeof(real)*m*dim); } #ifdef DEBUG _statistics[1] += iter-1; #endif #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "iter = %d, final stress = %f\n", iter, get_stress(m, dim, iw, jw, w, d, x, sm->scaling, sm->data, 1)); #endif RETURN: SparseMatrix_delete(Lwdd); if (Lc) { SparseMatrix_delete(Lc); SparseMatrix_delete(Lw); } if (x0) FREE(x0); if (y) FREE(y); if (x00) FREE(x00); return diff; }
real StressMajorizationSmoother_smooth(StressMajorizationSmoother sm, int dim, real *x, int maxit_sm, real tol) { SparseMatrix Lw = sm->Lw, Lwd = sm->Lwd, Lwdd = NULL; int i, j, m, *id, *jd, *iw, *jw, idiag, flag = 0, iter = 0; real *w, *dd, *d, *y = NULL, *x0 = NULL, *x00 = NULL, diag, diff = 1, *lambda = sm->lambda, maxit, res, alpha = 0., M = 0.; SparseMatrix Lc = NULL; Lwdd = SparseMatrix_copy(Lwd); m = Lw->m; x0 = N_GNEW(dim*m,real); if (!x0) goto RETURN; x0 = MEMCPY(x0, x, sizeof(real)*dim*m); y = N_GNEW(dim*m,real); if (!y) goto RETURN; id = Lwd->ia; jd = Lwd->ja; d = (real*) Lwd->a; dd = (real*) Lwdd->a; w = (real*) Lw->a; iw = Lw->ia; jw = Lw->ja; /* for the additional matrix L due to the position constraints */ if (sm->scheme == SM_SCHEME_NORMAL_ELABEL){ get_edge_label_matrix(sm->data, m, dim, x, &Lc, &x00); if (Lc) Lw = SparseMatrix_add(Lw, Lc); } else if (sm->scheme == SM_SCHEME_UNIFORM_STRESS){ alpha = ((real*) (sm->data))[0]; M = ((real*) (sm->data))[1]; } while (iter++ < maxit_sm && diff > tol){ for (i = 0; i < m; i++){ idiag = -1; diag = 0.; for (j = id[i]; j < id[i+1]; j++){ if (i == jd[j]) { idiag = j; continue; } dd[j] = d[j]/distance_cropped(x, dim, i, jd[j]); diag += dd[j]; } assert(idiag >= 0); dd[idiag] = -diag; } /* solve (Lw+lambda*I) x = Lwdd y + lambda x0 */ SparseMatrix_multiply_dense(Lwdd, FALSE, x, FALSE, &y, FALSE, dim); if (lambda){/* is there a penalty term? */ for (i = 0; i < m; i++){ for (j = 0; j < dim; j++){ y[i*dim+j] += lambda[i]*x0[i*dim+j]; } } } if (sm->scheme == SM_SCHEME_NORMAL_ELABEL){ for (i = 0; i < m; i++){ for (j = 0; j < dim; j++){ y[i*dim+j] += x00[i*dim+j]; } } } else if (sm->scheme == SM_SCHEME_UNIFORM_STRESS){/* this part can be done more efficiently using octree approximation */ uniform_stress_augment_rhs(m, dim, x, y, alpha, M); } #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "stress1 = %f\n",get_stress(m, dim, iw, jw, w, d, x, sm->scaling, sm->data, 0)); #endif maxit = sqrt((double) m); if (sm->scheme == SM_SCHEME_UNIFORM_STRESS){ res = uniform_stress_solve(Lw, alpha, dim, x, y, 0.01, maxit, &flag); } else { res = SparseMatrix_solve(Lw, dim, x, y, 0.01, maxit, SOLVE_METHOD_CG, &flag); } if (flag) goto RETURN; #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "stress2 = %f\n",get_stress(m, dim, iw, jw, w, d, y, sm->scaling, sm->data, 0)); #endif diff = total_distance(m, dim, x, y)/sqrt(vector_product(m*dim, x, x)); #ifdef DEBUG_PRINT if (Verbose){ fprintf(stderr, "Outer iter = %d, res = %g Stress Majorization diff = %g\n",iter, res, diff); } #endif MEMCPY(x, y, sizeof(real)*m*dim); } #ifdef DEBUG _statistics[1] += iter-1; #endif RETURN: SparseMatrix_delete(Lwdd); if (Lc) { SparseMatrix_delete(Lc); SparseMatrix_delete(Lw); } if (x0) FREE(x0); if (y) FREE(y); if (x00) FREE(x00); return diff; }