void StressMajorizationSmoother_delete(StressMajorizationSmoother sm){ if (!sm) return; if (sm->Lw) SparseMatrix_delete(sm->Lw); if (sm->Lwd) SparseMatrix_delete(sm->Lwd); if (sm->lambda) FREE(sm->lambda); if (sm->data) sm->data_deallocator(sm->data); FREE(sm); }
void Multilevel_delete(Multilevel grid){ if (!grid) return; if (grid->A){ if (grid->level == 0) { if (grid->delete_top_level_A) SparseMatrix_delete(grid->A); } else { SparseMatrix_delete(grid->A); } } SparseMatrix_delete(grid->P); SparseMatrix_delete(grid->R); if (grid->node_weights && grid->level > 0) FREE(grid->node_weights); Multilevel_delete(grid->next); FREE(grid); }
void mq_clustering(SparseMatrix A, int inplace, int maxcluster, int use_value, int *nclusters, int **assignment, real *mq, int *flag) { /* find a clustering of vertices by maximize mq A: symmetric square matrix n x n. If real value, value will be used as edges weights, otherwise edge weights are considered as 1. inplace: whether A can e modified. If true, A will be modified by removing diagonal. maxcluster: used to specify the maximum number of cluster desired, e.g., maxcluster=10 means that a maximum of 10 clusters . is desired. this may not always be realized, and mq may be low when this is specified. Default: maxcluster = 0 nclusters: on output the number of clusters assignment: dimension n. Node i is assigned to cluster "assignment[i]". 0 <= assignment < nclusters */ SparseMatrix B; *flag = 0; assert(A->m == A->n); B = SparseMatrix_symmetrize(A, FALSE); if (!inplace && B == A) { B = SparseMatrix_copy(A); } B = SparseMatrix_remove_diagonal(B); if (B->type != MATRIX_TYPE_REAL || !use_value) B = SparseMatrix_set_entries_to_real_one(B); hierachical_mq_clustering(B, maxcluster, nclusters, assignment, mq, flag); if (B != A) SparseMatrix_delete(B); }
SparseMatrix call_tri(int n, int dim, real * x) { real one = 1; int i, ii, jj; SparseMatrix A; SparseMatrix B; int* edgelist = NULL; real* xv = N_GNEW(n, real); real* yv = N_GNEW(n, real); int numberofedges; for (i = 0; i < n; i++) { xv[i] = x[i * 2]; yv[i] = x[i * 2 + 1]; } if (n > 2) { edgelist = delaunay_tri (xv, yv, n, &numberofedges); } else { numberofedges = 0; } A = SparseMatrix_new(n, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD); for (i = 0; i < numberofedges; i++) { ii = edgelist[i * 2]; jj = edgelist[i * 2 + 1]; SparseMatrix_coordinate_form_add_entries(A, 1, &(ii), &(jj), &one); } if (n == 2) { /* if two points, add edge i->j */ ii = 0; jj = 1; SparseMatrix_coordinate_form_add_entries(A, 1, &(ii), &(jj), &one); } for (i = 0; i < n; i++) { SparseMatrix_coordinate_form_add_entries(A, 1, &i, &i, &one); } B = SparseMatrix_from_coordinate_format(A); SparseMatrix_delete(A); A = SparseMatrix_symmetrize(B, FALSE); SparseMatrix_delete(B); B = A; free (edgelist); free (xv); free (yv); return B; }
void Multilevel_MQ_Clustering_delete(Multilevel_MQ_Clustering grid) { if (!grid) return; if (grid->A) { if (grid->level == 0) { if (grid->delete_top_level_A) SparseMatrix_delete(grid->A); } else { SparseMatrix_delete(grid->A); } } SparseMatrix_delete(grid->P); SparseMatrix_delete(grid->R); FREE(grid->matching); FREE(grid->deg_intra); FREE(grid->dout); FREE(grid->wgt); Multilevel_MQ_Clustering_delete(grid->next); FREE(grid); }
void uniform_stress(int dim, SparseMatrix A, real *x, int *flag){ UniformStressSmoother sm; real lambda0 = 10.1, M = 100, scaling = 1.; real res; int maxit = 300, samepoint = TRUE, i, k, n = A->m; SparseMatrix B = NULL; *flag = 0; /* just set random initial for now */ for (i = 0; i < dim*n; i++) { x[i] = M*drand(); } /* make sure x is not all at the same point */ for (i = 1; i < n; i++){ for (k = 0; k < dim; k++) { if (ABS(x[0*dim+k] - x[i*dim+k]) > MACHINEACC){ samepoint = FALSE; i = n; break; } } } if (samepoint){ srand(1); #ifdef DEBUG_PRINT fprintf(stderr,"input coordinates to uniform_stress are the same, use random coordinates as initial input"); #endif for (i = 0; i < dim*n; i++) x[i] = M*drand(); } B = get_distance_matrix(A, scaling); assert(SparseMatrix_is_symmetric(B, FALSE)); sm = UniformStressSmoother_new(dim, B, x, 1000000*lambda0, M, flag); res = UniformStressSmoother_smooth(sm, dim, x, maxit); UniformStressSmoother_delete(sm); sm = UniformStressSmoother_new(dim, B, x, 10000*lambda0, M, flag); res = UniformStressSmoother_smooth(sm, dim, x, maxit); UniformStressSmoother_delete(sm); sm = UniformStressSmoother_new(dim, B, x, 100*lambda0, M, flag); res = UniformStressSmoother_smooth(sm, dim, x, maxit); UniformStressSmoother_delete(sm); sm = UniformStressSmoother_new(dim, B, x, lambda0, M, flag); res = UniformStressSmoother_smooth(sm, dim, x, maxit); UniformStressSmoother_delete(sm); scale_to_box(0,0,7*70,10*70,A->m,dim,x);; SparseMatrix_delete(B); }
void stress_model_core(int dim, SparseMatrix B, real **x, int edge_len_weighted, int maxit_sm, real tol, int *flag){ int m; SparseStressMajorizationSmoother sm; real lambda = 0; /*int maxit_sm = 1000, i; tol = 0.001*/ int i; SparseMatrix A = B; if (!SparseMatrix_is_symmetric(A, FALSE) || A->type != MATRIX_TYPE_REAL){ if (A->type == MATRIX_TYPE_REAL){ A = SparseMatrix_symmetrize(A, FALSE); A = SparseMatrix_remove_diagonal(A); } else { A = SparseMatrix_get_real_adjacency_matrix_symmetrized(A); } } A = SparseMatrix_remove_diagonal(A); *flag = 0; m = A->m; if (!x) { *x = MALLOC(sizeof(real)*m*dim); srand(123); for (i = 0; i < dim*m; i++) (*x)[i] = drand(); } if (edge_len_weighted){ sm = SparseStressMajorizationSmoother_new(A, dim, lambda, *x, WEIGHTING_SCHEME_SQR_DIST, TRUE);/* do not under weight the long distances */ //sm = SparseStressMajorizationSmoother_new(A, dim, lambda, *x, WEIGHTING_SCHEME_INV_DIST, TRUE);/* do not under weight the long distances */ } else { sm = SparseStressMajorizationSmoother_new(A, dim, lambda, *x, WEIGHTING_SCHEME_NONE, TRUE);/* weight the long distances */ } if (!sm) { *flag = -1; goto RETURN; } sm->tol_cg = 0.1; /* we found that there is no need to solve the Laplacian accurately */ sm->scheme = SM_SCHEME_STRESS; SparseStressMajorizationSmoother_smooth(sm, dim, *x, maxit_sm, tol); for (i = 0; i < dim*m; i++) { (*x)[i] /= sm->scaling; } SparseStressMajorizationSmoother_delete(sm); RETURN: if (A != B) SparseMatrix_delete(A); }
static void get_neighborhood_precision_recall(char *outfile, SparseMatrix A0, real *ideal_dist_matrix, real *dist_matrix){ SparseMatrix A = A0; int i, j, k, n = A->m; // int *ia, *ja; int *g_order = NULL, *p_order = NULL;/* ordering using graph/physical distance */ real *gdist, *pdist, radius; int np_neighbors; int ng_neighbors; /*number of (graph theoretical) neighbors */ real node_dist;/* distance of a node to the center node */ real true_positive; real recall; FILE *fp; fp = fopen(outfile,"w"); if (!SparseMatrix_is_symmetric(A, FALSE)){ A = SparseMatrix_symmetrize(A, FALSE); } // ia = A->ia; // ja = A->ja; for (k = 5; k <= 50; k+= 5){ recall = 0; for (i = 0; i < n; i++){ gdist = &(ideal_dist_matrix[i*n]); vector_ordering(n, gdist, &g_order, TRUE); pdist = &(dist_matrix[i*n]); vector_ordering(n, pdist, &p_order, TRUE); ng_neighbors = MIN(n-1, k); /* set the number of closest neighbor in the graph space to consider, excluding the node itself */ np_neighbors = ng_neighbors;/* set the number of closest neighbor in the embedding to consider, excluding the node itself */ radius = pdist[p_order[np_neighbors]]; true_positive = 0; for (j = 1; j <= ng_neighbors; j++){ node_dist = pdist[g_order[j]];/* the phisical distance for j-th closest node (in graph space) */ if (node_dist <= radius) true_positive++; } recall += true_positive/np_neighbors; } recall /= n; fprintf(fp,"%d %f\n", k, recall); } fprintf(stderr,"wrote precision/recall in file %s\n", outfile); fclose(fp); if (A != A0) SparseMatrix_delete(A); FREE(g_order); FREE(p_order); }
void stress_model(int dim, SparseMatrix B, real **x, int maxit_sm, real tol, int *flag){ int m; SparseStressMajorizationSmoother sm; real lambda = 0; /*int maxit_sm = 1000, i; tol = 0.001*/ int i; SparseMatrix A = B; if (!SparseMatrix_is_symmetric(A, FALSE) || A->type != MATRIX_TYPE_REAL){ if (A->type == MATRIX_TYPE_REAL){ A = SparseMatrix_symmetrize(A, FALSE); A = SparseMatrix_remove_diagonal(A); } else { A = SparseMatrix_get_real_adjacency_matrix_symmetrized(A); } } A = SparseMatrix_remove_diagonal(A); *flag = 0; m = A->m; if (!x) { *x = MALLOC(sizeof(real)*m*dim); srand(123); for (i = 0; i < dim*m; i++) (*x)[i] = drand(); } sm = SparseStressMajorizationSmoother_new(A, dim, lambda, *x, WEIGHTING_SCHEME_NONE);/* do not under weight the long distances */ if (!sm) { *flag = -1; goto RETURN; } SparseStressMajorizationSmoother_smooth(sm, dim, *x, maxit_sm, 0.001); for (i = 0; i < dim*m; i++) { (*x)[i] /= sm->scaling; } SparseStressMajorizationSmoother_delete(sm); RETURN: if (A != B) SparseMatrix_delete(A); }
static SparseMatrix check_compatibility(SparseMatrix A, int ne, pedge *edges, int compatibility_method, real tol){ /* go through the links and make sure edges are compatible */ SparseMatrix B, C; int *ia, *ja, i, j, jj; real start; real dist; B = SparseMatrix_new(1, 1, 1, MATRIX_TYPE_REAL, FORMAT_COORD); ia = A->ia; ja = A->ja; //SparseMatrix_print("A",A); start = clock(); for (i = 0; i < ne; i++){ for (j = ia[i]; j < ia[i+1]; j++){ jj = ja[j]; if (i == jj) continue; if (compatibility_method == COMPATIBILITY_DIST){ dist = edge_compatibility_full(edges[i], edges[jj]); } else if (compatibility_method == COMPATIBILITY_FULL){ dist = edge_compatibility(edges[i], edges[jj]); } /* fprintf(stderr,"edge %d = {",i); pedge_print("", edges[i]); fprintf(stderr,"edge %d = {",jj); pedge_print("", edges[jj]); fprintf(stderr,"compatibility=%f\n",dist); */ if (ABS(dist) > tol){ B = SparseMatrix_coordinate_form_add_entries(B, 1, &i, &jj, &dist); B = SparseMatrix_coordinate_form_add_entries(B, 1, &jj, &i, &dist); } } } C = SparseMatrix_from_coordinate_format(B); //SparseMatrix_print("C",C); SparseMatrix_delete(B); B = C; if (Verbose > 1) fprintf(stderr, "edge compatibilitu time = %f\n",((real) (clock() - start))/CLOCKS_PER_SEC); return B; }
SparseMatrix call_tri2(int n, int dim, real * xx) { real *x, *y; v_data *delaunay; int i, j; SparseMatrix A; SparseMatrix B; real one = 1; x = N_GNEW(n, real); y = N_GNEW(n, real); for (i = 0; i < n; i++) { x[i] = xx[dim * i]; y[i] = xx[dim * i + 1]; } delaunay = UG_graph(x, y, n, 0); A = SparseMatrix_new(n, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD); for (i = 0; i < n; i++) { for (j = 1; j < delaunay[i].nedges; j++) { SparseMatrix_coordinate_form_add_entries(A, 1, &i, &(delaunay[i]. edges[j]), &one); } } for (i = 0; i < n; i++) { SparseMatrix_coordinate_form_add_entries(A, 1, &i, &i, &one); } B = SparseMatrix_from_coordinate_format(A); B = SparseMatrix_symmetrize(B, FALSE); SparseMatrix_delete(A); free (x); free (y); freeGraph (delaunay); return B; }
void Multilevel_coarsen(SparseMatrix A, SparseMatrix *cA, SparseMatrix D, SparseMatrix *cD, real *node_wgt, real **cnode_wgt, SparseMatrix *P, SparseMatrix *R, Multilevel_control ctrl, int *coarsen_scheme_used){ SparseMatrix cA0 = A, cD0 = NULL, P0 = NULL, R0 = NULL, M; real *cnode_wgt0 = NULL; int nc = 0, n; *P = NULL; *R = NULL; *cA = NULL; *cnode_wgt = NULL, *cD = NULL; n = A->n; do {/* this loop force a sufficient reduction */ node_wgt = cnode_wgt0; Multilevel_coarsen_internal(A, &cA0, D, &cD0, node_wgt, &cnode_wgt0, &P0, &R0, ctrl, coarsen_scheme_used); if (!cA0) return; nc = cA0->n; #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr,"nc=%d n = %d\n",nc,n); #endif if (*P){ assert(*R); M = SparseMatrix_multiply(*P, P0); SparseMatrix_delete(*P); SparseMatrix_delete(P0); *P = M; M = SparseMatrix_multiply(R0, *R); SparseMatrix_delete(*R); SparseMatrix_delete(R0); *R = M; } else { *P = P0; *R = R0; } if (*cA) SparseMatrix_delete(*cA); *cA = cA0; if (*cD) SparseMatrix_delete(*cD); *cD = cD0; if (*cnode_wgt) FREE(*cnode_wgt); *cnode_wgt = cnode_wgt0; A = cA0; D = cD0; node_wgt = cnode_wgt0; cnode_wgt0 = NULL; } while (nc > ctrl->min_coarsen_factor*n && ctrl->coarsen_mode == COARSEN_MODE_FORCEFUL); }
static void Multilevel_coarsen(SparseMatrix A, SparseMatrix *cA, real *node_wgt, real **cnode_wgt, SparseMatrix *P, SparseMatrix *R, Multilevel_control ctrl, int *coarsen_scheme_used){ int *matching = NULL, nmatch, nc, nzc, n, i; int *irn = NULL, *jcn = NULL, *ia = NULL, *ja = NULL; real *val = NULL; SparseMatrix B = NULL; int *vset = NULL, nvset, ncov, j; int *cluster, *clusterp, ncluster; assert(A->m == A->n); *cA = NULL; *P = NULL; *R = NULL; n = A->m; *coarsen_scheme_used = ctrl->coarsen_scheme; switch (ctrl->coarsen_scheme){ case COARSEN_HYBRID: #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "hybrid scheme, try COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_LEAVES_FIRST first\n"); #endif *coarsen_scheme_used = ctrl->coarsen_scheme = COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_LEAVES_FIRST; Multilevel_coarsen(A, cA, node_wgt, cnode_wgt, P, R, ctrl, coarsen_scheme_used); if (!(*cA)) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "switching to COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_SUPERNODES_FIRST\n"); #endif *coarsen_scheme_used = ctrl->coarsen_scheme = COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_SUPERNODES_FIRST; Multilevel_coarsen(A, cA, node_wgt, cnode_wgt, P, R, ctrl, coarsen_scheme_used); } if (!(*cA)) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "switching to COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_CLUSTER_PERNODE_LEAVES_FIRST\n"); #endif *coarsen_scheme_used = ctrl->coarsen_scheme = COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_CLUSTER_PERNODE_LEAVES_FIRST; Multilevel_coarsen(A, cA, node_wgt, cnode_wgt, P, R, ctrl, coarsen_scheme_used); } if (!(*cA)) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "switching to COARSEN_INDEPENDENT_VERTEX_SET\n"); #endif *coarsen_scheme_used = ctrl->coarsen_scheme = COARSEN_INDEPENDENT_VERTEX_SET; Multilevel_coarsen(A, cA, node_wgt, cnode_wgt, P, R, ctrl, coarsen_scheme_used); } if (!(*cA)) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "switching to COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE\n"); #endif *coarsen_scheme_used = ctrl->coarsen_scheme = COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE; Multilevel_coarsen(A, cA, node_wgt, cnode_wgt, P, R, ctrl, coarsen_scheme_used); } ctrl->coarsen_scheme = COARSEN_HYBRID; break; case COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_SUPERNODES_FIRST: case COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_CLUSTER_PERNODE_LEAVES_FIRST: case COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_LEAVES_FIRST: if (ctrl->coarsen_scheme == COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_LEAVES_FIRST) { maximal_independent_edge_set_heavest_edge_pernode_leaves_first(A, ctrl->randomize, &cluster, &clusterp, &ncluster); } else if (ctrl->coarsen_scheme == COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_SUPERNODES_FIRST) { maximal_independent_edge_set_heavest_edge_pernode_supernodes_first(A, ctrl->randomize, &cluster, &clusterp, &ncluster); } else { maximal_independent_edge_set_heavest_cluster_pernode_leaves_first(A, 4, ctrl->randomize, &cluster, &clusterp, &ncluster); } assert(ncluster <= n); nc = ncluster; if (nc > ctrl->min_coarsen_factor*n || nc < ctrl->minsize) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "nc = %d, nf = %d, minsz = %d, coarsen_factor = %f coarsening stops\n",nc, n, ctrl->minsize, ctrl->min_coarsen_factor); #endif goto RETURN; } irn = N_GNEW(n,int); jcn = N_GNEW(n,int); val = N_GNEW(n,real); nzc = 0; for (i = 0; i < ncluster; i++){ for (j = clusterp[i]; j < clusterp[i+1]; j++){ assert(clusterp[i+1] > clusterp[i]); irn[nzc] = cluster[j]; jcn[nzc] = i; val[nzc++] = 1.; } } assert(nzc == n); *P = SparseMatrix_from_coordinate_arrays(nzc, n, nc, irn, jcn, (void *) val, MATRIX_TYPE_REAL); *R = SparseMatrix_transpose(*P); B = SparseMatrix_multiply(*R, A); if (!B) goto RETURN; *cA = SparseMatrix_multiply(B, *P); if (!*cA) goto RETURN; SparseMatrix_multiply_vector(*R, node_wgt, cnode_wgt, FALSE); *R = SparseMatrix_divide_row_by_degree(*R); SparseMatrix_set_symmetric(*cA); SparseMatrix_set_pattern_symmetric(*cA); *cA = SparseMatrix_remove_diagonal(*cA); break; case COARSEN_INDEPENDENT_EDGE_SET: maximal_independent_edge_set(A, ctrl->randomize, &matching, &nmatch); case COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE: if (ctrl->coarsen_scheme == COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE) maximal_independent_edge_set_heavest_edge_pernode(A, ctrl->randomize, &matching, &nmatch); case COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_DEGREE_SCALED: if (ctrl->coarsen_scheme == COARSEN_INDEPENDENT_EDGE_SET_HEAVEST_EDGE_PERNODE_DEGREE_SCALED) maximal_independent_edge_set_heavest_edge_pernode_scaled(A, ctrl->randomize, &matching, &nmatch); nc = nmatch; if (nc > ctrl->min_coarsen_factor*n || nc < ctrl->minsize) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "nc = %d, nf = %d, minsz = %d, coarsen_factor = %f coarsening stops\n",nc, n, ctrl->minsize, ctrl->min_coarsen_factor); #endif goto RETURN; } irn = N_GNEW(n,int); jcn = N_GNEW(n,int); val = N_GNEW(n,real); nzc = 0; nc = 0; for (i = 0; i < n; i++){ if (matching[i] >= 0){ if (matching[i] == i){ irn[nzc] = i; jcn[nzc] = nc; val[nzc++] = 1.; } else { irn[nzc] = i; jcn[nzc] = nc; val[nzc++] = 1; irn[nzc] = matching[i]; jcn[nzc] = nc; val[nzc++] = 1; matching[matching[i]] = -1; } nc++; matching[i] = -1; } } assert(nc == nmatch); assert(nzc == n); *P = SparseMatrix_from_coordinate_arrays(nzc, n, nc, irn, jcn, (void *) val, MATRIX_TYPE_REAL); *R = SparseMatrix_transpose(*P); B = SparseMatrix_multiply(*R, A); if (!B) goto RETURN; *cA = SparseMatrix_multiply(B, *P); if (!*cA) goto RETURN; SparseMatrix_multiply_vector(*R, node_wgt, cnode_wgt, FALSE); *R = SparseMatrix_divide_row_by_degree(*R); SparseMatrix_set_symmetric(*cA); SparseMatrix_set_pattern_symmetric(*cA); *cA = SparseMatrix_remove_diagonal(*cA); break; case COARSEN_INDEPENDENT_VERTEX_SET: case COARSEN_INDEPENDENT_VERTEX_SET_RS: if (ctrl->coarsen_scheme == COARSEN_INDEPENDENT_VERTEX_SET){ maximal_independent_vertex_set(A, ctrl->randomize, &vset, &nvset, &nzc); } else { maximal_independent_vertex_set_RS(A, ctrl->randomize, &vset, &nvset, &nzc); } ia = A->ia; ja = A->ja; nc = nvset; if (nc > ctrl->min_coarsen_factor*n || nc < ctrl->minsize) { #ifdef DEBUG_PRINT if (Verbose) fprintf(stderr, "nc = %d, nf = %d, minsz = %d, coarsen_factor = %f coarsening stops\n",nc, n, ctrl->minsize, ctrl->min_coarsen_factor); #endif goto RETURN; } irn = N_GNEW(nzc,int); jcn = N_GNEW(nzc,int); val = N_GNEW(nzc,real); nzc = 0; for (i = 0; i < n; i++){ if (vset[i] == MAX_IND_VTX_SET_F){ ncov = 0; for (j = ia[i]; j < ia[i+1]; j++){ if (vset[ja[j]] >= MAX_IND_VTX_SET_C){ ncov++; } } assert(ncov > 0); for (j = ia[i]; j < ia[i+1]; j++){ if (vset[ja[j]] >= MAX_IND_VTX_SET_C){ irn[nzc] = i; jcn[nzc] = vset[ja[j]]; val[nzc++] = 1./(double) ncov; } } } else { assert(vset[i] >= MAX_IND_VTX_SET_C); irn[nzc] = i; jcn[nzc] = vset[i]; val[nzc++] = 1.; } } *P = SparseMatrix_from_coordinate_arrays(nzc, n, nc, irn, jcn, (void *) val, MATRIX_TYPE_REAL); *R = SparseMatrix_transpose(*P); B = SparseMatrix_multiply(*R, A); if (!B) goto RETURN; *cA = SparseMatrix_multiply(B, *P); if (!*cA) goto RETURN; SparseMatrix_multiply_vector(*R, node_wgt, cnode_wgt, FALSE); SparseMatrix_set_symmetric(*cA); SparseMatrix_set_pattern_symmetric(*cA); *cA = SparseMatrix_remove_diagonal(*cA); break; default: goto RETURN; } RETURN: if (matching) FREE(matching); if (vset) FREE(vset); if (irn) FREE(irn); if (jcn) FREE(jcn); if (val) FREE(val); if (B) SparseMatrix_delete(B); }
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; }
real overlap_scaling(int dim, int m, real *x, real *width, real scale_sta, real scale_sto, real epsilon, int maxiter){ /* do a bisection between scale_sta and scale_sto, up to maxiter iterations or till interval <= epsilon, to find the best scaling to avoid overlap m: number of points x: the coordinates width: label size scale_sta: starting bracket. If <= 0, assumed 0. If > 0, we will test this first and if no overlap, return. scale_sto: stopping bracket. This must be overlap free if positive. If <= 0, we will find automatically by doubling from scale_sta, or epsilon if scale_sta <= 0. typically usage: - for shrinking down a layout to reduce white space, we will assume scale_sta and scale_sto are both given and positive, and scale_sta is the current guess. - for scaling up, we assume scale_sta, scale_sto <= 0 */ real scale = -1, scale_best = -1; SparseMatrix C = NULL; int check_overlap_only = 1; int overlap = 0; real two = 2; int iter = 0; assert(epsilon > 0); if (scale_sta <= 0) { scale_sta = 0; } else { scale_coord(dim, m, x, scale_sta); C = get_overlap_graph(dim, m, x, width, check_overlap_only); if (!C || C->nz == 0) { if (Verbose) fprintf(stderr," shrinking with with %f works\n", scale_sta); SparseMatrix_delete(C); return scale_sta; } scale_coord(dim, m, x, 1./scale_sta); SparseMatrix_delete(C); } if (scale_sto < 0){ if (scale_sta == 0) { scale_sto = epsilon; } else { scale_sto = scale_sta; } scale_coord(dim, m, x, scale_sto); do { scale_sto *= two; scale_coord(dim, m, x, two); C = get_overlap_graph(dim, m, x, width, check_overlap_only); overlap = (C && C->nz > 0); SparseMatrix_delete(C); } while (overlap); scale_coord(dim, m, x, 1/scale_sto);/* unscale */ } scale_best = scale_sto; while (iter++ < maxiter && scale_sto - scale_sta > epsilon){ fprintf(stderr,"in overlap_scaling iter=%d, maxiter=%d, scaling bracket: {%f,%f}\n", iter, maxiter, scale_sta, scale_sto); scale = 0.5*(scale_sta + scale_sto); scale_coord(dim, m, x, scale); C = get_overlap_graph(dim, m, x, width, check_overlap_only); scale_coord(dim, m, x, 1./scale);/* unscale */ overlap = (C && C->nz > 0); SparseMatrix_delete(C); if (overlap){ scale_sta = scale; } else { scale_best = scale_sto = scale; } } /* final scaling */ scale_coord(dim, m, x, scale_best); return scale_best; }
static SparseMatrix get_overlap_graph(int dim, int n, real *x, real *width, int check_overlap_only){ /* if check_overlap_only = TRUE, we only check whether there is one overlap */ scan_point *scanpointsx, *scanpointsy; int i, k, neighbor; SparseMatrix A = NULL, B = NULL; rb_red_blk_node *newNode, *newNode0, *newNode2 = NULL; rb_red_blk_tree* treey; real one = 1; A = SparseMatrix_new(n, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD); scanpointsx = N_GNEW(2*n,scan_point); for (i = 0; i < n; i++){ scanpointsx[2*i].node = i; scanpointsx[2*i].x = x[i*dim] - width[i*dim]; scanpointsx[2*i].status = INTV_OPEN; scanpointsx[2*i+1].node = i+n; scanpointsx[2*i+1].x = x[i*dim] + width[i*dim]; scanpointsx[2*i+1].status = INTV_CLOSE; } qsort(scanpointsx, 2*n, sizeof(scan_point), comp_scan_points); scanpointsy = N_GNEW(2*n,scan_point); for (i = 0; i < n; i++){ scanpointsy[i].node = i; scanpointsy[i].x = x[i*dim+1] - width[i*dim+1]; scanpointsy[i].status = INTV_OPEN; scanpointsy[i+n].node = i; scanpointsy[i+n].x = x[i*dim+1] + width[i*dim+1]; scanpointsy[i+n].status = INTV_CLOSE; } treey = RBTreeCreate(NodeComp,NodeDest,InfoDest,NodePrint,InfoPrint); for (i = 0; i < 2*n; i++){ #ifdef DEBUG_RBTREE fprintf(stderr," k = %d node = %d x====%f\n",(scanpointsx[i].node)%n, (scanpointsx[i].node), (scanpointsx[i].x)); #endif k = (scanpointsx[i].node)%n; if (scanpointsx[i].status == INTV_OPEN){ #ifdef DEBUG_RBTREE fprintf(stderr, "inserting..."); treey->PrintKey(&(scanpointsy[k])); #endif RBTreeInsert(treey, &(scanpointsy[k]), NULL); /* add both open and close int for y */ #ifdef DEBUG_RBTREE fprintf(stderr, "inserting2..."); treey->PrintKey(&(scanpointsy[k+n])); #endif RBTreeInsert(treey, &(scanpointsy[k+n]), NULL); } else { real bsta, bbsta, bsto, bbsto; int ii; assert(scanpointsx[i].node >= n); newNode = newNode0 = RBExactQuery(treey, &(scanpointsy[k + n])); ii = ((scan_point *)newNode->key)->node; assert(ii < n); bsta = scanpointsy[ii].x; bsto = scanpointsy[ii+n].x; #ifdef DEBUG_RBTREE fprintf(stderr, "poping..%d....yinterval={%f,%f}\n", scanpointsy[k + n].node, bsta, bsto); treey->PrintKey(newNode->key); #endif assert(treey->nil != newNode); while ((newNode) && ((newNode = TreePredecessor(treey, newNode)) != treey->nil)){ neighbor = (((scan_point *)newNode->key)->node)%n; bbsta = scanpointsy[neighbor].x; bbsto = scanpointsy[neighbor+n].x;/* the y-interval of the node that has one end of the interval lower than the top of the leaving interval (bsto) */ #ifdef DEBUG_RBTREE fprintf(stderr," predecessor is node %d y = %f\n", ((scan_point *)newNode->key)->node, ((scan_point *)newNode->key)->x); #endif if (neighbor != k){ if (ABS(0.5*(bsta+bsto) - 0.5*(bbsta+bbsto)) < 0.5*(bsto-bsta) + 0.5*(bbsto-bbsta)){/* if the distance of the centers of the interval is less than sum of width, we have overlap */ A = SparseMatrix_coordinate_form_add_entries(A, 1, &neighbor, &k, &one); #ifdef DEBUG_RBTREE fprintf(stderr,"====================================== %d %d\n",k,neighbor); #endif if (check_overlap_only) goto check_overlap_RETURN; } } else { newNode2 = newNode; } } #ifdef DEBUG_RBTREE fprintf(stderr, "deleteing..."); treey->PrintKey(newNode0->key); #endif if (newNode0) RBDelete(treey,newNode0); if (newNode2 && newNode2 != treey->nil && newNode2 != newNode0) { #ifdef DEBUG_RBTREE fprintf(stderr, "deleteing2..."); treey->PrintKey(newNode2->key); #endif if (newNode0) RBDelete(treey,newNode2); } } } check_overlap_RETURN: FREE(scanpointsx); FREE(scanpointsy); RBTreeDestroy(treey); B = SparseMatrix_from_coordinate_format(A); SparseMatrix_delete(A); A = SparseMatrix_symmetrize(B, FALSE); SparseMatrix_delete(B); if (Verbose) fprintf(stderr, "found %d clashes\n", A->nz); return A; }
static void sfdpLayout(graph_t * g, spring_electrical_control ctrl, int hops, pointf pad) { real *sizes; real *pos; Agnode_t *n; int flag, i; int n_edge_label_nodes = 0, *edge_label_nodes = NULL; SparseMatrix D = NULL; SparseMatrix A; if (ctrl->method == METHOD_SPRING_MAXENT) /* maxent can work with distance matrix */ A = makeMatrix(g, Ndim, &D); else A = makeMatrix(g, Ndim, NULL); if (ctrl->overlap >= 0) { if (ctrl->edge_labeling_scheme > 0) sizes = getSizes(g, pad, &n_edge_label_nodes, &edge_label_nodes); else sizes = getSizes(g, pad, NULL, NULL); } else sizes = NULL; pos = getPos(g, ctrl); switch (ctrl->method) { case METHOD_SPRING_ELECTRICAL: case METHOD_SPRING_MAXENT: multilevel_spring_electrical_embedding(Ndim, A, D, ctrl, NULL, sizes, pos, n_edge_label_nodes, edge_label_nodes, &flag); break; case METHOD_UNIFORM_STRESS: uniform_stress(Ndim, A, pos, &flag); break; case METHOD_STRESS:{ int maxit = 200; real tol = 0.001; int weighted = TRUE; if (!D){ D = SparseMatrix_get_real_adjacency_matrix_symmetrized(A);/* all distance 1 */ weighted = FALSE; } else { D = SparseMatrix_symmetrize_nodiag(D, FALSE); weighted = TRUE; } if (hops > 0){ SparseMatrix DD; DD = SparseMatrix_distance_matrix_khops(hops, D, weighted); if (Verbose){ fprintf(stderr,"extracted a %d-neighborhood graph of %d edges from a graph of %d edges\n", hops, (DD->nz)/2, (D->nz/2)); } SparseMatrix_delete(D); D = DD; } stress_model(Ndim, A, D, &pos, TRUE, maxit, tol, &flag); } break; } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { real *npos = pos + (Ndim * ND_id(n)); for (i = 0; i < Ndim; i++) { ND_pos(n)[i] = npos[i]; } } free(sizes); free(pos); SparseMatrix_delete (A); if (D) SparseMatrix_delete (D); if (edge_label_nodes) FREE(edge_label_nodes); }
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; }
void country_graph_coloring(int seed, SparseMatrix A, int **p, real *norm_1){ int n = A->m, i, j, jj; SparseMatrix L, A2; int *ia = A->ia, *ja = A->ja; int a = -1.; real nrow; real *v = NULL; real norm1[2], norm2[2], norm11[2], norm22[2], norm = n; real pi, pj; int improved = TRUE; assert(A->m == A->n); A2 = SparseMatrix_symmetrize(A, TRUE); ia = A2->ia; ja = A2->ja; /* Laplacian */ L = SparseMatrix_new(n, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD); for (i = 0; i < n; i++){ nrow = 0.; for (j = ia[i]; j < ia[i+1]; j++){ jj = ja[j]; if (jj != i){ nrow ++; L = SparseMatrix_coordinate_form_add_entries(L, 1, &i, &jj, &a); } } L = SparseMatrix_coordinate_form_add_entries(L, 1, &i, &i, &nrow); } L = SparseMatrix_from_coordinate_format(L); /* largest eigen vector */ { int maxit = 100; real tol = 0.00001; power_method(L, seed, maxit, tol, &v); } vector_ordering(n, v, p, TRUE); /* swapping */ while (improved){ improved = FALSE; norm = n; for (i = 0; i < n; i++){ get_local_12_norm(n, i, ia, ja, *p, norm1); for (j = 0; j < n; j++){ if (j == i) continue; get_local_12_norm(n, j, ia, ja, *p, norm2); norm = MIN(norm, norm2[0]); pi = (*p)[i]; pj = (*p)[j]; (*p)[i] = pj; (*p)[j] = pi; get_local_12_norm(n, i, ia, ja, *p, norm11); get_local_12_norm(n, j, ia, ja, *p, norm22); if (MIN(norm11[0],norm22[0]) > MIN(norm1[0],norm2[0])){ // || //(MIN(norm11[0],norm22[0]) == MIN(norm1[0],norm2[0]) && norm11[1]+norm22[1] > norm1[1]+norm2[1])) { improved = TRUE; norm1[0] = norm11[0]; norm1[1] = norm11[1]; continue; } (*p)[i] = pi; (*p)[j] = pj; } } if (Verbose) { get_12_norm(n, ia, ja, *p, norm1); fprintf(stderr, "norm = %f", norm); fprintf(stderr, "norm1 = %f, norm2 = %f\n", norm1[0], norm1[1]); } } get_12_norm(n, ia, ja, *p, norm1); *norm_1 = norm1[0]; if (A2 != A) SparseMatrix_delete(A2); SparseMatrix_delete(L); }
StressMajorizationSmoother StressMajorizationSmoother2_new(SparseMatrix A, int dim, real lambda0, real *x, int ideal_dist_scheme){ /* use up to dist 2 neighbor */ /* use up to dist 2 neighbor. This is used in overcoming pherical effect with ideal distance of 2-neighbors equal graph distance etc. */ StressMajorizationSmoother sm; int i, j, k, l, m = A->m, *ia = A->ia, *ja = A->ja, *iw, *jw, *id, *jd; int *mask, nz; real *d, *w, *lambda; real *avg_dist, diag_d, diag_w, dist, s = 0, stop = 0, sbot = 0; SparseMatrix ID; assert(SparseMatrix_is_symmetric(A, FALSE)); ID = ideal_distance_matrix(A, dim, x); sm = GNEW(struct StressMajorizationSmoother_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; mask = N_GNEW(m,int); 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; } for (i = 0; i < m; i++) mask[i] = -1; nz = 0; for (i = 0; i < m; i++){ mask[i] = i; for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; if (mask[k] != i){ mask[k] = i; nz++; } } for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; for (l = ia[k]; l < ia[k+1]; l++){ if (mask[ja[l]] != i){ mask[ja[l]] = i; nz++; } } } } sm->Lw = SparseMatrix_new(m, m, nz + m, MATRIX_TYPE_REAL, FORMAT_CSR); sm->Lwd = SparseMatrix_new(m, m, nz + m, MATRIX_TYPE_REAL, FORMAT_CSR); if (!(sm->Lw) || !(sm->Lwd)) { StressMajorizationSmoother_delete(sm); return NULL; } iw = sm->Lw->ia; jw = sm->Lw->ja; w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a; id = sm->Lwd->ia; jd = sm->Lwd->ja; iw[0] = id[0] = 0; nz = 0; for (i = 0; i < m; i++){ mask[i] = i+m; diag_d = diag_w = 0; for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; if (mask[k] != i+m){ mask[k] = i+m; jw[nz] = k; if (ideal_dist_scheme == IDEAL_GRAPH_DIST){ dist = 1; } else if (ideal_dist_scheme == IDEAL_AVG_DIST){ dist = (avg_dist[i] + avg_dist[k])*0.5; } else if (ideal_dist_scheme == IDEAL_POWER_DIST){ dist = pow(distance_cropped(x,dim,i,k),.4); } else { fprintf(stderr,"ideal_dist_scheme value wrong"); assert(0); exit(1); } /* w[nz] = -1./(ia[i+1]-ia[i]+ia[ja[j]+1]-ia[ja[j]]); w[nz] = -2./(avg_dist[i]+avg_dist[k]);*/ /* w[nz] = -1.;*//* use unit weight for now, later can try 1/(deg(i)+deg(k)) */ w[nz] = -1/(dist*dist); diag_w += w[nz]; jd[nz] = k; /* d[nz] = w[nz]*distance(x,dim,i,k); d[nz] = w[nz]*dd[j]; d[nz] = w[nz]*(avg_dist[i] + avg_dist[k])*0.5; */ d[nz] = w[nz]*dist; stop += d[nz]*distance(x,dim,i,k); sbot += d[nz]*dist; diag_d += d[nz]; nz++; } } /* distance 2 neighbors */ for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; for (l = ia[k]; l < ia[k+1]; l++){ if (mask[ja[l]] != i+m){ mask[ja[l]] = i+m; if (ideal_dist_scheme == IDEAL_GRAPH_DIST){ dist = 2; } else if (ideal_dist_scheme == IDEAL_AVG_DIST){ dist = (avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5; } else if (ideal_dist_scheme == IDEAL_POWER_DIST){ dist = pow(distance_cropped(x,dim,i,ja[l]),.4); } else { fprintf(stderr,"ideal_dist_scheme value wrong"); assert(0); exit(1); } jw[nz] = ja[l]; /* w[nz] = -1/(ia[i+1]-ia[i]+ia[ja[l]+1]-ia[ja[l]]); w[nz] = -2/(avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]]);*/ /* w[nz] = -1.;*//* use unit weight for now, later can try 1/(deg(i)+deg(k)) */ w[nz] = -1/(dist*dist); diag_w += w[nz]; jd[nz] = ja[l]; /* d[nz] = w[nz]*(distance(x,dim,i,k)+distance(x,dim,k,ja[l])); d[nz] = w[nz]*(dd[j]+dd[l]); d[nz] = w[nz]*(avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5; */ d[nz] = w[nz]*dist; stop += d[nz]*distance(x,dim,ja[l],k); sbot += d[nz]*dist; diag_d += d[nz]; nz++; } } } jw[nz] = i; lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */ w[nz] = -diag_w + lambda[i]; jd[nz] = i; d[nz] = -diag_d; nz++; iw[i+1] = nz; id[i+1] = nz; } s = stop/sbot; for (i = 0; i < nz; i++) d[i] *= s; sm->scaling = s; sm->Lw->nz = nz; sm->Lwd->nz = nz; FREE(mask); FREE(avg_dist); SparseMatrix_delete(ID); return sm; }
void SpringSmoother_delete(SpringSmoother sm){ if (!sm) return; if (sm->D) SparseMatrix_delete(sm->D); if (sm->ctrl) spring_electrical_control_delete(sm->ctrl); }
/* ================================ spring and spring-electrical based smoother ================ */ SpringSmoother SpringSmoother_new(SparseMatrix A, int dim, spring_electrical_control ctrl, real *x){ SpringSmoother sm; int i, j, k, l, m = A->m, *ia = A->ia, *ja = A->ja, *id, *jd; int *mask, nz; real *d, *dd; real *avg_dist; SparseMatrix ID = NULL; assert(SparseMatrix_is_symmetric(A, FALSE)); ID = ideal_distance_matrix(A, dim, x); dd = (real*) ID->a; sm = N_GNEW(1,struct SpringSmoother_struct); mask = N_GNEW(m,int); 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; } for (i = 0; i < m; i++) mask[i] = -1; nz = 0; for (i = 0; i < m; i++){ mask[i] = i; for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; if (mask[k] != i){ mask[k] = i; nz++; } } for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; for (l = ia[k]; l < ia[k+1]; l++){ if (mask[ja[l]] != i){ mask[ja[l]] = i; nz++; } } } } sm->D = SparseMatrix_new(m, m, nz, MATRIX_TYPE_REAL, FORMAT_CSR); if (!(sm->D)){ SpringSmoother_delete(sm); return NULL; } id = sm->D->ia; jd = sm->D->ja; d = (real*) sm->D->a; id[0] = 0; nz = 0; for (i = 0; i < m; i++){ mask[i] = i+m; for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; if (mask[k] != i+m){ mask[k] = i+m; jd[nz] = k; d[nz] = (avg_dist[i] + avg_dist[k])*0.5; d[nz] = dd[j]; nz++; } } for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; for (l = ia[k]; l < ia[k+1]; l++){ if (mask[ja[l]] != i+m){ mask[ja[l]] = i+m; jd[nz] = ja[l]; d[nz] = (avg_dist[i] + 2*avg_dist[k] + avg_dist[ja[l]])*0.5; d[nz] = dd[j]+dd[l]; nz++; } } } id[i+1] = nz; } sm->D->nz = nz; sm->ctrl = spring_electrical_control_new(); *(sm->ctrl) = *ctrl; sm->ctrl->random_start = FALSE; sm->ctrl->multilevels = 1; sm->ctrl->step /= 2; sm->ctrl->maxiter = 20; FREE(mask); FREE(avg_dist); SparseMatrix_delete(ID); 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, 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; }
SparseMatrix DistanceMatrix_restrict_cluster(int ncluster, int *clusterp, int *cluster, SparseMatrix P, SparseMatrix R, SparseMatrix D){ #if 0 /* this construct a distance matrix of a coarse graph, for a coarsen give by merging all nodes in eahc cluster */ SparseMatrix cD = NULL; int i, j, nzc; int **irn, **jcn; real **val; int n = D->m; int *assignment = NULL; int nz; int *id = D->ia, jd = D->ja; int *mask = NULL; int *nnodes, *mask; real *d = NULL; assert(D->m == D->n); if (!D) return NULL; if (D->a && D->type == MATRIX_TYPE_REAL) d = (real*) D->val; irn = N_GNEW(ncluster,int*); jcn = N_GNEW(ncluster,int*); val = N_GNEW(ncluster,real*); assignment = N_GNEW(n,int); nz = N_GNEW(ncluster,int); mask = N_GNEW(n,int); nnodes = N_GNEW(ncluster,int); /* find ncluster-subgrahs induced by the ncluster -clusters, find the diameter of each, then use the radius as the distance from the supernode to the rest of the "world" */ for (i = 0; i < ncluster; i++) nz[i] = 0; for (i = 0; i < ncluster; i++){ for (j = clusterp[i]; j < clusterp[i+1]; j++){ assert(clusterp[i+1] > clusterp[i]); assignment[cluster[j]] = i; } } for (i = 0; i < n; i++){/* figure out how many entries per submatrix */ ic = asignment[i]; for (j = id[i]; j < id[i+1]; j++){ if (i != jd[j] && ic == assignment[jd[j]]) { nz[ic]++; } } } for (i = 0; i < ncluster; i++) { irn[i] = N_GNEW(nz[i],int); jcn[i] = N_GNEW(nz[i],int); val[i] = N_GNEW(nz[i],int); val[i] = NULL; } for (i = 0; i < ncluster; i++) nz[i] = 0;/* get subgraphs */ for (i = 0; i < n; i++) mask[i] = -1; for (i = 0; i < ncluster; i++) nnodes[i] = -1; for (i = 0; i < n; i++){ ic = asignment[i]; ii = mask[i]; if (ii < 0){ mask[i] = ii = nnodes[ic]; nnodes[ic]++; } for (j = id[i]; j < id[i+1]; j++){ jc = assignment[jd[j]]; if (i != jd[j] && ic == jc) { jj = mask[jd[j]]; if (jj < 0){ mask[jd[j]] = jj = nnodes[jc]; nnodes[jc]++; } irn[ic][nz[ic]] = ii; jcn[ic][nz[ic]] = jj; if (d) val[ic][nz[ic]] = d[j]; } } } for (i = 0; i < ncluster; i++){/* form subgraphs */ SparseMatrix A; A = SparseMatrix_from_coordinate_arrays(nz[nz[i]], nnodes[i], nnodes[i], irn[i], jcn[i], (void*) val[i], MATRIX_TYPE_REAL); SparseMatrix_delete(A); } for (i = 0; i < ncluster; i++){ for (j = clusterp[i]; j < clusterp[i+1]; j++){ assert(clusterp[i+1] > clusterp[i]); irn[nzc] = cluster[j]; jcn[nzc] = i; val[nzc++] = 1.; } } assert(nzc == n); cD = SparseMatrix_multiply3(R, D, P); SparseMatrix_set_symmetric(cD); SparseMatrix_set_pattern_symmetric(cD); cD = SparseMatrix_remove_diagonal(cD); FREE(nz); FREE(assignment); for (i = 0; i < ncluster; i++){ FREE(irn[i]); FREE(jcn[i]); FREE(val[i]); } FREE(irn); FREE(jcn); FREE(val); FREE(mask); FREE(nnodes); return cD; #endif return NULL; }
int main(int argc, char *argv[]) { char *infile; SparseMatrix B = NULL; int dim = 2, n = 0, i, *ia, *ja, j, k, nz = 0; real *x, *y, mean, dev, ratio, *z, r, theta, p, q, xx; FILE *fp; if (argc < 2){ fprintf(stderr,"Usage: similarity graph layout1 layout2\n"); } infile = argv[1]; fp = fopen(infile,"r"); while (fscanf(fp,"%lf %lf\n",&xx, &xx) == 2) n++; fclose(fp); infile = argv[1]; fp = fopen(infile,"r"); x = N_GNEW(n*2,real); for (i = 0; i < n; i++){ fscanf(fp,"%lf %lf\n",&(x[2*i]), &(x[2*i+1])); } fclose(fp); infile = argv[2]; fp = fopen(infile,"r"); y = N_GNEW(n*2,real); nz = 0; for (i = 0; i < n; i++){ if (fscanf(fp,"%lf %lf\n",&(y[2*i]), &(y[2*i+1])) != 2) goto ERROR; } fclose(fp); B = call_tri(n, 2, x); z = N_GNEW(B->nz,real); ia = B->ia; ja = B->ja; nz = 0; for (i = 0; i < n; i++){ for (j = ia[i]; j < ia[i+1]; j++){ k = ja[j]; if (k == i) continue; z[nz++] = distance(y,dim,i,k)/distance_cropped(x,dim,i,k); } } /* mean */ mean = 0; for (i = 0; i < nz; i++) mean += z[i]; mean /= nz; /* deviation*/ dev = 0; for (i = 0; i < nz; i++) { dev += (z[i]-mean)*(z[i]-mean); } dev /= nz; dev = sqrt(dev); /* bounding box area */ ratio = boundingbox_area(n, y); /*/MAX(boundingbox_area(n, x), 0.001);*/ fprintf(stderr, "mean = %f std = %f disimilarity = %f area = %f badness = %f displacement = %f\n", mean, dev, dev/mean, ratio, (dev/mean+1)*ratio, dispacement(n, x, y, &r, &theta, &p, &q)); fprintf(stderr, "theta = %f scaling = %f, shift = {%f, %f}\n",theta, 1/r, p, q); printf("%.2f %.2f %.2f\n",dev/mean, dispacement(n, x, y, &r, &theta, &p, &q),ratio/1000000.); SparseMatrix_delete(B); FREE(x); FREE(y); FREE(z); return 0; ERROR: printf("- - -\n"); return 0; }
static pedge* modularity_ink_bundling(int dim, int ne, SparseMatrix B, pedge* edges, real angle_param, real angle){ int *assignment = NULL, flag, nclusters; real modularity; int *clusterp, *clusters; SparseMatrix D, C; point_t meet1, meet2; real ink0, ink1; pedge e; int i, j, jj; int use_value_for_clustering = TRUE; //int use_value_for_clustering = FALSE; SparseMatrix BB; /* B may contain negative entries */ BB = SparseMatrix_copy(B); BB = SparseMatrix_apply_fun(BB, absfun); modularity_clustering(BB, TRUE, 0, use_value_for_clustering, &nclusters, &assignment, &modularity, &flag); SparseMatrix_delete(BB); #ifdef OPENGL clusters_global = assignment; #endif assert(!flag); if (Verbose > 1) fprintf(stderr, "there are %d clusters, modularity = %f\n",nclusters, modularity); C = SparseMatrix_new(1, 1, 1, MATRIX_TYPE_PATTERN, FORMAT_COORD); for (i = 0; i < ne; i++){ jj = assignment[i]; SparseMatrix_coordinate_form_add_entries(C, 1, &jj, &i, NULL); } D = SparseMatrix_from_coordinate_format(C); SparseMatrix_delete(C); clusterp = D->ia; clusters = D->ja; for (i = 0; i < nclusters; i++){ ink1 = ink(edges, clusterp[i+1] - clusterp[i], &(clusters[clusterp[i]]), &ink0, &meet1, &meet2, angle_param, angle); if (Verbose > 1) fprintf(stderr,"nedges = %d ink0 = %f, ink1 = %f\n",clusterp[i+1] - clusterp[i], ink0, ink1); if (ink1 < ink0){ for (j = clusterp[i]; j < clusterp[i+1]; j++){ /* make this edge 5 points, insert two meeting points at 1 and 2, make 3 the last point */ edges[clusters[j]] = pedge_double(edges[clusters[j]]); e = edges[clusters[j]] = pedge_double(edges[clusters[j]]); e->x[1*dim] = meet1.x; e->x[1*dim+1] = meet1.y; e->x[2*dim] = meet2.x; e->x[2*dim+1] = meet2.y; e->x[3*dim] = e->x[4*dim]; e->x[3*dim+1] = e->x[4*dim+1]; e->npoints = 4; } #ifdef OPENGL edges_global = edges; drawScene(); #endif } } SparseMatrix_delete(D); return edges; }
Multilevel_MQ_Clustering Multilevel_MQ_Clustering_establish(Multilevel_MQ_Clustering grid, int maxcluster) { int *matching = grid->matching; SparseMatrix A = grid->A; int n = grid->n, level = grid->level, nc = 0, nclusters = n; real mq = 0, mq_in = 0, mq_out = 0, mq_new, mq_in_new, mq_out_new, mq_max = 0, mq_in_max = 0, mq_out_max = 0; int *ia = A->ia, *ja = A->ja; real *a, amax = 0; real *deg_intra = grid->deg_intra, *wgt = grid->wgt; real *deg_intra_new, *wgt_new = NULL; int i, j, k, jj, jc, jmax; real *deg_inter, gain = 0, *dout = grid->dout, *dout_new, deg_in_i, deg_in_j, wgt_i, wgt_j, a_ij, dout_i, dout_j, dout_max = 0, wgt_jmax = 0; int *mask; real maxgain = 0; real total_gain = 0; SingleLinkedList *neighbors = NULL, lst; neighbors = MALLOC(sizeof(SingleLinkedList)*n); for (i = 0; i < n; i++) neighbors[i] = NULL; mq = grid->mq; mq_in = grid->mq_in; mq_out = grid->mq_out; deg_intra_new = MALLOC(sizeof(real)*n); wgt_new = MALLOC(sizeof(real)*n); deg_inter = MALLOC(sizeof(real)*n); mask = MALLOC(sizeof(int)*n); dout_new = MALLOC(sizeof(real)*n); for (i = 0; i < n; i++) mask[i] = -1; assert(n == A->n); for (i = 0; i < n; i++) matching[i] = UNMATCHED; /* gain in merging node A into cluster B is mq_in_new = mq_in - |E(A,A)|/(V(A))^2 - |E(B,B)|/(V(B))^2 + (|E(A,A)|+|E(B,B)|+|E(A,B)|)/(|V(A)|+|V(B)|)^2 . = mq_in - deg_intra(A)/|A|^2 - deg_intra(B)/|B|^2 + (deg_intra(A)+deg_intra(B)+a(A,B))/(|A|+|B|)^2 mq_out_new = mq_out - |E(A,B)|/(|V(A)|*V(B)|)-\sum_{C and A connected, C!=B} |E(A,C)|/(|V(A)|*|V(C)|)-\sum_{C and B connected,C!=B} |E(B,C)|/(|V(B)|*|V(C)|) . + \sum_{C connected to A or B, C!=A, C!=B} (|E(A,C)|+|E(B,C)|)/(|V(C)|*(|V(A)|+|V(B)|) . = mq_out + a(A,B)/(|A|*|B|)-\sum_{C and A connected} a(A,C)/(|A|*|C|)-\sum_{C and B connected} a(B,C)/(|B|*|C|) . + \sum_{C connected to A or B, C!=A, C!=B} (a(A,C)+a(B,C))/(|C|*(|A|+|B|)) Denote: dout(i) = \sum_{j -- i} a(i,j)/|j| then mq_out_new = mq_out - |E(A,B)|/(|V(A)|*V(B)|)-\sum_{C and A connected, C!=B} |E(A,C)|/(|V(A)|*|V(C)|)-\sum_{C and B connected,C!=B} |E(B,C)|/(|V(B)|*|V(C)|) . + \sum_{C connected to A or B, C!=A, C!=B} (|E(A,C)|+|E(B,C)|)/(|V(C)|*(|V(A)|+|V(B)|) . = mq_out + a(A,B)/(|A|*|B|)-dout(A)/|A| - dout(B)/|B| . + (dout(A)+dout(B))/(|A|+|B|) - (a(A,B)/|A|+a(A,B)/|B|)/(|A|+|B|) . = mq_out -dout(A)/|A| - dout(B)/|B| + (dout(A)+dout(B))/(|A|+|B|) after merging A and B into cluster AB, dout(AB) = dout(A) + dout(B); dout(C) := dout(C) - a(A,C)/|A| - a(B,C)/|B| + a(A,C)/(|A|+|B|) + a(B, C)/(|A|+|B|) mq_new = mq_in_new/(k-1) - mq_out_new/((k-1)*(k-2)) gain = mq_new - mq */ a = (real*) A->a; for (i = 0; i < n; i++) { if (matching[i] != UNMATCHED) continue; /* accumulate connections between i and clusters */ for (j = ia[i]; j < ia[i+1]; j++) { jj = ja[j]; if (jj == i) continue; if ((jc=matching[jj]) != UNMATCHED) { if (mask[jc] != i) { mask[jc] = i; deg_inter[jc] = a[j]; } else { deg_inter[jc] += a[j]; } } } deg_in_i = deg_intra[i]; wgt_i = wgt[i]; dout_i = dout[i]; maxgain = 0; jmax = -1; for (j = ia[i]; j < ia[i+1]; j++) { jj = ja[j]; if (jj == i) continue; jc = matching[jj]; if (jc == UNMATCHED) { a_ij = a[j]; wgt_j = wgt[jj]; deg_in_j = deg_intra[jj]; dout_j = dout[jj]; } else if (deg_inter[jc] < 0) { continue; } else { a_ij = deg_inter[jc]; wgt_j = wgt_new[jc]; deg_inter[jc] = -1; /* so that we do not redo the calulation when we hit another neighbor in cluster jc */ deg_in_j = deg_intra_new[jc]; dout_j = dout_new[jc]; } mq_in_new = mq_in - deg_in_i/pow(wgt_i, 2) - deg_in_j/pow(wgt_j,2) + (deg_in_i + deg_in_j + a_ij)/pow(wgt_i + wgt_j,2); mq_out_new = mq_out - dout_i/wgt_i - dout_j/wgt_j + (dout_i + dout_j)/(wgt_i + wgt_j); if (nclusters > 2) { mq_new = 2*(mq_in_new/(nclusters - 1) - mq_out_new/((nclusters - 1)*(nclusters - 2))); } else { mq_new = 2*mq_in_new/(nclusters - 1); } #ifdef DEBUG { int ncluster; double mq2, mq_in2, mq_out2, *dout2; int *matching2, nc2 = nc; matching2 = MALLOC(sizeof(int)*A->m); matching2 = MEMCPY(matching2, matching, sizeof(real)*A->m); if (jc != UNMATCHED) { matching2[i] = jc; } else { matching2[i] = nc2; matching2[jj] = nc2; nc2++; } for (k = 0; k < n; k++) if (matching2[k] == UNMATCHED) matching2[k] =nc2++; mq2 = get_mq(A, matching2, &ncluster, &mq_in2, &mq_out2, &dout2); fprintf(stderr," {dout_i, dout_j}={%f,%f}, {predicted, calculated}: mq = {%f, %f}, mq_in ={%f,%f}, mq_out = {%f,%f}\n",dout_i, dout_j, mq_new, mq2, mq_in_new, mq_in2, mq_out_new, mq_out2); mq_new = mq2; } #endif gain = mq_new - mq; if (Verbose) fprintf(stderr,"gain in merging node %d with node %d = %f-%f = %f\n", i, jj, mq, mq_new, gain); if (j == ia[i] || gain > maxgain) { maxgain = gain; jmax = jj; amax = a_ij; dout_max = dout_j; wgt_jmax = wgt_j; mq_max = mq_new; mq_in_max = mq_in_new; mq_out_max = mq_out_new; } } /* now merge i and jmax */ if (maxgain > 0 || (nc >= 1 && nc > maxcluster)) { total_gain += maxgain; jc = matching[jmax]; if (jc == UNMATCHED) { fprintf(stderr, "maxgain=%f, merge %d, %d\n",maxgain, i, jmax); neighbors[nc] = SingleLinkedList_new_int(jmax); neighbors[nc] = SingleLinkedList_prepend_int(neighbors[nc], i); dout_new[nc] = dout_i + dout_max; matching[i] = matching[jmax] = nc; wgt_new[nc] = wgt[i] + wgt[jmax]; deg_intra_new[nc] = deg_intra[i] + deg_intra[jmax] + amax; nc++; } else { fprintf(stderr,"maxgain=%f, merge with existing cluster %d, %d\n",maxgain, i, jc); neighbors[jc] = SingleLinkedList_prepend_int(neighbors[jc], i); dout_new[jc] = dout_i + dout_max; wgt_new[jc] += wgt[i]; matching[i] = jc; deg_intra_new[jc] += deg_intra[i] + amax; } mq = mq_max; mq_in = mq_in_max; mq_out = mq_out_max; nclusters--; } else { fprintf(stderr,"gain: %f -- no gain, skip merging node %d\n", maxgain, i); assert(maxgain <= 0); neighbors[nc] = SingleLinkedList_new_int(i); matching[i] = nc; deg_intra_new[nc] = deg_intra[i]; wgt_new[nc] = wgt[i]; nc++; } /* update scaled outdegree of neighbors of i and its merged node/cluster jmax */ jc = matching[i]; lst = neighbors[jc]; do { mask[*((int*) SingleLinkedList_get_data(lst))] = n+i; lst = SingleLinkedList_get_next(lst); } while (lst); lst = neighbors[jc]; do { k = *((int*) SingleLinkedList_get_data(lst)); for (j = ia[k]; j < ia[k+1]; j++) { jj = ja[j]; if (mask[jj] == n+i) continue;/* link to within cluster */ if ((jc = matching[jj]) == UNMATCHED) { if (k == i) { dout[jj] += -a[j]/wgt_i + a[j]/(wgt_i + wgt_jmax); } else { dout[jj] += -a[j]/wgt_jmax + a[j]/(wgt_i + wgt_jmax); } } else { if (k == i) { dout_new[jc] += -a[j]/wgt_i + a[j]/(wgt_i + wgt_jmax); } else { dout_new[jc] += -a[j]/wgt_jmax + a[j]/(wgt_i + wgt_jmax); } } } lst = SingleLinkedList_get_next(lst); } while (lst); } fprintf(stderr,"verbose=%d\n",Verbose); if (Verbose) fprintf(stderr,"mq = %f new mq = %f level = %d, n = %d, nc = %d, gain = %g, mq_in = %f, mq_out = %f\n", mq, mq + total_gain, level, n, nc, total_gain, mq_in, mq_out); #ifdef DEBUG { int ncluster; mq = get_mq(A, matching, &ncluster, &mq_in, &mq_out, &dout); fprintf(stderr," mq = %f\n",mq); } #endif if (nc >= 1 && (total_gain > 0 || nc < n)) { /* now set up restriction and prolongation operator */ SparseMatrix P, R, R0, B, cA; real one = 1.; Multilevel_MQ_Clustering cgrid; R0 = SparseMatrix_new(nc, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD); for (i = 0; i < n; i++) { jj = matching[i]; SparseMatrix_coordinate_form_add_entries(R0, 1, &jj, &i, &one); } R = SparseMatrix_from_coordinate_format(R0); SparseMatrix_delete(R0); P = SparseMatrix_transpose(R); B = SparseMatrix_multiply(R, A); if (!B) goto RETURN; cA = SparseMatrix_multiply(B, P); if (!cA) goto RETURN; SparseMatrix_delete(B); grid->P = P; grid->R = R; level++; cgrid = Multilevel_MQ_Clustering_init(cA, level); deg_intra_new = REALLOC(deg_intra_new, nc*sizeof(real)); wgt_new = REALLOC(wgt_new, nc*sizeof(real)); cgrid->deg_intra = deg_intra_new; cgrid->mq = grid->mq + total_gain; cgrid->wgt = wgt_new; dout_new = REALLOC(dout_new, nc*sizeof(real)); cgrid->dout = dout_new; cgrid = Multilevel_MQ_Clustering_establish(cgrid, maxcluster); grid->next = cgrid; cgrid->prev = grid; } else { /* no more improvement, stop and final clustering found */ for (i = 0; i < n; i++) matching[i] = i; FREE(deg_intra_new); FREE(wgt_new); FREE(dout_new); } RETURN: for (i = 0; i < n; i++) SingleLinkedList_delete(neighbors[i], free); FREE(neighbors); FREE(deg_inter); FREE(mask); return grid; }
pedge* edge_bundling(SparseMatrix A0, int dim, real *x, int maxit_outer, real K, int method, int nneighbor, int compatibility_method, int max_recursion, real angle_param, real angle, int open_gl){ /* bundle edges. A: edge graph x: edge i is at {p,q}, . where p = x[2*dim*i : 2*dim*i+dim-1] . and q = x[2*dim*i+dim : 2*dim*i+2*dim-1] maxit_outer: max outer iteration for force directed bundling. Every outer iter subdivide each edge segment into 2. K: norminal edge length in force directed bundling method: which method to use. nneighbor: number of neighbors to be used in forming nearest neighbor graph. Used only in agglomerative method compatibility_method: which method to use to calculate compatibility. Used only in force directed. max_recursion: used only in agglomerative method. Specify how many level of recursion to do to bundle bundled edges again open_gl: whether to plot in X. */ int ne = A0->m; pedge *edges; SparseMatrix A = A0, B = NULL; int i; real tol = 0.001; int k; real step0 = 0.1, start = 0.0; int maxit = 10; int flag; assert(A->n == ne); edges = MALLOC(sizeof(pedge)*ne); for (i = 0; i < ne; i++){ edges[i] = pedge_new(2, dim, &(x[dim*2*i])); } A = SparseMatrix_symmetrize(A0, TRUE); if (Verbose) start = clock(); if (method == METHOD_INK){ /* go through the links and make sure edges are compatible */ B = check_compatibility(A, ne, edges, compatibility_method, tol); edges = modularity_ink_bundling(dim, ne, B, edges, angle_param, angle); } else if (method == METHOD_INK_AGGLOMERATE){ #ifdef HAVE_ANN /* plan: merge a node with its neighbors if doing so improve. Form coarsening graph, repeat until no more ink saving */ edges = agglomerative_ink_bundling(dim, A, edges, nneighbor, max_recursion, angle_param, angle, open_gl, &flag); assert(!flag); #else agerr (AGERR, "Graphviz built without approximate nearest neighbor library ANN; agglomerative inking not available\n"); edges = edges; #endif } else if (method == METHOD_FD){/* FD method */ /* go through the links and make sure edges are compatible */ B = check_compatibility(A, ne, edges, compatibility_method, tol); for (k = 0; k < maxit_outer; k++){ for (i = 0; i < ne; i++){ edges[i] = pedge_double(edges[i]); } step0 = step0/2; edges = force_directed_edge_bundling(B, edges, maxit, step0, K, open_gl); } } else if (method == METHOD_NONE){ edges = edges; } else { assert(0); } if (Verbose) fprintf(stderr, "total edge bundling cpu = %f\n",((real) (clock() - start))/CLOCKS_PER_SEC); if (B != A) SparseMatrix_delete(B); if (A != A0) SparseMatrix_delete(A); return edges; }
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; }