1 /* -*- mode: C -*-  */
2 /* vim:set ts=4 sw=4 sts=4 et: */
3 /*
4    IGraph library.
5    Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>
6    334 Harvard street, Cambridge, MA 02139 USA
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301 USA
22 
23 */
24 
25 #include "igraph_paths.h"
26 #include "igraph_datatype.h"
27 #include "igraph_dqueue.h"
28 #include "igraph_iterators.h"
29 #include "igraph_interrupt_internal.h"
30 #include "igraph_vector.h"
31 #include "igraph_interface.h"
32 #include "igraph_adjlist.h"
33 
igraph_i_eccentricity(const igraph_t * graph,igraph_vector_t * res,igraph_vs_t vids,igraph_neimode_t mode,const igraph_adjlist_t * adjlist)34 static int igraph_i_eccentricity(const igraph_t *graph,
35                                  igraph_vector_t *res,
36                                  igraph_vs_t vids,
37                                  igraph_neimode_t mode,
38                                  const igraph_adjlist_t *adjlist) {
39 
40     int no_of_nodes = igraph_vcount(graph);
41     igraph_dqueue_long_t q;
42     igraph_vit_t vit;
43     igraph_vector_int_t counted;
44     int i, mark = 1;
45     igraph_vector_t vneis;
46     igraph_vector_int_t *neis;
47 
48     IGRAPH_CHECK(igraph_dqueue_long_init(&q, 100));
49     IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
50 
51     IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
52     IGRAPH_FINALLY(igraph_vit_destroy, &vit);
53 
54     IGRAPH_CHECK(igraph_vector_int_init(&counted, no_of_nodes));
55     IGRAPH_FINALLY(igraph_vector_int_destroy, &counted);
56 
57     if (!adjlist) {
58         IGRAPH_VECTOR_INIT_FINALLY(&vneis, 0);
59     }
60 
61     IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
62     igraph_vector_fill(res, -1);
63 
64     for (i = 0, IGRAPH_VIT_RESET(vit);
65          !IGRAPH_VIT_END(vit);
66          IGRAPH_VIT_NEXT(vit), mark++, i++) {
67 
68         long int source;
69         source = IGRAPH_VIT_GET(vit);
70         IGRAPH_CHECK(igraph_dqueue_long_push(&q, source));
71         IGRAPH_CHECK(igraph_dqueue_long_push(&q, 0));
72         VECTOR(counted)[source] = mark;
73 
74         IGRAPH_ALLOW_INTERRUPTION();
75 
76         while (!igraph_dqueue_long_empty(&q)) {
77             long int act = igraph_dqueue_long_pop(&q);
78             long int dist = igraph_dqueue_long_pop(&q);
79             int j, n;
80 
81             if (dist > VECTOR(*res)[i]) {
82                 VECTOR(*res)[i] = dist;
83             }
84 
85             if (adjlist) {
86                 neis = igraph_adjlist_get(adjlist, act);
87                 n = (int) igraph_vector_int_size(neis);
88                 for (j = 0; j < n; j++) {
89                     int nei = (int) VECTOR(*neis)[j];
90                     if (VECTOR(counted)[nei] != mark) {
91                         VECTOR(counted)[nei] = mark;
92                         IGRAPH_CHECK(igraph_dqueue_long_push(&q, nei));
93                         IGRAPH_CHECK(igraph_dqueue_long_push(&q, dist + 1));
94                     }
95                 }
96             } else {
97                 IGRAPH_CHECK(igraph_neighbors(graph, &vneis,
98                                               (igraph_integer_t) act, mode));
99                 n = (int) igraph_vector_size(&vneis);
100                 for (j = 0; j < n; j++) {
101                     int nei = (int) VECTOR(vneis)[j];
102                     if (VECTOR(counted)[nei] != mark) {
103                         VECTOR(counted)[nei] = mark;
104                         IGRAPH_CHECK(igraph_dqueue_long_push(&q, nei));
105                         IGRAPH_CHECK(igraph_dqueue_long_push(&q, dist + 1));
106                     }
107                 }
108             }
109         } /* while !igraph_dqueue_long_empty(dqueue) */
110 
111     } /* for IGRAPH_VIT_NEXT(vit) */
112 
113     if (!adjlist) {
114         igraph_vector_destroy(&vneis);
115         IGRAPH_FINALLY_CLEAN(1);
116     }
117     igraph_vector_int_destroy(&counted);
118     igraph_vit_destroy(&vit);
119     igraph_dqueue_long_destroy(&q);
120     IGRAPH_FINALLY_CLEAN(3);
121 
122     return 0;
123 }
124 
125 /**
126  * \function igraph_eccentricity
127  * Eccentricity of some vertices
128  *
129  * The eccentricity of a vertex is calculated by measuring the shortest
130  * distance from (or to) the vertex, to (or from) all vertices in the
131  * graph, and taking the maximum.
132  *
133  * </para><para>
134  * This implementation ignores vertex pairs that are in different
135  * components. Isolated vertices have eccentricity zero.
136  *
137  * \param graph The input graph, it can be directed or undirected.
138  * \param res Pointer to an initialized vector, the result is stored
139  *    here.
140  * \param vids The vertices for which the eccentricity is calculated.
141  * \param mode What kind of paths to consider for the calculation:
142  *    \c IGRAPH_OUT, paths that follow edge directions;
143  *    \c IGRAPH_IN, paths that follow the opposite directions; and
144  *    \c IGRAPH_ALL, paths that ignore edge directions. This argument
145  *    is ignored for undirected graphs.
146  * \return Error code.
147  *
148  * Time complexity: O(v*(|V|+|E|)), where |V| is the number of
149  * vertices, |E| is the number of edges and v is the number of
150  * vertices for which eccentricity is calculated.
151  *
152  * \sa \ref igraph_radius().
153  *
154  * \example examples/simple/igraph_eccentricity.c
155  */
156 
igraph_eccentricity(const igraph_t * graph,igraph_vector_t * res,igraph_vs_t vids,igraph_neimode_t mode)157 int igraph_eccentricity(const igraph_t *graph,
158                         igraph_vector_t *res,
159                         igraph_vs_t vids,
160                         igraph_neimode_t mode) {
161 
162     return igraph_i_eccentricity(graph, res, vids, mode, /*adjlist=*/ 0);
163 }
164 
165 /**
166  * \function igraph_radius
167  * Radius of a graph
168  *
169  * The radius of a graph is the defined as the minimum eccentricity of
170  * its vertices, see \ref igraph_eccentricity().
171  *
172  * \param graph The input graph, it can be directed or undirected.
173  * \param radius Pointer to a real variable, the result is stored
174  *   here.
175  * \param mode What kind of paths to consider for the calculation:
176  *    \c IGRAPH_OUT, paths that follow edge directions;
177  *    \c IGRAPH_IN, paths that follow the opposite directions; and
178  *    \c IGRAPH_ALL, paths that ignore edge directions. This argument
179  *    is ignored for undirected graphs.
180  * \return Error code.
181  *
182  * Time complexity: O(|V|(|V|+|E|)), where |V| is the number of
183  * vertices and |E| is the number of edges.
184  *
185  * \sa \ref igraph_eccentricity().
186  *
187  * \example examples/simple/igraph_radius.c
188  */
189 
igraph_radius(const igraph_t * graph,igraph_real_t * radius,igraph_neimode_t mode)190 int igraph_radius(const igraph_t *graph, igraph_real_t *radius,
191                   igraph_neimode_t mode) {
192 
193     int no_of_nodes = igraph_vcount(graph);
194 
195     if (no_of_nodes == 0) {
196         *radius = IGRAPH_NAN;
197     } else {
198         igraph_adjlist_t adjlist;
199         igraph_vector_t ecc;
200         IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, mode));
201         IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
202         IGRAPH_VECTOR_INIT_FINALLY(&ecc, igraph_vcount(graph));
203         IGRAPH_CHECK(igraph_i_eccentricity(graph, &ecc, igraph_vss_all(),
204                                            mode, &adjlist));
205         *radius = igraph_vector_min(&ecc);
206         igraph_vector_destroy(&ecc);
207         igraph_adjlist_destroy(&adjlist);
208         IGRAPH_FINALLY_CLEAN(2);
209     }
210 
211     return 0;
212 }
213