Initial revision
This commit is contained in:
329
src/graph.c
Normal file
329
src/graph.c
Normal file
@@ -0,0 +1,329 @@
|
||||
#include "graph.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "vstack.h"
|
||||
|
||||
//#define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#define abs_edge(e, i) (e % g->nedges + i * g->nedges)
|
||||
|
||||
struct __graph_t
|
||||
{
|
||||
uint32 nnodes;
|
||||
uint32 nedges;
|
||||
uint32 *edges;
|
||||
uint32 *first;
|
||||
uint32 *next;
|
||||
uint8 *critical_nodes; /* included -- Fabiano*/
|
||||
uint32 ncritical_nodes; /* included -- Fabiano*/
|
||||
uint32 cedges;
|
||||
int shrinking;
|
||||
};
|
||||
|
||||
static uint32 EMPTY = UINT_MAX;
|
||||
|
||||
graph_t *graph_new(uint32 nnodes, uint32 nedges)
|
||||
{
|
||||
graph_t *graph = (graph_t *)malloc(sizeof(graph_t));
|
||||
if (!graph) return NULL;
|
||||
|
||||
graph->edges = (uint32 *)malloc(sizeof(uint32) * 2 * nedges);
|
||||
graph->next = (uint32 *)malloc(sizeof(uint32) * 2 * nedges);
|
||||
graph->first = (uint32 *)malloc(sizeof(uint32) * nnodes);
|
||||
graph->critical_nodes = NULL; /* included -- Fabiano*/
|
||||
graph->ncritical_nodes = 0; /* included -- Fabiano*/
|
||||
graph->nnodes = nnodes;
|
||||
graph->nedges = nedges;
|
||||
|
||||
graph_clear_edges(graph);
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
||||
void graph_destroy(graph_t *graph)
|
||||
{
|
||||
DEBUGP("Destroying graph\n");
|
||||
free(graph->edges);
|
||||
free(graph->first);
|
||||
free(graph->next);
|
||||
free(graph->critical_nodes); /* included -- Fabiano*/
|
||||
free(graph);
|
||||
return;
|
||||
}
|
||||
|
||||
void graph_print(graph_t *g)
|
||||
{
|
||||
uint32 i, e;
|
||||
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)]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void graph_add_edge(graph_t *g, uint32 v1, uint32 v2)
|
||||
{
|
||||
uint32 e = g->cedges;
|
||||
|
||||
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, uint32 e, uint32 v1, uint32 v2)
|
||||
{
|
||||
DEBUGP("Checking edge %u %u looking for %u %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)], v1, v2);
|
||||
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;
|
||||
}
|
||||
|
||||
uint32 graph_edge_id(graph_t *g, uint32 v1, uint32 v2)
|
||||
{
|
||||
uint32 e;
|
||||
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, uint32 v1, uint32 v2)
|
||||
{
|
||||
uint32 e, prev;
|
||||
|
||||
DEBUGP("Deleting edge point %u %u\n", v1, v2);
|
||||
e = g->first[v1];
|
||||
if (check_edge(g, e, v1, v2))
|
||||
{
|
||||
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, uint32 v1, uint32 v2)
|
||||
{
|
||||
g->shrinking = 1;
|
||||
del_edge_point(g, v1, v2);
|
||||
del_edge_point(g, v2, v1);
|
||||
}
|
||||
|
||||
void graph_clear_edges(graph_t *g)
|
||||
{
|
||||
uint32 i;
|
||||
for (i = 0; i < g->nnodes; ++i) g->first[i] = EMPTY;
|
||||
for (i = 0; i < g->nedges*2; ++i)
|
||||
{
|
||||
g->edges[i] = EMPTY;
|
||||
g->next[i] = EMPTY;
|
||||
}
|
||||
g->cedges = 0;
|
||||
g->shrinking = 0;
|
||||
}
|
||||
|
||||
static int find_degree1_edge(graph_t *g, uint32 v, char *deleted, uint32 *e)
|
||||
{
|
||||
uint32 edge = g->first[v];
|
||||
char found = 0;
|
||||
DEBUGP("Checking degree of vertex %u\n", v);
|
||||
if (edge == EMPTY) return 0;
|
||||
else if (!deleted[abs_edge(edge, 0)])
|
||||
{
|
||||
found = 1;
|
||||
*e = edge;
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
edge = g->next[edge];
|
||||
if (edge == EMPTY) break;
|
||||
if (deleted[abs_edge(edge, 0)]) continue;
|
||||
if (found) return 0;
|
||||
DEBUGP("Found first edge\n");
|
||||
*e = edge;
|
||||
found = 1;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static void cyclic_del_edge(graph_t *g, uint32 v, char *deleted)
|
||||
{
|
||||
|
||||
uint32 e;
|
||||
char degree1;
|
||||
uint32 v1 = v;
|
||||
uint32 v2 = 0;
|
||||
|
||||
degree1 = find_degree1_edge(g, v1, deleted, &e);
|
||||
if (!degree1) return;
|
||||
while(1)
|
||||
{
|
||||
DEBUGP("Deleting edge %u (%u->%u)\n", e, g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
|
||||
deleted[abs_edge(e, 0)] = 1;
|
||||
|
||||
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);
|
||||
degree1 = find_degree1_edge(g, v2, deleted, &e);
|
||||
if (degree1)
|
||||
{
|
||||
DEBUGP("Inspecting vertex %u\n", v2);
|
||||
v1 = v2;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
int graph_is_cyclic(graph_t *g)
|
||||
{
|
||||
uint32 i;
|
||||
uint32 v;
|
||||
char *deleted = (char *)malloc(g->nedges*sizeof(char));
|
||||
memset(deleted, 0, g->nedges);
|
||||
|
||||
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 (!(deleted[i]))
|
||||
{
|
||||
DEBUGP("Edge %u %u->%u was not deleted\n", i, g->edges[i], g->edges[i + g->nedges]);
|
||||
free(deleted);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
free(deleted);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 graph_node_is_critical(graph_t * g, uint32 v) /* included -- Fabiano */
|
||||
{
|
||||
return g->critical_nodes[v];
|
||||
}
|
||||
|
||||
void graph_obtain_critical_nodes(graph_t *g) /* included -- Fabiano*/
|
||||
{
|
||||
uint32 i;
|
||||
uint32 v;
|
||||
char *deleted = (char *)malloc(g->nedges*sizeof(char));
|
||||
memset(deleted, 0, g->nedges);
|
||||
/* g->critical_nodes = (uint8 *)malloc((size_t)(ceil(g->nnodes*sizeof(uint8)/8.))); */
|
||||
g->critical_nodes = (uint8 *)malloc(g->nnodes*sizeof(uint8));
|
||||
g->ncritical_nodes = 0;
|
||||
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 (!(deleted[i]))
|
||||
{
|
||||
DEBUGP("Edge %u %u->%u belongs to the 2-core\n", i, g->edges[i], g->edges[i + g->nedges]);
|
||||
if(!(g->critical_nodes[g->edges[i]]))
|
||||
{
|
||||
g->ncritical_nodes ++;
|
||||
g->critical_nodes[g->edges[i]] = 1;
|
||||
}
|
||||
if(!(g->critical_nodes[g->edges[i + g->nedges]]))
|
||||
{
|
||||
g->ncritical_nodes ++;
|
||||
g->critical_nodes[g->edges[i + g->nedges]] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(deleted);
|
||||
}
|
||||
|
||||
uint8 graph_contains_edge(graph_t *g, uint32 v1, uint32 v2) /* included -- Fabiano*/
|
||||
{
|
||||
uint32 e;
|
||||
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;
|
||||
}
|
||||
|
||||
uint32 graph_vertex_id(graph_t *g, uint32 e, uint32 id) /* included -- Fabiano*/
|
||||
{
|
||||
return (g->edges[e + id*g->nedges]);
|
||||
}
|
||||
|
||||
uint32 graph_ncritical_nodes(graph_t *g) /* included -- Fabiano*/
|
||||
{
|
||||
return g->ncritical_nodes;
|
||||
}
|
||||
|
||||
graph_iterator_t graph_neighbors_it(graph_t *g, uint32 v)
|
||||
{
|
||||
graph_iterator_t it;
|
||||
it.vertex = v;
|
||||
it.edge = g->first[v];
|
||||
return it;
|
||||
}
|
||||
uint32 graph_next_neighbor(graph_t *g, graph_iterator_t* it)
|
||||
{
|
||||
uint32 ret;
|
||||
if(it->edge == EMPTY) return GRAPH_NO_NEIGHBOR;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user