Graphviz 14.1.3~dev.20260124.0732
Loading...
Searching...
No Matches
comp.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#include "config.h"
12
13/* comp.c:
14 * Written by Emden R. Gansner
15 *
16 * Support for "connected components". Components are either connected
17 * or have a port node or have a pinned node.
18 *
19 */
20
21/* use PRIVATE interface */
22#define FDP_PRIVATE 1
23
24#include <cgraph/cgraph.h>
25#include <fdpgen/fdp.h>
26#include <fdpgen/comp.h>
27#include <pack/pack.h>
28#include <assert.h>
29#include <stdbool.h>
30#include <stddef.h>
31#include <util/agxbuf.h>
32#include <util/alloc.h>
33#include <util/bitarray.h>
34#include <util/prisize_t.h>
35
36static void dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out, bitarray_t *marks) {
37 Agedge_t *e;
38 Agnode_t *other;
39
40 bitarray_set(marks, ND_id(n), true);
41 agsubnode(out,n,1);
42 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
43 if ((other = agtail(e)) == n)
44 other = aghead(e);
45 if (!bitarray_get(*marks, ND_id(other)))
46 dfs(g, other, out, marks);
47 }
48}
49
50/* findCComp:
51 * Finds generalized connected components of graph g.
52 * This merges all components containing a port node or a pinned node.
53 * Assumes nodes have unique id's in range [0,agnnodes(g)-1].
54 * Components are stored as subgraphs of g, with name sg_<i>.
55 * Returns 0-terminated array of components.
56 * If cnt is non-0, count of components is stored there.
57 * If pinned is non-0, *pinned is set to 1 if there are pinned nodes.
58 * Note that if ports and/or pinned nodes exists, they will all be
59 * in the first component returned by findCComp.
60 */
61static size_t C_cnt = 0;
62graph_t **findCComp(graph_t *g, size_t *cnt, int *pinned) {
63 node_t *n;
64 graph_t *subg;
65 agxbuf name = {0};
66 size_t c_cnt = 0;
67 bport_t *pp;
68 graph_t **comps;
69 graph_t **cp;
70 int pinflag = 0;
71
72 assert(agnnodes(g) >= 0);
73 bitarray_t marks = bitarray_new((size_t)agnnodes(g));
74
75 /* Create component based on port nodes */
76 subg = 0;
77 if ((pp = PORTS(g))) {
78 agxbprint(&name, "cc%s_%" PRISIZE_T, agnameof(g), c_cnt++ + C_cnt);
79 subg = agsubg(g, agxbuse(&name), 1);
80 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
81 GD_alg(subg) = gv_alloc(sizeof(gdata));
82 PORTS(subg) = pp;
83 NPORTS(subg) = NPORTS(g);
84 for (; pp->n; pp++) {
85 if (bitarray_get(marks, ND_id(pp->n)))
86 continue;
87 dfs(g, pp->n, subg, &marks);
88 }
89 }
90
91 /* Create/extend component based on pinned nodes */
92 /* Note that ports cannot be pinned */
93 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
94 if (bitarray_get(marks, ND_id(n)))
95 continue;
96 if (ND_pinned(n) != P_PIN)
97 continue;
98 if (!subg) {
99 agxbprint(&name, "cc%s_%" PRISIZE_T, agnameof(g), c_cnt++ + C_cnt);
100 subg = agsubg(g, agxbuse(&name), 1);
101 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
102 GD_alg(subg) = gv_alloc(sizeof(gdata));
103 }
104 pinflag = 1;
105 dfs(g, n, subg, &marks);
106 }
107 if (subg)
108 (void)graphviz_node_induce(subg, NULL);
109
110 /* Pick up remaining components */
111 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
112 if (bitarray_get(marks, ND_id(n)))
113 continue;
114 agxbprint(&name, "cc%s+%" PRISIZE_T, agnameof(g), c_cnt++ + C_cnt);
115 subg = agsubg(g, agxbuse(&name), 1);
116 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
117 GD_alg(subg) = gv_alloc(sizeof(gdata));
118 dfs(g, n, subg, &marks);
119 (void)graphviz_node_induce(subg, NULL);
120 }
121 bitarray_reset(&marks);
122 agxbfree(&name);
123 C_cnt += c_cnt;
124
125 if (cnt)
126 *cnt = c_cnt;
127 if (pinned)
128 *pinned = pinflag;
129 /* freed in layout */
130 comps = cp = gv_calloc(c_cnt + 1, sizeof(graph_t*));
131 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
132 *cp++ = subg;
133 c_cnt--;
134 }
135 assert(c_cnt == 0);
136 *cp = 0;
137
138 return comps;
139}
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
Definition agerror.c:86
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
API for compacted arrays of booleans.
static bitarray_t bitarray_new(size_t size_bits)
create an array of the given element length
Definition bitarray.h:47
static bool bitarray_get(bitarray_t self, size_t index)
get the value of the given element
Definition bitarray.h:65
static void bitarray_set(bitarray_t *self, size_t index, bool value)
set or clear the value of the given element
Definition bitarray.h:80
static void bitarray_reset(bitarray_t *self)
free underlying resources and leave a bit array empty
Definition bitarray.h:114
abstract graph C library, Cgraph API
static size_t C_cnt
Definition comp.c:61
graph_t ** findCComp(graph_t *g, size_t *cnt, int *pinned)
Definition comp.c:62
static void dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out, bitarray_t *marks)
Definition comp.c:36
#define P_PIN
Definition const.h:249
node NULL
Definition grammar.y:181
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:198
int agnnodes(Agraph_t *g)
Definition graph.c:157
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Definition node_induce.c:12
#define agtail(e)
Definition cgraph.h:977
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
#define GD_alg(g)
Definition types.h:358
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:254
#define ND_pinned(n)
Definition types.h:519
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:91
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:75
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:80
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:55
#define ND_id(n)
Definition mm2gv.c:41
support for connected components
#define PRISIZE_T
Definition prisize_t.h:25
graph or subgraph
Definition cgraph.h:424