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