2004-08-16 10:50:37 +01:00
|
|
|
/**
|
2004-08-18 15:06:14 +01:00
|
|
|
* Warshall's algorithm for transitive closure computation.
|
2004-08-16 10:50:37 +01:00
|
|
|
*/
|
|
|
|
|
2004-10-25 15:28:53 +01:00
|
|
|
#include <limits.h>
|
2004-08-18 15:06:14 +01:00
|
|
|
#include "warshall.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
2004-08-16 10:50:37 +01:00
|
|
|
void
|
|
|
|
graph_fill (int *graph, int nodes, int value)
|
|
|
|
{
|
|
|
|
int node;
|
|
|
|
|
2004-08-16 14:18:04 +01:00
|
|
|
node = 0;
|
|
|
|
while (node < (nodes * nodes))
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
|
|
|
graph[node] = value;
|
2004-08-16 14:18:04 +01:00
|
|
|
node++;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 10:48:29 +01:00
|
|
|
//! Show a graph
|
2004-08-18 15:06:14 +01:00
|
|
|
void
|
|
|
|
graph_display (int *graph, int nodes)
|
2004-08-17 10:48:29 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
int index (const int i, const int j)
|
|
|
|
{
|
|
|
|
return (i * nodes + j);
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (i < nodes)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
j = 0;
|
2004-08-18 15:06:14 +01:00
|
|
|
while (j < nodes)
|
2004-08-17 10:48:29 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
eprintf ("%i ", graph[index (i, j)]);
|
2004-08-17 10:48:29 +01:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
eprintf ("\n");
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//! Apply warshall's algorithm to determine the closure of a graph
|
2004-08-16 10:50:37 +01:00
|
|
|
/**
|
2004-08-17 10:48:29 +01:00
|
|
|
* If j<i and k<j, then k<i.
|
|
|
|
* Could be done more efficiently but that is irrelevant here.
|
|
|
|
*
|
|
|
|
*@param graph A pointer to the integer array of nodes*nodes elements.
|
|
|
|
*@param nodes The number of nodes in the graph.
|
|
|
|
*@Returns 0 if there is a cycle; and the algorithm aborts, 1 if there is no cycle and the result is okay.
|
2004-08-16 10:50:37 +01:00
|
|
|
*/
|
|
|
|
int
|
2004-08-17 10:48:29 +01:00
|
|
|
warshall (int *graph, int nodes)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-10-28 16:37:13 +01:00
|
|
|
int k;
|
2004-08-16 10:50:37 +01:00
|
|
|
|
2004-10-28 16:37:13 +01:00
|
|
|
int index (const int x, const int y)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-10-28 16:37:13 +01:00
|
|
|
return (x * nodes + y);
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
|
|
|
|
2004-10-28 16:37:13 +01:00
|
|
|
k = 0;
|
|
|
|
while (k < nodes)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-10-28 16:37:13 +01:00
|
|
|
int i;
|
2004-08-16 10:50:37 +01:00
|
|
|
|
2004-10-28 16:37:13 +01:00
|
|
|
i = 0;
|
|
|
|
while (i < nodes)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-10-28 16:37:13 +01:00
|
|
|
if (graph[index (i, k)] == 1)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-10-28 16:37:13 +01:00
|
|
|
int j;
|
2004-08-16 10:50:37 +01:00
|
|
|
|
2004-10-28 16:37:13 +01:00
|
|
|
j = 0;
|
|
|
|
while (j < nodes)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-08-17 10:48:29 +01:00
|
|
|
if (graph[index (k, j)] == 1)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-10-28 16:37:13 +01:00
|
|
|
if (i == j)
|
2004-08-16 10:50:37 +01:00
|
|
|
{
|
2004-08-17 10:48:29 +01:00
|
|
|
// Oh no! A cycle.
|
2004-10-28 16:37:13 +01:00
|
|
|
graph[index (i, j)] = 2;
|
2004-08-18 15:06:14 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (5))
|
|
|
|
{
|
|
|
|
graph_display (graph, nodes);
|
|
|
|
}
|
|
|
|
#endif
|
2004-08-16 10:50:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2004-10-28 16:37:13 +01:00
|
|
|
graph[index (i, j)] = 1;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
2004-10-28 16:37:13 +01:00
|
|
|
j++;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
|
|
|
}
|
2004-10-28 16:37:13 +01:00
|
|
|
i++;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
2004-10-28 16:37:13 +01:00
|
|
|
k++;
|
2004-08-16 10:50:37 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2004-10-25 15:28:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
//! Determine ranks for all nodes
|
|
|
|
/**
|
|
|
|
* Some crude algorithm I sketched on the blackboard.
|
|
|
|
*/
|
2004-11-16 12:07:55 +00:00
|
|
|
int
|
|
|
|
graph_ranks (int *graph, int *ranks, int nodes)
|
2004-10-25 15:28:53 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int todo;
|
|
|
|
int rank;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (i < nodes)
|
|
|
|
{
|
|
|
|
ranks[i] = INT_MAX;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
todo = nodes;
|
|
|
|
rank = 0;
|
|
|
|
while (todo > 0)
|
|
|
|
{
|
|
|
|
// There are still unassigned nodes
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while (n < nodes)
|
|
|
|
{
|
|
|
|
if (ranks[n] == INT_MAX)
|
|
|
|
{
|
|
|
|
// Does this node have incoming stuff from stuff with equal rank or higher?
|
|
|
|
int refn;
|
|
|
|
|
|
|
|
refn = 0;
|
|
|
|
while (refn < nodes)
|
|
|
|
{
|
2004-11-16 12:07:55 +00:00
|
|
|
if (ranks[refn] >= rank
|
|
|
|
&& graph[graph_index (refn, n)] != 0)
|
|
|
|
refn = nodes + 1;
|
2004-10-25 15:28:53 +01:00
|
|
|
else
|
2004-11-16 12:07:55 +00:00
|
|
|
refn++;
|
2004-10-25 15:28:53 +01:00
|
|
|
}
|
|
|
|
if (refn == nodes)
|
|
|
|
{
|
|
|
|
ranks[n] = rank;
|
|
|
|
todo--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
rank++;
|
|
|
|
}
|
|
|
|
return rank;
|
|
|
|
}
|