turbonss/src/graph.c

337 lines
7.9 KiB
C
Raw Normal View History

2004-12-23 15:16:30 +02:00
#include "graph.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include <string.h>
#include "vstack.h"
#include "bitbool.h"
2004-12-23 15:16:30 +02:00
2011-02-16 06:46:05 +02:00
// #define DEBUG
2004-12-23 15:16:30 +02:00
#include "debug.h"
/* static const cmph_uint8 bitmask[8] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; */
/* #define GETBIT(array, i) (array[(i) / 8] & bitmask[(i) % 8]) */
/* #define SETBIT(array, i) (array[(i) / 8] |= bitmask[(i) % 8]) */
/* #define UNSETBIT(array, i) (array[(i) / 8] &= (~(bitmask[(i) % 8]))) */
2004-12-23 15:16:30 +02:00
#define abs_edge(e, i) (e % g->nedges + i * g->nedges)
struct __graph_t
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 nnodes;
cmph_uint32 nedges;
cmph_uint32 *edges;
cmph_uint32 *first;
cmph_uint32 *next;
cmph_uint8 *critical_nodes; /* included -- Fabiano*/
cmph_uint32 ncritical_nodes; /* included -- Fabiano*/
cmph_uint32 cedges;
2004-12-23 15:16:30 +02:00
int shrinking;
};
2005-01-18 23:06:08 +02:00
static cmph_uint32 EMPTY = UINT_MAX;
2004-12-23 15:16:30 +02:00
graph_t *graph_new(cmph_uint32 nnodes, cmph_uint32 nedges)
2004-12-23 15:16:30 +02:00
{
graph_t *graph = (graph_t *)malloc(sizeof(graph_t));
2004-12-23 15:16:30 +02:00
if (!graph) return NULL;
2005-01-18 23:06:08 +02:00
graph->edges = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * 2 * nedges);
graph->next = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * 2 * nedges);
graph->first = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * nnodes);
2004-12-23 15:16:30 +02:00
graph->critical_nodes = NULL; /* included -- Fabiano*/
graph->ncritical_nodes = 0; /* included -- Fabiano*/
graph->nnodes = nnodes;
graph->nedges = nedges;
graph_clear_edges(graph);
2004-12-23 15:16:30 +02:00
return graph;
}
void graph_destroy(graph_t *graph)
2004-12-23 15:16:30 +02:00
{
DEBUGP("Destroying graph\n");
2004-12-23 15:16:30 +02:00
free(graph->edges);
free(graph->first);
free(graph->next);
free(graph->critical_nodes); /* included -- Fabiano*/
free(graph);
return;
}
void graph_print(graph_t *g)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 i, e;
2004-12-23 15:16:30 +02:00
for (i = 0; i < g->nnodes; ++i)
{
DEBUGP("Printing edges connected to %u\n", i);
e = g->first[i];
if (e != EMPTY)
{
printf("%u -> %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
while ((e = g->next[e]) != EMPTY)
{
printf("%u -> %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
}
}
2004-12-23 15:16:30 +02:00
}
return;
}
void graph_add_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 e = g->cedges;
2004-12-23 15:16:30 +02:00
assert(v1 < g->nnodes);
assert(v2 < g->nnodes);
assert(e < g->nedges);
assert(!g->shrinking);
g->next[e] = g->first[v1];
g->first[v1] = e;
g->edges[e] = v2;
g->next[e + g->nedges] = g->first[v2];
g->first[v2] = e + g->nedges;
g->edges[e + g->nedges] = v1;
++(g->cedges);
}
static int check_edge(graph_t *g, cmph_uint32 e, cmph_uint32 v1, cmph_uint32 v2)
2004-12-23 15:16:30 +02:00
{
DEBUGP("Checking edge %u %u looking for %u %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)], v1, v2);
2004-12-23 15:16:30 +02:00
if (g->edges[abs_edge(e, 0)] == v1 && g->edges[abs_edge(e, 1)] == v2) return 1;
if (g->edges[abs_edge(e, 0)] == v2 && g->edges[abs_edge(e, 1)] == v1) return 1;
return 0;
}
cmph_uint32 graph_edge_id(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 e;
2004-12-23 15:16:30 +02:00
e = g->first[v1];
assert(e != EMPTY);
if (check_edge(g, e, v1, v2)) return abs_edge(e, 0);
do
{
e = g->next[e];
assert(e != EMPTY);
}
while (!check_edge(g, e, v1, v2));
return abs_edge(e, 0);
}
static void del_edge_point(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 e, prev;
2004-12-23 15:16:30 +02:00
DEBUGP("Deleting edge point %u %u\n", v1, v2);
e = g->first[v1];
if (check_edge(g, e, v1, v2))
2004-12-23 15:16:30 +02:00
{
g->first[v1] = g->next[e];
//g->edges[e] = EMPTY;
DEBUGP("Deleted\n");
return;
}
DEBUGP("Checking linked list\n");
do
{
prev = e;
e = g->next[e];
assert(e != EMPTY);
}
while (!check_edge(g, e, v1, v2));
g->next[prev] = g->next[e];
//g->edges[e] = EMPTY;
DEBUGP("Deleted\n");
}
void graph_del_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
2004-12-23 15:16:30 +02:00
{
g->shrinking = 1;
del_edge_point(g, v1, v2);
del_edge_point(g, v2, v1);
}
void graph_clear_edges(graph_t *g)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 i;
2004-12-23 15:16:30 +02:00
for (i = 0; i < g->nnodes; ++i) g->first[i] = EMPTY;
for (i = 0; i < g->nedges*2; ++i)
2004-12-23 15:16:30 +02:00
{
g->edges[i] = EMPTY;
g->next[i] = EMPTY;
}
g->cedges = 0;
g->shrinking = 0;
}
static cmph_uint8 find_degree1_edge(graph_t *g, cmph_uint32 v, cmph_uint8 *deleted, cmph_uint32 *e)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 edge = g->first[v];
cmph_uint8 found = 0;
2011-02-16 06:46:05 +02:00
DEBUGP("Checking degree of vertex %u connected to edge %u\n", v, edge);
2004-12-23 15:16:30 +02:00
if (edge == EMPTY) return 0;
else if (!(GETBIT(deleted, abs_edge(edge, 0))))
2004-12-23 15:16:30 +02:00
{
found = 1;
*e = edge;
}
while(1)
{
edge = g->next[edge];
if (edge == EMPTY) break;
if (GETBIT(deleted, abs_edge(edge, 0))) continue;
2004-12-23 15:16:30 +02:00
if (found) return 0;
DEBUGP("Found first edge\n");
*e = edge;
found = 1;
}
return found;
}
static void cyclic_del_edge(graph_t *g, cmph_uint32 v, cmph_uint8 *deleted)
2004-12-23 15:16:30 +02:00
{
2009-03-15 01:24:05 +02:00
cmph_uint32 e = 0;
cmph_uint8 degree1;
2005-01-18 23:06:08 +02:00
cmph_uint32 v1 = v;
cmph_uint32 v2 = 0;
2004-12-23 15:16:30 +02:00
degree1 = find_degree1_edge(g, v1, deleted, &e);
if (!degree1) return;
while(1)
2004-12-23 15:16:30 +02:00
{
DEBUGP("Deleting edge %u (%u->%u)\n", e, g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
SETBIT(deleted, abs_edge(e, 0));
2004-12-23 15:16:30 +02:00
v2 = g->edges[abs_edge(e, 0)];
if (v2 == v1) v2 = g->edges[abs_edge(e, 1)];
DEBUGP("Checking if second endpoint %u has degree 1\n", v2);
2004-12-23 15:16:30 +02:00
degree1 = find_degree1_edge(g, v2, deleted, &e);
if (degree1)
2004-12-23 15:16:30 +02:00
{
DEBUGP("Inspecting vertex %u\n", v2);
2004-12-23 15:16:30 +02:00
v1 = v2;
}
else break;
}
}
int graph_is_cyclic(graph_t *g)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 i;
cmph_uint32 v;
cmph_uint8 *deleted = (cmph_uint8 *)malloc((g->nedges*sizeof(cmph_uint8))/8 + 1);
2008-04-12 09:17:21 +03:00
size_t deleted_len = g->nedges/8 + 1;
memset(deleted, 0, deleted_len);
2004-12-23 15:16:30 +02:00
DEBUGP("Looking for cycles in graph with %u vertices and %u edges\n", g->nnodes, g->nedges);
for (v = 0; v < g->nnodes; ++v)
{
cyclic_del_edge(g, v, deleted);
}
for (i = 0; i < g->nedges; ++i)
{
if (!(GETBIT(deleted, i)))
2004-12-23 15:16:30 +02:00
{
DEBUGP("Edge %u %u->%u was not deleted\n", i, g->edges[i], g->edges[i + g->nedges]);
2004-12-23 15:16:30 +02:00
free(deleted);
return 1;
}
}
free(deleted);
return 0;
}
cmph_uint8 graph_node_is_critical(graph_t * g, cmph_uint32 v) /* included -- Fabiano */
2004-12-23 15:16:30 +02:00
{
return (cmph_uint8)GETBIT(g->critical_nodes,v);
2004-12-23 15:16:30 +02:00
}
void graph_obtain_critical_nodes(graph_t *g) /* included -- Fabiano*/
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 i;
cmph_uint32 v;
cmph_uint8 *deleted = (cmph_uint8 *)malloc((g->nedges*sizeof(cmph_uint8))/8+1);
2008-04-12 09:17:21 +03:00
size_t deleted_len = g->nedges/8 + 1;
memset(deleted, 0, deleted_len);
2005-01-17 19:58:43 +02:00
free(g->critical_nodes);
2005-01-18 23:06:08 +02:00
g->critical_nodes = (cmph_uint8 *)malloc((g->nnodes*sizeof(cmph_uint8))/8 + 1);
2004-12-23 15:16:30 +02:00
g->ncritical_nodes = 0;
2005-01-18 23:06:08 +02:00
memset(g->critical_nodes, 0, (g->nnodes*sizeof(cmph_uint8))/8 + 1);
2004-12-23 15:16:30 +02:00
DEBUGP("Looking for the 2-core in graph with %u vertices and %u edges\n", g->nnodes, g->nedges);
for (v = 0; v < g->nnodes; ++v)
{
cyclic_del_edge(g, v, deleted);
}
for (i = 0; i < g->nedges; ++i)
{
if (!(GETBIT(deleted,i)))
2004-12-23 15:16:30 +02:00
{
DEBUGP("Edge %u %u->%u belongs to the 2-core\n", i, g->edges[i], g->edges[i + g->nedges]);
if(!(GETBIT(g->critical_nodes,g->edges[i])))
2004-12-23 15:16:30 +02:00
{
g->ncritical_nodes ++;
SETBIT(g->critical_nodes,g->edges[i]);
2004-12-23 15:16:30 +02:00
}
if(!(GETBIT(g->critical_nodes,g->edges[i + g->nedges])))
2004-12-23 15:16:30 +02:00
{
g->ncritical_nodes ++;
SETBIT(g->critical_nodes,g->edges[i + g->nedges]);
2004-12-23 15:16:30 +02:00
}
}
}
free(deleted);
}
cmph_uint8 graph_contains_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) /* included -- Fabiano*/
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 e;
2004-12-23 15:16:30 +02:00
e = g->first[v1];
if(e == EMPTY) return 0;
if (check_edge(g, e, v1, v2)) return 1;
do
{
e = g->next[e];
if(e == EMPTY) return 0;
}
while (!check_edge(g, e, v1, v2));
return 1;
}
cmph_uint32 graph_vertex_id(graph_t *g, cmph_uint32 e, cmph_uint32 id) /* included -- Fabiano*/
2004-12-23 15:16:30 +02:00
{
return (g->edges[e + id*g->nedges]);
}
cmph_uint32 graph_ncritical_nodes(graph_t *g) /* included -- Fabiano*/
2004-12-23 15:16:30 +02:00
{
return g->ncritical_nodes;
}
graph_iterator_t graph_neighbors_it(graph_t *g, cmph_uint32 v)
2004-12-23 15:16:30 +02:00
{
graph_iterator_t it;
2004-12-23 15:16:30 +02:00
it.vertex = v;
it.edge = g->first[v];
return it;
}
cmph_uint32 graph_next_neighbor(graph_t *g, graph_iterator_t* it)
2004-12-23 15:16:30 +02:00
{
2005-01-18 23:06:08 +02:00
cmph_uint32 ret;
if(it->edge == EMPTY) return GRAPH_NO_NEIGHBOR;
2004-12-23 15:16:30 +02:00
if (g->edges[it->edge] == it->vertex) ret = g->edges[it->edge + g->nedges];
else ret = g->edges[it->edge];
it->edge = g->next[it->edge];
return ret;
}