4
Copyright (C) 2005 Gabor Csardi <csardi@rmki.kfki.hu>
5
MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26
#include "igraph_math.h"
30
#include <ctype.h> /* isspace */
35
* \section about_loadsave
37
* <para>These functions can write a graph to a file, or read a graph
40
* <para>Note that as \a igraph uses the traditional C streams, it is
41
* possible to read/write files from/to memory, at least on GNU
42
* operating systems supporting \quote non-standard\endquote streams.</para>
47
* \function igraph_read_graph_edgelist
48
* \brief Reads an edge list from a file and creates a graph.
51
* This format is simply a series of even number integers separated by
52
* whitespace. The one edge (ie. two integers) per line format is thus
53
* not required (but recommended for readability). Edges of directed
54
* graphs are assumed to be in from, to order.
55
* \param graph Pointer to an uninitialized graph object.
56
* \param instream Pointer to a stream, it should be readable.
57
* \param n The number of vertices in the graph. If smaller than the
58
* largest integer in the file it will be ignored. It is thus
59
* safe to supply zero here.
60
* \param directed Logical, if true the graph is directed, if false it
63
* \c IGRAPH_PARSEERROR: if there is a
64
* problem reading the file, or the file is syntactically
67
* Time complexity: O(|V|+|E|), the
68
* number of vertices plus the number of edges. It is assumed that
69
* reading an integer requires O(1)
73
int igraph_read_graph_edgelist(igraph_t *graph, FILE *instream,
74
igraph_integer_t n, igraph_bool_t directed) {
76
igraph_vector_t edges=IGRAPH_VECTOR_NULL;
80
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
81
IGRAPH_CHECK(igraph_vector_reserve(&edges, 100));
83
/* skip all whitespace */
86
} while (isspace (c));
89
while (!feof(instream)) {
92
IGRAPH_ALLOW_INTERRUPTION();
94
read=fscanf(instream, "%li", &from);
96
IGRAPH_ERROR("parsing edgelist file failed", IGRAPH_PARSEERROR);
98
read=fscanf(instream, "%li", &to);
100
IGRAPH_ERROR("parsing edgelist file failed", IGRAPH_PARSEERROR);
102
IGRAPH_CHECK(igraph_vector_push_back(&edges, from));
103
IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
105
/* skip all whitespace */
108
} while (isspace (c));
109
ungetc (c, instream);
112
IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
113
igraph_vector_destroy(&edges);
114
IGRAPH_FINALLY_CLEAN(1);
118
extern int igraph_ncol_yyparse(void);
119
extern FILE *igraph_ncol_yyin;
120
extern int igraph_i_ncol_eof;
121
long int igraph_ncol_mylineno;
122
igraph_vector_t *igraph_ncol_vector=0;
123
igraph_vector_t *igraph_ncol_weights=0;
124
igraph_trie_t *igraph_ncol_trie=0;
125
extern char *igraph_i_ncol_errmsg;
129
* \function igraph_read_graph_ncol
130
* \brief Reads a <code>.ncol</code> file used by LGL.
132
* Also useful for creating graphs from \quote named\endquote (and
133
* optionally weighted) edge lists.
136
* This format is used by the Large Graph Layout program
137
* (http://bioinformatics.icmb.utexas.edu/lgl/), and it is simply a
138
* symbolic weighted edge list. It is a simple text file with one edge
139
* per line. An edge is defined by two symbolic vertex names separated
140
* by whitespace. (The symbolic vertex names themselves cannot contain
141
* whitespace. They might follow by an optional number, this will be
142
* the weight of the edge; the number can be negative and can be in
143
* scientific notation. If there is no weight specified to an edge it
144
* is assumed to be zero.
147
* The resulting graph is always undirected.
148
* LGL cannot deal with files which contain multiple or loop edges,
149
* this is however not checked here, as \a igraph is happy with
151
* \param graph Pointer to an uninitialized graph object.
152
* \param instream Pointer to a stream, it should be readable.
153
* \param predefnames Pointer to the symbolic names of the vertices in
154
* the file. If \c NULL is given here then vertex ids will be
155
* assigned to vertex names in the order of their appearence in
156
* the \c .ncol file. If it is not \c NULL and some unknown
157
* vertex names are found in the \c .ncol file then new vertex
158
* ids will be assigned to them.
159
* \param names Logical value, if TRUE the symbolic names of the
160
* vertices will be added to the graph as a vertex attribute
161
* called \quote name\endquote.
162
* \param weights Logical value, if TRUE the weights of the
163
* edges is added to the graph as an edge attribute called
164
* \quote weight\endquote.
165
* \param directed Whether to create a directed graph. As this format
166
* was originally used only for undirected graphs there is no
167
* information in the file about the directedness of the graph.
168
* Set this parameter to \c IGRAPH_DIRECTED or \c
169
* IGRAPH_UNDIRECTED to create a directed or undirected graph.
170
* \return Error code:
171
* \c IGRAPH_PARSEERROR: if there is a
173
* the file, or the file is syntactically incorrect.
176
* O(|V|+|E|log(|V|)) if we neglect
177
* the time required by the parsing. As usual
178
* |V| is the number of vertices,
179
* while |E| is the number of edges.
181
* \sa \ref igraph_read_graph_lgl(), \ref igraph_write_graph_ncol()
184
int igraph_read_graph_ncol(igraph_t *graph, FILE *instream,
185
igraph_strvector_t *predefnames,
186
igraph_bool_t names, igraph_bool_t weights, igraph_bool_t directed) {
188
igraph_vector_t edges, ws;
189
igraph_trie_t trie=IGRAPH_TRIE_NULL;
190
long int no_predefined=0;
191
igraph_vector_ptr_t name, weight;
192
igraph_vector_ptr_t *pname=0, *pweight=0;
193
igraph_i_attribute_record_t namerec, weightrec;
194
const char *namestr="name", *weightstr="weight";
196
IGRAPH_CHECK(igraph_empty(graph, 0, directed));
197
IGRAPH_FINALLY(igraph_destroy, graph);
198
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
200
IGRAPH_TRIE_INIT_FINALLY(&trie, names);
201
IGRAPH_VECTOR_INIT_FINALLY(&ws, 0);
203
/* Add the predefined names, if any */
204
if (predefnames != 0) {
207
n=no_predefined=igraph_strvector_size(predefnames);
208
for (i=0; i<n; i++) {
209
igraph_strvector_get(predefnames, i, &key);
210
igraph_trie_get(&trie, key, &id);
212
IGRAPH_WARNING("reading NCOL file, duplicate entry in predefnames");
218
igraph_ncol_vector=&edges;
219
igraph_ncol_weights=&ws;
220
igraph_ncol_trie=≜
221
igraph_ncol_yyin=instream;
222
igraph_ncol_mylineno=1;
224
igraph_i_ncol_errmsg=0;
226
if (igraph_ncol_yyparse()) {
227
if (igraph_i_ncol_errmsg) {
228
IGRAPH_ERROR(igraph_i_ncol_errmsg, IGRAPH_PARSEERROR);
230
IGRAPH_ERROR("Cannot read NCOL file", IGRAPH_PARSEERROR);
234
if (predefnames != 0 &&
235
igraph_trie_size(&trie) != no_predefined) {
236
IGRAPH_WARNING("unknown vertex/vertices found, predefnames extended");
240
const igraph_strvector_t *namevec;
241
IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1));
243
igraph_trie_getkeys(&trie, &namevec); /* dirty */
244
namerec.name=namestr;
245
namerec.type=IGRAPH_ATTRIBUTE_STRING;
246
namerec.value=namevec;
247
VECTOR(name)[0]=&namerec;
251
IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1));
253
weightrec.name=weightstr;
254
weightrec.type=IGRAPH_ATTRIBUTE_NUMERIC;
256
VECTOR(weight)[0]=&weightrec;
259
IGRAPH_CHECK(igraph_add_vertices(graph, igraph_vector_max(&edges)+1, pname));
260
IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight));
263
igraph_vector_ptr_destroy(pname);
266
igraph_vector_ptr_destroy(pweight);
268
igraph_vector_destroy(&ws);
269
igraph_trie_destroy(&trie);
270
igraph_vector_destroy(&edges);
271
IGRAPH_FINALLY_CLEAN(4);
276
extern int igraph_lgl_yyparse(void);
277
extern FILE *igraph_lgl_yyin;
278
extern int igraph_i_lgl_eof;
279
long int igraph_lgl_mylineno;
280
igraph_vector_t *igraph_lgl_vector=0;
281
igraph_vector_t *igraph_lgl_weights=0;
282
igraph_trie_t *igraph_lgl_trie=0;
283
extern char *igraph_i_lgl_errmsg;
287
* \function igraph_read_graph_lgl
288
* \brief Reads a graph from an <code>.lgl</code> file
291
* The <code>.lgl</code> format is used by the Large Graph
292
* Layout visualization software
293
* (http://bioinformatics.icmb.utexas.edu/lgl/), it can
294
* describe undirected optionally weighted graphs. From the LGL
297
* \blockquote <para>The second format is the LGL file format
298
* (<code>.lgl</code> file
299
* suffix). This is yet another graph file format that tries to be as
300
* stingy as possible with space, yet keeping the edge file in a human
301
* readable (not binary) format. The format itself is like the
303
* \verbatim # vertex1name
304
vertex2name [optionalWeight]
305
vertex3name [optionalWeight] \endverbatim
306
* Here, the first vertex of an edge is preceded with a pound sign
307
* '#'. Then each vertex that shares an edge with that vertex is
308
* listed one per line on subsequent lines.</para> \endblockquote
311
* LGL cannot handle loop and multiple edges or directed graphs, but
312
* in \a igraph it is not an error to have multiple and loop edges.
313
* \param graph Pointer to an uninitialized graph object.
314
* \param instream A stream, it should be readable.
315
* \param names Logical value, if TRUE the symbolic names of the
316
* vertices will be added to the graph as a vertex attribute
317
* called \quote name\endquote.
318
* \param weights Logical value, if TRUE the weights of the
319
* edges is added to the graph as an edge attribute called
320
* \quote weight\endquote.
321
* \return Error code:
322
* \c IGRAPH_PARSEERROR: if there is a
323
* problem reading the file, or the file is syntactically
327
* O(|V|+|E|log(|V|)) if we neglect
328
* the time required by the parsing. As usual
329
* |V| is the number of vertices,
330
* while |E| is the number of edges.
332
* \sa \ref igraph_read_graph_ncol(), \ref igraph_write_graph_lgl()
335
int igraph_read_graph_lgl(igraph_t *graph, FILE *instream,
336
igraph_bool_t names, igraph_bool_t weights) {
338
igraph_vector_t edges=IGRAPH_VECTOR_NULL, ws=IGRAPH_VECTOR_NULL;
339
igraph_trie_t trie=IGRAPH_TRIE_NULL;
340
igraph_vector_ptr_t name, weight;
341
igraph_vector_ptr_t *pname=0, *pweight=0;
342
igraph_i_attribute_record_t namerec, weightrec;
343
const char *namestr="name", *weightstr="weight";
345
IGRAPH_VECTOR_INIT_FINALLY(&ws, 0);
346
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
347
IGRAPH_TRIE_INIT_FINALLY(&trie, names);
349
igraph_lgl_vector=&edges;
350
igraph_lgl_weights=&ws;
351
igraph_lgl_trie=≜
352
igraph_lgl_yyin=instream;
353
igraph_lgl_mylineno=1;
355
igraph_i_lgl_errmsg=0;
357
if (igraph_lgl_yyparse()) {
358
if (igraph_i_lgl_errmsg) {
359
IGRAPH_ERROR(igraph_i_lgl_errmsg, IGRAPH_PARSEERROR);
361
IGRAPH_ERROR("Cannot read LGL file", IGRAPH_PARSEERROR);
365
IGRAPH_CHECK(igraph_empty(graph, 0, IGRAPH_UNDIRECTED));
366
IGRAPH_FINALLY(igraph_destroy, graph);
369
const igraph_strvector_t *namevec;
370
IGRAPH_CHECK(igraph_vector_ptr_init(&name, 1));
371
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &name);
373
igraph_trie_getkeys(&trie, &namevec); /* dirty */
374
namerec.name=namestr;
375
namerec.type=IGRAPH_ATTRIBUTE_STRING;
376
namerec.value=namevec;
377
VECTOR(name)[0]=&namerec;
381
IGRAPH_CHECK(igraph_vector_ptr_init(&weight, 1));
382
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &weight);
384
weightrec.name=weightstr;
385
weightrec.type=IGRAPH_ATTRIBUTE_NUMERIC;
387
VECTOR(weight)[0]=&weightrec;
390
IGRAPH_CHECK(igraph_add_vertices(graph, igraph_trie_size(&trie), pname));
391
IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight));
394
igraph_vector_ptr_destroy(pweight);
395
IGRAPH_FINALLY_CLEAN(1);
398
igraph_vector_ptr_destroy(pname);
399
IGRAPH_FINALLY_CLEAN(1);
401
igraph_trie_destroy(&trie);
402
igraph_vector_destroy(&edges);
403
igraph_vector_destroy(&ws);
404
IGRAPH_FINALLY_CLEAN(4);
409
extern int igraph_pajek_yyparse(void);
410
extern FILE *igraph_pajek_yyin;
411
extern int igraph_i_pajek_eof;
412
long int igraph_pajek_mylineno;
413
igraph_vector_t *igraph_pajek_vector=0;
414
igraph_bool_t igraph_pajek_directed;
415
long int igraph_pajek_vcount;
416
long int igraph_pajek_actfrom, igraph_pajek_actto;
417
int igraph_pajek_mode=0; /* 0 - general, 1 - vertex, 2 - edge */
418
igraph_trie_t *igraph_i_pajek_vertex_attribute_names;
419
igraph_vector_ptr_t *igraph_i_pajek_vertex_attributes;
420
igraph_trie_t *igraph_i_pajek_edge_attribute_names;
421
igraph_vector_ptr_t *igraph_i_pajek_edge_attributes;
422
long int igraph_i_pajek_vertexid=0;
423
long int igraph_i_pajek_actvertex=0;
424
long int igraph_i_pajek_actedge=0;
425
extern char *igraph_i_pajek_errmsg;
427
/* int vector_print(igraph_vector_t *v) { */
428
/* long int i, size=igraph_vector_size(v); */
429
/* for (i=0; i<size; i++) { */
430
/* printf("%f|", VECTOR(*v)[i]); */
436
/* int strvector_print(igraph_strvector_t *sv) { */
437
/* long int i, size=igraph_strvector_size(sv); */
439
/* for (i=0; i<size; i++) { */
440
/* igraph_strvector_get(sv, i, &str); */
441
/* printf("%s|", str); */
448
* \function igraph_read_graph_pajek
449
* \brief Reads a file in Pajek format
451
* \param graph Pointer to an uninitialized graph object.
452
* \param file An already opened file handler.
453
* \return Error code.
456
* Only a subset of the Pajek format is implemented. This is partially
457
* because this format is not very well documented, but also because
458
* <command>igraph</command> does not support some Pajek features, like
462
* The list of the current limitations:
464
* \oli Only <filename>.net</filename> files are supported, Pajek
465
* project files (<filename>.paj</filename>) are not. These might be
466
* supported in the future if there is need for it.
467
* \oli Time events networks are not supported.
468
* \oli Hypergraphs (ie. graphs with non-binary edges) are not
470
* \oli Graphs with both directed and non-directed edges are not
471
* supported, are they cannot be represented in
472
* <command>igraph</command>.
473
* \oli Bipartite or affiliation networks are not supported. They can
474
* be imported but the vertex type information is omitted.
475
* \oli Only Pajek networks are supported, permutations, hierarchies,
476
* clusters and vectors are not.
477
* \oli Graphs with multiple edge sets are not supported.
481
* If there are attribute handlers installed,
482
* <command>igraph</command> also reads the vertex and edge attributes
483
* from the file. Most attributes are renamed to be more informative:
484
* `\c color' instead of `\c c', `\c xfact' instead of `\c x_fact',
485
* `\c yfact' instead of `y_fact', `\c labeldist' instead of `\c lr',
486
* `\c labeldegree2' instead of `\c lphi', `\c framewidth' instead of `\c bw',
488
* instead of `\c fos', `\c rotation' instead of `\c phi', `\c radius' instead
490
* `\c diamondratio' instead of `\c q', `\c labeldegree' instead of `\c la',
492
* instead of `\c size', `\c color' instead of `\c ic', `\c framecolor' instead of
493
* `\c bc', `\c labelcolor' instead of `\c lc', these belong to vertices.
496
* Edge attributes are also renamed, `\c s' to `\c arrowsize', `\c w'
497
* to `\c edgewidth', `\c h1' to `\c hook1', `\c h2' to `\c hook2',
498
* `\c a1' to `\c angle1', `\c a2' to `\c angle2', `\c k1' to
499
* `\c velocity1', `\c k2' to `\c velocity2', `\c ap' to `\c
500
* arrowpos', `\c lp' to `\c labelpos', `\c lr' to
501
* `\c labelangle', `\c lphi' to `\c labelangle2', `\c la' to `\c
502
* labeldegree', `\c fos' to
503
* `\c fontsize', `\c a' to `\c arrowtype', `\c p' to `\c
504
* linepattern', `\c l' to `\c label', `\c lc' to
505
* `\c labelcolor', `\c c' to `\c color'.
508
* In addition the following vertex attributes might be added: `\c id'
509
* if there are vertex ids in the file, `\c x' and `\c y' or `\c x'
510
* and `\c y' and `\c z' if there are vertex coordinates in the file,
511
* `\c color-red', `\c color-green' and `\c color-blue' if the vertex
512
* color is given in RGB notation, `\c framecolor-red', `\c
513
* framecolor-green' and `\c framecolor-blue` if the frame color is
514
* given in RGB notation and finally `\c labelcolor-red', `\c
515
* labelcolor-green' and `\c labelcolor-blue' if the label color is
516
* given in RGB notation.
518
* </para><para>The following additional edge attributes might be
519
* added: `\c weight' if there are edge weights present, `\c
520
* color-red', `\c color-green' and `\c color-blue' if the edge color
521
* is given in RGB notation.
524
* See the pajek homepage:
525
* http://vlado.fmf.uni-lj.si/pub/networks/pajek/ for more info on
526
* Pajek and the Pajek manual:
527
* http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/pajekman.pdf for
528
* information on the Pajek file format.
531
* Time complexity: O(|V|+|E|+|A|), |V| is the number of vertices, |E|
532
* the number of edges, |A| the number of attributes (vertex + edge)
533
* in the graph if there are attribute handlers installed.
535
* \sa \ref igraph_write_graph_pajek() for writing Pajek files, \ref
536
* igraph_read_graph_graphml() for reading GraphML files.
539
int igraph_read_graph_pajek(igraph_t *graph, FILE *instream) {
541
igraph_vector_t edges;
542
igraph_trie_t vattrnames;
543
igraph_vector_ptr_t vattrs;
544
igraph_trie_t eattrnames;
545
igraph_vector_ptr_t eattrs;
546
/* igraph_hashtable_t vattrhash; */
547
/* igraph_hashtable_t eattrhash; */
550
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
552
IGRAPH_TRIE_INIT_FINALLY(&vattrnames, 1);
553
IGRAPH_VECTOR_PTR_INIT_FINALLY(&vattrs, 0);
554
IGRAPH_TRIE_INIT_FINALLY(&eattrnames, 1);
555
IGRAPH_VECTOR_PTR_INIT_FINALLY(&eattrs, 0);
557
igraph_pajek_vector=&edges;
558
igraph_pajek_yyin=instream;
561
igraph_pajek_vcount=-1;
562
igraph_i_pajek_vertexid=0;
563
igraph_i_pajek_vertex_attribute_names=&vattrnames;
564
igraph_i_pajek_vertex_attributes=&vattrs;
565
igraph_i_pajek_edge_attribute_names=&eattrnames;
566
igraph_i_pajek_edge_attributes=&eattrs;
567
igraph_i_pajek_actedge=0;
568
igraph_pajek_mylineno=1;
569
igraph_i_pajek_eof=0;
570
igraph_i_pajek_errmsg=0;
572
if (igraph_pajek_yyparse()) {
573
if (igraph_i_pajek_errmsg) {
574
IGRAPH_ERROR(igraph_i_pajek_errmsg, IGRAPH_PARSEERROR);
576
IGRAPH_ERROR("Cannot read Pajek file", IGRAPH_PARSEERROR);
580
if (igraph_pajek_vcount < 0)
581
IGRAPH_ERROR("invalid vertex count in Pajek file", IGRAPH_EINVAL);
583
for (i=0; i<igraph_vector_ptr_size(&eattrs); i++) {
584
igraph_i_attribute_record_t *rec=VECTOR(eattrs)[i];
585
if (rec->type==IGRAPH_ATTRIBUTE_NUMERIC) {
586
igraph_vector_t *vec=(igraph_vector_t*)rec->value;
587
long int origsize=igraph_vector_size(vec);
588
igraph_vector_resize(vec, igraph_i_pajek_actedge);
589
for (j=origsize; j<igraph_i_pajek_actedge; j++) {
590
VECTOR(*vec)[j] = IGRAPH_NAN;
592
} else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
593
igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
594
long int origsize=igraph_strvector_size(strvec);
595
igraph_strvector_resize(strvec, igraph_i_pajek_actedge);
596
for (j=origsize; j<igraph_i_pajek_actedge; j++) {
597
igraph_strvector_set(strvec, j, "");
602
IGRAPH_CHECK(igraph_empty(graph, 0, igraph_pajek_directed));
603
IGRAPH_FINALLY(igraph_destroy, graph);
604
IGRAPH_CHECK(igraph_add_vertices(graph, igraph_pajek_vcount, &vattrs));
605
IGRAPH_CHECK(igraph_add_edges(graph, &edges, &eattrs));
607
for (i=0; i<igraph_vector_ptr_size(&vattrs); i++) {
608
igraph_i_attribute_record_t *rec=VECTOR(vattrs)[i];
609
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
610
igraph_vector_t *vec=(igraph_vector_t*) rec->value;
611
igraph_vector_destroy(vec);
613
} else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
614
igraph_strvector_t *strvec=(igraph_strvector_t *)rec->value;
615
igraph_strvector_destroy(strvec);
618
igraph_free( (char*)(rec->name));
622
for (i=0; i<igraph_vector_ptr_size(&eattrs); i++) {
623
igraph_i_attribute_record_t *rec=VECTOR(eattrs)[i];
624
if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
625
igraph_vector_t *vec=(igraph_vector_t*) rec->value;
626
igraph_vector_destroy(vec);
628
} else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
629
igraph_strvector_t *strvec=(igraph_strvector_t *)rec->value;
630
igraph_strvector_destroy(strvec);
633
igraph_free( (char*)(rec->name));
637
igraph_vector_destroy(&edges);
638
igraph_vector_ptr_destroy(&eattrs);
639
igraph_trie_destroy(&eattrnames);
640
igraph_vector_ptr_destroy(&vattrs);
641
igraph_trie_destroy(&vattrnames);
643
IGRAPH_FINALLY_CLEAN(6);
648
* \function igraph_read_graph_dimacs
649
* \brief Read a graph in DIMACS format.
651
* This function reads the DIMACS file format, more specifically the
652
* version for network flow problems, see the files at
653
* ftp://dimacs.rutgers.edu/pub/netflow/general-info/
656
* This is a line-oriented text file (ASCII) format. The first
657
* character of each line defines the type of the line. If the first
658
* character is <code>c</code> the line is a comment line and it is
659
* ignored. There is one problem line (<code>p</code> in the file, it
660
* must appear before any node and arc descriptor lines. The problem
661
* line has three fields separated by spaces: the problem type
662
* (<code>min</code>, <code>max</code> or <code>asn</code>), the
663
* number of vertices and number of edges in the graph.
664
* Exactly two node identification lines are expected
665
* (<code>n</code>), one for the source, one for the target vertex.
666
* These have two fields: the id of the vertex and the type of the
667
* vertex, either <code>s</code> (=source) or <code>t</code>
668
* (=target). Arc lines start with <code>a</code> and have three
669
* fields: the source vertex, the target vertex and the edge capacity.
672
* Vertex ids are numbered from 1.
673
* \param graph Pointer to an uninitialized graph object.
674
* \param instream The file to read from.
675
* \param source Pointer to an integer, the id of the source node will
676
* be stored here. (The igraph vertex id, which is one less than
677
* the actual number in the file.) It is ignored if
679
* \param target Pointer to an integer, the (igraph) id of the target
680
* node will be stored here. It is ignored if <code>NULL</code>.
681
* \param capacity Pointer to an initialized vector, the capacity of
682
* the edges will be stored here if not <code>NULL</code>.
683
* \param directed Boolean, whether to create a directed graph.
684
* \return Error code.
686
* Time complexity: O(|V|+|E|+c), the number of vertices plus the
687
* number of edges, plus the size of the file in characters.
689
* \sa \ref igraph_write_graph_dimacs()
692
int igraph_read_graph_dimacs(igraph_t *graph, FILE *instream,
693
igraph_strvector_t *problem,
694
igraph_vector_t *label,
695
igraph_integer_t *source,
696
igraph_integer_t *target,
697
igraph_vector_t *capacity,
698
igraph_bool_t directed) {
700
igraph_vector_t edges;
701
long int no_of_nodes=-1;
702
long int no_of_edges=-1;
709
#define PROBLEM_EDGE 1
710
#define PROBLEM_MAX 2
712
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
714
igraph_vector_clear(capacity);
717
while (!feof(instream)) {
721
IGRAPH_ALLOW_INTERRUPTION();
723
read=fscanf(instream, "%2c", str);
724
if (feof(instream)) {
728
IGRAPH_ERROR("parsing dimacs file failed", IGRAPH_PARSEERROR);
740
if (no_of_nodes != -1) {
741
IGRAPH_ERROR("reading dimacs file failed, double 'p' line",
744
read=fscanf(instream, "%20s %li %li", prob,
745
&no_of_nodes, &no_of_edges);
747
IGRAPH_ERROR("reading dimacs file failed", IGRAPH_PARSEERROR);
749
if (!strcmp(prob, "edge")) {
751
problem_type=PROBLEM_EDGE;
754
IGRAPH_CHECK(igraph_vector_resize(label, no_of_nodes));
755
for (i=0; i<no_of_nodes; i++) {
756
VECTOR(*label)[i]=i+1;
759
} else if (!strcmp(prob, "max")) {
760
/* maximum flow problem */
761
problem_type=PROBLEM_MAX;
763
IGRAPH_CHECK(igraph_vector_reserve(capacity, no_of_edges));
766
IGRAPH_ERROR("Unknown problem type, should be 'edge' or 'max'",
770
igraph_strvector_clear(problem);
771
IGRAPH_CHECK(igraph_strvector_add(problem, prob));
773
IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
777
/* for MAX this is either the source or target vertex,
778
for EDGE this is a vertex label */
779
if (problem_type == PROBLEM_MAX) {
781
read=fscanf(instream, "%li %1s", &tmp, str);
784
IGRAPH_ERROR("reading dimacsfile: multiple source vertex line",
789
} else if (str[0]=='t') {
791
IGRAPH_ERROR("reading dimacsfile: multiple target vertex line",
797
IGRAPH_ERROR("invalid node descriptor line in dimacs file",
801
read=fscanf(instream, "%li %li", &tmp, &tmp2);
803
VECTOR(*label)[tmp]=tmp2;
810
/* This is valid only for MAX, a weighted edge */
811
if (problem_type != PROBLEM_MAX) {
812
IGRAPH_ERROR("'a' lines are allowed only in MAX problem files",
815
read=fscanf(instream, "%li %li %lf", &from, &to, &cap);
817
IGRAPH_ERROR("reading dimacs file", IGRAPH_PARSEERROR);
819
IGRAPH_CHECK(igraph_vector_push_back(&edges, from-1));
820
IGRAPH_CHECK(igraph_vector_push_back(&edges, to-1));
822
IGRAPH_CHECK(igraph_vector_push_back(capacity, cap));
827
/* Edge line, only in EDGE */
828
if (problem_type != PROBLEM_EDGE) {
829
IGRAPH_ERROR("'e' lines are allowed only in EDGE problem files",
832
read=fscanf(instream, "%li %li", &from, &to);
834
IGRAPH_ERROR("reading dimacs file", IGRAPH_PARSEERROR);
836
IGRAPH_CHECK(igraph_vector_push_back(&edges, from-1));
837
IGRAPH_CHECK(igraph_vector_push_back(&edges, to-1));
841
IGRAPH_ERROR("unknown line type in dimacs file", IGRAPH_PARSEERROR);
844
/* Go to next line */
845
while (!feof(instream) && (c=getc(instream)) != '\n') ;
855
IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed));
856
igraph_vector_destroy(&edges);
858
IGRAPH_FINALLY_CLEAN(1);
863
int igraph_i_read_graph_graphdb_getword(FILE *instream) {
865
unsigned char c1, c2;
866
b1 = fgetc(instream);
867
b2 = fgetc(instream);
877
* \function igraph_read_graph_graphdb
878
* \brief Read a graph in the binary graph database format.
880
* This is a binary format, used in the graph database
881
* for isomorphism testing (http://amalfi.dis.unina.it/graph/)
882
* From the graph database homepage
883
* (http://amalfi.dis.unina.it/graph/db/doc/graphdbat-2.html):
887
* The graphs are stored in a compact binary format, one graph per
888
* file. The file is composed of 16 bit words, which are represented
889
* using the so-called little-endian convention, i.e. the least
890
* significant byte of the word is stored first.</para>
893
* Then, for each node, the file contains the list of edges coming
894
* out of the node itself. The list is represented by a word encoding
895
* its length, followed by a word for each edge, representing the
896
* destination node of the edge. Node numeration is 0-based, so the
897
* first node of the graph has index 0.</para> \endblockquote
900
* Only unlabelled graphs are implemented.
901
* \param graph Pointer to an uninitialized graph object.
902
* \param instream The stream to read from.
903
* \param directed Logical scalar, whether to create a directed graph.
904
* \return Error code.
906
* Time complexity: O(|V|+|E|), the number of vertices plus the
910
int igraph_read_graph_graphdb(igraph_t *graph, FILE *instream,
911
igraph_bool_t directed) {
913
igraph_vector_t edges;
918
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
920
nodes=igraph_i_read_graph_graphdb_getword(instream);
922
IGRAPH_ERROR("Can't read from file", IGRAPH_EFILE);
924
for (i=0; !end && i<nodes; i++) {
925
long int len=igraph_i_read_graph_graphdb_getword(instream);
930
for (j=0; ! end && j<len; j++) {
931
long int to=igraph_i_read_graph_graphdb_getword(instream);
936
IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
937
IGRAPH_CHECK(igraph_vector_push_back(&edges, to));
942
IGRAPH_ERROR("Truncated graphdb file", IGRAPH_EFILE);
945
IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
946
igraph_vector_destroy(&edges);
948
IGRAPH_FINALLY_CLEAN(1);
952
extern int igraph_gml_yyparse(void);
953
extern FILE *igraph_gml_yyin;
954
extern int igraph_gml_eof;
955
extern igraph_gml_tree_t *igraph_i_gml_parsed_tree;
956
long int igraph_gml_mylineno;
957
extern char *igraph_i_gml_errmsg;
959
void igraph_i_gml_destroy_attrs(igraph_vector_ptr_t **ptr) {
961
igraph_vector_ptr_t *vec;
962
for (i=0; i<3; i++) {
965
for (j=0; j<igraph_vector_ptr_size(vec); j++) {
966
igraph_i_attribute_record_t *atrec=VECTOR(*vec)[j];
967
if (atrec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
968
igraph_vector_t *value=(igraph_vector_t*)atrec->value;
969
igraph_vector_destroy(value);
972
igraph_strvector_t *value=(igraph_strvector_t*)atrec->value;
973
igraph_strvector_destroy(value);
976
igraph_Free(atrec->name);
979
igraph_vector_ptr_destroy(vec);
983
igraph_real_t igraph_i_gml_toreal(igraph_gml_tree_t *node, long int pos) {
985
igraph_real_t value=0.0;
986
int type=igraph_gml_tree_type(node, pos);
989
case IGRAPH_I_GML_TREE_INTEGER:
990
value=igraph_gml_tree_get_integer(node, pos);
992
case IGRAPH_I_GML_TREE_REAL:
993
value=igraph_gml_tree_get_real(node, pos);
996
IGRAPH_ERROR("Internal error while parsing GML file", IGRAPH_FAILURE);
1003
const char *igraph_i_gml_tostring(igraph_gml_tree_t *node, long int pos) {
1005
int type=igraph_gml_tree_type(node, pos);
1006
static char tmp[256];
1012
case IGRAPH_I_GML_TREE_INTEGER:
1013
i=igraph_gml_tree_get_integer(node, pos);
1014
snprintf(tmp, sizeof(tmp)/sizeof(char), "%li", i);
1016
case IGRAPH_I_GML_TREE_REAL:
1017
d=igraph_gml_tree_get_real(node, pos);
1018
snprintf(tmp, sizeof(tmp)/sizeof(char), "%g", d);
1020
case IGRAPH_I_GML_TREE_STRING:
1021
p=igraph_gml_tree_get_string(node, pos);
1031
* \function igraph_read_graph_gml
1032
* \brief Read a graph in GML format.
1034
* GML is a simple textual format, see
1035
* http://www.infosun.fim.uni-passau.de/Graphlet/GML/ for details.
1038
* Although all syntactically correct GML can be parsed,
1039
* we implement only a subset of this format, some attributes might be
1040
* ignored. Here is a list of all the differences:
1042
* \oli Only <code>node</code> and <code>edge</code> attributes are
1043
* used, and only if they have a simple type: integer, real or
1044
* string. So if an attribute is an array or a record, then it is
1045
* ignored. This is also true if only some values of the
1046
* attribute are complex.
1047
* \oli Top level attributes except for <code>Version</code> and the
1048
* first <code>graph</code> attribute are completely ignored.
1049
* \oli Graph attributes except for <code>node</code> and
1050
* <code>edge</code> are completely ignored.
1051
* \oli There is no maximum line length.
1052
* \oli There is no maximum keyword length.
1053
* \oli Character entities in strings are not interpreted.
1054
* \oli We allow <code>inf</code> (infinity) and <code>nan</code>
1055
* (not a number) as a real number. This is case insensitive, so
1056
* <code>nan</code>, <code>NaN</code> and <code>NAN</code> are equal.
1059
* </para><para> Please contact us if you cannot live with these
1060
* limitations of the GML parser.
1061
* \param graph Pointer to an uninitialized graph object.
1062
* \param instream The stream to read the GML file from.
1063
* \return Error code.
1065
* Time complexity: should be proportional to the length of the file.
1067
* \sa \ref igraph_read_graph_graphml() for a more modern format,
1068
* \ref igraph_write_graph_gml() for writing GML files.
1071
int igraph_read_graph_gml(igraph_t *graph, FILE *instream) {
1074
long int no_of_nodes=0, no_of_edges=0;
1076
igraph_vector_t edges;
1077
igraph_bool_t directed=IGRAPH_UNDIRECTED;
1078
igraph_gml_tree_t *gtree;
1080
igraph_trie_t vattrnames;
1081
igraph_trie_t eattrnames;
1082
igraph_trie_t gattrnames;
1083
igraph_vector_ptr_t gattrs=IGRAPH_VECTOR_PTR_NULL,
1084
vattrs=IGRAPH_VECTOR_PTR_NULL, eattrs=IGRAPH_VECTOR_PTR_NULL;
1085
igraph_vector_ptr_t *attrs[3];
1088
attrs[0]=&gattrs; attrs[1]=&vattrs; attrs[2]=&eattrs;
1090
igraph_gml_yyin=instream;
1091
igraph_gml_mylineno=1;
1093
igraph_i_gml_errmsg=0;
1095
i=igraph_gml_yyparse();
1097
if (igraph_i_gml_errmsg) {
1098
IGRAPH_ERROR(igraph_i_gml_errmsg, IGRAPH_PARSEERROR);
1100
IGRAPH_ERROR("Cannot read GML file", IGRAPH_PARSEERROR);
1104
IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
1106
/* Check version, if present, integer and not '1' then ignored */
1107
i=igraph_gml_tree_find(igraph_i_gml_parsed_tree, "Version", 0);
1109
igraph_gml_tree_type(igraph_i_gml_parsed_tree, i)==IGRAPH_I_GML_TREE_INTEGER &&
1110
igraph_gml_tree_get_integer(igraph_i_gml_parsed_tree, i) != 1) {
1111
igraph_gml_tree_destroy(igraph_i_gml_parsed_tree);
1112
IGRAPH_ERROR("Unknown GML version", IGRAPH_UNIMPLEMENTED);
1113
/* RETURN HERE!!!! */
1117
gidx=igraph_gml_tree_find(igraph_i_gml_parsed_tree, "graph", 0);
1119
IGRAPH_ERROR("No 'graph' object in GML file", IGRAPH_PARSEERROR);
1121
if (igraph_gml_tree_type(igraph_i_gml_parsed_tree, gidx) !=
1122
IGRAPH_I_GML_TREE_TREE) {
1123
IGRAPH_ERROR("Invalid type for 'graph' object in GML file", IGRAPH_PARSEERROR);
1125
gtree=igraph_gml_tree_get_tree(igraph_i_gml_parsed_tree, gidx);
1127
IGRAPH_FINALLY(igraph_i_gml_destroy_attrs, &attrs);
1128
igraph_vector_ptr_init(&gattrs, 0);
1129
igraph_vector_ptr_init(&vattrs, 0);
1130
igraph_vector_ptr_init(&eattrs, 0);
1132
IGRAPH_TRIE_INIT_FINALLY(&trie, 0);
1133
IGRAPH_TRIE_INIT_FINALLY(&vattrnames, 0);
1134
IGRAPH_TRIE_INIT_FINALLY(&eattrnames, 0);
1135
IGRAPH_TRIE_INIT_FINALLY(&gattrnames, 0);
1137
/* Is is directed? */
1138
i=igraph_gml_tree_find(gtree, "directed", 0);
1139
if (i>=0 && igraph_gml_tree_type(gtree, i)==IGRAPH_I_GML_TREE_INTEGER) {
1140
if (igraph_gml_tree_get_integer(gtree, i) == 1) {
1141
directed=IGRAPH_DIRECTED;
1145
/* Now we go over all objects in the graph and collect the attribute names and
1146
types. Plus we collect node ids. We also do some checks. */
1147
for (i=0; i<igraph_gml_tree_length(gtree); i++) {
1150
const char *name=igraph_gml_tree_name(gtree, i);
1151
if (!strcmp(name, "node")) {
1152
igraph_gml_tree_t *node;
1153
igraph_bool_t hasid;
1155
if (igraph_gml_tree_type(gtree, i) != IGRAPH_I_GML_TREE_TREE) {
1156
IGRAPH_ERROR("'node' is not a list", IGRAPH_PARSEERROR);
1158
node=igraph_gml_tree_get_tree(gtree, i);
1160
for (j=0; j<igraph_gml_tree_length(node); j++) {
1161
const char *name=igraph_gml_tree_name(node, j);
1162
long int trieid, triesize=igraph_trie_size(&vattrnames);
1163
IGRAPH_CHECK(igraph_trie_get(&vattrnames, name, &trieid));
1164
if (trieid==triesize) {
1166
igraph_i_attribute_record_t *atrec=igraph_Calloc(1, igraph_i_attribute_record_t);
1167
int type=igraph_gml_tree_type(node, j);
1169
IGRAPH_ERROR("Cannot read GML file", IGRAPH_ENOMEM);
1171
IGRAPH_CHECK(igraph_vector_ptr_push_back(&vattrs, atrec));
1172
atrec->name=strdup(name);
1173
if (type==IGRAPH_I_GML_TREE_INTEGER || type==IGRAPH_I_GML_TREE_REAL) {
1174
atrec->type=IGRAPH_ATTRIBUTE_NUMERIC;
1176
atrec->type=IGRAPH_ATTRIBUTE_STRING;
1179
/* already seen, should we update type? */
1180
igraph_i_attribute_record_t *atrec=VECTOR(vattrs)[trieid];
1181
int type1=atrec->type;
1182
int type2=igraph_gml_tree_type(node, j);
1183
if (type1==IGRAPH_ATTRIBUTE_NUMERIC && type2==IGRAPH_I_GML_TREE_STRING) {
1184
atrec->type=IGRAPH_ATTRIBUTE_STRING;
1188
if (!hasid && !strcmp(name, "id")) {
1190
if (igraph_gml_tree_type(node, j) != IGRAPH_I_GML_TREE_INTEGER) {
1191
IGRAPH_ERROR("Non-integer node id in GML file", IGRAPH_PARSEERROR);
1193
id=igraph_gml_tree_get_integer(node, j);
1194
snprintf(cname, sizeof(cname)/sizeof(char)-1, "%li", id);
1195
IGRAPH_CHECK(igraph_trie_get(&trie, cname, &id));
1200
IGRAPH_ERROR("Node without 'id' while parsing GML file", IGRAPH_PARSEERROR);
1202
} else if (!strcmp(name, "edge")) {
1203
igraph_gml_tree_t *edge;
1204
igraph_bool_t has_source=0, has_target=0;
1206
if (igraph_gml_tree_type(gtree, i) != IGRAPH_I_GML_TREE_TREE) {
1207
IGRAPH_ERROR("'edge' is not a list", IGRAPH_PARSEERROR);
1209
edge=igraph_gml_tree_get_tree(gtree, i);
1210
has_source=has_target=0;
1211
for (j=0; j<igraph_gml_tree_length(edge); j++) {
1212
const char *name=igraph_gml_tree_name(edge, j);
1213
if (!strcmp(name, "source")) {
1215
if (igraph_gml_tree_type(edge, j) != IGRAPH_I_GML_TREE_INTEGER) {
1216
IGRAPH_ERROR("Non-integer 'source' for an edge in GML file",
1219
} else if (!strcmp(name, "target")) {
1221
if (igraph_gml_tree_type(edge, j) != IGRAPH_I_GML_TREE_INTEGER) {
1222
IGRAPH_ERROR("Non-integer 'source' for an edge in GML file",
1226
long int trieid, triesize=igraph_trie_size(&eattrnames);
1227
IGRAPH_CHECK(igraph_trie_get(&eattrnames, name, &trieid));
1228
if (trieid==triesize) {
1230
igraph_i_attribute_record_t *atrec=igraph_Calloc(1, igraph_i_attribute_record_t);
1231
int type=igraph_gml_tree_type(edge, j);
1233
IGRAPH_ERROR("Cannot read GML file", IGRAPH_ENOMEM);
1235
IGRAPH_CHECK(igraph_vector_ptr_push_back(&eattrs, atrec));
1236
atrec->name=strdup(name);
1237
if (type==IGRAPH_I_GML_TREE_INTEGER || type==IGRAPH_I_GML_TREE_REAL) {
1238
atrec->type=IGRAPH_ATTRIBUTE_NUMERIC;
1240
atrec->type=IGRAPH_ATTRIBUTE_STRING;
1243
/* already seen, should we update type? */
1244
igraph_i_attribute_record_t *atrec=VECTOR(eattrs)[trieid];
1245
int type1=atrec->type;
1246
int type2=igraph_gml_tree_type(edge, j);
1247
if (type1==IGRAPH_ATTRIBUTE_NUMERIC && type2==IGRAPH_I_GML_TREE_STRING) {
1248
atrec->type=IGRAPH_ATTRIBUTE_STRING;
1254
IGRAPH_ERROR("No 'source' for edge in GML file", IGRAPH_PARSEERROR);
1257
IGRAPH_ERROR("No 'target' for edge in GML file", IGRAPH_PARSEERROR);
1260
/* anything to do? Maybe add as graph attribute.... */
1264
/* check vertex id uniqueness */
1265
if (igraph_trie_size(&trie) != no_of_nodes) {
1266
IGRAPH_ERROR("Node 'id' not unique", IGRAPH_PARSEERROR);
1269
/* now we allocate the vectors and strvectors for the attributes */
1270
for (i=0; i<igraph_vector_ptr_size(&vattrs); i++) {
1271
igraph_i_attribute_record_t *atrec=VECTOR(vattrs)[i];
1272
int type=atrec->type;
1273
if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
1274
igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
1276
IGRAPH_CHECK(igraph_vector_init(p, no_of_nodes));
1277
} else if (type == IGRAPH_ATTRIBUTE_STRING) {
1278
igraph_strvector_t *p=igraph_Calloc(1, igraph_strvector_t);
1280
IGRAPH_CHECK(igraph_strvector_init(p, no_of_nodes));
1282
IGRAPH_WARNING("A composite attribute ignored");
1286
for (i=0; i<igraph_vector_ptr_size(&eattrs); i++) {
1287
igraph_i_attribute_record_t *atrec=VECTOR(eattrs)[i];
1288
int type=atrec->type;
1289
if (type == IGRAPH_ATTRIBUTE_NUMERIC) {
1290
igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t);
1292
IGRAPH_CHECK(igraph_vector_init(p, no_of_edges));
1293
} else if (type == IGRAPH_ATTRIBUTE_STRING) {
1294
igraph_strvector_t *p=igraph_Calloc(1, igraph_strvector_t);
1296
IGRAPH_CHECK(igraph_strvector_init(p, no_of_edges));
1298
IGRAPH_WARNING("A composite attribute ignored");
1302
/* Ok, now the edges, attributes too */
1303
IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*2));
1305
while ( (p=igraph_gml_tree_find(gtree, "edge", p+1)) != -1) {
1306
igraph_gml_tree_t *edge;
1307
long int from, to, fromidx=0, toidx=0;
1310
edge=igraph_gml_tree_get_tree(gtree, p);
1311
for (j=0; j<igraph_gml_tree_length(edge); j++) {
1312
const char *n=igraph_gml_tree_name(edge, j);
1313
if (!strcmp(n, "source")) {
1314
fromidx=igraph_gml_tree_find(edge, "source", 0);
1315
} else if (!strcmp(n, "target")) {
1316
toidx=igraph_gml_tree_find(edge, "target", 0);
1318
long int edgeid=edgeptr/2;
1320
igraph_i_attribute_record_t *atrec;
1322
igraph_trie_get(&eattrnames, n, &trieidx);
1323
atrec=VECTOR(eattrs)[trieidx];
1325
if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
1326
igraph_vector_t *v=(igraph_vector_t *)atrec->value;
1327
VECTOR(*v)[edgeid]=igraph_i_gml_toreal(edge, j);
1328
} else if (type==IGRAPH_ATTRIBUTE_STRING) {
1329
igraph_strvector_t *v=(igraph_strvector_t *)atrec->value;
1330
const char *value=igraph_i_gml_tostring(edge, j);
1331
IGRAPH_CHECK(igraph_strvector_set(v, edgeid, value));
1335
from=igraph_gml_tree_get_integer(edge, fromidx);
1336
to=igraph_gml_tree_get_integer(edge, toidx);
1337
snprintf(name, sizeof(name)/sizeof(char)-1, "%li", from);
1338
IGRAPH_CHECK(igraph_trie_get(&trie, name, &from));
1339
snprintf(name, sizeof(name)/sizeof(char)-1, "%li", to);
1340
IGRAPH_CHECK(igraph_trie_get(&trie, name, &to));
1341
if (igraph_trie_size(&trie) != no_of_nodes) {
1342
IGRAPH_ERROR("Unkown node id found at an edge", IGRAPH_PARSEERROR);
1344
VECTOR(edges)[edgeptr++]=from;
1345
VECTOR(edges)[edgeptr++]=to;
1348
/* and add vertex attributes */
1349
for (i=0; i<igraph_gml_tree_length(gtree); i++) {
1353
n=igraph_gml_tree_name(gtree, i);
1354
if (!strcmp(n, "node")) {
1355
igraph_gml_tree_t *node=igraph_gml_tree_get_tree(gtree, i);
1356
long int iidx=igraph_gml_tree_find(node, "id", 0);
1357
long int id=igraph_gml_tree_get_integer(node, iidx);
1358
snprintf(name, sizeof(name)/sizeof(char)-1, "%li", id);
1359
igraph_trie_get(&trie, name, &id);
1360
for (j=0; j<igraph_gml_tree_length(node); j++) {
1361
const char *aname=igraph_gml_tree_name(node, j);
1362
igraph_i_attribute_record_t *atrec;
1364
igraph_trie_get(&vattrnames, aname, &k);
1365
atrec=VECTOR(vattrs)[k];
1367
if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
1368
igraph_vector_t *v=(igraph_vector_t *)atrec->value;
1369
VECTOR(*v)[id]=igraph_i_gml_toreal(node, j);
1370
} else if (type==IGRAPH_ATTRIBUTE_STRING) {
1371
igraph_strvector_t *v=(igraph_strvector_t *)atrec->value;
1372
const char *value=igraph_i_gml_tostring(node, j);
1373
IGRAPH_CHECK(igraph_strvector_set(v, id, value));
1379
igraph_gml_tree_destroy(igraph_i_gml_parsed_tree);
1381
igraph_trie_destroy(&trie);
1382
igraph_trie_destroy(&gattrnames);
1383
igraph_trie_destroy(&vattrnames);
1384
igraph_trie_destroy(&eattrnames);
1385
IGRAPH_FINALLY_CLEAN(4);
1387
IGRAPH_CHECK(igraph_empty_attrs(graph, 0, directed, 0)); /* TODO */
1388
IGRAPH_CHECK(igraph_add_vertices(graph, no_of_nodes, &vattrs));
1389
IGRAPH_CHECK(igraph_add_edges(graph, &edges, &eattrs));
1391
igraph_i_gml_destroy_attrs(attrs);
1392
igraph_vector_destroy(&edges);
1393
IGRAPH_FINALLY_CLEAN(2);
1400
* \function igraph_write_graph_edgelist
1401
* \brief Writes the edge list of a graph to a file.
1404
* One edge is written per line, separated by a single space.
1405
* For directed graphs edges are written in from, to order.
1406
* \param graph The graph object to write.
1407
* \param outstream Pointer to a stream, it should be writable.
1408
* \return Error code:
1409
* \c IGRAPH_EFILE if there is an error writing the
1412
* Time complexity: O(|E|), the
1413
* number of edges in the graph. It is assumed that writing an
1414
* integer to the file requires O(1)
1418
int igraph_write_graph_edgelist(const igraph_t *graph, FILE *outstream) {
1422
IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1424
IGRAPH_FINALLY(igraph_eit_destroy, &it);
1426
while (!IGRAPH_EIT_END(it)) {
1427
igraph_integer_t from, to;
1429
igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
1430
ret=fprintf(outstream, "%li %li\n",
1434
IGRAPH_ERROR("Write error", IGRAPH_EFILE);
1436
IGRAPH_EIT_NEXT(it);
1439
igraph_eit_destroy(&it);
1440
IGRAPH_FINALLY_CLEAN(1);
1446
* \function igraph_write_graph_ncol
1447
* \brief Writes the graph to a file in <code>.ncol</code> format
1450
* <code>.ncol</code> is a format used by LGL, see \ref
1451
* igraph_read_graph_ncol() for details.
1454
* Note that having multiple or loop edges in an
1455
* <code>.ncol</code> file breaks the LGL software but
1456
* \a igraph does not check for this condition.
1457
* \param graph The graph to write.
1458
* \param outstream The stream object to write to, it should be
1460
* \param names The name of the vertex attribute, if symbolic names
1461
* are written to the file. If not, supply 0 here.
1462
* \param weights The name of the edge attribute, if they are also
1463
* written to the file. If you don't want weights, supply 0
1465
* \return Error code:
1466
* \c IGRAPH_EFILE if there is an error writing the
1469
* Time complexity: O(|E|), the
1470
* number of edges. All file operations are expected to have time
1473
* \sa \ref igraph_read_graph_ncol(), \ref igraph_write_graph_lgl()
1476
int igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream,
1477
const char *names, const char *weights) {
1479
igraph_attribute_type_t nametype, weighttype;
1481
IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1483
IGRAPH_FINALLY(igraph_eit_destroy, &it);
1485
/* Check if we have the names attribute */
1486
if (names && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
1489
IGRAPH_WARNING("names attribute does not exists");
1492
IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &nametype,
1493
IGRAPH_ATTRIBUTE_VERTEX, names));
1495
if (names && nametype != IGRAPH_ATTRIBUTE_NUMERIC &&
1496
nametype != IGRAPH_ATTRIBUTE_STRING) {
1497
IGRAPH_WARNING("ignoring names attribute, unknown attribute type");
1501
/* Check the weights as well */
1502
if (weights && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
1505
IGRAPH_WARNING("weights attribute does not exists");
1508
IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &weighttype,
1509
IGRAPH_ATTRIBUTE_EDGE, weights));
1511
if (weights && weighttype != IGRAPH_ATTRIBUTE_NUMERIC) {
1512
IGRAPH_WARNING("ignoring weights attribute, unknown attribute type");
1516
if (names==0 && weights ==0) {
1517
/* No names, no weights */
1518
while (!IGRAPH_EIT_END(it)) {
1519
igraph_integer_t from, to;
1521
igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
1522
ret=fprintf(outstream, "%li %li\n",
1526
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1528
IGRAPH_EIT_NEXT(it);
1530
} else if (weights==0) {
1531
/* No weights, but use names */
1532
igraph_strvector_t nvec;
1533
IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
1534
IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
1535
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
1538
while (!IGRAPH_EIT_END(it)) {
1539
igraph_integer_t edge=IGRAPH_EIT_GET(it);
1540
igraph_integer_t from, to;
1543
igraph_edge(graph, edge, &from, &to);
1544
igraph_strvector_get(&nvec, from, &str1);
1545
igraph_strvector_get(&nvec, to, &str2);
1546
ret=fprintf(outstream, "%s %s\n", str1, str2);
1548
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1550
IGRAPH_EIT_NEXT(it);
1552
igraph_strvector_destroy(&nvec);
1553
IGRAPH_FINALLY_CLEAN(1);
1554
} else if (names==0) {
1555
/* No names but weights */
1556
igraph_vector_t wvec;
1557
IGRAPH_VECTOR_INIT_FINALLY(&wvec, igraph_ecount(graph));
1558
IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, weights,
1559
igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1561
while (!IGRAPH_EIT_END(it)) {
1562
igraph_integer_t edge=IGRAPH_EIT_GET(it);
1563
igraph_integer_t from, to;
1565
igraph_edge(graph, edge, &from, &to);
1566
ret=fprintf(outstream, "%li %li %f\n",
1567
(long int)from, (long int)to, VECTOR(wvec)[(long int)edge]);
1569
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1571
IGRAPH_EIT_NEXT(it);
1573
igraph_vector_destroy(&wvec);
1574
IGRAPH_FINALLY_CLEAN(1);
1576
/* Both names and weights */
1577
igraph_strvector_t nvec;
1578
igraph_vector_t wvec;
1579
IGRAPH_VECTOR_INIT_FINALLY(&wvec, igraph_ecount(graph));
1580
IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
1581
IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
1582
IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, weights,
1583
igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1585
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
1588
while (!IGRAPH_EIT_END(it)) {
1589
igraph_integer_t edge=IGRAPH_EIT_GET(it);
1590
igraph_integer_t from, to;
1593
igraph_edge(graph, edge, &from, &to);
1594
igraph_strvector_get(&nvec, from, &str1);
1595
igraph_strvector_get(&nvec, to, &str2);
1596
ret=fprintf(outstream, "%s %s ", str1, str2);
1598
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1600
ret=fprintf(outstream, "%f\n", VECTOR(wvec)[(long int)edge]);
1602
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1604
IGRAPH_EIT_NEXT(it);
1606
igraph_strvector_destroy(&nvec);
1607
igraph_vector_destroy(&wvec);
1608
IGRAPH_FINALLY_CLEAN(2);
1611
igraph_eit_destroy(&it);
1612
IGRAPH_FINALLY_CLEAN(1);
1618
* \function igraph_write_graph_lgl
1619
* \brief Writes the graph to a file in <code>.lgl</code> format
1622
* <code>.lgl</code> is a format used by LGL, see \ref
1623
* igraph_read_graph_lgl() for details.
1626
* Note that having multiple or loop edges in an
1627
* <code>.lgl</code> file breaks the LGL software but \a igraph
1628
* does not check for this condition.
1629
* \param graph The graph to write.
1630
* \param outstream The stream object to write to, it should be
1632
* \param names The name of the vertex attribute, if symbolic names
1633
* are written to the file. If not supply 0 here.
1634
* \param weights The name of the edge attribute, if they are also
1635
* written to the file. If you don't want weights supply 0
1637
* \param isolates Logical, if TRUE isolated vertices are also written
1638
* to the file. If FALSE they will be omitted.
1639
* \return Error code:
1640
* \c IGRAPH_EFILE if there is an error
1643
* Time complexity: O(|E|), the
1644
* number of edges if \p isolates is
1645
* FALSE, O(|V|+|E|) otherwise. All
1646
* file operations are expected to have time complexity
1649
* \sa \ref igraph_read_graph_ncol(), \ref igraph_write_graph_lgl()
1652
int igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream,
1653
const char *names, const char *weights,
1654
igraph_bool_t isolates) {
1656
long int actvertex=-1;
1657
igraph_attribute_type_t nametype, weighttype;
1659
IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1661
IGRAPH_FINALLY(igraph_eit_destroy, &it);
1663
/* Check if we have the names attribute */
1664
if (names && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
1667
IGRAPH_WARNING("names attribute does not exists");
1670
IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &nametype,
1671
IGRAPH_ATTRIBUTE_VERTEX, names));
1673
if (names && nametype != IGRAPH_ATTRIBUTE_NUMERIC &&
1674
nametype != IGRAPH_ATTRIBUTE_STRING) {
1675
IGRAPH_WARNING("ignoring names attribute, unknown attribute type");
1679
/* Check the weights as well */
1680
if (weights && !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
1683
IGRAPH_WARNING("weights attribute does not exists");
1686
IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &weighttype,
1687
IGRAPH_ATTRIBUTE_EDGE, weights));
1689
if (weights && weighttype != IGRAPH_ATTRIBUTE_NUMERIC) {
1690
IGRAPH_WARNING("ignoring weights attribute, unknown attribute type");
1694
if (names==0 && weights==0) {
1695
/* No names, no weights */
1696
while (!IGRAPH_EIT_END(it)) {
1697
igraph_integer_t from, to;
1699
igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
1700
if (from==actvertex) {
1701
ret=fprintf(outstream, "%li\n", (long int)to);
1704
ret=fprintf(outstream, "# %li\n%li\n", (long int)from, (long int)to);
1707
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1709
IGRAPH_EIT_NEXT(it);
1711
} else if (weights==0) {
1712
/* No weights but use names */
1713
igraph_strvector_t nvec;
1714
IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
1715
IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
1716
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
1719
while (!IGRAPH_EIT_END(it)) {
1720
igraph_integer_t edge=IGRAPH_EIT_GET(it);
1721
igraph_integer_t from, to;
1724
igraph_edge(graph, edge, &from, &to);
1725
igraph_strvector_get(&nvec, to, &str2);
1727
if (from==actvertex) {
1728
ret=fprintf(outstream, "%s\n", str2);
1731
igraph_strvector_get(&nvec, from, &str1);
1732
ret=fprintf(outstream, "# %s\n%s\n", str1, str2);
1735
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1737
IGRAPH_EIT_NEXT(it);
1739
IGRAPH_FINALLY_CLEAN(1);
1740
} else if (names==0) {
1741
igraph_strvector_t wvec;
1742
IGRAPH_CHECK(igraph_strvector_init(&wvec, igraph_ecount(graph)));
1743
IGRAPH_FINALLY(igraph_strvector_destroy, &wvec);
1744
IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, weights,
1745
igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1747
/* No names but weights */
1748
while (!IGRAPH_EIT_END(it)) {
1749
igraph_integer_t edge=IGRAPH_EIT_GET(it);
1750
igraph_integer_t from, to;
1753
igraph_edge(graph, edge, &from, &to);
1754
igraph_strvector_get(&wvec, edge, &str1);
1755
if (from==actvertex) {
1756
ret=fprintf(outstream, "%li %s\n", (long)to, str1);
1759
ret=fprintf(outstream, "# %li\n%li %s\n", (long)from, (long)to, str1);
1762
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1764
IGRAPH_EIT_NEXT(it);
1766
igraph_strvector_destroy(&wvec);
1767
IGRAPH_FINALLY_CLEAN(1);
1769
/* Both names and weights */
1770
igraph_strvector_t nvec, wvec;
1771
IGRAPH_CHECK(igraph_strvector_init(&wvec, igraph_ecount(graph)));
1772
IGRAPH_FINALLY(igraph_strvector_destroy, &wvec);
1773
IGRAPH_CHECK(igraph_strvector_init(&nvec, igraph_vcount(graph)));
1774
IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
1775
IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, weights,
1776
igraph_ess_all(IGRAPH_EDGEORDER_FROM),
1778
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
1781
while (!IGRAPH_EIT_END(it)) {
1782
igraph_integer_t edge=IGRAPH_EIT_GET(it);
1783
igraph_integer_t from, to;
1785
char *str1, *str2, *str3;
1786
igraph_edge(graph, edge, &from, &to);
1787
igraph_strvector_get(&nvec, to, &str2);
1788
igraph_strvector_get(&wvec, edge, &str3);
1789
if (from==actvertex) {
1790
ret=fprintf(outstream, "%s ", str2);
1793
igraph_strvector_get(&nvec, from, &str1);
1794
ret=fprintf(outstream, "# %s\n%s ", str1, str2);
1797
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1799
ret=fprintf(outstream, "%s\n", str3);
1801
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1803
IGRAPH_EIT_NEXT(it);
1805
igraph_strvector_destroy(&nvec);
1806
igraph_strvector_destroy(&wvec);
1807
IGRAPH_FINALLY_CLEAN(2);
1811
long int nov=igraph_vcount(graph);
1814
igraph_vector_t deg;
1815
igraph_strvector_t nvec;
1818
IGRAPH_VECTOR_INIT_FINALLY(°, 1);
1819
IGRAPH_CHECK(igraph_strvector_init(&nvec, 1));
1820
IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);
1821
for (i=0; i<nov; i++) {
1822
igraph_degree(graph, °, igraph_vss_1(i), IGRAPH_ALL, IGRAPH_LOOPS);
1823
if (VECTOR(deg)[0]==0) {
1825
ret=fprintf(outstream, "# %li\n", i);
1827
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, names,
1830
igraph_strvector_get(&nvec, 0, &str);
1831
ret=fprintf(outstream, "# %s\n", str);
1835
IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1838
igraph_strvector_destroy(&nvec);
1839
igraph_vector_destroy(°);
1840
IGRAPH_FINALLY_CLEAN(2);
1843
igraph_eit_destroy(&it);
1844
IGRAPH_FINALLY_CLEAN(1);
1848
/* Order matters here! */
1856
#define V_COLOR_RED 7
1857
#define V_COLOR_GREEN 8
1858
#define V_COLOR_BLUE 9
1859
#define V_FRAMECOLOR_RED 10
1860
#define V_FRAMECOLOR_GREEN 11
1861
#define V_FRAMECOLOR_BLUE 12
1862
#define V_LABELCOLOR_RED 13
1863
#define V_LABELCOLOR_GREEN 14
1864
#define V_LABELCOLOR_BLUE 15
1865
#define V_LABELDIST 16
1866
#define V_LABELDEGREE2 17
1867
#define V_FRAMEWIDTH 18
1868
#define V_FONTSIZE 19
1869
#define V_ROTATION 20
1871
#define V_DIAMONDRATIO 22
1872
#define V_LABELDEGREE 23
1873
#define V_VERTEXSIZE 24
1877
#define V_FRAMECOLOR 28
1878
#define V_LABELCOLOR 29
1882
#define E_COLOR_RED 1
1883
#define E_COLOR_GREEN 2
1884
#define E_COLOR_BLUE 3
1885
#define E_ARROWSIZE 4
1886
#define E_EDGEWIDTH 5
1891
#define E_VELOCITY1 10
1892
#define E_VELOCITY2 11
1893
#define E_ARROWPOS 12
1894
#define E_LABELPOS 13
1895
#define E_LABELANGLE 14
1896
#define E_LABELANGLE2 15
1897
#define E_LABELDEGREE 16
1898
#define E_FONTSIZE 17
1899
#define E_ARROWTYPE 18
1900
#define E_LINEPATTERN 19
1902
#define E_LABELCOLOR 21
1907
* \function igraph_write_graph_pajek
1908
* \brief Writes a graph to a file in Pajek format.
1911
* The Pajek vertex and edge parameters (like color) are determined by
1912
* the attributes of the vertices and edges, of course this requires
1913
* an attribute handler to be installed. The names of the
1914
* corresponding vertex and edge attributes are listed at \ref
1915
* igraph_read_graph_pajek(), eg. the `\c color' vertex attributes
1916
* determines the color (`\c c' in Pajek) parameter.
1917
* \param graph The graph object to write.
1918
* \param outstream The file to write to. It should be opened and
1919
* writable. Make sure that you open the file in binary format if you use MS Windows,
1920
* otherwise end of line characters will be messed up. (igraph will be able
1921
* to read back these messed up files, but Pajek won't.)
1922
* \return Error code.
1924
* Time complexity: O(|V|+|E|+|A|), |V| is the number of vertices, |E|
1925
* is the number of edges, |A| the number of attributes (vertex +
1926
* edge) in the graph if there are attribute handlers installed.
1928
* \sa \ref igraph_read_graph_pajek() for reading Pajek graphs, \ref
1929
* igraph_write_graph_graphml() for writing a graph in GraphML format,
1930
* this suites <command>igraph</command> graphs better.
1933
int igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream) {
1934
long int no_of_nodes=igraph_vcount(graph);
1937
igraph_attribute_type_t vtypes[V_LAST], etypes[E_LAST];
1938
igraph_bool_t write_vertex_attrs=0;
1940
/* Same order as the #define's */
1941
const char *vnames[] = { "id", "x", "y", "z", "shape", "xfact", "yfact",
1942
"color-red", "color-green", "color-blue",
1943
"framecolor-red", "framecolor-green",
1944
"framecolor-blue", "labelcolor-red",
1945
"labelcolor-green", "labelcolor-blue",
1946
"labeldist", "labeldegree2", "framewidth",
1947
"fontsize", "rotation", "radius",
1948
"diamondratio", "labeldegree", "vertexsize",
1949
"font", "url", "color", "framecolor",
1952
const char *vnumnames[] = { "xfact", "yfact", "labeldist",
1953
"labeldegree2", "framewidth", "fontsize",
1954
"rotation", "radius", "diamondratio",
1955
"labeldegree", "vertexsize" };
1956
const char *vnumnames2[]= { "x_fact", "y_fact", "lr", "lphi", "bw",
1957
"fos", "phi", "r", "q", "la", "size" };
1958
const char *vstrnames[] = { "font", "url", "color", "framecolor",
1960
const char *vstrnames2[]= { "font", "url", "ic", "bc", "lc" };
1962
const char *enames[] = { "weight", "color-red", "color-green", "color-blue",
1963
"arrowsize", "edgewidth", "hook1", "hook2",
1964
"angle1", "angle2", "velocity1", "velocity2",
1965
"arrowpos", "labelpos", "labelangle",
1966
"labelangle2", "labeldegree", "fontsize",
1967
"arrowtype", "linepattern", "label", "labelcolor",
1969
const char *enumnames[] = { "arrowsize", "edgewidth", "hook1", "hook2",
1970
"angle1", "angle2", "velocity1", "velocity2",
1971
"arrowpos", "labelpos", "labelangle",
1972
"labelangle2", "labeldegree", "fontsize" };
1973
const char *enumnames2[]= { "s", "w", "h1", "h2", "a1", "a2", "k1", "k2",
1974
"ap", "lp", "lr", "lphi", "la", "fos" };
1975
const char *estrnames[] = { "arrowtype", "linepattern", "label",
1976
"labelcolor", "color" };
1977
const char *estrnames2[]= { "a", "p", "l", "lc", "c" };
1979
const char *newline="\x0d\x0a";
1984
igraph_vector_t numv;
1985
igraph_strvector_t strv;
1987
igraph_vector_t ex_numa;
1988
igraph_vector_t ex_stra;
1989
igraph_vector_t vx_numa;
1990
igraph_vector_t vx_stra;
1992
IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
1993
IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
1995
IGRAPH_VECTOR_INIT_FINALLY(&ex_numa, 0);
1996
IGRAPH_VECTOR_INIT_FINALLY(&ex_stra, 0);
1997
IGRAPH_VECTOR_INIT_FINALLY(&vx_numa, 0);
1998
IGRAPH_VECTOR_INIT_FINALLY(&vx_stra, 0);
2001
if (fprintf(outstream, "*Vertices %li%s", no_of_nodes, newline) < 0) {
2002
IGRAPH_ERROR("Cannot write pajek file", IGRAPH_EFILE);
2005
/* Check the vertex attributes */
2006
memset(vtypes, 0, sizeof(vtypes[0])*V_LAST);
2007
for (i=0; i<V_LAST; i++) {
2008
if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
2010
igraph_i_attribute_gettype(graph, &vtypes[i], IGRAPH_ATTRIBUTE_VERTEX,
2012
write_vertex_attrs=1;
2017
for (i=0; i<sizeof(vnumnames)/sizeof(const char*); i++) {
2018
igraph_attribute_type_t type;
2019
if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
2021
igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_VERTEX,
2023
if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
2024
IGRAPH_CHECK(igraph_vector_push_back(&vx_numa, i));
2028
for (i=0; i<sizeof(vstrnames)/sizeof(const char*); i++) {
2029
igraph_attribute_type_t type;
2030
if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX,
2032
igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_VERTEX,
2034
if (type==IGRAPH_ATTRIBUTE_STRING) {
2035
IGRAPH_CHECK(igraph_vector_push_back(&vx_stra, i));
2040
/* Write vertices */
2041
if (write_vertex_attrs) {
2042
for (i=0; i<no_of_nodes; i++) {
2045
fprintf(outstream, "%li", i+1);
2046
if (vtypes[V_ID] == IGRAPH_ATTRIBUTE_NUMERIC) {
2047
igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_ID],
2048
igraph_vss_1(i), &numv);
2049
fprintf(outstream, " \"%g\"", VECTOR(numv)[0]);
2050
} else if (vtypes[V_ID] == IGRAPH_ATTRIBUTE_STRING) {
2052
igraph_i_attribute_get_string_vertex_attr(graph, vnames[V_ID],
2053
igraph_vss_1(i), &strv);
2054
igraph_strvector_get(&strv, 0, &s);
2055
fprintf(outstream, " \"%s\"", s);
2059
if (vtypes[V_X] == IGRAPH_ATTRIBUTE_NUMERIC &&
2060
vtypes[V_Y] == IGRAPH_ATTRIBUTE_NUMERIC) {
2061
igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_X],
2062
igraph_vss_1(i), &numv);
2063
fprintf(outstream, " %g", VECTOR(numv)[0]);
2064
igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_Y],
2065
igraph_vss_1(i), &numv);
2066
fprintf(outstream, " %g", VECTOR(numv)[0]);
2067
if (vtypes[V_Z] == IGRAPH_ATTRIBUTE_NUMERIC) {
2068
igraph_i_attribute_get_numeric_vertex_attr(graph, vnames[V_Z],
2069
igraph_vss_1(i), &numv);
2070
fprintf(outstream, " %g", VECTOR(numv)[0]);
2075
if (vtypes[V_SHAPE] == IGRAPH_ATTRIBUTE_STRING) {
2077
igraph_i_attribute_get_string_vertex_attr(graph, vnames[V_SHAPE],
2078
igraph_vss_1(i), &strv);
2079
igraph_strvector_get(&strv, 0, &s);
2080
fprintf(outstream, " %s", s);
2083
/* numeric parameters */
2084
for (j=0; j<igraph_vector_size(&vx_numa); j++) {
2085
int idx=VECTOR(vx_numa)[j];
2086
igraph_i_attribute_get_numeric_vertex_attr(graph, vnumnames[idx],
2087
igraph_vss_1(i), &numv);
2088
fprintf(outstream, " %s %g", vnumnames2[idx], VECTOR(numv)[0]);
2091
/* string parameters */
2092
for (j=0; j<igraph_vector_size(&vx_stra); j++) {
2093
int idx=VECTOR(vx_numa)[j];
2095
igraph_i_attribute_get_string_vertex_attr(graph, vstrnames[idx],
2096
igraph_vss_1(i), &strv);
2097
igraph_strvector_get(&strv, 0, &s);
2098
fprintf(outstream, " %s \"%s\"", vstrnames2[idx], s);
2101
/* trailing newline */
2102
fprintf(outstream, "%s", newline);
2107
if (igraph_is_directed(graph)) {
2108
fprintf(outstream, "*Arcs%s", newline);
2110
fprintf(outstream, "*Edges%s", newline);
2113
IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
2114
IGRAPH_FINALLY(igraph_es_destroy, &es);
2115
IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
2116
IGRAPH_FINALLY(igraph_eit_destroy, &eit);
2118
/* Check edge attributes */
2119
for (i=0; i<E_LAST; i++) {
2120
if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
2122
igraph_i_attribute_gettype(graph, &etypes[i], IGRAPH_ATTRIBUTE_EDGE,
2128
for (i=0; i<sizeof(enumnames)/sizeof(const char*); i++) {
2129
igraph_attribute_type_t type;
2130
if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
2132
igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_EDGE,
2134
if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
2135
IGRAPH_CHECK(igraph_vector_push_back(&ex_numa, i));
2139
for (i=0; i<sizeof(estrnames)/sizeof(const char*); i++) {
2140
igraph_attribute_type_t type;
2141
if (igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE,
2143
igraph_i_attribute_gettype(graph, &type, IGRAPH_ATTRIBUTE_EDGE,
2145
if (type==IGRAPH_ATTRIBUTE_STRING) {
2146
IGRAPH_CHECK(igraph_vector_push_back(&ex_stra, i));
2151
for (i=0; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit), i++) {
2152
long int edge=IGRAPH_EIT_GET(eit);
2153
igraph_integer_t from, to;
2154
igraph_edge(graph, edge, &from, &to);
2155
fprintf(outstream, "%li %li", (long int) from+1, (long int) to+1);
2158
if (etypes[E_WEIGHT] == IGRAPH_ATTRIBUTE_NUMERIC) {
2159
igraph_i_attribute_get_numeric_edge_attr(graph, enames[E_WEIGHT],
2160
igraph_ess_1(edge), &numv);
2161
fprintf(outstream, " %g", VECTOR(numv)[0]);
2164
/* numeric parameters */
2165
for (j=0; j<igraph_vector_size(&ex_numa); j++) {
2166
int idx=VECTOR(ex_numa)[j];
2167
igraph_i_attribute_get_numeric_edge_attr(graph, enumnames[idx],
2168
igraph_ess_1(edge), &numv);
2169
fprintf(outstream, " %s %g", enumnames2[idx], VECTOR(numv)[0]);
2172
/* string parameters */
2173
for (j=0; j<igraph_vector_size(&ex_stra); j++) {
2174
int idx=VECTOR(ex_stra)[j];
2176
igraph_i_attribute_get_string_edge_attr(graph, estrnames[idx],
2177
igraph_ess_1(edge), &strv);
2178
igraph_strvector_get(&strv, 0, &s);
2179
fprintf(outstream, " %s \"%s\"", estrnames2[idx], s);
2182
/* trailing newline */
2183
fprintf(outstream, "%s", newline);
2186
igraph_eit_destroy(&eit);
2187
igraph_es_destroy(&es);
2188
igraph_vector_destroy(&ex_numa);
2189
igraph_vector_destroy(&ex_stra);
2190
igraph_vector_destroy(&vx_numa);
2191
igraph_vector_destroy(&vx_stra);
2192
igraph_strvector_destroy(&strv);
2193
igraph_vector_destroy(&numv);
2194
IGRAPH_FINALLY_CLEAN(8);
2199
* \function igraph_write_graph_dimacs
2200
* \brief Write a graph in DIMACS format.
2202
* This function writes a graph to an output stream in DIMACS format,
2203
* describing a maximum flow problem.
2204
* See ftp://dimacs.rutgers.edu/pub/netflow/general-info/
2207
* This file format is discussed in the documentation of \ref
2208
* igraph_read_graph_dimacs(), see that for more information.
2210
* \param graph The graph to write to the stream.
2211
* \param outstream The stream.
2212
* \param source Integer, the id of the source vertex for the maximum
2214
* \param target Integer, the id of the target vertex.
2215
* \param capacity Pointer to an initialized vector containing the
2216
* edge capacity values.
2217
* \return Error code.
2219
* Time complexity: O(|E|), the number of edges in the graph.
2221
* \sa igraph_read_graph_dimacs()
2224
int igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream,
2225
long int source, long int target,
2226
const igraph_vector_t *capacity) {
2228
long int no_of_nodes=igraph_vcount(graph);
2229
long int no_of_edges=igraph_ecount(graph);
2234
if (igraph_vector_size(capacity) != no_of_edges) {
2235
IGRAPH_ERROR("invalid capacity vector length", IGRAPH_EINVAL);
2238
IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID),
2240
IGRAPH_FINALLY(igraph_eit_destroy, &it);
2242
ret=fprintf(outstream,
2243
"c created by igraph\np max %li %li\nn %li s\nn %li t\n",
2244
no_of_nodes, no_of_edges, source+1, target+1);
2246
IGRAPH_ERROR("Write error", IGRAPH_EFILE);
2250
while (!IGRAPH_EIT_END(it)) {
2251
igraph_integer_t from, to, cap;
2252
igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
2253
cap=VECTOR(*capacity)[i++];
2254
ret=fprintf(outstream, "a %li %li %g\n",
2255
(long int) from+1, (long int) to+1, cap);
2257
IGRAPH_ERROR("Write error", IGRAPH_EFILE);
2259
IGRAPH_EIT_NEXT(it);
2262
igraph_eit_destroy(&it);
2263
IGRAPH_FINALLY_CLEAN(1);
2267
int igraph_i_gml_convert_to_key(const char *orig, char **key) {
2270
long int i, len=strlen(orig), newlen=0, plen=0;
2271
igraph_bool_t pref=0;
2272
/* do we need a prefix? */
2273
if (len==0 || !isalpha(orig[0])) {
2275
snprintf(strno, sizeof(strno)-1, "igraph");
2276
plen=newlen=strlen(strno);
2278
for (i=0; i<len; i++) {
2279
if (isalnum(orig[i])) { newlen++; }
2281
*key=igraph_Calloc(newlen+1, char);
2283
IGRAPH_ERROR("Writing GML file failed", IGRAPH_ENOMEM);
2285
memcpy(*key, strno, plen*sizeof(char));
2286
for (i=0; i<len; i++) {
2287
if (isalnum(orig[i])) {
2288
(*key)[plen++] = orig[i];
2291
(*key)[newlen]='\0';
2296
#define CHECK(cmd) do { ret=cmd; if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE); } while (0)
2299
* \function igraph_write_graph_gml
2300
* \brief Write the graph to a stream in GML format
2302
* GML is a quite general textual format, see
2303
* http://www.infosun.fim.uni-passau.de/Graphlet/GML/ for details.
2305
* </para><para> The graph, vertex and edges attributes are written to the
2306
* file as well, if they are numeric of string.
2308
* </para><para> As igraph is more forgiving about attribute names, it might
2309
* be neccessary to simplify the them before writing to the GML file.
2310
* This way we'll have a syntactically correct GML file. The following
2311
* simple procedure is performed on each attribute name: first the alphanumeric
2312
* characters are extracted, the others are ignored. Then if the first character
2313
* is not a letter then the attribute name is prefixed with <quote>igraph</quote>.
2314
* Note that this might result identical names for two attributes, igraph
2315
* does not check this.
2317
* </para><para> The <quote>id</quote> vertex attribute is treated specially.
2318
* If the <parameter>id</parameter> argument is not 0 then it should be a numeric
2319
* vector with the vertex ids and the <quote>id</quote> vertex attribute is
2320
* ignored (if there is one). If <parameter>id</parameter> is 0 and there is a
2321
* numeric <quote>id</quote> vertex attribute that is used instead. If ids
2322
* are not specified in either way then the regular igraph vertex ids are used.
2324
* </para><para> Note that whichever way vertex ids are specified, their
2325
* uniqueness is not checked.
2327
* </para><para> If the graph has edge attributes named <quote>source</quote>
2328
* or <quote>target</quote> they're silently ignored. GML uses these attributes
2329
* to specify the edges, so we cannot write them to the file. Rename them
2330
* before calling this function if you want to preserve them.
2331
* \param graph The graph to write to the stream.
2332
* \param outstream The stream to write the file to.
2333
* \param id Either <code>NULL</code> or a numeric vector with the vertex ids.
2334
* See details above.
2335
* \param creator An optional string to write to the stream in the creator line.
2336
* If this is 0 then the current date and time is added.
2337
* \return Error code.
2339
* Time complexity: should be proportional to the number of characters written
2342
* \sa \ref igraph_read_graph_gml() for reading GML files,
2343
* \ref igraph_read_graph_graphml() for a more modern format.
2346
int igraph_write_graph_gml(const igraph_t *graph, FILE *outstream,
2347
const igraph_vector_t *id, const char *creator) {
2349
igraph_strvector_t gnames, vnames, enames;
2350
igraph_vector_t gtypes, vtypes, etypes;
2351
igraph_vector_t numv;
2352
igraph_strvector_t strv;
2354
long int no_of_nodes=igraph_vcount(graph);
2355
long int no_of_edges=igraph_ecount(graph);
2357
igraph_vector_t v_myid;
2358
const igraph_vector_t *myid=id;
2360
time_t curtime=time(0);
2361
char *timestr=ctime(&curtime);
2362
timestr[strlen(timestr)-1]='\0'; /* nicely remove \n */
2364
CHECK(fprintf(outstream,
2365
"Creator \"igraph version %s %s\"\nVersion 1\ngraph\n[\n",
2366
PACKAGE_VERSION, creator ? creator : timestr));
2368
IGRAPH_STRVECTOR_INIT_FINALLY(&gnames, 0);
2369
IGRAPH_STRVECTOR_INIT_FINALLY(&vnames, 0);
2370
IGRAPH_STRVECTOR_INIT_FINALLY(&enames, 0);
2371
IGRAPH_VECTOR_INIT_FINALLY(>ypes, 0);
2372
IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
2373
IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
2374
IGRAPH_CHECK(igraph_i_attribute_get_info(graph,
2379
IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
2380
IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
2382
/* Check whether there is an 'id' node attribute if the supplied is 0 */
2384
igraph_bool_t found=0;
2385
for (i=0; i<igraph_vector_size(&vtypes); i++) {
2387
igraph_strvector_get(&vnames, i, &n);
2388
if (!strcmp(n, "id") && VECTOR(vtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
2393
IGRAPH_VECTOR_INIT_FINALLY(&v_myid, no_of_nodes);
2394
IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, "id",
2402
CHECK(fprintf(outstream, " directed %i\n", igraph_is_directed(graph) ? 1 : 0));
2404
/* Graph attributes first */
2405
for (i=0; i<igraph_vector_size(>ypes); i++) {
2406
char *name, *newname;
2407
igraph_strvector_get(&gnames, i, &name);
2408
IGRAPH_CHECK(igraph_i_gml_convert_to_key(name, &newname));
2409
if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
2410
IGRAPH_CHECK(igraph_i_attribute_get_numeric_graph_attr(graph, name, &numv));
2411
CHECK(fprintf(outstream, " %s %g\n", newname, VECTOR(numv)[0]));
2412
igraph_Free(newname);
2413
} else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
2415
IGRAPH_CHECK(igraph_i_attribute_get_string_graph_attr(graph, name, &strv));
2416
igraph_strvector_get(&strv, 0, &s);
2417
CHECK(fprintf(outstream, " %s \"%s\"\n", newname, s));
2418
igraph_Free(newname);
2420
igraph_Free(newname);
2421
IGRAPH_WARNING("A non-numeric, non-string graph attribute ignored");
2425
/* Now come the vertices */
2426
for (i=0; i<no_of_nodes; i++) {
2428
CHECK(fprintf(outstream, " node\n [\n"));
2430
CHECK(fprintf(outstream, " id %li\n", myid ? (long int)VECTOR(*myid)[i] : i));
2431
/* other attributes */
2432
for (j=0; j<igraph_vector_size(&vtypes); j++) {
2433
int type=VECTOR(vtypes)[j];
2434
char *name, *newname;
2435
igraph_strvector_get(&vnames, j, &name);
2436
if (!strcmp(name, "id")) { continue; }
2437
IGRAPH_CHECK(igraph_i_gml_convert_to_key(name, &newname));
2438
if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
2439
IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, name,
2442
CHECK(fprintf(outstream, " %s %g\n", newname, VECTOR(numv)[0]));
2443
} else if (type==IGRAPH_ATTRIBUTE_STRING) {
2445
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, name,
2448
igraph_strvector_get(&strv, 0, &s);
2449
CHECK(fprintf(outstream, " %s \"%s\"\n", newname, s));
2451
igraph_Free(newname);
2453
CHECK(fprintf(outstream, " ]\n"));
2457
for (i=0; i<no_of_edges; i++) {
2458
long int from=IGRAPH_FROM(graph, i);
2459
long int to=IGRAPH_TO(graph, i);
2461
CHECK(fprintf(outstream, " edge\n [\n"));
2462
/* source and target */
2463
CHECK(fprintf(outstream, " source %li\n",
2464
myid ? (long int)VECTOR(*myid)[from] : from));
2465
CHECK(fprintf(outstream, " target %li\n",
2466
myid ? (long int)VECTOR(*myid)[to] : to));
2468
/* other attributes */
2469
for (j=0; j<igraph_vector_size(&etypes); j++) {
2470
int type=VECTOR(etypes)[j];
2471
char *name, *newname;
2472
igraph_strvector_get(&enames, j, &name);
2473
if (!strcmp(name, "source") || !strcmp(name, "target")) { continue; }
2474
IGRAPH_CHECK(igraph_i_gml_convert_to_key(name, &newname));
2475
if (type==IGRAPH_ATTRIBUTE_NUMERIC) {
2476
IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, name,
2479
CHECK(fprintf(outstream, " %s %g\n", newname, VECTOR(numv)[0]));
2480
} else if (type==IGRAPH_ATTRIBUTE_STRING) {
2482
IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, name,
2485
igraph_strvector_get(&strv, 0, &s);
2486
CHECK(fprintf(outstream, " %s \"%s\"\n", newname, s));
2488
igraph_Free(newname);
2490
CHECK(fprintf(outstream, " ]\n"));
2493
CHECK(fprintf(outstream, "]\n"));
2495
if (&v_myid == myid) {
2496
igraph_vector_destroy(&v_myid);
2497
IGRAPH_FINALLY_CLEAN(1);
2500
igraph_strvector_destroy(&strv);
2501
igraph_vector_destroy(&numv);
2502
igraph_vector_destroy(&etypes);
2503
igraph_vector_destroy(&vtypes);
2504
igraph_vector_destroy(>ypes);
2505
igraph_strvector_destroy(&enames);
2506
igraph_strvector_destroy(&vnames);
2507
igraph_strvector_destroy(&gnames);
2508
IGRAPH_FINALLY_CLEAN(8);
2513
int igraph_i_dot_escape(const char *orig, char **result) {
2514
/* do we have to escape the string at all? */
2515
long int i, j, len=strlen(orig), newlen=0;
2516
igraph_bool_t need_quote=0, is_number=1;
2517
for (i=0; i<len; i++) {
2518
if (isdigit(orig[i])) { newlen++; }
2519
else if (orig[i] == '-' && i==0) { newlen++; }
2520
else if (orig[i] == '.') {
2521
if (is_number) { newlen++; }
2522
else { need_quote=1; newlen++; }
2523
} else if (orig[i] == '_') {
2524
is_number=0; newlen++;
2525
} else if (orig[i] == '\\') {
2526
need_quote=1; is_number=0; newlen+=2; /* will be escaped */
2527
} else if (orig[i] == '"') {
2528
need_quote=1; is_number=0; newlen+=2; /* will be escaped */
2529
} else if (isalpha(orig[i])) {
2530
is_number=0; newlen++;
2532
is_number=0; need_quote=1; newlen++;
2535
if (is_number && orig[len-1] == '.') is_number=0;
2536
if (!is_number && isdigit(orig[0])) need_quote=1;
2538
if (is_number || !need_quote) {
2539
*result=strdup(orig);
2540
if (!*result) IGRAPH_ERROR("Writing DOT file failed", IGRAPH_ENOMEM);
2542
*result=igraph_Calloc(newlen+3, char);
2544
(*result)[newlen+1]='"';
2545
(*result)[newlen+2]='\0';
2546
for (i=0, j=1; i<len; i++) {
2547
if (orig[i] == '\\' || orig[i] == '"') (*result)[j++] = '\\';
2548
(*result)[j++] = orig[i];
2556
* \function igraph_write_graph_dot
2557
* \brief Write the graph to a stream in DOT format
2559
* DOT is the format used by the widely known GraphViz software, see
2560
* http://www.graphviz.org for details. The grammar of the DOT format
2561
* can be found here: http://www.graphviz.org/doc/info/lang.html
2563
* </para><para>This is only a preliminary implementation, only the vertices
2564
* and the edges are written but not the attributes or any visualization
2567
* \param graph The graph to write to the stream.
2568
* \param outstream The stream to write the file to.
2570
* Time complexity: should be proportional to the number of characters written
2573
* \sa \ref igraph_write_graph_graphml() for a more modern format.
2575
int igraph_write_graph_dot(const igraph_t *graph, FILE* outstream) {
2578
long int no_of_nodes=igraph_vcount(graph);
2579
long int no_of_edges=igraph_ecount(graph);
2581
igraph_strvector_t gnames, vnames, enames;
2582
igraph_vector_t gtypes, vtypes, etypes;
2583
igraph_vector_t numv;
2584
igraph_strvector_t strv;
2586
IGRAPH_STRVECTOR_INIT_FINALLY(&gnames, 0);
2587
IGRAPH_STRVECTOR_INIT_FINALLY(&vnames, 0);
2588
IGRAPH_STRVECTOR_INIT_FINALLY(&enames, 0);
2589
IGRAPH_VECTOR_INIT_FINALLY(>ypes, 0);
2590
IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
2591
IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
2592
IGRAPH_CHECK(igraph_i_attribute_get_info(graph,
2597
IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
2598
IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
2600
CHECK(fprintf(outstream, "/* Created by igraph %s */\n",
2603
if (igraph_is_directed(graph)) {
2604
CHECK(fprintf(outstream, "digraph {\n"));
2605
strcpy(edgeop, "->");
2607
CHECK(fprintf(outstream, "graph {\n"));
2608
strcpy(edgeop, "--");
2611
/* Write the graph attributes */
2612
if (igraph_vector_size(>ypes)>0) {
2613
CHECK(fprintf(outstream, " graph [\n"));
2614
for (i=0; i<igraph_vector_size(>ypes); i++) {
2615
char *name, *newname;
2616
igraph_strvector_get(&gnames, i, &name);
2617
IGRAPH_CHECK(igraph_i_dot_escape(name, &newname));
2618
if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
2619
IGRAPH_CHECK(igraph_i_attribute_get_numeric_graph_attr(graph, name, &numv));
2620
if (VECTOR(numv)[0] == (long)VECTOR(numv)[0])
2621
CHECK(fprintf(outstream, " %s=%ld\n", newname, (long)VECTOR(numv)[0]));
2623
CHECK(fprintf(outstream, " %s=%f\n", newname, VECTOR(numv)[0]));
2624
igraph_Free(newname);
2625
} else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
2627
IGRAPH_CHECK(igraph_i_attribute_get_string_graph_attr(graph, name, &strv));
2628
igraph_strvector_get(&strv, 0, &s);
2629
IGRAPH_CHECK(igraph_i_dot_escape(s, &news));
2630
CHECK(fprintf(outstream, " %s=%s\n", newname, news));
2631
igraph_Free(newname);
2634
IGRAPH_WARNING("A non-numeric, non-string graph attribute ignored");
2637
CHECK(fprintf(outstream, " ];\n"));
2640
/* Write the vertices */
2641
if (igraph_vector_size(&vtypes) > 0) {
2642
for (i=0; i<no_of_nodes; i++) {
2643
CHECK(fprintf(outstream, " %ld [\n", i));
2644
for (j=0; j<igraph_vector_size(&vtypes); j++) {
2645
char *name, *newname;
2646
igraph_strvector_get(&vnames, j, &name);
2647
IGRAPH_CHECK(igraph_i_dot_escape(name, &newname));
2648
if (VECTOR(vtypes)[j] == IGRAPH_ATTRIBUTE_NUMERIC) {
2649
IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(graph, name, igraph_vss_1(i), &numv));
2650
if (VECTOR(numv)[0] == (long)VECTOR(numv)[0])
2651
CHECK(fprintf(outstream, " %s=%ld\n", newname, (long)VECTOR(numv)[0]));
2653
CHECK(fprintf(outstream, " %s=%f\n", newname, VECTOR(numv)[0]));
2654
igraph_Free(newname);
2655
} else if (VECTOR(vtypes)[j] == IGRAPH_ATTRIBUTE_STRING) {
2657
IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(graph, name, igraph_vss_1(i), &strv));
2658
igraph_strvector_get(&strv, 0, &s);
2659
IGRAPH_CHECK(igraph_i_dot_escape(s, &news));
2660
CHECK(fprintf(outstream, " %s=%s\n", newname, news));
2661
igraph_Free(newname);
2664
IGRAPH_WARNING("A non-numeric, non-string graph attribute ignored");
2667
CHECK(fprintf(outstream, " ];\n"));
2670
for (i=0; i<no_of_nodes; i++)
2671
CHECK(fprintf(outstream, " %ld;\n", i));
2673
CHECK(fprintf(outstream, "\n"));
2675
/* Write the edges */
2676
if (igraph_vector_size(&etypes) > 0) {
2677
for (i=0; i<no_of_edges; i++) {
2678
long int from=IGRAPH_FROM(graph, i);
2679
long int to=IGRAPH_TO(graph, i);
2680
CHECK(fprintf(outstream, " %ld %s %ld [\n", from, edgeop, to));
2681
for (j=0; j<igraph_vector_size(&etypes); j++) {
2682
char *name, *newname;
2683
igraph_strvector_get(&enames, j, &name);
2684
IGRAPH_CHECK(igraph_i_dot_escape(name, &newname));
2685
if (VECTOR(etypes)[j] == IGRAPH_ATTRIBUTE_NUMERIC) {
2686
IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(graph, name, igraph_ess_1(i), &numv));
2687
if (VECTOR(numv)[0] == (long)VECTOR(numv)[0])
2688
CHECK(fprintf(outstream, " %s=%ld\n", newname, (long)VECTOR(numv)[0]));
2690
CHECK(fprintf(outstream, " %s=%f\n", newname, VECTOR(numv)[0]));
2691
igraph_Free(newname);
2692
} else if (VECTOR(etypes)[j] == IGRAPH_ATTRIBUTE_STRING) {
2694
IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(graph, name, igraph_ess_1(i), &strv));
2695
igraph_strvector_get(&strv, 0, &s);
2696
IGRAPH_CHECK(igraph_i_dot_escape(s, &news));
2697
CHECK(fprintf(outstream, " %s=%s\n", newname, news));
2698
igraph_Free(newname);
2701
IGRAPH_WARNING("A non-numeric, non-string graph attribute ignored");
2704
CHECK(fprintf(outstream, " ];\n"));
2707
for (i=0; i<no_of_edges; i++) {
2708
long int from=IGRAPH_FROM(graph, i);
2709
long int to=IGRAPH_TO(graph, i);
2710
CHECK(fprintf(outstream, " %ld %s %ld;\n", from, edgeop, to));
2713
CHECK(fprintf(outstream, "}\n"));
2715
igraph_strvector_destroy(&strv);
2716
igraph_vector_destroy(&numv);
2717
igraph_vector_destroy(&etypes);
2718
igraph_vector_destroy(&vtypes);
2719
igraph_vector_destroy(>ypes);
2720
igraph_strvector_destroy(&enames);
2721
igraph_strvector_destroy(&vnames);
2722
igraph_strvector_destroy(&gnames);
2723
IGRAPH_FINALLY_CLEAN(8);