Graphviz 14.1.2~dev.20251224.0902
Loading...
Searching...
No Matches
mm2gv.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16#include "config.h"
17#include <util/alloc.h>
18#include <util/itos.h>
19
20#define STANDALONE
21#include <cgraph/cgraph.h>
22#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <math.h>
27#include <assert.h>
28#include "mmio.h"
29#include <sparse/SparseMatrix.h>
30#include <util/agxbuf.h>
31#include <util/prisize_t.h>
32#include <util/unreachable.h>
33#include "matrix_market.h"
34#include <getopt.h>
35
36typedef struct {
37 Agrec_t h;
38 int id;
40
41#define ND_id(n) (((Agnodeinfo_t*)(n->base.data))->id)
42
43static char *cmd;
44
45static double Hue2RGB(double v1, double v2, double H)
46{
47 if (H < 0.0)
48 H += 1.0;
49 if (H > 1.0)
50 H -= 1.0;
51 if (6.0 * H < 1.0)
52 return (v1 + (v2 - v1) * 6.0 * H);
53 if (2.0 * H < 1.0)
54 return v2;
55 if (3.0 * H < 2.0)
56 return v1 + (v2 - v1) * (2.0 / 3.0 - H) * 6.0;
57 return v1;
58}
59
60static char *hue2rgb(double hue, agxbuf *xb) {
61 double v1, v2, lightness = .5, saturation = 1;
62 int red, blue, green;
63
64 v2 = lightness + saturation - saturation * lightness;
65
66 v1 = 2.0 * lightness - v2;
67
68 red = (int) (255.0 * Hue2RGB(v1, v2, hue + 1.0 / 3.0) + 0.5);
69 green = (int) (255.0 * Hue2RGB(v1, v2, hue) + 0.5);
70 blue = (int) (255.0 * Hue2RGB(v1, v2, hue - 1.0 / 3.0) + 0.5);
71 agxbprint(xb, "#%02x%02x%02x", red, green, blue);
72 return agxbuse(xb);
73}
74
75static Agraph_t *makeDotGraph(SparseMatrix A, char *name, int dim,
76 double * x, int with_color, int with_label, int with_val)
77{
78 Agraph_t *g;
79 Agnode_t *n;
80 Agnode_t *h;
81 Agedge_t *e;
82 int i, j;
83 Agsym_t *sym = NULL, *sym2 = NULL, *sym3 = NULL;
84 int *ia = A->ia;
85 int *ja = A->ja;
86 double *val = A->a;
87 Agnode_t **arr = gv_calloc(A->m, sizeof(Agnode_t*));
88 double *color = NULL;
89
90 name = strip_dir(name);
91
92 if (with_color) {
93 if (A->type == MATRIX_TYPE_REAL && !val) {
94 fprintf (stderr, "Warning: input matrix has no values, -c flag ignored\n");
95 with_color = 0;
96 }
97 else if (A->type != MATRIX_TYPE_REAL && !x) {
98 fprintf (stderr, "Warning: input has no coordinates, -c flag ignored\n");
99 with_color = 0;
100 }
101 }
102
103 if (A->is_undirected) {
104 g = agopen("G", Agundirected, NULL);
105 } else {
106 g = agopen("G", Agdirected, NULL);
107 }
108
109 if (with_val) {
110 sym = agattr_text(g, AGEDGE, "len", "1");
111 }
112 agxbuf xb = {0};
113 if (with_label) {
114 agxbprint(&xb, "%s. %d nodes, %" PRISIZE_T " edges.", name, A->m, A->nz);
115 agattr_text(g, AGRAPH, "label", agxbuse (&xb));
116 }
117
118 for (i = 0; i < A->m; i++) {
119 n = agnode(g, ITOS(i), 1);
120 agbindrec(n, "nodeinfo", sizeof(Agnodeinfo_t), true);
121 ND_id(n) = i;
122 arr[i] = n;
123 }
124
125 if (with_color) {
126 double maxdist = 0.;
127 double mindist = 0.;
128 bool first = true;
129
130 sym2 = agattr_text(g, AGEDGE, "color", "");
131 sym3 = agattr_text(g, AGEDGE, "wt", "");
132 agattr_text(g, AGRAPH, "bgcolor", "black");
133 color = gv_calloc(A->nz, sizeof(double));
134 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
135 i = ND_id(n);
136 if (A->type != MATRIX_TYPE_REAL) {
137 for (j = ia[i]; j < ia[i + 1]; j++) {
138 color[j] = distance(x, dim, i, ja[j]);
139 if (i != ja[j]) {
140 if (first) {
141 mindist = color[j];
142 first = false;
143 } else {
144 mindist = fmin(mindist, color[j]);
145 }
146 }
147 maxdist = fmax(color[j], maxdist);
148 }
149 } else {
150 for (j = ia[i]; j < ia[i + 1]; j++) {
151 if (val) color[j] = fabs(val[j]);
152 else color[j] = 1;
153 if (i != ja[j]) {
154 if (first) {
155 mindist = color[j];
156 first = false;
157 } else {
158 mindist = fmin(mindist, color[j]);
159 }
160 }
161 maxdist = fmax(color[j], maxdist);
162 }
163 }
164 }
165 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
166 i = ND_id(n);
167 for (j = ia[i]; j < ia[i + 1]; j++) {
168 color[j] = (color[j] - mindist) / fmax(maxdist - mindist, 0.000001);
169 }
170 }
171 }
172
173 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
174 i = ND_id(n);
175 for (j = ia[i]; j < ia[i + 1]; j++) {
176 h = arr[ja[j]];
177 e = agedge(g, n, h, NULL, 1);
178 if (sym && val) {
179 agxbprint(&xb, "%f", val[j]);
180 agxset(e, sym, agxbuse(&xb));
181 }
182 if (with_color) {
183 agxset(e, sym2, hue2rgb(.65 * color[j], &xb));
184 agxbprint(&xb, "%f", color[j]);
185 agxset(e, sym3, agxbuse(&xb));
186 }
187 }
188 }
189
190 agxbfree (&xb);
191 free(color);
192 free(arr);
193 return g;
194}
195
196static char* useString = "Usage: %s [-uvcl] [-o file] matrix_market_filename\n\
197 -u - make graph undirected\n\
198 -U i - treat non-square matrix as a bipartite graph\n\
199 i = 0 never\n\
200 i = 1 if pattern unsymmetric (default)\n\
201 i = 2 if matrix unsymmetric\n\
202 i = 3 always\n\
203 -v - assign len to edges\n\
204 -c - assign color and wt to edges\n\
205 -l - add label\n\
206 -o <file> - output file \n";
207
208static void usage(int eval)
209{
210 fprintf(stderr, useString, cmd);
212}
213
214static FILE *openF(char *fname, char *mode)
215{
216 FILE *f = fopen(fname, mode);
217 if (!f) {
218 fprintf(stderr, "Could not open %s for %s\n", fname,
219 *mode == 'r' ? "reading" : "writing");
220 graphviz_exit(1);
221 }
222 return f;
223}
224
225typedef struct {
226 FILE *inf;
227 FILE *outf;
228 char *infile;
234} parms_t;
235
236static void init(int argc, char **argv, parms_t * p)
237{
238 int c;
239
240 cmd = argv[0];
241 opterr = 0;
242 while ((c = getopt(argc, argv, ":o:uvclU:?")) != -1) {
243 switch (c) {
244 case 'o':
245 p->outf = openF(optarg, "w");
246 break;
247 case 'l':
248 p->with_label = 1;
249 break;
250 case 'u':
251 p->undirected = 1;
252 break;
253 case 'v':
254 p->with_val = 1;
255 break;
256 case 'c':
257 p->with_color = 1;
258 break;
259 case 'U':{
260 int u;
261 if (sscanf(optarg,"%d",&u) <= 0 || u < 0 || u > BIPARTITE_ALWAYS) {
262 usage(1);
263 } else {
264 p->bipartite = u;
265 }
266 break;
267 }
268 case ':':
269 fprintf(stderr, "%s: option -%c missing argument - ignored\n", cmd, optopt);
270 break;
271 case '?':
272 if (optopt == '\0' || optopt == '?')
273 usage(0);
274 else {
275 fprintf(stderr,
276 "%s: option -%c unrecognized\n", cmd,
277 optopt);
278 usage(1);
279 }
280 break;
281 default:
282 UNREACHABLE();
283 }
284 }
285 argv += optind;
286 argc -= optind;
287
288 if (argc > 0) {
289 p->infile = argv[0];
290 p->inf = openF(argv[0], "r");
291 }
292}
293
294int main(int argc, char *argv[])
295{
296 Agraph_t *g = 0;
298 int dim=0;
299 parms_t pv;
300
301 /* ======================= set parameters ==================== */
302 pv.inf = stdin;
303 pv.outf = stdout;
304 pv.infile = "stdin";
305 pv.undirected = 0;
306 pv.with_label = 0;
307 pv.with_color = 0;
308 pv.with_val = 0;
310 init(argc, argv, &pv);
311
312 /* ======================= read graph ==================== */
313
315 if (!A) {
316 fprintf (stderr, "Unable to read input file \"%s\"\n", pv.infile);
317 usage(1);
318 }
319
321
322 if (!A) {
323 fprintf(stderr, "cannot import from file %s\n", pv.infile);
324 graphviz_exit(1);
325 }
326
327 if (pv.undirected) {
331 A = B;
332 }
333 g = makeDotGraph(A, pv.infile, dim, NULL, pv.with_color, pv.with_label, pv.with_val);
334
335 agwrite(g, pv.outf);
336
337 graphviz_exit(0);
338}
339
SparseMatrix SparseMatrix_to_square_matrix(SparseMatrix A, int bipartite_options)
void SparseMatrix_delete(SparseMatrix A)
SparseMatrix SparseMatrix_make_undirected(SparseMatrix A)
@ MATRIX_TYPE_REAL
@ BIPARTITE_PATTERN_UNSYM
@ BIPARTITE_ALWAYS
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
abstract graph C library, Cgraph API
mode
Definition cvtgxl.c:33
static char * fname
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
#define A(n, t)
Definition expr.h:76
static int eval(Agraph_t *g, int root)
Definition gc.c:269
char * strip_dir(char *s)
Definition general.c:137
double distance(double *x, int dim, int i, int j)
Definition general.c:121
void free(void *)
node NULL
Definition grammar.y:181
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:334
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:522
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:253
Agdesc_t Agundirected
undirected
Definition graph.c:272
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:42
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:667
Agdesc_t Agdirected
directed
Definition graph.c:270
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:141
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
@ AGEDGE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
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
static void color(Agraph_t *g)
Definition gvcolor.c:129
static const char * usage
Definition gvpr.c:52
#define B
Definition hierarchy.c:118
#define ITOS(i)
Definition itos.h:43
SparseMatrix SparseMatrix_import_matrix_market(FILE *f)
import Matrix Market
#define ND_id(n)
Definition mm2gv.c:41
static char * hue2rgb(double hue, agxbuf *xb)
Definition mm2gv.c:60
static void init(int argc, char **argv, parms_t *p)
Definition mm2gv.c:236
static char * cmd
Definition mm2gv.c:43
static FILE * openF(char *fname, char *mode)
Definition mm2gv.c:214
static Agraph_t * makeDotGraph(SparseMatrix A, char *name, int dim, double *x, int with_color, int with_label, int with_val)
Definition mm2gv.c:75
static char * useString
Definition mm2gv.c:196
static double Hue2RGB(double v1, double v2, double H)
Definition mm2gv.c:45
Matrix Market I/O API
static const int dim
#define PRISIZE_T
Definition prisize_t.h:25
graph or subgraph
Definition cgraph.h:424
implementation of Agrec_t
Definition cgraph.h:172
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:640
int bipartite
Definition mm2gv.c:233
int with_val
Definition mm2gv.c:232
char * infile
Definition mm2gv.c:228
int with_label
Definition mm2gv.c:230
FILE * outf
Definition mm2gv.c:227
FILE * inf
Definition mm2gv.c:226
int with_color
Definition mm2gv.c:231
int undirected
Definition mm2gv.c:229
int main()
#define UNREACHABLE()
Definition unreachable.h:30