1
0
mirror of git://projects.qi-hardware.com/fped.git synced 2024-11-18 11:30:18 +02:00
fped/tsort.c
werner bc27b094af With a little help from m8cutils and abyss, we now have regression tests for
the topological sort. "make test" or "make tests" invokes the regression tests,
"make valgrind" runs them under valgrind's watchful eyes.

- fped.c (usage, main): added option -T to force batch mode (for regression
  testing)
- Makefile, test/Common: added regression test infrastructure
- test/tsort: test cases for the topological sort
- README: added pointer to test/tsort



git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5943 99fdad57-331a-0410-800a-d7fa5415bdb3
2010-04-26 21:30:21 +00:00

163 lines
4.0 KiB
C

/*
* tsort.c - Topological sort
*
* Written 2010 by Werner Almesberger
* Copyright 2010 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
/*
* We use a slight variation of Kahn's algorithm. The difference is that we add
* a priority. Edges with the highest priority get selected before edges with
* lower priority.
*
* We maintain the initial list of nodes in the order in which they were added.
* Therefore, the first node with inbound edges will always be sorted first.
* E.g., the root frame.
*
* add_node and add_edge can be invoked multiple times with the same
* parameters. In the case of add_node, simply the existing node is returned.
* In the case of add_edge, the new edge's priority is added to the priority of
* the previous edges.
*
* Priority is accumulated in a node until the node is output. If a node has
* the "decay" flag set, it resets the priorities of all other nodes when
* output. E.g., when outputting a vector, all priorities accumulated from
* previous vectors (towards referencing them with ".") lose their effect.
*
* Last but not least, the algorithm is stable: a pre-existing order that
* conflicts neither with the partial order nor the priorities is preserved.
*
* Thus, we have the following sorting criteria, in decreasing importance:
* - the destination if an edge never precedes its origin
* - higher priority comes before lower priority
* - earlier add_node comes before later
*/
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "util.h"
#include "tsort.h"
struct edge {
struct node *to;
int priority; /* edge priority */
struct edge *next;
};
struct node {
void *user;
struct edge *edges; /* outbound edges */
int incoming; /* number of incoming edges */
int priority; /* cumulative node priority */
int decay; /* all node prio. decay after issuing this */
struct node *next;
};
struct tsort {
struct node *nodes;
struct node **next_node;
int n_nodes;
};
void add_edge(struct node *from, struct node *to, int priority)
{
struct edge **edge;
for (edge = &from->edges; *edge; edge = &(*edge)->next)
if ((*edge)->to == to) {
(*edge)->priority += priority;
return;
}
*edge = alloc_type(struct edge);
(*edge)->to = to;
(*edge)->priority = priority;
(*edge)->next = NULL;
to->incoming++;
}
struct node *add_node(struct tsort *tsort, void *user, int decay)
{
struct node *node;
for (node = tsort->nodes; node; node = node->next)
if (node->user == user)
return node;
node = alloc_type(struct node);
node->user = user;
node->edges = NULL;
node->incoming = 0;
node->priority = 0;
node->decay = decay;
node->next = NULL;
*tsort->next_node = node;
tsort->next_node = &node->next;
tsort->n_nodes++;
return node;
}
struct tsort *begin_tsort(void)
{
struct tsort *tsort;
tsort = alloc_type(struct tsort);
tsort->nodes = NULL;
tsort->next_node = &tsort->nodes;
tsort->n_nodes = 0;
return tsort;
}
void **end_tsort(struct tsort *tsort)
{
struct node **walk, **first, *node;
struct edge *edge;
void **res;
int n = 0;
res = alloc_size(sizeof(void *)*(tsort->n_nodes+1));
while (1) {
first = NULL;
for (walk = &tsort->nodes; *walk; walk = &(*walk)->next) {
if ((*walk)->incoming)
continue;
if (!first || (*first)->priority < (*walk)->priority)
first = walk;
}
if (!first)
break;
if ((*first)->decay)
for (node = tsort->nodes; node; node = node->next)
node->priority = 0;
node = *first;
*first = node->next;
res[n++] = node->user;
while (node->edges) {
edge = node->edges;
edge->to->incoming--;
edge->to->priority += edge->priority;
node->edges = edge->next;
free(edge);
}
free(node);
}
if (tsort->nodes) {
fprintf(stderr, "cycle detected in partial order\n");
abort();
}
free(tsort);
res[n] = NULL;
return res;
}