Graphviz  2.29.20120524.0446
lib/neatogen/kkutils.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 
00015 #include "bfs.h"
00016 #include "dijkstra.h"
00017 #include "kkutils.h"
00018 #include <stdlib.h>
00019 #include <math.h>
00020 
00021 int common_neighbors(vtx_data * graph, int v, int u, int *v_vector)
00022 {
00023     /* count number of common neighbors of 'v' and 'u' */
00024     int neighbor;
00025     int num_shared_neighbors = 0;
00026     int j;
00027     for (j = 1; j < graph[u].nedges; j++) {
00028         neighbor = graph[u].edges[j];
00029         if (v_vector[neighbor] > 0) {
00030             /* a shared neighobr */
00031             num_shared_neighbors++;
00032         }
00033     }
00034     return num_shared_neighbors;
00035 }
00036 void fill_neighbors_vec_unweighted(vtx_data * graph, int vtx, int *vtx_vec)
00037 {
00038     /* a node is NOT a neighbor of itself! */
00039     /* unlike the other version of this function */
00040     int j;
00041     for (j = 1; j < graph[vtx].nedges; j++) {
00042         vtx_vec[graph[vtx].edges[j]] = 1;
00043     }
00044 }
00045 
00046 void empty_neighbors_vec(vtx_data * graph, int vtx, int *vtx_vec)
00047 {
00048     int j;
00049     /* a node is NOT a neighbor of itself! */
00050     /* unlike the other version ofthis function */
00051     for (j = 1; j < graph[vtx].nedges; j++) {
00052         vtx_vec[graph[vtx].edges[j]] = 0;
00053     }
00054 }
00055 
00056 /* compute_apsp_dijkstra:
00057  * Assumes the graph has weights
00058  */
00059 static DistType **compute_apsp_dijkstra(vtx_data * graph, int n)
00060 {
00061     int i;
00062     DistType *storage;
00063     DistType **dij;
00064 
00065     storage = N_GNEW(n * n, DistType);
00066     dij = N_GNEW(n, DistType *);
00067     for (i = 0; i < n; i++)
00068         dij[i] = storage + i * n;
00069 
00070     for (i = 0; i < n; i++) {
00071         dijkstra(i, graph, n, dij[i]);
00072     }
00073     return dij;
00074 }
00075 
00076 static DistType **compute_apsp_simple(vtx_data * graph, int n)
00077 {
00078     /* compute all pairs shortest path */
00079     /* for unweighted graph */
00080     int i;
00081     DistType *storage = N_GNEW(n * n, int);
00082     DistType **dij;
00083     Queue Q;
00084 
00085     dij = N_GNEW(n, DistType *);
00086     for (i = 0; i < n; i++) {
00087         dij[i] = storage + i * n;
00088     }
00089     mkQueue(&Q, n);
00090     for (i = 0; i < n; i++) {
00091         bfs(i, graph, n, dij[i], &Q);
00092     }
00093     freeQueue(&Q);
00094     return dij;
00095 }
00096 
00097 DistType **compute_apsp(vtx_data * graph, int n)
00098 {
00099     if (graph->ewgts)
00100         return compute_apsp_dijkstra(graph, n);
00101     else
00102         return compute_apsp_simple(graph, n);
00103 }
00104 
00105 DistType **compute_apsp_artifical_weights(vtx_data * graph, int n)
00106 {
00107     DistType **Dij;
00108     /* compute all-pairs-shortest-path-length while weighting the graph */
00109     /* so high-degree nodes are distantly located */
00110 
00111     float *old_weights = graph[0].ewgts;
00112 
00113     compute_new_weights(graph, n);
00114     Dij = compute_apsp_dijkstra(graph, n);
00115     restore_old_weights(graph, n, old_weights);
00116     return Dij;
00117 }
00118 
00119 
00120 /**********************/
00121 /*                    */
00122 /*  Quick Sort        */
00123 /*                    */
00124 /**********************/
00125 
00126 static void
00127 split_by_place(double *place, int *nodes, int first, int last, int *middle)
00128 {
00129     unsigned int splitter=((unsigned int)rand()|((unsigned int)rand())<<16)%(unsigned int)(last-first+1)+(unsigned int)first;
00130     int val;
00131     double place_val;
00132     int left = first + 1;
00133     int right = last;
00134     int temp;
00135 
00136     val = nodes[splitter];
00137     nodes[splitter] = nodes[first];
00138     nodes[first] = val;
00139     place_val = place[val];
00140 
00141     while (left < right) {
00142         while (left < right && place[nodes[left]] <= place_val)
00143             left++;
00144         /* use here ">" and not ">=" to enable robustness
00145          * by ensuring that ALL equal values move to the same side
00146          */
00147         while (left < right && place[nodes[right]] > place_val)
00148             right--;
00149         if (left < right) {
00150             temp = nodes[left];
00151             nodes[left] = nodes[right];
00152             nodes[right] = temp;
00153             left++;
00154             right--;            /* (1) */
00155 
00156         }
00157     }
00158     /* at this point either, left==right (meeting), or 
00159      * left=right+1 (because of (1)) 
00160      * we have to decide to which part the meeting point (or left) belongs.
00161      *
00162      * notice that always left>first, because of its initialization
00163      */
00164     if (place[nodes[left]] > place_val)
00165         left = left - 1;
00166     *middle = left;
00167     nodes[first] = nodes[left];
00168     nodes[left] = val;
00169 }
00170 
00171 double distance_kD(double **coords, int dim, int i, int j)
00172 {
00173     /* compute a k-D Euclidean distance between 'coords[*][i]' and 'coords[*][j]' */
00174     double sum = 0;
00175     int k;
00176     for (k = 0; k < dim; k++) {
00177         sum +=
00178             (coords[k][i] - coords[k][j]) * (coords[k][i] - coords[k][j]);
00179     }
00180     return sqrt(sum);
00181 }
00182 
00183 static float* fvals;
00184 static int
00185 fcmpf (int* ip1, int* ip2)
00186 {
00187     float d1 = fvals[*ip1];
00188     float d2 = fvals[*ip2];
00189     if (d1 < d2) return -1;
00190     else if (d1 > d2) return 1;
00191     else return 0;
00192 }
00193 
00194 void quicksort_placef(float *place, int *ordering, int first, int last)
00195 {
00196     if (first < last) {
00197         fvals = place;
00198         qsort(ordering+first, last-first+1, sizeof(ordering[0]), (qsort_cmpf)fcmpf);
00199     }
00200 }
00201 
00202 static int 
00203 sorted_place(double * place, int * ordering, int first,int last)
00204 {
00205     int i, isSorted = 1; 
00206     for (i=first+1; i<=last && isSorted; i++) {
00207         if (place[ordering[i-1]]>place[ordering[i]]) {
00208             isSorted = 0;
00209         }
00210     }
00211     return isSorted;
00212 }
00213 
00214 /* quicksort_place:
00215  * For now, we keep the current implementation for stability, but
00216  * we should consider replacing this with an implementation similar to
00217  * quicksort_placef above.
00218  */
00219 void quicksort_place(double *place, int *ordering, int first, int last)
00220 {
00221     if (first < last) {
00222         int middle;
00223 #ifdef __cplusplus
00224         split_by_place(place, ordering, first, last, middle);
00225 #else
00226         split_by_place(place, ordering, first, last, &middle);
00227 #endif
00228         quicksort_place(place, ordering, first, middle - 1);
00229         quicksort_place(place, ordering, middle + 1, last);
00230         /* Checking for "already sorted" dramatically improves running time 
00231          * and robustness (against uneven recursion) when not all values are 
00232          * distinct (thefore we expect emerging chunks of equal values)
00233          * it never increased running time even when values were distinct
00234          */
00235         if (!sorted_place(place,ordering,first,middle-1))
00236             quicksort_place(place,ordering,first,middle-1);
00237         if (!sorted_place(place,ordering,middle+1,last))
00238             quicksort_place(place,ordering,middle+1,last);
00239     }
00240 }
00241 
00242 void compute_new_weights(vtx_data * graph, int n)
00243 {
00244     /* Reweight graph so that high degree nodes will be separated */
00245 
00246     int i, j;
00247     int nedges = 0;
00248     float *weights;
00249     int *vtx_vec = N_GNEW(n, int);
00250     int deg_i, deg_j, neighbor;
00251 
00252     for (i = 0; i < n; i++) {
00253         nedges += graph[i].nedges;
00254     }
00255     weights = N_GNEW(nedges, float);
00256 
00257     for (i = 0; i < n; i++) {
00258         vtx_vec[i] = 0;
00259     }
00260 
00261     for (i = 0; i < n; i++) {
00262         graph[i].ewgts = weights;
00263         fill_neighbors_vec_unweighted(graph, i, vtx_vec);
00264         deg_i = graph[i].nedges - 1;
00265         for (j = 1; j <= deg_i; j++) {
00266             neighbor = graph[i].edges[j];
00267             deg_j = graph[neighbor].nedges - 1;
00268             weights[j] =
00269                 (float) (deg_i + deg_j -
00270                          2 * common_neighbors(graph, i, neighbor,
00271                                               vtx_vec));
00272         }
00273         empty_neighbors_vec(graph, i, vtx_vec);
00274         weights += graph[i].nedges;
00275     }
00276     free(vtx_vec);
00277 }
00278 
00279 void restore_old_weights(vtx_data * graph, int n, float *old_weights)
00280 {
00281     int i;
00282     free(graph[0].ewgts);
00283     graph[0].ewgts = NULL;
00284     if (old_weights != NULL) {
00285         for (i = 0; i < n; i++) {
00286             graph[i].ewgts = old_weights;
00287             old_weights += graph[i].nedges;
00288         }
00289     }
00290 }