Graphviz 14.1.2~dev.20260118.1035
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 "config.h"
21
22#include <dotgen/dot.h>
23#include <stddef.h>
24#include <stdint.h>
25#include <util/alloc.h>
26#include <util/list.h>
27
29static size_t Cmark;
30
31static void
36
37static void
39{
40 ND_mark(n) = Cmark;
41 if (Last_node) {
42 ND_prev(n) = Last_node;
43 ND_next(Last_node) = n;
44 } else {
45 ND_prev(n) = NULL;
46 GD_nlist(g) = n;
47 }
48 Last_node = n;
49 ND_next(n) = NULL;
50}
51
52static void
54{
55 size_t i = GD_comp(g).size++;
56 GD_comp(g).list = gv_recalloc(GD_comp(g).list, GD_comp(g).size - 1,
57 GD_comp(g).size, sizeof(node_t *));
58 GD_comp(g).list[i] = GD_nlist(g);
59}
60
61typedef LIST(node_t *) node_stack_t;
62
63static void push(node_stack_t *sp, node_t *np) {
64 ND_mark(np) = Cmark + 1;
65 LIST_PUSH_BACK(sp, np);
66}
67
68static node_t *pop(node_stack_t *sp) {
69
70 if (LIST_IS_EMPTY(sp)) {
71 return NULL;
72 }
73
74 return LIST_POP_BACK(sp);
75}
76
77/* iterative dfs for components.
78 * We process the edges in reverse order of the recursive version to maintain
79 * the processing order of the nodes.
80 * Since we are using a stack, we need to indicate nodes on the stack. Nodes
81 * unprocessed in this call to decompose will have mark < Cmark; processed nodes
82 * will have mark=Cmark; so we use mark = Cmark+1 to indicate nodes on the
83 * stack.
84 */
85static void search_component(node_stack_t *stk, graph_t *g, node_t *n) {
86 node_t *other;
87
88 push(stk, n);
89 while ((n = pop(stk))) {
90 if (ND_mark(n) == Cmark) continue;
91 add_to_component(g, n);
92 elist vec[] = {ND_flat_in(n), ND_flat_out(n), ND_in(n), ND_out(n)};
93
94 for (size_t c = 0; c < sizeof(vec) / sizeof(vec[0]); ++c) {
95 if (vec[c].list && vec[c].size != 0) {
96 for (size_t i = vec[c].size - 1; i != SIZE_MAX; i--) {
97 edge_t *const e = vec[c].list[i];
98 if ((other = aghead(e)) == n)
99 other = agtail(e);
100 if (ND_mark(other) != Cmark && other == UF_find(other))
101 push(stk, other);
102 }
103 }
104 }
105 }
106}
107
108void decompose(graph_t * g, int pass)
109{
110 graph_t *subg;
111 node_t *n, *v;
112 node_stack_t stk = {0};
113
114 if (++Cmark == 0)
115 Cmark = 1;
116 GD_comp(g).size = 0;
117 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
118 v = n;
119 if (pass > 0 && (subg = ND_clust(v)))
120 v = GD_rankleader(subg)[ND_rank(v)];
121 else if (v != UF_find(v))
122 continue;
123 if (ND_mark(v) != Cmark) {
125 search_component(&stk, g, v);
126 end_component(g);
127 }
128 }
129 LIST_FREE(&stk);
130}
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:222
node_t * UF_find(node_t *n)
Definition utils.c:104
static void begin_component(graph_t *g)
Definition decomp.c:32
void decompose(graph_t *g, int pass)
Definition decomp.c:108
static void add_to_component(graph_t *g, node_t *n)
Definition decomp.c:38
static void end_component(graph_t *g)
Definition decomp.c:53
static void search_component(node_stack_t *stk, graph_t *g, node_t *n)
Definition decomp.c:85
static size_t Cmark
Definition decomp.c:29
static node_t * Last_node
Definition decomp.c:28
#define SIZE_MAX
Definition gmlscan.c:347
static gstack_t * push(gstack_t *s, Agraph_t *subg)
Definition grammar.c:1655
node NULL
Definition grammar.y:181
#define agtail(e)
Definition cgraph.h:977
#define aghead(e)
Definition cgraph.h:978
#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:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
#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:30
type-generic dynamically expanding list
#define LIST(type)
Definition list.h:55
#define LIST_FREE(list)
Definition list.h:370
#define LIST_POP_BACK(list)
Definition list.h:407
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define LIST_PUSH_BACK(list, item)
Definition list.h:384
graph or subgraph
Definition cgraph.h:424
Definition types.h:251
edge_t ** list
Definition types.h:252