1 /* -*- mode: C -*- */
2 /*
3 IGraph library.
4 Copyright (C) 2005-2020 The igraph development team
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
20
21 */
22
23 #include "igraph_foreign.h"
24
25 #include "igraph_attributes.h"
26 #include "igraph_interface.h"
27 #include "igraph_iterators.h"
28
29 #include "graph/attributes.h"
30
31 #include <string.h>
32
33 #define CHECK(cmd) do { ret=cmd; if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE); } while (0)
34
35 /**
36 * \function igraph_write_graph_leda
37 * \brief Write a graph in LEDA native graph format.
38 *
39 * This function writes a graph to an output stream in LEDA format.
40 * See http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
41 *
42 * </para><para>
43 * The support for the LEDA format is very basic at the moment; igraph
44 * writes only the LEDA graph section which supports one selected vertex
45 * and edge attribute and no layout information or visual attributes.
46 *
47 * \param graph The graph to write to the stream.
48 * \param outstream The stream.
49 * \param vertex_attr_name The name of the vertex attribute whose values
50 * are to be stored in the output or \c NULL if no
51 * vertex attribute has to be stored.
52 * \param edge_attr_name The name of the edge attribute whose values
53 * are to be stored in the output or \c NULL if no
54 * edge attribute has to be stored.
55 * \return Error code.
56 *
57 * Time complexity: O(|V|+|E|), the number of vertices and edges in the
58 * graph.
59 *
60 * \example examples/simple/igraph_write_graph_leda.c
61 */
62
igraph_write_graph_leda(const igraph_t * graph,FILE * outstream,const char * vertex_attr_name,const char * edge_attr_name)63 int igraph_write_graph_leda(const igraph_t *graph, FILE *outstream,
64 const char* vertex_attr_name,
65 const char* edge_attr_name) {
66 long int no_of_nodes = igraph_vcount(graph);
67 long int no_of_edges = igraph_ecount(graph);
68 igraph_eit_t it;
69 long int i = 0;
70 int ret;
71 igraph_attribute_type_t vertex_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
72 igraph_attribute_type_t edge_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
73 igraph_integer_t from, to, rev;
74
75 IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_FROM),
76 &it));
77 IGRAPH_FINALLY(igraph_eit_destroy, &it);
78
79 /* Check if we have the vertex attribute */
80 if (vertex_attr_name &&
81 !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_VERTEX, vertex_attr_name)) {
82 vertex_attr_name = 0;
83 IGRAPH_WARNING("specified vertex attribute does not exist");
84 }
85 if (vertex_attr_name) {
86 IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &vertex_attr_type,
87 IGRAPH_ATTRIBUTE_VERTEX, vertex_attr_name));
88 if (vertex_attr_type != IGRAPH_ATTRIBUTE_NUMERIC &&
89 vertex_attr_type != IGRAPH_ATTRIBUTE_STRING) {
90 vertex_attr_name = 0; vertex_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
91 IGRAPH_WARNING("specified vertex attribute must be numeric or string");
92 }
93 }
94
95 /* Check if we have the edge attribute */
96 if (edge_attr_name &&
97 !igraph_i_attribute_has_attr(graph, IGRAPH_ATTRIBUTE_EDGE, edge_attr_name)) {
98 edge_attr_name = 0;
99 IGRAPH_WARNING("specified edge attribute does not exist");
100 }
101 if (edge_attr_name) {
102 IGRAPH_CHECK(igraph_i_attribute_gettype(graph, &edge_attr_type,
103 IGRAPH_ATTRIBUTE_EDGE, edge_attr_name));
104 if (edge_attr_type != IGRAPH_ATTRIBUTE_NUMERIC &&
105 edge_attr_type != IGRAPH_ATTRIBUTE_STRING) {
106 edge_attr_name = 0; edge_attr_type = IGRAPH_ATTRIBUTE_DEFAULT;
107 IGRAPH_WARNING("specified edge attribute must be numeric or string");
108 }
109 }
110
111 /* Start writing header */
112 CHECK(fprintf(outstream, "LEDA.GRAPH\n"));
113
114 switch (vertex_attr_type) {
115 case IGRAPH_ATTRIBUTE_NUMERIC:
116 CHECK(fprintf(outstream, "float\n"));
117 break;
118 case IGRAPH_ATTRIBUTE_STRING:
119 CHECK(fprintf(outstream, "string\n"));
120 break;
121 default:
122 CHECK(fprintf(outstream, "void\n"));
123 }
124
125 switch (edge_attr_type) {
126 case IGRAPH_ATTRIBUTE_NUMERIC:
127 CHECK(fprintf(outstream, "float\n"));
128 break;
129 case IGRAPH_ATTRIBUTE_STRING:
130 CHECK(fprintf(outstream, "string\n"));
131 break;
132 default:
133 CHECK(fprintf(outstream, "void\n"));
134 }
135
136 CHECK(fprintf(outstream, "%d\n", (igraph_is_directed(graph) ? -1 : -2)));
137
138 /* Start writing vertices */
139 CHECK(fprintf(outstream, "# Vertices\n"));
140 CHECK(fprintf(outstream, "%ld\n", no_of_nodes));
141
142 if (vertex_attr_type == IGRAPH_ATTRIBUTE_NUMERIC) {
143 /* Vertices with numeric attributes */
144 igraph_vector_t values;
145
146 IGRAPH_VECTOR_INIT_FINALLY(&values, no_of_nodes);
147 IGRAPH_CHECK(igraph_i_attribute_get_numeric_vertex_attr(
148 graph, vertex_attr_name, igraph_vss_all(), &values));
149
150 for (i = 0; i < no_of_nodes; i++) {
151 CHECK(fprintf(outstream, "|{"));
152 CHECK(igraph_real_fprintf_precise(outstream, VECTOR(values)[i]));
153 CHECK(fprintf(outstream, "}|\n"));
154 }
155
156 igraph_vector_destroy(&values);
157 IGRAPH_FINALLY_CLEAN(1);
158 } else if (vertex_attr_type == IGRAPH_ATTRIBUTE_STRING) {
159 /* Vertices with string attributes */
160 igraph_strvector_t values;
161
162 IGRAPH_CHECK(igraph_strvector_init(&values, no_of_nodes));
163 IGRAPH_FINALLY(igraph_strvector_destroy, &values);
164
165 IGRAPH_CHECK(igraph_i_attribute_get_string_vertex_attr(
166 graph, vertex_attr_name, igraph_vss_all(), &values));
167
168 for (i = 0; i < no_of_nodes; i++) {
169 const char* str = STR(values, i);
170 if (strchr(str, '\n') != 0) {
171 IGRAPH_ERROR("edge attribute values cannot contain newline characters",
172 IGRAPH_EINVAL);
173 }
174 CHECK(fprintf(outstream, "|{%s}|\n", str));
175 }
176
177 igraph_strvector_destroy(&values);
178 IGRAPH_FINALLY_CLEAN(1);
179 } else {
180 /* Vertices with no attributes */
181 for (i = 0; i < no_of_nodes; i++) {
182 CHECK(fprintf(outstream, "|{}|\n"));
183 }
184 }
185
186 CHECK(fprintf(outstream, "# Edges\n"));
187 CHECK(fprintf(outstream, "%ld\n", no_of_edges));
188
189 if (edge_attr_type == IGRAPH_ATTRIBUTE_NUMERIC) {
190 /* Edges with numeric attributes */
191 igraph_vector_t values;
192 IGRAPH_VECTOR_INIT_FINALLY(&values, no_of_nodes);
193 IGRAPH_CHECK(igraph_i_attribute_get_numeric_edge_attr(
194 graph, edge_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values));
195 while (!IGRAPH_EIT_END(it)) {
196 long int eid = IGRAPH_EIT_GET(it);
197 igraph_edge(graph, (igraph_integer_t) eid, &from, &to);
198 igraph_get_eid(graph, &rev, to, from, 1, 0);
199 if (rev == IGRAPH_EIT_GET(it)) {
200 rev = -1;
201 }
202 CHECK(fprintf(outstream, "%ld %ld %ld |{",
203 (long int) from + 1, (long int) to + 1,
204 (long int) rev + 1));
205 CHECK(igraph_real_fprintf_precise(outstream, VECTOR(values)[eid]));
206 CHECK(fprintf(outstream, "}|\n"));
207 IGRAPH_EIT_NEXT(it);
208 }
209 igraph_vector_destroy(&values);
210 IGRAPH_FINALLY_CLEAN(1);
211 } else if (edge_attr_type == IGRAPH_ATTRIBUTE_STRING) {
212 /* Edges with string attributes */
213 igraph_strvector_t values;
214 IGRAPH_CHECK(igraph_strvector_init(&values, no_of_nodes));
215 IGRAPH_FINALLY(igraph_strvector_destroy, &values);
216 IGRAPH_CHECK(igraph_i_attribute_get_string_edge_attr(
217 graph, edge_attr_name, igraph_ess_all(IGRAPH_EDGEORDER_ID), &values));
218 while (!IGRAPH_EIT_END(it)) {
219 long int eid = IGRAPH_EIT_GET(it);
220 const char* str = STR(values, eid);
221 igraph_edge(graph, (igraph_integer_t) eid, &from, &to);
222 igraph_get_eid(graph, &rev, to, from, 1, 0);
223 if (rev == IGRAPH_EIT_GET(it)) {
224 rev = -1;
225 }
226 if (strchr(str, '\n') != 0) {
227 IGRAPH_ERROR("edge attribute values cannot contain newline characters",
228 IGRAPH_EINVAL);
229 }
230 CHECK(fprintf(outstream, "%ld %ld %ld |{%s}|\n",
231 (long int) from + 1, (long int) to + 1,
232 (long int) rev + 1, str));
233 IGRAPH_EIT_NEXT(it);
234 }
235 igraph_strvector_destroy(&values);
236 IGRAPH_FINALLY_CLEAN(1);
237 } else {
238 /* Edges with no attributes */
239 while (!IGRAPH_EIT_END(it)) {
240 igraph_edge(graph, IGRAPH_EIT_GET(it), &from, &to);
241 igraph_get_eid(graph, &rev, to, from, 1, 0);
242 if (rev == IGRAPH_EIT_GET(it)) {
243 rev = -1;
244 }
245 CHECK(fprintf(outstream, "%ld %ld %ld |{}|\n",
246 (long int) from + 1, (long int) to + 1,
247 (long int) rev + 1));
248 IGRAPH_EIT_NEXT(it);
249 }
250 }
251
252 igraph_eit_destroy(&it);
253 IGRAPH_FINALLY_CLEAN(1);
254
255 return 0;
256 }
257
258 #undef CHECK
259