Graphviz  2.29.20120524.0446
lib/neatogen/overlap.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #if ((defined(HAVE_GTS) || defined(HAVE_TRIANGLE)) && defined(SFDP))
00019 
00020 #include "SparseMatrix.h"
00021 #include "overlap.h"
00022 #include "call_tri.h"
00023 #include "red_black_tree.h"
00024 #include "types.h"
00025 #include "memory.h"
00026 #include "globals.h"
00027 #include <time.h>
00028 
00029 static void ideal_distance_avoid_overlap(int dim, SparseMatrix A, real *x, real *width, real *ideal_distance, real *tmax, real *tmin){
00030   /*  if (x1>x2 && y1 > y2) we want either x1 + t (x1-x2) - x2 > (width1+width2), or y1 + t (y1-y2) - y2 > (height1+height2),
00031       hence t = MAX(expandmin, MIN(expandmax, (width1+width2)/(x1-x2) - 1, (height1+height2)/(y1-y2) - 1)), and
00032       new ideal distance = (1+t) old_distance. t can be negative sometimes.
00033       The result ideal distance is set to negative if the edge needs shrinking
00034   */
00035   int i, j, jj;
00036   int *ia = A->ia, *ja = A->ja;
00037   real dist, dx, dy, wx, wy, t;
00038   real expandmax = 1.5, expandmin = 1;
00039 
00040   *tmax = 0;
00041   *tmin = 1.e10;
00042   assert(SparseMatrix_is_symmetric(A, FALSE));
00043   for (i = 0; i < A->m; i++){
00044     for (j = ia[i]; j < ia[i+1]; j++){
00045       jj = ja[j];
00046       if (jj == i) continue;
00047       dist = distance(x, dim, i, jj);
00048       dx = ABS(x[i*dim] - x[jj*dim]);
00049       dy = ABS(x[i*dim+1] - x[jj*dim+1]);
00050       wx = width[i*dim]+width[jj*dim];
00051       wy = width[i*dim+1]+width[jj*dim+1];
00052       if (dx < MACHINEACC*wx && dy < MACHINEACC*wy){
00053         ideal_distance[j] = sqrt(wx*wx+wy*wy);
00054         *tmax = 2;
00055       } else {
00056         if (dx < MACHINEACC*wx){
00057           t = wy/dy;
00058         } else if (dy < MACHINEACC*wy){
00059           t = wx/dx;
00060         } else {
00061           t = MIN(wx/dx, wy/dy);
00062         }
00063         if (t > 1) t = MAX(t, 1.001);/* no point in things like t = 1.00000001 as this slow down convergence */
00064         *tmax = MAX(*tmax, t);
00065         *tmin = MIN(*tmin, t);
00066         t = MIN(expandmax, t);
00067         t = MAX(expandmin, t);
00068         if (t > 1) {
00069           ideal_distance[j] = t*dist;
00070         } else {
00071           ideal_distance[j] = -t*dist;
00072         }
00073       }
00074 
00075     }
00076   }
00077   return;
00078 }
00079 
00080 #define collide(i,j) ((ABS(x[(i)*dim] - x[(j)*dim]) < width[(i)*dim]+width[(j)*dim]) || (ABS(x[(i)*dim+1] - x[(j)*dim+1]) < width[(i)*dim+1]+width[(j)*dim+1]))
00081 
00082 enum {INTV_OPEN, INTV_CLOSE};
00083 
00084 struct scan_point_struct{
00085   int node;
00086   real x;
00087   int status;
00088 };
00089 
00090 typedef struct scan_point_struct scan_point;
00091 
00092 
00093 static int comp_scan_points(const void *p, const void *q){
00094   scan_point *pp = (scan_point *) p;
00095   scan_point *qq = (scan_point *) q;
00096   if (pp->x > qq->x){
00097     return 1;
00098   } else if (pp->x < qq->x){
00099     return -1;
00100   } else {
00101     if (pp->node > qq->node){
00102       return 1;
00103     } else if (pp->node < qq->node){
00104       return -1;
00105     }
00106     return 0;
00107   }
00108   return 0;
00109 }
00110 
00111 
00112 void NodeDest(void* a) {
00113   /*  free((int*)a);*/
00114 }
00115 
00116 
00117 
00118 int NodeComp(const void* a,const void* b) {
00119   return comp_scan_points(a,b);
00120 
00121 }
00122 
00123 void NodePrint(const void* a) {
00124   scan_point *aa;
00125 
00126   aa = (scan_point *) a;
00127   fprintf(stderr, "node {%d, %f, %d}\n", aa->node, aa->x, aa->status);
00128 
00129 }
00130 
00131 void InfoPrint(void* a) {
00132   ;
00133 }
00134 
00135 void InfoDest(void *a){
00136   ;
00137 }
00138 
00139 static SparseMatrix get_overlap_graph(int dim, int n, real *x, real *width){
00140   scan_point *scanpointsx, *scanpointsy;
00141   int i, k, neighbor;
00142   SparseMatrix A = NULL, B = NULL;
00143   rb_red_blk_node *newNode, *newNode0;
00144   rb_red_blk_tree* treey;
00145   real one = 1;
00146 
00147   A = SparseMatrix_new(n, n, 1, MATRIX_TYPE_REAL, FORMAT_COORD);
00148 
00149   scanpointsx = N_GNEW(2*n,scan_point);
00150   for (i = 0; i < n; i++){
00151     scanpointsx[2*i].node = i;
00152     scanpointsx[2*i].x = x[i*dim] - width[i*dim];
00153     scanpointsx[2*i].status = INTV_OPEN;
00154     scanpointsx[2*i+1].node = i+n;
00155     scanpointsx[2*i+1].x = x[i*dim] + width[i*dim];
00156     scanpointsx[2*i+1].status = INTV_CLOSE;
00157   }
00158   qsort(scanpointsx, 2*n, sizeof(scan_point), comp_scan_points);
00159 
00160   scanpointsy = N_GNEW(2*n,scan_point);
00161   for (i = 0; i < n; i++){
00162     scanpointsy[i].node = i;
00163     scanpointsy[i].x = x[i*dim+1] - width[i*dim+1];
00164     scanpointsy[i].status = INTV_OPEN;
00165     scanpointsy[i+n].node = i;
00166     scanpointsy[i+n].x = x[i*dim+1] + width[i*dim+1];
00167     scanpointsy[i+n].status = INTV_CLOSE;
00168   }
00169 
00170 
00171   treey = RBTreeCreate(NodeComp,NodeDest,InfoDest,NodePrint,InfoPrint);
00172 
00173   for (i = 0; i < 2*n; i++){
00174 #ifdef DEBUG_RBTREE
00175     fprintf(stderr," k = %d node = %d x====%f\n",(scanpointsx[i].node)%n, (scanpointsx[i].node), (scanpointsx[i].x));
00176 #endif
00177 
00178     k = (scanpointsx[i].node)%n;
00179 
00180 
00181     if (scanpointsx[i].status == INTV_OPEN){
00182 #ifdef DEBUG_RBTREE
00183       fprintf(stderr, "inserting...");
00184       treey->PrintKey(&(scanpointsy[k]));
00185 #endif
00186 
00187       RBTreeInsert(treey, &(scanpointsy[k]), NULL); /* add both open and close int for y */
00188 
00189 #ifdef DEBUG_RBTREE
00190       fprintf(stderr, "inserting2...");
00191       treey->PrintKey(&(scanpointsy[k+n]));
00192 #endif
00193 
00194       RBTreeInsert(treey, &(scanpointsy[k+n]), NULL);
00195     } else {
00196       assert(scanpointsx[i].node >= n);
00197 
00198       newNode = newNode0 = RBExactQuery(treey, &(scanpointsy[k + n]));
00199 
00200 #ifdef DEBUG_RBTREE
00201       fprintf(stderr, "poping..%d....", scanpointsy[k + n].node);
00202       treey->PrintKey(newNode->key);
00203 #endif
00204 
00205       assert(treey->nil != newNode);
00206       while ((newNode) && ((newNode = TreePredecessor(treey, newNode)) != treey->nil) && ((scan_point *)newNode->key)->node != k){
00207         neighbor = (((scan_point *)newNode->key)->node)%n;
00208         A = SparseMatrix_coordinate_form_add_entries(A, 1, &neighbor, &k, &one);
00209 #ifdef DEBUG_RBTREE
00210         fprintf(stderr,"%d %d\n",k,neighbor);
00211 #endif
00212 
00213       }
00214 
00215 #ifdef DEBUG_RBTREE
00216       fprintf(stderr, "deleteing...");
00217       treey->PrintKey(newNode0->key);
00218 #endif
00219 
00220       if (newNode0) RBDelete(treey,newNode0);
00221       if (newNode != treey->nil && newNode != newNode0) {
00222 
00223 #ifdef DEBUG_RBTREE
00224         fprintf(stderr, "deleting2...");
00225         treey->PrintKey(newNode->key)
00226 #endif
00227 
00228         if (newNode0) RBDelete(treey,newNode);
00229       }
00230     }
00231   }
00232 
00233   FREE(scanpointsx);
00234   FREE(scanpointsy);
00235   RBTreeDestroy(treey);
00236 
00237   B = SparseMatrix_from_coordinate_format(A);
00238   SparseMatrix_delete(A);
00239   A = SparseMatrix_symmetrize(B, FALSE);
00240   SparseMatrix_delete(B);
00241   if (Verbose) fprintf(stderr, "found %d clashes\n", A->nz);
00242   return A;
00243 }
00244 
00245 
00246 
00247 /* ============================== label overlap smoother ==================*/
00248 
00249 
00250 static void relative_position_constraints_delete(void *d){
00251   relative_position_constraints data;
00252   if (!d) return;
00253   data = (relative_position_constraints) d;
00254   if (data->irn) FREE(data->irn);
00255   if (data->jcn) FREE(data->jcn);
00256   if (data->val) FREE(data->val);
00257   /* other stuff inside relative_position_constraints is assed back to the user hence no need to deallocator*/
00258   FREE(d);
00259 }
00260 
00261 static relative_position_constraints relative_position_constraints_new(SparseMatrix A_constr, int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes){
00262     relative_position_constraints data;
00263     assert(A_constr);
00264     data = MALLOC(sizeof(struct relative_position_constraints_struct));
00265     data->constr_penalty = 1;
00266     data->edge_labeling_scheme = edge_labeling_scheme;
00267     data->n_constr_nodes = n_constr_nodes;
00268     data->constr_nodes = constr_nodes;
00269     data->A_constr = A_constr;
00270     data->irn = NULL;
00271     data->jcn = NULL;
00272     data->val = NULL;
00273 
00274     return data;
00275 }
00276 
00277 OverlapSmoother OverlapSmoother_new(SparseMatrix A, int m, 
00278                                     int dim, real lambda0, real *x, real *width, int include_original_graph, int neighborhood_only, 
00279                                     real *max_overlap, real *min_overlap,
00280                                     int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int shrink
00281                                     ){
00282   OverlapSmoother sm;
00283   int i, j, k, *iw, *jw, *id, *jd, jdiag;
00284   SparseMatrix B;
00285   real *lambda, *d, *w, diag_d, diag_w, dist;
00286 
00287   assert((!A) || SparseMatrix_is_symmetric(A, FALSE));
00288 
00289   sm = GNEW(struct OverlapSmoother_struct);
00290   sm->scheme = SM_SCHEME_NORMAL;
00291   if (constr_nodes && n_constr_nodes > 0 && edge_labeling_scheme != ELSCHEME_NONE){
00292     sm->scheme = SM_SCHEME_NORMAL_ELABEL;
00293     sm->data = relative_position_constraints_new(A_constr, edge_labeling_scheme, n_constr_nodes, constr_nodes);
00294     sm->data_deallocator = relative_position_constraints_delete;
00295   } else {
00296     sm->data = NULL;
00297   }
00298 
00299   lambda = sm->lambda = N_GNEW(m,real);
00300   for (i = 0; i < m; i++) sm->lambda[i] = lambda0;
00301   
00302   B= call_tri(m, dim, x);
00303 
00304   if (!neighborhood_only){
00305     SparseMatrix C, D;
00306     C = get_overlap_graph(dim, m, x, width);
00307     D = SparseMatrix_add(B, C);
00308     SparseMatrix_delete(B);
00309     SparseMatrix_delete(C);
00310     B = D;
00311   }
00312   if (include_original_graph){
00313     sm->Lw = SparseMatrix_add(A, B);
00314     SparseMatrix_delete(B);
00315   } else {
00316     sm->Lw = B;
00317   }
00318   sm->Lwd = SparseMatrix_copy(sm->Lw);
00319 
00320 #ifdef DEBUG
00321   {
00322     FILE *fp;
00323     fp = fopen("/tmp/111","w");
00324     export_embedding(fp, dim, sm->Lwd, x, NULL);
00325     fclose(fp);
00326   }
00327 #endif
00328 
00329   if (!(sm->Lw) || !(sm->Lwd)) {
00330     OverlapSmoother_delete(sm);
00331     return NULL;
00332   }
00333 
00334   assert((sm->Lwd)->type == MATRIX_TYPE_REAL);
00335   
00336   ideal_distance_avoid_overlap(dim, sm->Lwd, x, width, (real*) (sm->Lwd->a), max_overlap, min_overlap);
00337 
00338   /* no overlap at all! */
00339   if (*max_overlap < 1 && shrink){
00340     if (Verbose) fprintf(stderr," no overlap (overlap = %f), rescale to shrink\n", *max_overlap - 1);
00341     for (i = 0; i < dim*m; i++) {
00342       x[i] *= (*max_overlap);
00343     }
00344     *max_overlap = 1;
00345     goto RETURN;
00346   }
00347 
00348   iw = sm->Lw->ia; jw = sm->Lw->ja;
00349   id = sm->Lwd->ia; jd = sm->Lwd->ja;
00350   w = (real*) sm->Lw->a; d = (real*) sm->Lwd->a;
00351 
00352   for (i = 0; i < m; i++){
00353     diag_d = diag_w = 0;
00354     jdiag = -1;
00355     for (j = iw[i]; j < iw[i+1]; j++){
00356       k = jw[j];
00357       if (k == i){
00358         jdiag = j;
00359         continue;
00360       }
00361       if (d[j] > 0){/* those edges that needs expansion */
00362         w[j] = -100/d[j]/d[j];
00363         /*w[j] = 100/d[j]/d[j];*/
00364       } else {/* those that needs shrinking is set to negative in ideal_distance_avoid_overlap */
00365         /*w[j] = 1/d[j]/d[j];*/
00366         w[j] = -1/d[j]/d[j];
00367         d[j] = -d[j];
00368       }
00369       dist = d[j];
00370       diag_w += w[j];
00371       d[j] = w[j]*dist;
00372       diag_d += d[j];
00373 
00374     }
00375 
00376     lambda[i] *= (-diag_w);/* alternatively don't do that then we have a constant penalty term scaled by lambda0 */
00377 
00378     assert(jdiag >= 0);
00379     w[jdiag] = -diag_w + lambda[i];
00380     d[jdiag] = -diag_d;
00381   }
00382  RETURN:
00383   return sm;
00384 }
00385 
00386 void OverlapSmoother_delete(OverlapSmoother sm){
00387 
00388   StressMajorizationSmoother_delete(sm);
00389 
00390 }
00391 
00392 real OverlapSmoother_smooth(OverlapSmoother sm, int dim, real *x){
00393   int maxit_sm = 1;/* only using 1 iteration of stress majorization 
00394                       is found to give better results and save time! */
00395   real res = StressMajorizationSmoother_smooth(sm, dim, x, maxit_sm, 0.001);
00396 #ifdef DEBUG
00397   {FILE *fp;
00398   fp = fopen("/tmp/222","w");
00399   export_embedding(fp, dim, sm->Lwd, x, NULL);
00400   fclose(fp);}
00401 #endif
00402   return res;
00403 }
00404 
00405 /*================================= end OverlapSmoother =============*/
00406 
00407 static void scale_to_edge_length(int dim, SparseMatrix A, real *x, real avg_label_size){
00408   real dist;
00409   int i;
00410 
00411   if (!A) return;
00412   dist = average_edge_length(A, dim, x);
00413   if (Verbose) fprintf(stderr,"avg edge len=%f avg_label-size= %f\n", dist, avg_label_size);
00414 
00415 
00416   dist = avg_label_size/MAX(dist, MACHINEACC);
00417 
00418   for (i = 0; i < dim*A->m; i++) x[i] *= dist;
00419 }
00420 
00421 static void print_bounding_box(int n, int dim, real *x){
00422   real *xmin, *xmax;
00423   int i, k;
00424 
00425   xmin = N_GNEW(dim,real);
00426   xmax = N_GNEW(dim,real);
00427 
00428   for (i = 0; i < dim; i++) xmin[i]=xmax[i] = x[i];
00429 
00430   for (i = 0; i < n; i++){
00431     for (k = 0; k < dim; k++){
00432       xmin[k] = MIN(xmin[k],x[i*dim+k]);
00433       xmax[k] = MAX(xmax[k],x[i*dim+k]);
00434     }
00435   }
00436   fprintf(stderr,"bounding box = \n");
00437   for (i = 0; i < dim; i++) fprintf(stderr,"{%f,%f}, ",xmin[i], xmax[i]);
00438   fprintf(stderr,"\n");
00439 
00440   FREE(xmin);
00441   FREE(xmax);
00442 }
00443 
00444 static int check_convergence(real max_overlap, real res, int has_penalty_terms, real epsilon){
00445   if (!has_penalty_terms) return (max_overlap <= 1);
00446   return res < epsilon;
00447 }
00448 
00449 void remove_overlap(int dim, SparseMatrix A, real *x, real *label_sizes, int ntry, real initial_scaling, 
00450                     int edge_labeling_scheme, int n_constr_nodes, int *constr_nodes, SparseMatrix A_constr, int *flag){
00451   /* 
00452      edge_labeling_scheme: if ELSCHEME_NONE, n_constr_nodes/constr_nodes/A_constr are not used
00453 
00454      n_constr_nodes: number of nodes that has constraints, these are nodes that is
00455      .               constrained to be close to the average of its neighbors.
00456      constr_nodes: a list of nodes that need to be constrained. If NULL, unused.
00457      A_constr: neighbors of node i are in the row i of this matrix. i needs to sit
00458      .         in between these neighbors as much as possible. this must not be NULL
00459      .         if constr_nodes != NULL.
00460 
00461   */
00462 
00463   real lambda = 0.00;
00464   OverlapSmoother sm;
00465   int include_original_graph = 0, i;
00466   real LARGE = 100000;
00467   real avg_label_size, res = LARGE;
00468   real max_overlap = 0, min_overlap = 999;
00469   int neighborhood_only = TRUE;
00470   int has_penalty_terms = FALSE;
00471   real epsilon = 0.005;
00472   int shrink = 0;
00473 
00474 #ifdef TIME
00475   clock_t  cpu;
00476 #endif
00477 
00478 #ifdef TIME
00479   cpu = clock();
00480 #endif
00481 
00482   if (!label_sizes) return;
00483 
00484   if (initial_scaling < 0) {
00485     avg_label_size = 0;
00486     for (i = 0; i < A->m; i++) avg_label_size += label_sizes[i*dim]+label_sizes[i*dim+1];
00487     /*  for (i = 0; i < A->m; i++) avg_label_size += 2*MAX(label_sizes[i*dim],label_sizes[i*dim+1]);*/
00488     avg_label_size /= A->m;
00489     scale_to_edge_length(dim, A, x, -initial_scaling*avg_label_size);
00490   } else if (initial_scaling > 0){
00491     scale_to_edge_length(dim, A, x, initial_scaling);
00492   }
00493 
00494   if (!ntry) return;
00495 
00496   *flag = 0;
00497 
00498 #ifdef DEBUG
00499   _statistics[0] = _statistics[1] = 0.;
00500   {FILE*fp;
00501   fp = fopen("x1","w");
00502   for (i = 0; i < A->m; i++){
00503     fprintf(fp, "%f %f\n",x[i*2],x[i*2+1]);
00504   }
00505   fclose(fp);
00506   }
00507 #endif
00508 
00509 #ifdef ANIMATE
00510   {FILE*fp;
00511     fp = fopen("/tmp/m","wa");
00512     fprintf(fp,"{");
00513 #endif
00514 
00515   has_penalty_terms = (edge_labeling_scheme != ELSCHEME_NONE && n_constr_nodes > 0);
00516   for (i = 0; i < ntry; i++){
00517     if (Verbose) print_bounding_box(A->m, dim, x);
00518     sm = OverlapSmoother_new(A, A->m, dim, lambda, x, label_sizes, include_original_graph, neighborhood_only,
00519                              &max_overlap, &min_overlap, edge_labeling_scheme, n_constr_nodes, constr_nodes, A_constr, shrink); 
00520     if (Verbose) fprintf(stderr, "overlap removal neighbors only?= %d iter -- %d, overlap factor = %g underlap factor = %g\n", neighborhood_only, i, max_overlap - 1, min_overlap);
00521     if (check_convergence(max_overlap, res, has_penalty_terms, epsilon)){
00522     
00523       OverlapSmoother_delete(sm);
00524       if (neighborhood_only == FALSE){
00525         break;
00526       } else {
00527         res = LARGE;
00528         neighborhood_only = FALSE; shrink = 1;
00529         continue;
00530       }
00531     }
00532     
00533     res = OverlapSmoother_smooth(sm, dim, x);
00534     if (Verbose) fprintf(stderr,"res = %f\n",res);
00535 #ifdef ANIMATE
00536     if (i != 0) fprintf(fp,",");
00537     export_embedding(fp, dim, A, x, label_sizes);
00538 #endif
00539     OverlapSmoother_delete(sm);
00540   }
00541   if (Verbose) 
00542     fprintf(stderr, "overlap removal neighbors only?= %d iter -- %d, overlap factor = %g underlap factor = %g\n", neighborhood_only, i, max_overlap - 1, min_overlap);
00543 
00544 #ifdef ANIMATE
00545   fprintf(fp,"}");
00546     fclose(fp);
00547   }
00548 #endif
00549 
00550   if (has_penalty_terms){
00551     /* now do without penalty */
00552     remove_overlap(dim, A, x, label_sizes, ntry, 0.,
00553                    ELSCHEME_NONE, 0, NULL, NULL, flag);
00554   }
00555 
00556 #ifdef DEBUG
00557   fprintf(stderr," number of cg iter = %f, number of stress majorization iter = %f number of overlap removal try = %d\n",
00558           _statistics[0], _statistics[1], i - 1);
00559 
00560   {FILE*fp;
00561   fp = fopen("x2","w");
00562   for (i = 0; i < A->m; i++){
00563     fprintf(fp, "%f %f\n",x[i*2],x[i*2+1]);
00564   }
00565   fclose(fp);
00566   }
00567 #endif
00568 
00569 #ifdef DEBUG
00570   {FILE*fp;
00571   fp = fopen("/tmp/m","w");
00572   if (A) export_embedding(fp, dim, A, x, label_sizes);
00573   fclose(fp);
00574   }
00575 #endif
00576 #ifdef TIME
00577   fprintf(stderr, "post processing %f\n",((real) (clock() - cpu)) / CLOCKS_PER_SEC);
00578 #endif
00579 }
00580 
00581 #else
00582 #include "types.h"
00583 #include "SparseMatrix.h"
00584 void remove_overlap(int dim, SparseMatrix A, int m, real *x, real *label_sizes, int ntry, real initial_scaling, int *flag)
00585 {
00586     agerr(AGERR, "remove_overlap: Graphviz not built with triangulation library\n");
00587 }
00588 #endif