Graphviz  2.29.20120523.0446
lib/neatogen/closest.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 "kkutils.h"
00016 #include "closest.h"
00017 #include <stdlib.h>
00018 
00019 /*****************************************
00020 ** This module contains functions that  **
00021 ** given a 1-D layout construct a graph **
00022 ** where close nodes in this layout are **
00023 ** adjacent                             **
00024 *****************************************/
00025 
00026 typedef struct {
00027     /* this structure represents two nodes in the 1-D layout */
00028     int left;                   /* the left node in the pair */
00029     int right;                  /* the right node in the pair */
00030     double dist;                /* distance between the nodes in the layout */
00031 } Pair;
00032 
00033 #define LT(p,q) ((p).dist < (q).dist)
00034 #define EQ(p,q) ((p).dist == (q).dist)
00035 
00036 /*
00037 Pair(int v, int u) {left=v; right=u;}
00038 bool operator>(Pair other) {return dist>other.dist;}
00039 bool operator>=(Pair other) {return dist>=other.dist;}
00040 bool operator<(Pair other) {return dist<other.dist;}
00041 bool operator<=(Pair other) {return dist<=other.dist;}
00042 bool operator==(Pair other) {return dist==other.dist;}
00043 */
00044 
00045 typedef struct {
00046     Pair *data;
00047     int max_size;
00048     int top;
00049 } PairStack;
00050 
00051 static void initStack(PairStack * s, int n)
00052 {
00053     s->data = N_GNEW(n, Pair);
00054     s->max_size = n;
00055     s->top = 0;
00056 }
00057 
00058 static void freeStack(PairStack * s)
00059 {
00060     free(s->data);
00061 }
00062 
00063 #define push(s,x) { \
00064         if (s->top>=s->max_size) { \
00065                 s->max_size *= 2; \
00066                 s->data = (Pair*) realloc(s->data, s->max_size*sizeof(Pair)); \
00067         } \
00068         s->data[s->top++] = x; \
00069 }
00070 
00071 #define pop(s,x) ((s->top==0) ? FALSE : (s->top--, x = s->data[s->top], TRUE))
00072 
00073 #define read_top(h,x) ((s->top==0) ? FALSE : (x = s->data[s->top-1], TRUE))
00074 
00075 #define sub(h,i) (h->data[i])
00076 
00077 /* An auxulliary data structure (a heap) for 
00078  * finding the closest pair in the layout
00079  */
00080 typedef struct {
00081     Pair *data;
00082     int heapSize;
00083     int maxSize;
00084 } PairHeap;
00085 
00086 #define left(i) (2*(i))
00087 #define right(i) (2*(i)+1)
00088 #define parent(i) ((i)/2)
00089 #define insideHeap(h,i) ((i)<h->heapSize)
00090 #define greaterPriority(h,i,j) \
00091   (LT(h->data[i],h->data[j]) || ((EQ(h->data[i],h->data[j])) && (rand()%2)))
00092 
00093 #define exchange(h,i,j) {Pair temp; \
00094         temp=h->data[i]; \
00095         h->data[i]=h->data[j]; \
00096         h->data[j]=temp; \
00097 }
00098 #define assign(h,i,j) {h->data[i]=h->data[j]}
00099 
00100 static void heapify(PairHeap * h, int i)
00101 {
00102     int l, r, largest;
00103     while (1) {
00104         l = left(i);
00105         r = right(i);
00106         if (insideHeap(h, l) && greaterPriority(h, l, i))
00107             largest = l;
00108         else
00109             largest = i;
00110         if (insideHeap(h, r) && greaterPriority(h, r, largest))
00111             largest = r;
00112         if (largest == i)
00113             break;
00114 
00115         exchange(h, largest, i);
00116         i = largest;
00117     }
00118 }
00119 
00120 #ifdef UNUSED
00121 static void mkHeap(PairHeap * h, int size)
00122 {
00123     h->data = N_GNEW(size, Pair);
00124     h->maxSize = size;
00125     h->heapSize = 0;
00126 }
00127 #endif
00128 
00129 static void freeHeap(PairHeap * h)
00130 {
00131     free(h->data);
00132 }
00133 
00134 static void initHeap(PairHeap * h, double *place, int *ordering, int n)
00135 {
00136     int i;
00137     Pair edge;
00138     int j;
00139 
00140     h->heapSize = n - 1;
00141 #ifdef REDO
00142     if (h->heapSize > h->maxSize) {
00143         h->maxSize = h->heapSize;
00144         h->data = (Pair *) realloc(h->data, h->maxSize * sizeof(Pair));
00145     }
00146 #else
00147     h->maxSize = h->heapSize;
00148     h->data = N_GNEW(h->maxSize, Pair);
00149 #endif
00150 
00151     for (i = 0; i < n - 1; i++) {
00152         edge.left = ordering[i];
00153         edge.right = ordering[i + 1];
00154         edge.dist = place[ordering[i + 1]] - place[ordering[i]];
00155         h->data[i] = edge;
00156     }
00157     for (j = (n - 1) / 2; j >= 0; j--) {
00158         heapify(h, j);
00159     }
00160 }
00161 
00162 static boolean extractMax(PairHeap * h, Pair * max)
00163 {
00164     if (h->heapSize == 0)
00165         return FALSE;
00166 
00167     *max = h->data[0];
00168     h->data[0] = h->data[h->heapSize - 1];
00169     h->heapSize--;
00170     heapify(h, 0);
00171     return TRUE;
00172 }
00173 
00174 static void insert(PairHeap * h, Pair edge)
00175 {
00176     int i = h->heapSize;
00177     if (h->heapSize == h->maxSize) {
00178         h->maxSize *= 2;
00179         h->data = (Pair *) realloc(h->data, h->maxSize * sizeof(Pair));
00180     }
00181     h->heapSize++;
00182     h->data[i] = edge;
00183     while (i > 0 && greaterPriority(h, i, parent(i))) {
00184         exchange(h, i, parent(i));
00185         i = parent(i);
00186     }
00187 }
00188 
00189 /*
00190 static bool
00191 isheap(PairHeap* h)
00192 {
00193         int i,l,r;
00194         for (i=0; i<h->heapSize; i++) {
00195                 l=left(i); r=right(i);
00196                 if (insideHeap(h,l) && greaterPriority(h,l,i))
00197                         return FALSE;
00198                 if (insideHeap(h,r) && greaterPriority(h,r,i))
00199                         return FALSE;
00200         }
00201         return TRUE;
00202 }
00203 */
00204 
00205 static void
00206 find_closest_pairs(double *place, int n, int num_pairs,
00207                    PairStack * pairs_stack)
00208 {
00209     /* Fill the stack 'pairs_stack' with 'num_pairs' closest pairs int the 1-D layout 'place' */
00210     int i;
00211     PairHeap heap;
00212     int *left = N_GNEW(n, int);
00213     int *right = N_GNEW(n, int);
00214     Pair pair = { 0, 0 }, new_pair;
00215 
00216     /* Order the nodes according to their place */
00217     int *ordering = N_GNEW(n, int);
00218     int *inv_ordering = N_GNEW(n, int);
00219 
00220     for (i = 0; i < n; i++) {
00221         ordering[i] = i;
00222     }
00223     quicksort_place(place, ordering, 0, n - 1);
00224     for (i = 0; i < n; i++) {
00225         inv_ordering[ordering[i]] = i;
00226     }
00227 
00228     /* Intialize heap with all consecutive pairs */
00229     initHeap(&heap, place, ordering, n);
00230 
00231     /* store the leftmost and rightmost neighbors of each node that were entered into heap */
00232     for (i = 1; i < n; i++) {
00233         left[ordering[i]] = ordering[i - 1];
00234     }
00235     for (i = 0; i < n - 1; i++) {
00236         right[ordering[i]] = ordering[i + 1];
00237     }
00238 
00239     /* extract the 'num_pairs' closest pairs */
00240     for (i = 0; i < num_pairs; i++) {
00241         int left_index;
00242         int right_index;
00243         int neighbor;
00244 
00245         if (!extractMax(&heap, &pair)) {
00246             break;              /* not enough pairs */
00247         }
00248         push(pairs_stack, pair);
00249         /* insert to heap "descendant" pairs */
00250         left_index = inv_ordering[pair.left];
00251         right_index = inv_ordering[pair.right];
00252         if (left_index > 0) {
00253             neighbor = ordering[left_index - 1];
00254             if (inv_ordering[right[neighbor]] < right_index) {
00255                 /* we have a new pair */
00256                 new_pair.left = neighbor;
00257                 new_pair.right = pair.right;
00258                 new_pair.dist = place[pair.right] - place[neighbor];
00259                 insert(&heap, new_pair);
00260                 right[neighbor] = pair.right;
00261                 left[pair.right] = neighbor;
00262             }
00263         }
00264         if (right_index < n - 1) {
00265             neighbor = ordering[right_index + 1];
00266             if (inv_ordering[left[neighbor]] > left_index) {
00267                 /* we have a new pair */
00268                 new_pair.left = pair.left;
00269                 new_pair.right = neighbor;
00270                 new_pair.dist = place[neighbor] - place[pair.left];
00271                 insert(&heap, new_pair);
00272                 left[neighbor] = pair.left;
00273                 right[pair.left] = neighbor;
00274             }
00275         }
00276     }
00277     free(left);
00278     free(right);
00279     free(ordering);
00280     free(inv_ordering);
00281     freeHeap(&heap);
00282 }
00283 
00284 static void add_edge(vtx_data * graph, int u, int v)
00285 {
00286     int i;
00287     for (i = 0; i < graph[u].nedges; i++) {
00288         if (graph[u].edges[i] == v) {
00289             /* edge already exist */
00290             return;
00291         }
00292     }
00293     /* add the edge */
00294     graph[u].edges[graph[u].nedges++] = v;
00295     graph[v].edges[graph[v].nedges++] = u;
00296     if (graph[0].ewgts != NULL) {
00297         graph[u].ewgts[0]--;
00298         graph[v].ewgts[0]--;
00299     }
00300 }
00301 
00302 static void
00303 construct_graph(int n, PairStack * edges_stack, vtx_data ** New_graph)
00304 {
00305     /* construct an unweighted graph using the edges 'edges_stack' */
00306     int i;
00307     vtx_data *new_graph;
00308 
00309     /* first compute new degrees and nedges; */
00310     int *degrees = N_GNEW(n, int);
00311     int top = edges_stack->top;
00312     int new_nedges = 2 * top + n;
00313     Pair pair;
00314     int *edges = N_GNEW(new_nedges, int);
00315     float *weights = N_GNEW(new_nedges, float);
00316 
00317     for (i = 0; i < n; i++) {
00318         degrees[i] = 1;         /* save place for the self loop */
00319     }
00320     for (i = 0; i < top; i++) {
00321         pair = sub(edges_stack, i);
00322         degrees[pair.left]++;
00323         degrees[pair.right]++;
00324     }
00325 
00326     /* copy graph into new_graph: */
00327     for (i = 0; i < new_nedges; i++) {
00328         weights[i] = 1.0;
00329     }
00330 
00331     *New_graph = new_graph = N_GNEW(n, vtx_data);
00332     for (i = 0; i < n; i++) {
00333         new_graph[i].nedges = 1;
00334         new_graph[i].ewgts = weights;
00335 #ifdef USE_STYLES
00336         new_graph[i].styles = NULL;
00337 #endif
00338         new_graph[i].edges = edges;
00339         *edges = i;             /* self loop for Lap */
00340         *weights = 0;           /* self loop weight for Lap */
00341         weights += degrees[i];
00342         edges += degrees[i];    /* reserve space for possible more edges */
00343     }
00344 
00345     free(degrees);
00346 
00347     /* add all edges from stack */
00348     while (pop(edges_stack, pair)) {
00349         add_edge(new_graph, pair.left, pair.right);
00350     }
00351 }
00352 
00353 void
00354 closest_pairs2graph(double *place, int n, int num_pairs, vtx_data ** graph)
00355 {
00356     /* build a graph with with edges between the 'num_pairs' closest pairs in the 1-D space: 'place' */
00357     PairStack pairs_stack;
00358     initStack(&pairs_stack, num_pairs);
00359     find_closest_pairs(place, n, num_pairs, &pairs_stack);
00360     construct_graph(n, &pairs_stack, graph);
00361     freeStack(&pairs_stack);
00362 }