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