Blame isl-0.16.1/isl_tarjan.c

Packit fb9d21
/*
Packit fb9d21
 * Copyright 2010-2011 INRIA Saclay
Packit fb9d21
 * Copyright 2012      Ecole Normale Superieure
Packit fb9d21
 *
Packit fb9d21
 * Use of this software is governed by the MIT license
Packit fb9d21
 *
Packit fb9d21
 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
Packit fb9d21
 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
Packit fb9d21
 * 91893 Orsay, France
Packit fb9d21
 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
Packit fb9d21
 */
Packit fb9d21
Packit fb9d21
#include <stdlib.h>
Packit fb9d21
#include <isl/ctx.h>
Packit fb9d21
#include <isl_tarjan.h>
Packit fb9d21
Packit fb9d21
void isl_tarjan_graph_free(struct isl_tarjan_graph *g)
Packit fb9d21
{
Packit fb9d21
	if (!g)
Packit fb9d21
		return;
Packit fb9d21
	free(g->node);
Packit fb9d21
	free(g->stack);
Packit fb9d21
	free(g->order);
Packit fb9d21
	free(g);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
Packit fb9d21
{
Packit fb9d21
	struct isl_tarjan_graph *g;
Packit fb9d21
	int i;
Packit fb9d21
Packit fb9d21
	g = isl_calloc_type(ctx, struct isl_tarjan_graph);
Packit fb9d21
	if (!g)
Packit fb9d21
		return NULL;
Packit fb9d21
	g->len = len;
Packit fb9d21
	g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
Packit fb9d21
	if (len && !g->node)
Packit fb9d21
		goto error;
Packit fb9d21
	for (i = 0; i < len; ++i)
Packit fb9d21
		g->node[i].index = -1;
Packit fb9d21
	g->stack = isl_alloc_array(ctx, int, len);
Packit fb9d21
	if (len && !g->stack)
Packit fb9d21
		goto error;
Packit fb9d21
	g->order = isl_alloc_array(ctx, int, 2 * len);
Packit fb9d21
	if (len && !g->order)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	g->sp = 0;
Packit fb9d21
	g->index = 0;
Packit fb9d21
	g->op = 0;
Packit fb9d21
Packit fb9d21
	return g;
Packit fb9d21
error:
Packit fb9d21
	isl_tarjan_graph_free(g);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Perform Tarjan's algorithm for computing the strongly connected components
Packit fb9d21
 * in the graph with g->len nodes and with edges defined by "follows".
Packit fb9d21
 */
Packit fb9d21
static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i,
Packit fb9d21
	isl_bool (*follows)(int i, int j, void *user), void *user)
Packit fb9d21
{
Packit fb9d21
	int j;
Packit fb9d21
Packit fb9d21
	g->node[i].index = g->index;
Packit fb9d21
	g->node[i].min_index = g->index;
Packit fb9d21
	g->node[i].on_stack = 1;
Packit fb9d21
	g->index++;
Packit fb9d21
	g->stack[g->sp++] = i;
Packit fb9d21
Packit fb9d21
	for (j = g->len - 1; j >= 0; --j) {
Packit fb9d21
		isl_bool f;
Packit fb9d21
Packit fb9d21
		if (j == i)
Packit fb9d21
			continue;
Packit fb9d21
		if (g->node[j].index >= 0 &&
Packit fb9d21
			(!g->node[j].on_stack ||
Packit fb9d21
			 g->node[j].index > g->node[i].min_index))
Packit fb9d21
			continue;
Packit fb9d21
Packit fb9d21
		f = follows(i, j, user);
Packit fb9d21
		if (f < 0)
Packit fb9d21
			return isl_stat_error;
Packit fb9d21
		if (!f)
Packit fb9d21
			continue;
Packit fb9d21
Packit fb9d21
		if (g->node[j].index < 0) {
Packit fb9d21
			isl_tarjan_components(g, j, follows, user);
Packit fb9d21
			if (g->node[j].min_index < g->node[i].min_index)
Packit fb9d21
				g->node[i].min_index = g->node[j].min_index;
Packit fb9d21
		} else if (g->node[j].index < g->node[i].min_index)
Packit fb9d21
			g->node[i].min_index = g->node[j].index;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	if (g->node[i].index != g->node[i].min_index)
Packit fb9d21
		return isl_stat_ok;
Packit fb9d21
Packit fb9d21
	do {
Packit fb9d21
		j = g->stack[--g->sp];
Packit fb9d21
		g->node[j].on_stack = 0;
Packit fb9d21
		g->order[g->op++] = j;
Packit fb9d21
	} while (j != i);
Packit fb9d21
	g->order[g->op++] = -1;
Packit fb9d21
Packit fb9d21
	return isl_stat_ok;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Decompose the graph with "len" nodes and edges defined by "follows"
Packit fb9d21
 * into strongly connected components (SCCs).
Packit fb9d21
 * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
Packit fb9d21
 * It should return -1 on error.
Packit fb9d21
 *
Packit fb9d21
 * If SCC a contains a node i that follows a node j in another SCC b
Packit fb9d21
 * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b
Packit fb9d21
 * in the result.
Packit fb9d21
 */
Packit fb9d21
struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
Packit fb9d21
	isl_bool (*follows)(int i, int j, void *user), void *user)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
	struct isl_tarjan_graph *g = NULL;
Packit fb9d21
Packit fb9d21
	g = isl_tarjan_graph_alloc(ctx, len);
Packit fb9d21
	if (!g)
Packit fb9d21
		return NULL;
Packit fb9d21
	for (i = len - 1; i >= 0; --i) {
Packit fb9d21
		if (g->node[i].index >= 0)
Packit fb9d21
			continue;
Packit fb9d21
		if (isl_tarjan_components(g, i, follows, user) < 0)
Packit fb9d21
			goto error;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return g;
Packit fb9d21
error:
Packit fb9d21
	isl_tarjan_graph_free(g);
Packit fb9d21
	return NULL;
Packit fb9d21
}