|
Graphviz
2.29.20120523.0446
|
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 #include <digcola.h> 00015 #ifdef DIGCOLA 00016 #include "kkutils.h" 00017 00018 static int *given_levels = NULL; 00019 /* 00020 * This function partitions the graph nodes into levels 00021 * according to the minimizer of the hierarchy energy. 00022 * 00023 * To allow more flexibility we define a new level only 00024 * when the hierarchy energy shows a significant jump 00025 * (to compensate for noise). 00026 * This is controlled by two parameters: 'abs_tol' and 00027 * 'relative_tol'. The smaller these two are, the more 00028 * levels we'll get. 00029 * More speciffically: 00030 * We never consider gaps smaller than 'abs_tol' 00031 * Additionally, we never consider gaps smaller than 'abs_tol'*<avg_gap> 00032 * 00033 * The output is an ordering of the nodes according to 00034 * their levels, as follows: 00035 * First level: 00036 * ordering[0],ordering[1],...ordering[levels[0]-1] 00037 * Second level: 00038 * ordering[levels[0]],ordering[levels[0]+1],...ordering[levels[1]-1] 00039 * ... 00040 * Last level: 00041 * ordering[levels[num_levels-1]],ordering[levels[num_levels-1]+1],...ordering[n-1] 00042 * 00043 * Hence, the nodes were partitioned into 'num_levels'+1 00044 * levels. 00045 * 00046 * Please note that 'ordering[levels[i]]' contains the first node at level i+1, 00047 * and not the last node of level i. 00048 */ 00049 int 00050 compute_hierarchy(vtx_data * graph, int n, double abs_tol, 00051 double relative_tol, double *given_coords, 00052 int **orderingp, int **levelsp, int *num_levelsp) 00053 { 00054 double *y; 00055 int i, rv=0; 00056 double spread; 00057 int use_given_levels = FALSE; 00058 int *ordering; 00059 int *levels; 00060 double tol; /* node 'i' precedes 'j' in hierachy iff y[i]-y[j]>tol */ 00061 double hierarchy_span; 00062 int num_levels; 00063 00064 /* compute optimizer of hierarchy energy: 'y' */ 00065 if (given_coords) { 00066 y = given_coords; 00067 } else { 00068 y = N_GNEW(n, double); 00069 if (compute_y_coords(graph, n, y, n)) { 00070 rv = 1; 00071 goto finish; 00072 } 00073 } 00074 00075 /* sort nodes accoridng to their y-ordering */ 00076 *orderingp = ordering = N_NEW(n, int); 00077 for (i = 0; i < n; i++) { 00078 ordering[i] = i; 00079 } 00080 quicksort_place(y, ordering, 0, n - 1); 00081 00082 spread = y[ordering[n - 1]] - y[ordering[0]]; 00083 00084 /* after spread is computed, we may take the y-coords as the given levels */ 00085 if (given_levels) { 00086 use_given_levels = TRUE; 00087 for (i = 0; i < n; i++) { 00088 use_given_levels = use_given_levels && given_levels[i] >= 0; 00089 } 00090 } 00091 if (use_given_levels) { 00092 for (i = 0; i < n; i++) { 00093 y[i] = given_levels[i]; 00094 ordering[i] = i; 00095 } 00096 quicksort_place(y, ordering, 0, n - 1); 00097 } 00098 00099 /* compute tolerance 00100 * take the maximum between 'abs_tol' and a fraction of the average gap 00101 * controlled by 'relative_tol' 00102 */ 00103 hierarchy_span = y[ordering[n - 1]] - y[ordering[0]]; 00104 tol = MAX(abs_tol, relative_tol * hierarchy_span / (n - 1)); 00105 /* 'hierarchy_span/(n-1)' - average gap between consecutive nodes */ 00106 00107 00108 /* count how many levels the hierarchy contains (a SINGLE_LINK clustering */ 00109 /* alternatively we could use COMPLETE_LINK clustering) */ 00110 num_levels = 0; 00111 for (i = 1; i < n; i++) { 00112 if (y[ordering[i]] - y[ordering[i - 1]] > tol) { 00113 num_levels++; 00114 } 00115 } 00116 *num_levelsp = num_levels; 00117 if (num_levels == 0) { 00118 *levelsp = levels = N_GNEW(1, int); 00119 levels[0] = n; 00120 } else { 00121 int count = 0; 00122 *levelsp = levels = N_GNEW(num_levels, int); 00123 for (i = 1; i < n; i++) { 00124 if (y[ordering[i]] - y[ordering[i - 1]] > tol) { 00125 levels[count++] = i; 00126 } 00127 } 00128 } 00129 finish: 00130 if (!given_coords) { 00131 free(y); 00132 } 00133 00134 return rv; 00135 } 00136 00137 #endif /* DIGCOLA */
1.7.5