Graphviz 12.1.1~dev.20240814.0213
Loading...
Searching...
No Matches
decomp.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12/*
13 * Decompose finds the connected components of a graph.
14 * It searches the temporary edges and ignores non-root nodes.
15 * The roots of the search are the real nodes of the graph,
16 * but any virtual nodes discovered are also included in the
17 * component.
18 */
19
20#include <cgraph/alloc.h>
21#include <cgraph/list.h>
22#include <dotgen/dot.h>
23#include <stddef.h>
24#include <stdint.h>
25
27static size_t Cmark;
28
29static void
34
35static void
37{
38 ND_mark(n) = Cmark;
39 if (Last_node) {
40 ND_prev(n) = Last_node;
41 ND_next(Last_node) = n;
42 } else {
43 ND_prev(n) = NULL;
44 GD_nlist(g) = n;
45 }
46 Last_node = n;
47 ND_next(n) = NULL;
48}
49
50static void
52{
53 size_t i = GD_comp(g).size++;
54 GD_comp(g).list = gv_recalloc(GD_comp(g).list, GD_comp(g).size - 1,
55 GD_comp(g).size, sizeof(node_t *));
56 GD_comp(g).list[i] = GD_nlist(g);
57}
58
59DEFINE_LIST(node_stack, node_t *)
60
61static void push(node_stack_t *sp, node_t *np) {
62 ND_mark(np) = Cmark + 1;
63 node_stack_push_back(sp, np);
64}
65
66static node_t *pop(node_stack_t *sp) {
67
68 if (node_stack_is_empty(sp)) {
69 return NULL;
70 }
71
72 return node_stack_pop_back(sp);
73}
74
75/* search_component:
76 * iterative dfs for components.
77 * We process the edges in reverse order of the recursive version to maintain
78 * the processing order of the nodes.
79 * Since are using a stack, we need to indicate nodes on the stack. Nodes unprocessed
80 * in this call to decompose will have mark < Cmark; processed nodes will have mark=Cmark;
81 * so we use mark = Cmark+1 to indicate nodes on the stack.
82 */
83static void search_component(node_stack_t *stk, graph_t *g, node_t *n) {
84 int c;
85 elist vec[4];
86 node_t *other;
87 edge_t *e;
88 edge_t **ep;
89
90 push(stk, n);
91 while ((n = pop(stk))) {
92 if (ND_mark(n) == Cmark) continue;
93 add_to_component(g, n);
94 vec[0] = ND_out(n);
95 vec[1] = ND_in(n);
96 vec[2] = ND_flat_out(n);
97 vec[3] = ND_flat_in(n);
98
99 for (c = 3; c >= 0; c--) {
100 if (vec[c].list && vec[c].size != 0) {
101 size_t i;
102 for (i = vec[c].size - 1, ep = vec[c].list + i; i != SIZE_MAX; i--, ep--) {
103 e = *ep;
104 if ((other = aghead(e)) == n)
105 other = agtail(e);
106 if ((ND_mark(other) != Cmark) && (other == UF_find(other)))
107 push(stk, other);
108 }
109 }
110 }
111 }
112}
113
114void decompose(graph_t * g, int pass)
115{
116 graph_t *subg;
117 node_t *n, *v;
118 node_stack_t stk = {0};
119
120 if (++Cmark == 0)
121 Cmark = 1;
122 GD_comp(g).size = 0;
123 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
124 v = n;
125 if ((pass > 0) && (subg = ND_clust(v)))
126 v = GD_rankleader(subg)[ND_rank(v)];
127 else if (v != UF_find(v))
128 continue;
129 if (ND_mark(v) != Cmark) {
131 search_component(&stk, g, v);
132 end_component(g);
133 }
134 }
135 node_stack_free(&stk);
136}
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
static Agnode_t * pop(void)
Definition ccomps.c:238
node_t * UF_find(node_t *n)
Definition utils.c:100
static void begin_component(graph_t *g)
Definition decomp.c:30
void decompose(graph_t *g, int pass)
Definition decomp.c:114
static void add_to_component(graph_t *g, node_t *n)
Definition decomp.c:36
static void end_component(graph_t *g)
Definition decomp.c:51
static void search_component(node_stack_t *stk, graph_t *g, node_t *n)
Definition decomp.c:83
static size_t Cmark
Definition decomp.c:27
static void push(node_stack_t *sp, node_t *np)
Definition decomp.c:61
static node_t * Last_node
Definition decomp.c:26
#define SIZE_MAX
Definition gmlscan.c:347
node NULL
Definition grammar.y:150
#define agtail(e)
Definition cgraph.h:889
#define aghead(e)
Definition cgraph.h:890
#define GD_nlist(g)
Definition types.h:393
#define GD_comp(g)
Definition types.h:362
#define GD_rankleader(g)
Definition types.h:396
#define ND_rank(n)
Definition types.h:523
#define ND_prev(n)
Definition types.h:521
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define ND_next(n)
Definition types.h:510
#define ND_clust(n)
Definition types.h:489
#define ND_flat_out(n)
Definition types.h:493
#define ND_flat_in(n)
Definition types.h:492
#define ND_in(n)
Definition types.h:501
#define ND_out(n)
Definition types.h:515
#define ND_mark(n)
Definition acyclic.c:28
#define DEFINE_LIST(name, type)
Definition list.h:26
graph or subgraph
Definition cgraph.h:425
Definition types.h:251