1 /* -*- mode: C -*- */
2 /* vim:set ts=4 sw=4 sts=4 et: */
3 /*
4 IGraph library.
5 Copyright (C) 2005-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_structural.h"
26 #include "igraph_transitivity.h"
27 #include "igraph_paths.h"
28 #include "igraph_math.h"
29 #include "igraph_memory.h"
30 #include "igraph_random.h"
31 #include "igraph_adjlist.h"
32 #include "igraph_interface.h"
33 #include "igraph_progress.h"
34 #include "igraph_interrupt_internal.h"
35 #include "igraph_centrality.h"
36 #include "igraph_components.h"
37 #include "igraph_constructors.h"
38 #include "igraph_conversion.h"
39 #include "igraph_types_internal.h"
40 #include "igraph_dqueue.h"
41 #include "igraph_attributes.h"
42 #include "igraph_neighborhood.h"
43 #include "igraph_topology.h"
44 #include "igraph_qsort.h"
45 #include "config.h"
46 #include "structural_properties_internal.h"
47
48 #include <assert.h>
49 #include <string.h>
50 #include <limits.h>
51
52 /**
53 * \section about_structural
54 *
55 * <para>These functions usually calculate some structural property
56 * of a graph, like its diameter, the degree of the nodes, etc.</para>
57 */
58
59 /**
60 * \ingroup structural
61 * \function igraph_diameter
62 * \brief Calculates the diameter of a graph (longest geodesic).
63 *
64 * \param graph The graph object.
65 * \param pres Pointer to an integer, if not \c NULL then it will contain
66 * the diameter (the actual distance).
67 * \param pfrom Pointer to an integer, if not \c NULL it will be set to the
68 * source vertex of the diameter path.
69 * \param pto Pointer to an integer, if not \c NULL it will be set to the
70 * target vertex of the diameter path.
71 * \param path Pointer to an initialized vector. If not \c NULL the actual
72 * longest geodesic path will be stored here. The vector will be
73 * resized as needed.
74 * \param directed Boolean, whether to consider directed
75 * paths. Ignored for undirected graphs.
76 * \param unconn What to do if the graph is not connected. If
77 * \c TRUE the longest geodesic within a component
78 * will be returned, otherwise the number of vertices is
79 * returned. (The rationale behind the latter is that this is
80 * always longer than the longest possible diameter in a
81 * graph.)
82 * \return Error code:
83 * \c IGRAPH_ENOMEM, not enough memory for
84 * temporary data.
85 *
86 * Time complexity: O(|V||E|), the
87 * number of vertices times the number of edges.
88 *
89 * \example examples/simple/igraph_diameter.c
90 */
91
igraph_diameter(const igraph_t * graph,igraph_integer_t * pres,igraph_integer_t * pfrom,igraph_integer_t * pto,igraph_vector_t * path,igraph_bool_t directed,igraph_bool_t unconn)92 int igraph_diameter(const igraph_t *graph, igraph_integer_t *pres,
93 igraph_integer_t *pfrom, igraph_integer_t *pto,
94 igraph_vector_t *path,
95 igraph_bool_t directed, igraph_bool_t unconn) {
96
97 long int no_of_nodes = igraph_vcount(graph);
98 long int i, j, n;
99 long int *already_added;
100 long int nodes_reached;
101 long int from = 0, to = 0;
102 long int res = 0;
103
104 igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
105 igraph_vector_int_t *neis;
106 igraph_neimode_t dirmode;
107 igraph_adjlist_t allneis;
108
109 if (directed) {
110 dirmode = IGRAPH_OUT;
111 } else {
112 dirmode = IGRAPH_ALL;
113 }
114 already_added = igraph_Calloc(no_of_nodes, long int);
115 if (already_added == 0) {
116 IGRAPH_ERROR("diameter failed", IGRAPH_ENOMEM);
117 }
118 IGRAPH_FINALLY(igraph_free, already_added);
119 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
120
121 IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, dirmode));
122 IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
123
124 for (i = 0; i < no_of_nodes; i++) {
125 nodes_reached = 1;
126 IGRAPH_CHECK(igraph_dqueue_push(&q, i));
127 IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
128 already_added[i] = i + 1;
129
130 IGRAPH_PROGRESS("Diameter: ", 100.0 * i / no_of_nodes, NULL);
131
132 IGRAPH_ALLOW_INTERRUPTION();
133
134 while (!igraph_dqueue_empty(&q)) {
135 long int actnode = (long int) igraph_dqueue_pop(&q);
136 long int actdist = (long int) igraph_dqueue_pop(&q);
137 if (actdist > res) {
138 res = actdist;
139 from = i;
140 to = actnode;
141 }
142
143 neis = igraph_adjlist_get(&allneis, actnode);
144 n = igraph_vector_int_size(neis);
145 for (j = 0; j < n; j++) {
146 long int neighbor = (long int) VECTOR(*neis)[j];
147 if (already_added[neighbor] == i + 1) {
148 continue;
149 }
150 already_added[neighbor] = i + 1;
151 nodes_reached++;
152 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
153 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
154 }
155 } /* while !igraph_dqueue_empty */
156
157 /* not connected, return largest possible */
158 if (nodes_reached != no_of_nodes && !unconn) {
159 res = no_of_nodes;
160 from = -1;
161 to = -1;
162 break;
163 }
164 } /* for i<no_of_nodes */
165
166 IGRAPH_PROGRESS("Diameter: ", 100.0, NULL);
167
168 /* return the requested info */
169 if (pres != 0) {
170 *pres = (igraph_integer_t) res;
171 }
172 if (pfrom != 0) {
173 *pfrom = (igraph_integer_t) from;
174 }
175 if (pto != 0) {
176 *pto = (igraph_integer_t) to;
177 }
178 if (path != 0) {
179 if (res == no_of_nodes) {
180 igraph_vector_clear(path);
181 } else {
182 igraph_vector_ptr_t tmpptr;
183 igraph_vector_ptr_init(&tmpptr, 1);
184 IGRAPH_FINALLY(igraph_vector_ptr_destroy, &tmpptr);
185 VECTOR(tmpptr)[0] = path;
186 IGRAPH_CHECK(igraph_get_shortest_paths(graph, &tmpptr, 0,
187 (igraph_integer_t) from,
188 igraph_vss_1((igraph_integer_t)to),
189 dirmode, 0, 0));
190 igraph_vector_ptr_destroy(&tmpptr);
191 IGRAPH_FINALLY_CLEAN(1);
192 }
193 }
194
195 /* clean */
196 igraph_Free(already_added);
197 igraph_dqueue_destroy(&q);
198 igraph_adjlist_destroy(&allneis);
199 IGRAPH_FINALLY_CLEAN(3);
200
201 return 0;
202 }
203
204 /**
205 * \ingroup structural
206 * \function igraph_average_path_length
207 * \brief Calculates the average shortest path length between all vertex pairs.
208 *
209 * \param graph The graph object.
210 * \param res Pointer to a real number, this will contain the result.
211 * \param directed Boolean, whether to consider directed
212 * paths. Ignored for undirected graphs.
213 * \param unconn What to do if the graph is not connected. If
214 * \c TRUE, only those vertex pairs will be included in the calculation
215 * between which there is a path. If \c FALSE, the number of vertices is
216 * used as the distance between vertices unreachable from each other.
217 * The rationale behind this is that this is always longer than the longest
218 * possible geodesic in a graph.
219 * \return Error code:
220 * \c IGRAPH_ENOMEM, not enough memory for
221 * data structures
222 *
223 * Time complexity: O(|V||E|), the
224 * number of vertices times the number of edges.
225 *
226 * \example examples/simple/igraph_average_path_length.c
227 */
228
igraph_average_path_length(const igraph_t * graph,igraph_real_t * res,igraph_bool_t directed,igraph_bool_t unconn)229 int igraph_average_path_length(const igraph_t *graph, igraph_real_t *res,
230 igraph_bool_t directed, igraph_bool_t unconn) {
231 long int no_of_nodes = igraph_vcount(graph);
232 long int i, j, n;
233 long int *already_added;
234 long int nodes_reached = 0;
235 igraph_real_t normfact = 0.0;
236
237 igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
238 igraph_vector_int_t *neis;
239 igraph_neimode_t dirmode;
240 igraph_adjlist_t allneis;
241
242 *res = 0;
243 if (directed) {
244 dirmode = IGRAPH_OUT;
245 } else {
246 dirmode = IGRAPH_ALL;
247 }
248 already_added = igraph_Calloc(no_of_nodes, long int);
249 if (already_added == 0) {
250 IGRAPH_ERROR("average path length failed", IGRAPH_ENOMEM);
251 }
252 IGRAPH_FINALLY(free, already_added); /* TODO: hack */
253 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
254
255 igraph_adjlist_init(graph, &allneis, dirmode);
256 IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
257
258 for (i = 0; i < no_of_nodes; i++) {
259 nodes_reached = 0;
260 IGRAPH_CHECK(igraph_dqueue_push(&q, i));
261 IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
262 already_added[i] = i + 1;
263
264 IGRAPH_ALLOW_INTERRUPTION();
265
266 while (!igraph_dqueue_empty(&q)) {
267 long int actnode = (long int) igraph_dqueue_pop(&q);
268 long int actdist = (long int) igraph_dqueue_pop(&q);
269
270 neis = igraph_adjlist_get(&allneis, actnode);
271 n = igraph_vector_int_size(neis);
272 for (j = 0; j < n; j++) {
273 long int neighbor = (long int) VECTOR(*neis)[j];
274 if (already_added[neighbor] == i + 1) {
275 continue;
276 }
277 already_added[neighbor] = i + 1;
278 nodes_reached++;
279 *res += actdist + 1;
280 normfact += 1;
281 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
282 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
283 }
284 } /* while !igraph_dqueue_empty */
285
286 /* not connected, return largest possible */
287 if (!unconn) {
288 *res += (no_of_nodes * (no_of_nodes - 1 - nodes_reached));
289 normfact += no_of_nodes - 1 - nodes_reached;
290 }
291 } /* for i<no_of_nodes */
292
293
294 if (normfact > 0) {
295 *res /= normfact;
296 } else {
297 *res = IGRAPH_NAN;
298 }
299
300 /* clean */
301 igraph_Free(already_added);
302 igraph_dqueue_destroy(&q);
303 igraph_adjlist_destroy(&allneis);
304 IGRAPH_FINALLY_CLEAN(3);
305
306 return 0;
307 }
308
309 /**
310 * \function igraph_path_length_hist
311 * Create a histogram of all shortest path lengths.
312 *
313 * This function calculates a histogram, by calculating the
314 * shortest path length between each pair of vertices. For directed
315 * graphs both directions might be considered and then every pair of vertices
316 * appears twice in the histogram.
317 * \param graph The input graph.
318 * \param res Pointer to an initialized vector, the result is stored
319 * here. The first (i.e. zeroth) element contains the number of
320 * shortest paths of length 1, etc. The supplied vector is resized
321 * as needed.
322 * \param unconnected Pointer to a real number, the number of
323 * pairs for which the second vertex is not reachable from the
324 * first is stored here.
325 * \param directed Whether to consider directed paths in a directed
326 * graph (if not zero). This argument is ignored for undirected
327 * graphs.
328 * \return Error code.
329 *
330 * Time complexity: O(|V||E|), the number of vertices times the number
331 * of edges.
332 *
333 * \sa \ref igraph_average_path_length() and \ref igraph_shortest_paths()
334 */
335
igraph_path_length_hist(const igraph_t * graph,igraph_vector_t * res,igraph_real_t * unconnected,igraph_bool_t directed)336 int igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res,
337 igraph_real_t *unconnected, igraph_bool_t directed) {
338
339 long int no_of_nodes = igraph_vcount(graph);
340 long int i, j, n;
341 igraph_vector_long_t already_added;
342 long int nodes_reached;
343
344 igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
345 igraph_vector_int_t *neis;
346 igraph_neimode_t dirmode;
347 igraph_adjlist_t allneis;
348 igraph_real_t unconn = 0;
349 long int ressize;
350
351 if (directed) {
352 dirmode = IGRAPH_OUT;
353 } else {
354 dirmode = IGRAPH_ALL;
355 }
356
357 IGRAPH_CHECK(igraph_vector_long_init(&already_added, no_of_nodes));
358 IGRAPH_FINALLY(igraph_vector_long_destroy, &already_added);
359 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
360 IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, dirmode));
361 IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
362
363 IGRAPH_CHECK(igraph_vector_resize(res, 0));
364 ressize = 0;
365
366 for (i = 0; i < no_of_nodes; i++) {
367 nodes_reached = 1; /* itself */
368 IGRAPH_CHECK(igraph_dqueue_push(&q, i));
369 IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
370 VECTOR(already_added)[i] = i + 1;
371
372 IGRAPH_PROGRESS("Path-hist: ", 100.0 * i / no_of_nodes, NULL);
373
374 IGRAPH_ALLOW_INTERRUPTION();
375
376 while (!igraph_dqueue_empty(&q)) {
377 long int actnode = (long int) igraph_dqueue_pop(&q);
378 long int actdist = (long int) igraph_dqueue_pop(&q);
379
380 neis = igraph_adjlist_get(&allneis, actnode);
381 n = igraph_vector_int_size(neis);
382 for (j = 0; j < n; j++) {
383 long int neighbor = (long int) VECTOR(*neis)[j];
384 if (VECTOR(already_added)[neighbor] == i + 1) {
385 continue;
386 }
387 VECTOR(already_added)[neighbor] = i + 1;
388 nodes_reached++;
389 if (actdist + 1 > ressize) {
390 IGRAPH_CHECK(igraph_vector_resize(res, actdist + 1));
391 for (; ressize < actdist + 1; ressize++) {
392 VECTOR(*res)[ressize] = 0;
393 }
394 }
395 VECTOR(*res)[actdist] += 1;
396
397 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
398 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
399 }
400 } /* while !igraph_dqueue_empty */
401
402 unconn += (no_of_nodes - nodes_reached);
403
404 } /* for i<no_of_nodes */
405
406 IGRAPH_PROGRESS("Path-hist: ", 100.0, NULL);
407
408 /* count every pair only once for an undirected graph */
409 if (!directed || !igraph_is_directed(graph)) {
410 for (i = 0; i < ressize; i++) {
411 VECTOR(*res)[i] /= 2;
412 }
413 unconn /= 2;
414 }
415
416 igraph_vector_long_destroy(&already_added);
417 igraph_dqueue_destroy(&q);
418 igraph_adjlist_destroy(&allneis);
419 IGRAPH_FINALLY_CLEAN(3);
420
421 if (unconnected) {
422 *unconnected = unconn;
423 }
424
425 return 0;
426 }
427
428 /**
429 * \ingroup structural
430 * \function igraph_shortest_paths
431 * \brief The length of the shortest paths between vertices.
432 *
433 * \param graph The graph object.
434 * \param res The result of the calculation, a matrix. A pointer to an
435 * initialized matrix, to be more precise. The matrix will be
436 * resized if needed. It will have the same
437 * number of rows as the length of the \c from
438 * argument, and its number of columns is the number of
439 * vertices in the \c to argument. One row of the matrix shows the
440 * distances from/to a given vertex to the ones in \c to.
441 * For the unreachable vertices IGRAPH_INFINITY is returned.
442 * \param from Vector of the vertex ids for which the path length
443 * calculations are done.
444 * \param to Vector of the vertex ids to which the path length
445 * calculations are done. It is not allowed to have duplicated
446 * vertex ids here.
447 * \param mode The type of shortest paths to be used for the
448 * calculation in directed graphs. Possible values:
449 * \clist
450 * \cli IGRAPH_OUT
451 * the lengths of the outgoing paths are calculated.
452 * \cli IGRAPH_IN
453 * the lengths of the incoming paths are calculated.
454 * \cli IGRAPH_ALL
455 * the directed graph is considered as an undirected one for
456 * the computation.
457 * \endclist
458 * \return Error code:
459 * \clist
460 * \cli IGRAPH_ENOMEM
461 * not enough memory for temporary
462 * data.
463 * \cli IGRAPH_EINVVID
464 * invalid vertex id passed.
465 * \cli IGRAPH_EINVMODE
466 * invalid mode argument.
467 * \endclist
468 *
469 * Time complexity: O(n(|V|+|E|)),
470 * n is the
471 * number of vertices to calculate, |V| and
472 * |E| are the number of vertices and
473 * edges in the graph.
474 *
475 * \sa \ref igraph_get_shortest_paths() to get the paths themselves,
476 * \ref igraph_shortest_paths_dijkstra() for the weighted version.
477 */
478
igraph_shortest_paths(const igraph_t * graph,igraph_matrix_t * res,const igraph_vs_t from,const igraph_vs_t to,igraph_neimode_t mode)479 int igraph_shortest_paths(const igraph_t *graph, igraph_matrix_t *res,
480 const igraph_vs_t from, const igraph_vs_t to,
481 igraph_neimode_t mode) {
482
483 long int no_of_nodes = igraph_vcount(graph);
484 long int no_of_from, no_of_to;
485 long int *already_counted;
486 igraph_adjlist_t adjlist;
487 igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
488 igraph_vector_int_t *neis;
489 igraph_bool_t all_to;
490
491 long int i, j;
492 igraph_vit_t fromvit, tovit;
493 igraph_real_t my_infinity = IGRAPH_INFINITY;
494 igraph_vector_t indexv;
495
496 if (mode != IGRAPH_OUT && mode != IGRAPH_IN &&
497 mode != IGRAPH_ALL) {
498 IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
499 }
500
501 IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
502 IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
503 no_of_from = IGRAPH_VIT_SIZE(fromvit);
504
505 IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, mode));
506 IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
507
508 already_counted = igraph_Calloc(no_of_nodes, long int);
509 if (already_counted == 0) {
510 IGRAPH_ERROR("shortest paths failed", IGRAPH_ENOMEM);
511 }
512 IGRAPH_FINALLY(free, already_counted);
513 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
514
515 if ( (all_to = igraph_vs_is_all(&to)) ) {
516 no_of_to = no_of_nodes;
517 } else {
518 IGRAPH_VECTOR_INIT_FINALLY(&indexv, no_of_nodes);
519 IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
520 IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
521 no_of_to = IGRAPH_VIT_SIZE(tovit);
522 for (i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) {
523 long int v = IGRAPH_VIT_GET(tovit);
524 if (VECTOR(indexv)[v]) {
525 IGRAPH_ERROR("Duplicate vertices in `to', this is not allowed",
526 IGRAPH_EINVAL);
527 }
528 VECTOR(indexv)[v] = ++i;
529 }
530 }
531
532 IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
533 igraph_matrix_fill(res, my_infinity);
534
535 for (IGRAPH_VIT_RESET(fromvit), i = 0;
536 !IGRAPH_VIT_END(fromvit);
537 IGRAPH_VIT_NEXT(fromvit), i++) {
538 long int reached = 0;
539 IGRAPH_CHECK(igraph_dqueue_push(&q, IGRAPH_VIT_GET(fromvit)));
540 IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
541 already_counted[ (long int) IGRAPH_VIT_GET(fromvit) ] = i + 1;
542
543 IGRAPH_ALLOW_INTERRUPTION();
544
545 while (!igraph_dqueue_empty(&q)) {
546 long int act = (long int) igraph_dqueue_pop(&q);
547 long int actdist = (long int) igraph_dqueue_pop(&q);
548
549 if (all_to) {
550 MATRIX(*res, i, act) = actdist;
551 } else {
552 if (VECTOR(indexv)[act]) {
553 MATRIX(*res, i, (long int)(VECTOR(indexv)[act] - 1)) = actdist;
554 reached++;
555 if (reached == no_of_to) {
556 igraph_dqueue_clear(&q);
557 break;
558 }
559 }
560 }
561
562 neis = igraph_adjlist_get(&adjlist, act);
563 for (j = 0; j < igraph_vector_int_size(neis); j++) {
564 long int neighbor = (long int) VECTOR(*neis)[j];
565 if (already_counted[neighbor] == i + 1) {
566 continue;
567 }
568 already_counted[neighbor] = i + 1;
569 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
570 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
571 }
572 }
573 }
574
575 /* Clean */
576 if (!all_to) {
577 igraph_vit_destroy(&tovit);
578 igraph_vector_destroy(&indexv);
579 IGRAPH_FINALLY_CLEAN(2);
580 }
581
582 igraph_Free(already_counted);
583 igraph_dqueue_destroy(&q);
584 igraph_vit_destroy(&fromvit);
585 igraph_adjlist_destroy(&adjlist);
586 IGRAPH_FINALLY_CLEAN(4);
587
588 return 0;
589 }
590
591 /**
592 * \ingroup structural
593 * \function igraph_get_shortest_paths
594 * \brief Calculates the shortest paths from/to one vertex.
595 *
596 * </para><para>
597 * If there is more than one geodesic between two vertices, this
598 * function gives only one of them.
599 * \param graph The graph object.
600 * \param vertices The result, the ids of the vertices along the paths.
601 * This is a pointer vector, each element points to a vector
602 * object. These should be initialized before passing them to
603 * the function, which will properly clear and/or resize them
604 * and fill the ids of the vertices along the geodesics from/to
605 * the vertices. Supply a null pointer here if you don't need
606 * these vectors.
607 * \param edges The result, the ids of the edges along the paths.
608 * This is a pointer vector, each element points to a vector
609 * object. These should be initialized before passing them to
610 * the function, which will properly clear and/or resize them
611 * and fill the ids of the vertices along the geodesics from/to
612 * the vertices. Supply a null pointer here if you don't need
613 * these vectors.
614 * \param from The id of the vertex from/to which the geodesics are
615 * calculated.
616 * \param to Vertex sequence with the ids of the vertices to/from which the
617 * shortest paths will be calculated. A vertex might be given multiple
618 * times.
619 * \param mode The type of shortest paths to be used for the
620 * calculation in directed graphs. Possible values:
621 * \clist
622 * \cli IGRAPH_OUT
623 * the outgoing paths are calculated.
624 * \cli IGRAPH_IN
625 * the incoming paths are calculated.
626 * \cli IGRAPH_ALL
627 * the directed graph is considered as an
628 * undirected one for the computation.
629 * \endclist
630 * \param predecessors A pointer to an initialized igraph vector or null.
631 * If not null, a vector containing the predecessor of each vertex in
632 * the single source shortest path tree is returned here. The
633 * predecessor of vertex i in the tree is the vertex from which vertex i
634 * was reached. The predecessor of the start vertex (in the \c from
635 * argument) is itself by definition. If the predecessor is -1, it means
636 * that the given vertex was not reached from the source during the
637 * search. Note that the search terminates if all the vertices in
638 * \c to are reached.
639 * \param inbound_edges A pointer to an initialized igraph vector or null.
640 * If not null, a vector containing the inbound edge of each vertex in
641 * the single source shortest path tree is returned here. The
642 * inbound edge of vertex i in the tree is the edge via which vertex i
643 * was reached. The start vertex and vertices that were not reached
644 * during the search will have -1 in the corresponding entry of the
645 * vector. Note that the search terminates if all the vertices in
646 * \c to are reached.
647 *
648 * \return Error code:
649 * \clist
650 * \cli IGRAPH_ENOMEM
651 * not enough memory for temporary data.
652 * \cli IGRAPH_EINVVID
653 * \p from is invalid vertex id, or the length of \p to is
654 * not the same as the length of \p res.
655 * \cli IGRAPH_EINVMODE
656 * invalid mode argument.
657 * \endclist
658 *
659 * Time complexity: O(|V|+|E|),
660 * |V| is the number of vertices,
661 * |E| the number of edges in the
662 * graph.
663 *
664 * \sa \ref igraph_shortest_paths() if you only need the path length but
665 * not the paths themselves.
666 *
667 * \example examples/simple/igraph_get_shortest_paths.c
668 */
669
670
igraph_get_shortest_paths(const igraph_t * graph,igraph_vector_ptr_t * vertices,igraph_vector_ptr_t * edges,igraph_integer_t from,const igraph_vs_t to,igraph_neimode_t mode,igraph_vector_long_t * predecessors,igraph_vector_long_t * inbound_edges)671 int igraph_get_shortest_paths(const igraph_t *graph,
672 igraph_vector_ptr_t *vertices,
673 igraph_vector_ptr_t *edges,
674 igraph_integer_t from, const igraph_vs_t to,
675 igraph_neimode_t mode,
676 igraph_vector_long_t *predecessors,
677 igraph_vector_long_t *inbound_edges) {
678
679 /* TODO: use inclist_t if to is long (longer than 1?) */
680
681 long int no_of_nodes = igraph_vcount(graph);
682 long int *father;
683
684 igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
685
686 long int i, j;
687 igraph_vector_t tmp = IGRAPH_VECTOR_NULL;
688
689 igraph_vit_t vit;
690
691 long int to_reach;
692 long int reached = 0;
693
694 if (from < 0 || from >= no_of_nodes) {
695 IGRAPH_ERROR("cannot get shortest paths", IGRAPH_EINVVID);
696 }
697 if (mode != IGRAPH_OUT && mode != IGRAPH_IN &&
698 mode != IGRAPH_ALL) {
699 IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
700 }
701
702 IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
703 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
704
705 if (vertices && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(vertices)) {
706 IGRAPH_ERROR("Size of the `vertices' and the `to' should match", IGRAPH_EINVAL);
707 }
708 if (edges && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(edges)) {
709 IGRAPH_ERROR("Size of the `edges' and the `to' should match", IGRAPH_EINVAL);
710 }
711
712 father = igraph_Calloc(no_of_nodes, long int);
713 if (father == 0) {
714 IGRAPH_ERROR("cannot get shortest paths", IGRAPH_ENOMEM);
715 }
716 IGRAPH_FINALLY(igraph_free, father);
717 IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
718 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
719
720 /* Mark the vertices we need to reach */
721 to_reach = IGRAPH_VIT_SIZE(vit);
722 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
723 if (father[ (long int) IGRAPH_VIT_GET(vit) ] == 0) {
724 father[ (long int) IGRAPH_VIT_GET(vit) ] = -1;
725 } else {
726 to_reach--; /* this node was given multiple times */
727 }
728 }
729
730 /* Meaning of father[i]:
731 *
732 * - If father[i] < 0, it means that vertex i has to be reached and has not
733 * been reached yet.
734 *
735 * - If father[i] = 0, it means that vertex i does not have to be reached and
736 * it has not been reached yet.
737 *
738 * - If father[i] = 1, it means that vertex i is the start vertex.
739 *
740 * - Otherwise, father[i] is the ID of the edge from which vertex i was
741 * reached plus 2.
742 */
743
744 IGRAPH_CHECK(igraph_dqueue_push(&q, from + 1));
745 if (father[ (long int) from ] < 0) {
746 reached++;
747 }
748 father[ (long int)from ] = 1;
749
750 while (!igraph_dqueue_empty(&q) && reached < to_reach) {
751 long int act = (long int) igraph_dqueue_pop(&q) - 1;
752
753 IGRAPH_CHECK(igraph_incident(graph, &tmp, (igraph_integer_t) act, mode));
754 for (j = 0; j < igraph_vector_size(&tmp); j++) {
755 long int edge = (long int) VECTOR(tmp)[j];
756 long int neighbor = IGRAPH_OTHER(graph, edge, act);
757 if (father[neighbor] > 0) {
758 continue;
759 } else if (father[neighbor] < 0) {
760 reached++;
761 }
762 father[neighbor] = edge + 2;
763 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor + 1));
764 }
765 }
766
767 if (reached < to_reach) {
768 IGRAPH_WARNING("Couldn't reach some vertices");
769 }
770
771 /* Create `predecessors' if needed */
772 if (predecessors) {
773 IGRAPH_CHECK(igraph_vector_long_resize(predecessors, no_of_nodes));
774
775 for (i = 0; i < no_of_nodes; i++) {
776 if (father[i] <= 0) {
777 /* i was not reached */
778 VECTOR(*predecessors)[i] = -1;
779 } else if (father[i] == 1) {
780 /* i is the start vertex */
781 VECTOR(*predecessors)[i] = i;
782 } else {
783 /* i was reached via the edge with ID = father[i] - 2 */
784 VECTOR(*predecessors)[i] = IGRAPH_OTHER(graph, father[i] - 2, i);
785 }
786 }
787 }
788
789 /* Create `inbound_edges' if needed */
790 if (inbound_edges) {
791 IGRAPH_CHECK(igraph_vector_long_resize(inbound_edges, no_of_nodes));
792
793 for (i = 0; i < no_of_nodes; i++) {
794 if (father[i] <= 1) {
795 /* i was not reached or i is the start vertex */
796 VECTOR(*inbound_edges)[i] = -1;
797 } else {
798 /* i was reached via the edge with ID = father[i] - 2 */
799 VECTOR(*inbound_edges)[i] = father[i] - 2;
800 }
801 }
802 }
803
804 /* Create `vertices' and `edges' if needed */
805 if (vertices || edges) {
806 for (IGRAPH_VIT_RESET(vit), j = 0;
807 !IGRAPH_VIT_END(vit);
808 IGRAPH_VIT_NEXT(vit), j++) {
809 long int node = IGRAPH_VIT_GET(vit);
810 igraph_vector_t *vvec = 0, *evec = 0;
811 if (vertices) {
812 vvec = VECTOR(*vertices)[j];
813 igraph_vector_clear(vvec);
814 }
815 if (edges) {
816 evec = VECTOR(*edges)[j];
817 igraph_vector_clear(evec);
818 }
819
820 IGRAPH_ALLOW_INTERRUPTION();
821
822 if (father[node] > 0) {
823 long int act = node;
824 long int size = 0;
825 long int edge;
826 while (father[act] > 1) {
827 size++;
828 edge = father[act] - 2;
829 act = IGRAPH_OTHER(graph, edge, act);
830 }
831 if (vvec) {
832 IGRAPH_CHECK(igraph_vector_resize(vvec, size + 1));
833 VECTOR(*vvec)[size] = node;
834 }
835 if (evec) {
836 IGRAPH_CHECK(igraph_vector_resize(evec, size));
837 }
838 act = node;
839 while (father[act] > 1) {
840 size--;
841 edge = father[act] - 2;
842 act = IGRAPH_OTHER(graph, edge, act);
843 if (vvec) {
844 VECTOR(*vvec)[size] = act;
845 }
846 if (evec) {
847 VECTOR(*evec)[size] = edge;
848 }
849 }
850 }
851 }
852 }
853
854 /* Clean */
855 igraph_Free(father);
856 igraph_dqueue_destroy(&q);
857 igraph_vector_destroy(&tmp);
858 igraph_vit_destroy(&vit);
859 IGRAPH_FINALLY_CLEAN(4);
860
861 return 0;
862 }
863
864 /**
865 * \function igraph_get_shortest_path
866 * Shortest path from one vertex to another one.
867 *
868 * Calculates and returns a single unweighted shortest path from a
869 * given vertex to another one. If there are more than one shortest
870 * paths between the two vertices, then an arbitrary one is returned.
871 *
872 * </para><para>This function is a wrapper to \ref
873 * igraph_get_shortest_paths(), for the special case when only one
874 * target vertex is considered.
875 * \param graph The input graph, it can be directed or
876 * undirected. Directed paths are considered in directed
877 * graphs.
878 * \param vertices Pointer to an initialized vector or a null
879 * pointer. If not a null pointer, then the vertex ids along
880 * the path are stored here, including the source and target
881 * vertices.
882 * \param edges Pointer to an uninitialized vector or a null
883 * pointer. If not a null pointer, then the edge ids along the
884 * path are stored here.
885 * \param from The id of the source vertex.
886 * \param to The id of the target vertex.
887 * \param mode A constant specifying how edge directions are
888 * considered in directed graphs. Valid modes are:
889 * \c IGRAPH_OUT, follows edge directions;
890 * \c IGRAPH_IN, follows the opposite directions; and
891 * \c IGRAPH_ALL, ignores edge directions. This argument is
892 * ignored for undirected graphs.
893 * \return Error code.
894 *
895 * Time complexity: O(|V|+|E|), linear in the number of vertices and
896 * edges in the graph.
897 *
898 * \sa \ref igraph_get_shortest_paths() for the version with more target
899 * vertices.
900 */
901
igraph_get_shortest_path(const igraph_t * graph,igraph_vector_t * vertices,igraph_vector_t * edges,igraph_integer_t from,igraph_integer_t to,igraph_neimode_t mode)902 int igraph_get_shortest_path(const igraph_t *graph,
903 igraph_vector_t *vertices,
904 igraph_vector_t *edges,
905 igraph_integer_t from,
906 igraph_integer_t to,
907 igraph_neimode_t mode) {
908
909 igraph_vector_ptr_t vertices2, *vp = &vertices2;
910 igraph_vector_ptr_t edges2, *ep = &edges2;
911
912 if (vertices) {
913 IGRAPH_CHECK(igraph_vector_ptr_init(&vertices2, 1));
914 IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vertices2);
915 VECTOR(vertices2)[0] = vertices;
916 } else {
917 vp = 0;
918 }
919 if (edges) {
920 IGRAPH_CHECK(igraph_vector_ptr_init(&edges2, 1));
921 IGRAPH_FINALLY(igraph_vector_ptr_destroy, &edges2);
922 VECTOR(edges2)[0] = edges;
923 } else {
924 ep = 0;
925 }
926
927 IGRAPH_CHECK(igraph_get_shortest_paths(graph, vp, ep, from,
928 igraph_vss_1(to), mode, 0, 0));
929
930 if (edges) {
931 igraph_vector_ptr_destroy(&edges2);
932 IGRAPH_FINALLY_CLEAN(1);
933 }
934 if (vertices) {
935 igraph_vector_ptr_destroy(&vertices2);
936 IGRAPH_FINALLY_CLEAN(1);
937 }
938
939 return 0;
940 }
941
942 void igraph_i_gasp_paths_destroy(igraph_vector_ptr_t *v);
943
igraph_i_gasp_paths_destroy(igraph_vector_ptr_t * v)944 void igraph_i_gasp_paths_destroy(igraph_vector_ptr_t *v) {
945 long int i;
946 for (i = 0; i < igraph_vector_ptr_size(v); i++) {
947 if (VECTOR(*v)[i] != 0) {
948 igraph_vector_destroy(VECTOR(*v)[i]);
949 igraph_Free(VECTOR(*v)[i]);
950 }
951 }
952 igraph_vector_ptr_destroy(v);
953 }
954
955 /**
956 * \function igraph_get_all_shortest_paths
957 * \brief Finds all shortest paths (geodesics) from a vertex to all other vertices.
958 *
959 * \param graph The graph object.
960 * \param res Pointer to an initialized pointer vector, the result
961 * will be stored here in igraph_vector_t objects. Each vector
962 * object contains the vertices along a shortest path from \p from
963 * to another vertex. The vectors are ordered according to their
964 * target vertex: first the shortest paths to vertex 0, then to
965 * vertex 1, etc. No data is included for unreachable vertices.
966 * \param nrgeo Pointer to an initialized igraph_vector_t object or
967 * NULL. If not NULL the number of shortest paths from \p from are
968 * stored here for every vertex in the graph. Note that the values
969 * will be accurate only for those vertices that are in the target
970 * vertex sequence (see \p to), since the search terminates as soon
971 * as all the target vertices have been found.
972 * \param from The id of the vertex from/to which the geodesics are
973 * calculated.
974 * \param to Vertex sequence with the ids of the vertices to/from which the
975 * shortest paths will be calculated. A vertex might be given multiple
976 * times.
977 * \param mode The type of shortest paths to be use for the
978 * calculation in directed graphs. Possible values:
979 * \clist
980 * \cli IGRAPH_OUT
981 * the lengths of the outgoing paths are calculated.
982 * \cli IGRAPH_IN
983 * the lengths of the incoming paths are calculated.
984 * \cli IGRAPH_ALL
985 * the directed graph is considered as an
986 * undirected one for the computation.
987 * \endclist
988 * \return Error code:
989 * \clist
990 * \cli IGRAPH_ENOMEM
991 * not enough memory for temporary data.
992 * \cli IGRAPH_EINVVID
993 * \p from is invalid vertex id.
994 * \cli IGRAPH_EINVMODE
995 * invalid mode argument.
996 * \endclist
997 *
998 * Added in version 0.2.</para><para>
999 *
1000 * Time complexity: O(|V|+|E|) for most graphs, O(|V|^2) in the worst
1001 * case.
1002 */
1003
igraph_get_all_shortest_paths(const igraph_t * graph,igraph_vector_ptr_t * res,igraph_vector_t * nrgeo,igraph_integer_t from,const igraph_vs_t to,igraph_neimode_t mode)1004 int igraph_get_all_shortest_paths(const igraph_t *graph,
1005 igraph_vector_ptr_t *res,
1006 igraph_vector_t *nrgeo,
1007 igraph_integer_t from, const igraph_vs_t to,
1008 igraph_neimode_t mode) {
1009
1010 long int no_of_nodes = igraph_vcount(graph);
1011 long int *geodist;
1012 igraph_vector_ptr_t paths;
1013 igraph_dqueue_t q;
1014 igraph_vector_t *vptr;
1015 igraph_vector_t neis;
1016 igraph_vector_t ptrlist;
1017 igraph_vector_t ptrhead;
1018 long int n, j, i;
1019 long int to_reach, reached = 0, maxdist = 0;
1020
1021 igraph_vit_t vit;
1022
1023 if (from < 0 || from >= no_of_nodes) {
1024 IGRAPH_ERROR("cannot get shortest paths", IGRAPH_EINVVID);
1025 }
1026 if (mode != IGRAPH_OUT && mode != IGRAPH_IN &&
1027 mode != IGRAPH_ALL) {
1028 IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
1029 }
1030
1031 IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
1032 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
1033
1034 /* paths will store the shortest paths during the search */
1035 IGRAPH_CHECK(igraph_vector_ptr_init(&paths, 0));
1036 IGRAPH_FINALLY(igraph_i_gasp_paths_destroy, &paths);
1037 /* neis is a temporary vector holding the neighbors of the
1038 * node being examined */
1039 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
1040 /* ptrlist stores indices into the paths vector, in the order
1041 * of how they were found. ptrhead is a second-level index that
1042 * will be used to find paths that terminate in a given vertex */
1043 IGRAPH_VECTOR_INIT_FINALLY(&ptrlist, 0);
1044 /* ptrhead contains indices into ptrlist.
1045 * ptrhead[i] = j means that element #j-1 in ptrlist contains
1046 * the shortest path from the root to node i. ptrhead[i] = 0
1047 * means that node i was not reached so far */
1048 IGRAPH_VECTOR_INIT_FINALLY(&ptrhead, no_of_nodes);
1049 /* geodist[i] == 0 if i was not reached yet and it is not in the
1050 * target vertex sequence, or -1 if i was not reached yet and it
1051 * is in the target vertex sequence. Otherwise it is
1052 * one larger than the length of the shortest path from the
1053 * source */
1054 geodist = igraph_Calloc(no_of_nodes, long int);
1055 if (geodist == 0) {
1056 IGRAPH_ERROR("Cannot calculate shortest paths", IGRAPH_ENOMEM);
1057 }
1058 IGRAPH_FINALLY(igraph_free, geodist);
1059 /* dequeue to store the BFS queue -- odd elements are the vertex indices,
1060 * even elements are the distances from the root */
1061 IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
1062 IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
1063
1064 if (nrgeo) {
1065 IGRAPH_CHECK(igraph_vector_resize(nrgeo, no_of_nodes));
1066 igraph_vector_null(nrgeo);
1067 }
1068
1069 /* use geodist to count how many vertices we have to reach */
1070 to_reach = IGRAPH_VIT_SIZE(vit);
1071 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
1072 if (geodist[ (long int) IGRAPH_VIT_GET(vit) ] == 0) {
1073 geodist[ (long int) IGRAPH_VIT_GET(vit) ] = -1;
1074 } else {
1075 to_reach--; /* this node was given multiple times */
1076 }
1077 }
1078
1079 if (geodist[ (long int) from ] < 0) {
1080 reached++;
1081 }
1082
1083 /* from -> from */
1084 vptr = igraph_Calloc(1, igraph_vector_t); /* TODO: dirty */
1085 IGRAPH_CHECK(igraph_vector_ptr_push_back(&paths, vptr));
1086 IGRAPH_CHECK(igraph_vector_init(vptr, 1));
1087 VECTOR(*vptr)[0] = from;
1088 geodist[(long int)from] = 1;
1089 VECTOR(ptrhead)[(long int)from] = 1;
1090 IGRAPH_CHECK(igraph_vector_push_back(&ptrlist, 0));
1091 if (nrgeo) {
1092 VECTOR(*nrgeo)[(long int)from] = 1;
1093 }
1094
1095 /* Init queue */
1096 IGRAPH_CHECK(igraph_dqueue_push(&q, from));
1097 IGRAPH_CHECK(igraph_dqueue_push(&q, 0.0));
1098 while (!igraph_dqueue_empty(&q)) {
1099 long int actnode = (long int) igraph_dqueue_pop(&q);
1100 long int actdist = (long int) igraph_dqueue_pop(&q);
1101
1102 IGRAPH_ALLOW_INTERRUPTION();
1103
1104 if (reached >= to_reach) {
1105 /* all nodes were reached. Since we need all the shortest paths
1106 * to all these nodes, we can stop the search only if the distance
1107 * of the current node to the root is larger than the distance of
1108 * any of the nodes we wanted to reach */
1109 if (actdist > maxdist) {
1110 /* safety check, maxdist should have been set when we reached the last node */
1111 if (maxdist < 0) {
1112 IGRAPH_ERROR("possible bug in igraph_get_all_shortest_paths, "
1113 "maxdist is negative", IGRAPH_EINVAL);
1114 }
1115 break;
1116 }
1117 }
1118
1119 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actnode,
1120 mode));
1121 n = igraph_vector_size(&neis);
1122 for (j = 0; j < n; j++) {
1123 long int neighbor = (long int) VECTOR(neis)[j];
1124 long int fatherptr;
1125
1126 if (geodist[neighbor] > 0 &&
1127 geodist[neighbor] - 1 < actdist + 1) {
1128 /* this node was reached via a shorter path before */
1129 continue;
1130 }
1131
1132 /* yay, found another shortest path to neighbor */
1133
1134 if (nrgeo) {
1135 /* the number of geodesics leading to neighbor must be
1136 * increased by the number of geodesics leading to actnode */
1137 VECTOR(*nrgeo)[neighbor] += VECTOR(*nrgeo)[actnode];
1138 }
1139 if (geodist[neighbor] <= 0) {
1140 /* this node was not reached yet, push it into the queue */
1141 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
1142 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
1143 if (geodist[neighbor] < 0) {
1144 reached++;
1145 }
1146 if (reached == to_reach) {
1147 maxdist = actdist;
1148 }
1149 }
1150 geodist[neighbor] = actdist + 2;
1151
1152 /* copy all existing paths to the parent */
1153 fatherptr = (long int) VECTOR(ptrhead)[actnode];
1154 while (fatherptr != 0) {
1155 /* allocate a new igraph_vector_t at the end of paths */
1156 vptr = igraph_Calloc(1, igraph_vector_t);
1157 IGRAPH_CHECK(igraph_vector_ptr_push_back(&paths, vptr));
1158 IGRAPH_CHECK(igraph_vector_copy(vptr, VECTOR(paths)[fatherptr - 1]));
1159 IGRAPH_CHECK(igraph_vector_reserve(vptr, actdist + 2));
1160 IGRAPH_CHECK(igraph_vector_push_back(vptr, neighbor));
1161
1162 IGRAPH_CHECK(igraph_vector_push_back(&ptrlist,
1163 VECTOR(ptrhead)[neighbor]));
1164 VECTOR(ptrhead)[neighbor] = igraph_vector_size(&ptrlist);
1165
1166 fatherptr = (long int) VECTOR(ptrlist)[fatherptr - 1];
1167 }
1168 }
1169 }
1170
1171 igraph_dqueue_destroy(&q);
1172 IGRAPH_FINALLY_CLEAN(1);
1173
1174 /* mark the nodes for which we need the result */
1175 memset(geodist, 0, sizeof(long int) * (size_t) no_of_nodes);
1176 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
1177 geodist[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
1178 }
1179
1180 /* count the number of paths in the result */
1181 n = 0;
1182 for (i = 0; i < no_of_nodes; i++) {
1183 long int fatherptr = (long int) VECTOR(ptrhead)[i];
1184 if (geodist[i] > 0) {
1185 while (fatherptr != 0) {
1186 n++;
1187 fatherptr = (long int) VECTOR(ptrlist)[fatherptr - 1];
1188 }
1189 }
1190 }
1191
1192 IGRAPH_CHECK(igraph_vector_ptr_resize(res, n));
1193 j = 0;
1194 for (i = 0; i < no_of_nodes; i++) {
1195 long int fatherptr = (long int) VECTOR(ptrhead)[i];
1196
1197 IGRAPH_ALLOW_INTERRUPTION();
1198
1199 /* do we need the paths leading to vertex i? */
1200 if (geodist[i] > 0) {
1201 /* yes, copy them to the result vector */
1202 while (fatherptr != 0) {
1203 VECTOR(*res)[j++] = VECTOR(paths)[fatherptr - 1];
1204 fatherptr = (long int) VECTOR(ptrlist)[fatherptr - 1];
1205 }
1206 } else {
1207 /* no, free them */
1208 while (fatherptr != 0) {
1209 igraph_vector_destroy(VECTOR(paths)[fatherptr - 1]);
1210 igraph_Free(VECTOR(paths)[fatherptr - 1]);
1211 fatherptr = (long int) VECTOR(ptrlist)[fatherptr - 1];
1212 }
1213 }
1214 }
1215
1216 igraph_Free(geodist);
1217 igraph_vector_destroy(&ptrlist);
1218 igraph_vector_destroy(&ptrhead);
1219 igraph_vector_destroy(&neis);
1220 igraph_vector_ptr_destroy(&paths);
1221 igraph_vit_destroy(&vit);
1222 IGRAPH_FINALLY_CLEAN(6);
1223
1224 return 0;
1225 }
1226
1227
1228 /**
1229 * \ingroup structural
1230 * \function igraph_subcomponent
1231 * \brief The vertices in the same component as a given vertex.
1232 *
1233 * \param graph The graph object.
1234 * \param res The result, vector with the ids of the vertices in the
1235 * same component.
1236 * \param vertex The id of the vertex of which the component is
1237 * searched.
1238 * \param mode Type of the component for directed graphs, possible
1239 * values:
1240 * \clist
1241 * \cli IGRAPH_OUT
1242 * the set of vertices reachable \em from the
1243 * \p vertex,
1244 * \cli IGRAPH_IN
1245 * the set of vertices from which the
1246 * \p vertex is reachable.
1247 * \cli IGRAPH_ALL
1248 * the graph is considered as an
1249 * undirected graph. Note that this is \em not the same
1250 * as the union of the previous two.
1251 * \endclist
1252 * \return Error code:
1253 * \clist
1254 * \cli IGRAPH_ENOMEM
1255 * not enough memory for temporary data.
1256 * \cli IGRAPH_EINVVID
1257 * \p vertex is an invalid vertex id
1258 * \cli IGRAPH_EINVMODE
1259 * invalid mode argument passed.
1260 * \endclist
1261 *
1262 * Time complexity: O(|V|+|E|),
1263 * |V| and
1264 * |E| are the number of vertices and
1265 * edges in the graph.
1266 *
1267 * \sa \ref igraph_subgraph() if you want a graph object consisting only
1268 * a given set of vertices and the edges between them.
1269 */
1270
igraph_subcomponent(const igraph_t * graph,igraph_vector_t * res,igraph_real_t vertex,igraph_neimode_t mode)1271 int igraph_subcomponent(const igraph_t *graph, igraph_vector_t *res, igraph_real_t vertex,
1272 igraph_neimode_t mode) {
1273
1274 long int no_of_nodes = igraph_vcount(graph);
1275 igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;
1276 char *already_added;
1277 long int i;
1278 igraph_vector_t tmp = IGRAPH_VECTOR_NULL;
1279
1280 if (!IGRAPH_FINITE(vertex) || vertex < 0 || vertex >= no_of_nodes) {
1281 IGRAPH_ERROR("subcomponent failed", IGRAPH_EINVVID);
1282 }
1283 if (mode != IGRAPH_OUT && mode != IGRAPH_IN &&
1284 mode != IGRAPH_ALL) {
1285 IGRAPH_ERROR("invalid mode argument", IGRAPH_EINVMODE);
1286 }
1287
1288 already_added = igraph_Calloc(no_of_nodes, char);
1289 if (already_added == 0) {
1290 IGRAPH_ERROR("subcomponent failed", IGRAPH_ENOMEM);
1291 }
1292 IGRAPH_FINALLY(free, already_added); /* TODO: hack */
1293
1294 igraph_vector_clear(res);
1295
1296 IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
1297 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
1298
1299 IGRAPH_CHECK(igraph_dqueue_push(&q, vertex));
1300 IGRAPH_CHECK(igraph_vector_push_back(res, vertex));
1301 already_added[(long int)vertex] = 1;
1302
1303 while (!igraph_dqueue_empty(&q)) {
1304 long int actnode = (long int) igraph_dqueue_pop(&q);
1305
1306 IGRAPH_ALLOW_INTERRUPTION();
1307
1308 IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) actnode,
1309 mode));
1310 for (i = 0; i < igraph_vector_size(&tmp); i++) {
1311 long int neighbor = (long int) VECTOR(tmp)[i];
1312
1313 if (already_added[neighbor]) {
1314 continue;
1315 }
1316 already_added[neighbor] = 1;
1317 IGRAPH_CHECK(igraph_vector_push_back(res, neighbor));
1318 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
1319 }
1320 }
1321
1322 igraph_dqueue_destroy(&q);
1323 igraph_vector_destroy(&tmp);
1324 igraph_Free(already_added);
1325 IGRAPH_FINALLY_CLEAN(3);
1326
1327 return 0;
1328 }
1329
1330 /**
1331 * \ingroup structural
1332 * \function igraph_pagerank_old
1333 * \brief Calculates the Google PageRank for the specified vertices.
1334 *
1335 * </para><para>This is an old implementation,
1336 * it is provided for compatibility with igraph versions earlier than
1337 * 0.5. Please use the new implementation \ref igraph_pagerank() in
1338 * new projects.
1339 *
1340 * </para><para>
1341 * From version 0.7 this function is deprecated and its use gives a
1342 * warning message.
1343 *
1344 * </para><para>
1345 * Please note that the PageRank of a given vertex depends on the PageRank
1346 * of all other vertices, so even if you want to calculate the PageRank for
1347 * only some of the vertices, all of them must be calculated. Requesting
1348 * the PageRank for only some of the vertices does not result in any
1349 * performance increase at all.
1350 * </para>
1351 * <para>
1352 * Since the calculation is an iterative
1353 * process, the algorithm is stopped after a given count of iterations
1354 * or if the PageRank value differences between iterations are less than
1355 * a predefined value.
1356 * </para>
1357 *
1358 * <para>
1359 * For the explanation of the PageRank algorithm, see the following
1360 * webpage:
1361 * http://infolab.stanford.edu/~backrub/google.html , or the
1362 * following reference:
1363 * </para>
1364 *
1365 * <para>
1366 * Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual
1367 * Web Search Engine. Proceedings of the 7th World-Wide Web Conference,
1368 * Brisbane, Australia, April 1998.
1369 * </para>
1370 * <para>
1371 * \param graph The graph object.
1372 * \param res The result vector containing the PageRank values for the
1373 * given nodes.
1374 * \param vids Vector with the vertex ids
1375 * \param directed Logical, if true directed paths will be considered
1376 * for directed graphs. It is ignored for undirected graphs.
1377 * \param niter The maximum number of iterations to perform
1378 * \param eps The algorithm will consider the calculation as complete
1379 * if the difference of PageRank values between iterations change
1380 * less than this value for every node
1381 * \param damping The damping factor ("d" in the original paper)
1382 * \param old Boolean, whether to use the pre-igraph 0.5 way to
1383 * calculate page rank. Not recommended for new applications,
1384 * only included for compatibility. If this is non-zero then the damping
1385 * factor is not divided by the number of vertices before adding it
1386 * to the weighted page rank scores to calculate the
1387 * new scores. I.e. the formula in the original PageRank paper
1388 * is used. Furthermore, if this is non-zero then the PageRank
1389 * vector is renormalized after each iteration.
1390 * \return Error code:
1391 * \c IGRAPH_ENOMEM, not enough memory for
1392 * temporary data.
1393 * \c IGRAPH_EINVVID, invalid vertex id in
1394 * \p vids.
1395 *
1396 * Time complexity: O(|V|+|E|) per iteration. A handful iterations
1397 * should be enough. Note that if the old-style dumping is used then
1398 * the iteration might not converge at all.
1399 *
1400 * \sa \ref igraph_pagerank() for the new implementation.
1401 */
1402
igraph_pagerank_old(const igraph_t * graph,igraph_vector_t * res,const igraph_vs_t vids,igraph_bool_t directed,igraph_integer_t niter,igraph_real_t eps,igraph_real_t damping,igraph_bool_t old)1403 int igraph_pagerank_old(const igraph_t *graph, igraph_vector_t *res,
1404 const igraph_vs_t vids, igraph_bool_t directed,
1405 igraph_integer_t niter, igraph_real_t eps,
1406 igraph_real_t damping, igraph_bool_t old) {
1407 long int no_of_nodes = igraph_vcount(graph);
1408 long int i, j, n, nodes_to_calc;
1409 igraph_real_t *prvec, *prvec_new, *prvec_aux, *prvec_scaled;
1410 igraph_vector_int_t *neis;
1411 igraph_vector_t outdegree;
1412 igraph_neimode_t dirmode;
1413 igraph_adjlist_t allneis;
1414 igraph_real_t maxdiff = eps;
1415 igraph_vit_t vit;
1416
1417 IGRAPH_WARNING("igraph_pagerank_old is deprecated from igraph 0.7, "
1418 "use igraph_pagerank instead");
1419
1420 if (niter <= 0) {
1421 IGRAPH_ERROR("Invalid iteration count", IGRAPH_EINVAL);
1422 }
1423 if (eps <= 0) {
1424 IGRAPH_ERROR("Invalid epsilon value", IGRAPH_EINVAL);
1425 }
1426 if (damping <= 0 || damping >= 1) {
1427 IGRAPH_ERROR("Invalid damping factor", IGRAPH_EINVAL);
1428 }
1429
1430 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
1431 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
1432 nodes_to_calc = IGRAPH_VIT_SIZE(vit);
1433
1434 IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
1435 igraph_vector_null(res);
1436
1437 IGRAPH_VECTOR_INIT_FINALLY(&outdegree, no_of_nodes);
1438
1439 prvec = igraph_Calloc(no_of_nodes, igraph_real_t);
1440 if (prvec == 0) {
1441 IGRAPH_ERROR("pagerank failed", IGRAPH_ENOMEM);
1442 }
1443 IGRAPH_FINALLY(igraph_free, prvec);
1444
1445 prvec_new = igraph_Calloc(no_of_nodes, igraph_real_t);
1446 if (prvec_new == 0) {
1447 IGRAPH_ERROR("pagerank failed", IGRAPH_ENOMEM);
1448 }
1449 IGRAPH_FINALLY(igraph_free, prvec_new);
1450
1451 prvec_scaled = igraph_Calloc(no_of_nodes, igraph_real_t);
1452 if (prvec_scaled == 0) {
1453 IGRAPH_ERROR("pagerank failed", IGRAPH_ENOMEM);
1454 }
1455 IGRAPH_FINALLY(igraph_free, prvec_scaled);
1456
1457 if (directed) {
1458 dirmode = IGRAPH_IN;
1459 } else {
1460 dirmode = IGRAPH_ALL;
1461 }
1462 igraph_adjlist_init(graph, &allneis, dirmode);
1463 IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);
1464
1465 /* Calculate outdegrees for every node */
1466 igraph_degree(graph, &outdegree, igraph_vss_all(),
1467 directed ? IGRAPH_OUT : IGRAPH_ALL, 0);
1468 /* Initialize PageRank values */
1469 for (i = 0; i < no_of_nodes; i++) {
1470 prvec[i] = 1 - damping;
1471 /* The next line is necessary to avoid division by zero in the
1472 * calculation of prvec_scaled. This won't cause any problem,
1473 * since if a node doesn't have any outgoing links, its
1474 * prvec_scaled value won't be used anywhere */
1475 if (VECTOR(outdegree)[i] == 0) {
1476 VECTOR(outdegree)[i] = 1;
1477 }
1478 }
1479
1480 /* We will always calculate the new PageRank values into prvec_new
1481 * based on the existing values from prvec. To avoid unnecessary
1482 * copying from prvec_new to prvec at the end of every iteration,
1483 * the pointers are swapped after every iteration */
1484 while (niter > 0 && maxdiff >= eps) {
1485 igraph_real_t sumfrom = 0, sum = 0;
1486 niter--;
1487 maxdiff = 0;
1488
1489 /* Calculate the quotient of the actual PageRank value and the
1490 * outdegree for every node */
1491 sumfrom = 0.0; sum = 0.0;
1492 for (i = 0; i < no_of_nodes; i++) {
1493 sumfrom += prvec[i];
1494 prvec_scaled[i] = prvec[i] / VECTOR(outdegree)[i];
1495 }
1496
1497 /* Calculate new PageRank values based on the old ones */
1498 for (i = 0; i < no_of_nodes; i++) {
1499
1500 IGRAPH_ALLOW_INTERRUPTION();
1501
1502 prvec_new[i] = 0;
1503 neis = igraph_adjlist_get(&allneis, i);
1504 n = igraph_vector_int_size(neis);
1505 for (j = 0; j < n; j++) {
1506 long int neighbor = (long int) VECTOR(*neis)[j];
1507 prvec_new[i] += prvec_scaled[neighbor];
1508 }
1509 prvec_new[i] *= damping;
1510 if (!old) {
1511 prvec_new[i] += (1 - damping) / no_of_nodes;
1512 } else {
1513 prvec_new[i] += (1 - damping);
1514 }
1515 sum += prvec_new[i];
1516
1517 }
1518 for (i = 0; i < no_of_nodes; i++) {
1519 if (!old) {
1520 prvec_new[i] /= sum;
1521 }
1522
1523 if (prvec_new[i] - prvec[i] > maxdiff) {
1524 maxdiff = prvec_new[i] - prvec[i];
1525 } else if (prvec[i] - prvec_new[i] > maxdiff) {
1526 maxdiff = prvec[i] - prvec_new[i];
1527 }
1528 }
1529
1530 /* Swap the vectors */
1531 prvec_aux = prvec_new;
1532 prvec_new = prvec;
1533 prvec = prvec_aux;
1534 }
1535
1536 /* Copy results from prvec to res */
1537 for (IGRAPH_VIT_RESET(vit), i = 0;
1538 !IGRAPH_VIT_END(vit);
1539 IGRAPH_VIT_NEXT(vit), i++) {
1540 long int vid = IGRAPH_VIT_GET(vit);
1541 VECTOR(*res)[i] = prvec[vid];
1542 }
1543
1544 igraph_adjlist_destroy(&allneis);
1545 igraph_vit_destroy(&vit);
1546 igraph_vector_destroy(&outdegree);
1547 igraph_Free(prvec);
1548 igraph_Free(prvec_new);
1549 igraph_Free(prvec_scaled);
1550
1551 IGRAPH_FINALLY_CLEAN(6);
1552
1553 return 0;
1554 }
1555
1556 /* Not declared static so that the testsuite can use it, but not part of the public API. */
igraph_i_rewire(igraph_t * graph,igraph_integer_t n,igraph_rewiring_t mode,igraph_bool_t use_adjlist)1557 int igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode, igraph_bool_t use_adjlist) {
1558 long int no_of_nodes = igraph_vcount(graph);
1559 long int no_of_edges = igraph_ecount(graph);
1560 char message[256];
1561 igraph_integer_t a, b, c, d, dummy, num_swaps, num_successful_swaps;
1562 igraph_vector_t eids, edgevec, alledges;
1563 igraph_bool_t directed, loops, ok;
1564 igraph_es_t es;
1565 igraph_adjlist_t al;
1566
1567 if (no_of_nodes < 4) {
1568 IGRAPH_ERROR("graph unsuitable for rewiring", IGRAPH_EINVAL);
1569 }
1570
1571 directed = igraph_is_directed(graph);
1572 loops = (mode & IGRAPH_REWIRING_SIMPLE_LOOPS);
1573
1574 RNG_BEGIN();
1575
1576 IGRAPH_VECTOR_INIT_FINALLY(&eids, 2);
1577
1578 if (use_adjlist) {
1579 /* As well as the sorted adjacency list, we maintain an unordered
1580 * list of edges for picking a random edge in constant time.
1581 */
1582 IGRAPH_CHECK(igraph_adjlist_init(graph, &al, IGRAPH_OUT));
1583 IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
1584 IGRAPH_VECTOR_INIT_FINALLY(&alledges, no_of_edges * 2);
1585 igraph_get_edgelist(graph, &alledges, /*bycol=*/ 0);
1586 } else {
1587 IGRAPH_VECTOR_INIT_FINALLY(&edgevec, 4);
1588 es = igraph_ess_vector(&eids);
1589 }
1590
1591 /* We don't want the algorithm to get stuck in an infinite loop when
1592 * it can't choose two edges satisfying the conditions. Instead of
1593 * this, we choose two arbitrary edges and if they have endpoints
1594 * in common, we just decrease the number of trials left and continue
1595 * (so unsuccessful rewirings still count as a trial)
1596 */
1597
1598 num_swaps = num_successful_swaps = 0;
1599 while (num_swaps < n) {
1600
1601 IGRAPH_ALLOW_INTERRUPTION();
1602 if (num_swaps % 1000 == 0) {
1603 snprintf(message, sizeof(message),
1604 "Random rewiring (%.2f%% of the trials were successful)",
1605 num_swaps > 0 ? ((100.0 * num_successful_swaps) / num_swaps) : 0.0);
1606 IGRAPH_PROGRESS(message, (100.0 * num_swaps) / n, 0);
1607 }
1608
1609 switch (mode) {
1610 case IGRAPH_REWIRING_SIMPLE:
1611 case IGRAPH_REWIRING_SIMPLE_LOOPS:
1612 ok = 1;
1613
1614 /* Choose two edges randomly */
1615 VECTOR(eids)[0] = RNG_INTEGER(0, no_of_edges - 1);
1616 do {
1617 VECTOR(eids)[1] = RNG_INTEGER(0, no_of_edges - 1);
1618 } while (VECTOR(eids)[0] == VECTOR(eids)[1]);
1619
1620 /* Get the endpoints */
1621 if (use_adjlist) {
1622 a = VECTOR(alledges)[((igraph_integer_t)VECTOR(eids)[0]) * 2];
1623 b = VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[0]) * 2) + 1];
1624 c = VECTOR(alledges)[((igraph_integer_t)VECTOR(eids)[1]) * 2];
1625 d = VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[1]) * 2) + 1];
1626 } else {
1627 IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) VECTOR(eids)[0],
1628 &a, &b));
1629 IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) VECTOR(eids)[1],
1630 &c, &d));
1631 }
1632
1633 /* For an undirected graph, we have two "variants" of each edge, i.e.
1634 * a -- b and b -- a. Since some rewirings can be performed only when we
1635 * "swap" the endpoints, we do it now with probability 0.5 */
1636 if (!directed && RNG_UNIF01() < 0.5) {
1637 dummy = c; c = d; d = dummy;
1638 if (use_adjlist) {
1639 /* Flip the edge in the unordered edge-list, so the update later on
1640 * hits the correct end. */
1641 VECTOR(alledges)[((igraph_integer_t)VECTOR(eids)[1]) * 2] = c;
1642 VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[1]) * 2) + 1] = d;
1643 }
1644 }
1645
1646 /* If we do not touch loops, check whether a == b or c == d and disallow
1647 * the swap if needed */
1648 if (!loops && (a == b || c == d)) {
1649 ok = 0;
1650 } else {
1651 /* Check whether they are suitable for rewiring */
1652 if (a == c || b == d) {
1653 /* Swapping would have no effect */
1654 ok = 0;
1655 } else {
1656 /* a != c && b != d */
1657 /* If a == d or b == c, the swap would generate at least one loop, so
1658 * we disallow them unless we want to have loops */
1659 ok = loops || (a != d && b != c);
1660 /* Also, if a == b and c == d and we allow loops, doing the swap
1661 * would result in a multiple edge if the graph is undirected */
1662 ok = ok && (directed || a != b || c != d);
1663 }
1664 }
1665
1666 /* All good so far. Now check for the existence of a --> d and c --> b to
1667 * disallow the creation of multiple edges */
1668 if (ok) {
1669 if (use_adjlist) {
1670 if (igraph_adjlist_has_edge(&al, a, d, directed)) {
1671 ok = 0;
1672 }
1673 } else {
1674 IGRAPH_CHECK(igraph_are_connected(graph, a, d, &ok));
1675 ok = !ok;
1676 }
1677 }
1678 if (ok) {
1679 if (use_adjlist) {
1680 if (igraph_adjlist_has_edge(&al, c, b, directed)) {
1681 ok = 0;
1682 }
1683 } else {
1684 IGRAPH_CHECK(igraph_are_connected(graph, c, b, &ok));
1685 ok = !ok;
1686 }
1687 }
1688
1689 /* If we are still okay, we can perform the rewiring */
1690 if (ok) {
1691 /* printf("Deleting: %ld -> %ld, %ld -> %ld\n",
1692 (long)a, (long)b, (long)c, (long)d); */
1693 if (use_adjlist) {
1694 // Replace entry in sorted adjlist:
1695 IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, a, b, d, directed));
1696 IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, c, d, b, directed));
1697 // Also replace in unsorted edgelist:
1698 VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[0]) * 2) + 1] = d;
1699 VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[1]) * 2) + 1] = b;
1700 } else {
1701 IGRAPH_CHECK(igraph_delete_edges(graph, es));
1702 VECTOR(edgevec)[0] = a; VECTOR(edgevec)[1] = d;
1703 VECTOR(edgevec)[2] = c; VECTOR(edgevec)[3] = b;
1704 /* printf("Adding: %ld -> %ld, %ld -> %ld\n",
1705 (long)a, (long)d, (long)c, (long)b); */
1706 igraph_add_edges(graph, &edgevec, 0);
1707 }
1708 num_successful_swaps++;
1709 }
1710 break;
1711 default:
1712 RNG_END();
1713 IGRAPH_ERROR("unknown rewiring mode", IGRAPH_EINVMODE);
1714 }
1715 num_swaps++;
1716 }
1717
1718 if (use_adjlist) {
1719 /* Replace graph edges with the adjlist current state */
1720 IGRAPH_CHECK(igraph_delete_edges(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID)));
1721 IGRAPH_CHECK(igraph_add_edges(graph, &alledges, 0));
1722 }
1723
1724 IGRAPH_PROGRESS("Random rewiring: ", 100.0, 0);
1725
1726 if (use_adjlist) {
1727 igraph_vector_destroy(&alledges);
1728 igraph_adjlist_destroy(&al);
1729 } else {
1730 igraph_vector_destroy(&edgevec);
1731 }
1732
1733 igraph_vector_destroy(&eids);
1734 IGRAPH_FINALLY_CLEAN(use_adjlist ? 3 : 2);
1735
1736 RNG_END();
1737
1738 return 0;
1739 }
1740
1741 /**
1742 * \ingroup structural
1743 * \function igraph_rewire
1744 * \brief Randomly rewires a graph while preserving the degree distribution.
1745 *
1746 * </para><para>
1747 * This function generates a new graph based on the original one by randomly
1748 * rewiring edges while preserving the original graph's degree distribution.
1749 * Please note that the rewiring is done "in place", so no new graph will
1750 * be allocated. If you would like to keep the original graph intact, use
1751 * \ref igraph_copy() beforehand.
1752 *
1753 * \param graph The graph object to be rewired.
1754 * \param n Number of rewiring trials to perform.
1755 * \param mode The rewiring algorithm to be used. It can be one of the following flags:
1756 * \clist
1757 * \cli IGRAPH_REWIRING_SIMPLE
1758 * Simple rewiring algorithm which chooses two arbitrary edges
1759 * in each step (namely (a,b) and (c,d)) and substitutes them
1760 * with (a,d) and (c,b) if they don't exist. The method will
1761 * neither destroy nor create self-loops.
1762 * \cli IGRAPH_REWIRING_SIMPLE_LOOPS
1763 * Same as \c IGRAPH_REWIRING_SIMPLE but allows the creation or
1764 * destruction of self-loops.
1765 * \endclist
1766 *
1767 * \return Error code:
1768 * \clist
1769 * \cli IGRAPH_EINVMODE
1770 * Invalid rewiring mode.
1771 * \cli IGRAPH_EINVAL
1772 * Graph unsuitable for rewiring (e.g. it has
1773 * less than 4 nodes in case of \c IGRAPH_REWIRING_SIMPLE)
1774 * \cli IGRAPH_ENOMEM
1775 * Not enough memory for temporary data.
1776 * \endclist
1777 *
1778 * Time complexity: TODO.
1779 *
1780 * \example examples/simple/igraph_rewire.c
1781 */
1782
1783 #define REWIRE_ADJLIST_THRESHOLD 10
1784
igraph_rewire(igraph_t * graph,igraph_integer_t n,igraph_rewiring_t mode)1785 int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode) {
1786
1787 igraph_bool_t use_adjlist = n >= REWIRE_ADJLIST_THRESHOLD;
1788 return igraph_i_rewire(graph, n, mode, use_adjlist);
1789
1790 }
1791
1792 /**
1793 * Subgraph creation, old version: it copies the graph and then deletes
1794 * unneeded vertices.
1795 */
igraph_i_subgraph_copy_and_delete(const igraph_t * graph,igraph_t * res,const igraph_vs_t vids,igraph_vector_t * map,igraph_vector_t * invmap)1796 int igraph_i_subgraph_copy_and_delete(const igraph_t *graph, igraph_t *res,
1797 const igraph_vs_t vids,
1798 igraph_vector_t *map,
1799 igraph_vector_t *invmap) {
1800 long int no_of_nodes = igraph_vcount(graph);
1801 igraph_vector_t delete = IGRAPH_VECTOR_NULL;
1802 char *remain;
1803 long int i;
1804 igraph_vit_t vit;
1805
1806 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
1807 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
1808
1809 IGRAPH_VECTOR_INIT_FINALLY(&delete, 0);
1810 remain = igraph_Calloc(no_of_nodes, char);
1811 if (remain == 0) {
1812 IGRAPH_ERROR("subgraph failed", IGRAPH_ENOMEM);
1813 }
1814 IGRAPH_FINALLY(free, remain); /* TODO: hack */
1815 IGRAPH_CHECK(igraph_vector_reserve(&delete, no_of_nodes - IGRAPH_VIT_SIZE(vit)));
1816
1817 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
1818 remain[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
1819 }
1820
1821 for (i = 0; i < no_of_nodes; i++) {
1822
1823 IGRAPH_ALLOW_INTERRUPTION();
1824
1825 if (remain[i] == 0) {
1826 IGRAPH_CHECK(igraph_vector_push_back(&delete, i));
1827 }
1828 }
1829
1830 igraph_Free(remain);
1831 IGRAPH_FINALLY_CLEAN(1);
1832
1833 /* must set res->attr to 0 before calling igraph_copy */
1834 res->attr = 0; /* Why is this needed? TODO */
1835 IGRAPH_CHECK(igraph_copy(res, graph));
1836 IGRAPH_FINALLY(igraph_destroy, res);
1837 IGRAPH_CHECK(igraph_delete_vertices_idx(res, igraph_vss_vector(&delete),
1838 map, invmap));
1839
1840 igraph_vector_destroy(&delete);
1841 igraph_vit_destroy(&vit);
1842 IGRAPH_FINALLY_CLEAN(3);
1843 return 0;
1844 }
1845
1846 /**
1847 * Subgraph creation, new version: creates the new graph instead of
1848 * copying the old one.
1849 */
igraph_i_subgraph_create_from_scratch(const igraph_t * graph,igraph_t * res,const igraph_vs_t vids,igraph_vector_t * map,igraph_vector_t * invmap)1850 int igraph_i_subgraph_create_from_scratch(const igraph_t *graph,
1851 igraph_t *res,
1852 const igraph_vs_t vids,
1853 igraph_vector_t *map,
1854 igraph_vector_t *invmap) {
1855 igraph_bool_t directed = igraph_is_directed(graph);
1856 long int no_of_nodes = igraph_vcount(graph);
1857 long int no_of_new_nodes = 0;
1858 long int i, j, n;
1859 long int to;
1860 igraph_integer_t eid;
1861 igraph_vector_t vids_old2new, vids_new2old;
1862 igraph_vector_t eids_new2old;
1863 igraph_vector_t nei_edges;
1864 igraph_vector_t new_edges;
1865 igraph_vit_t vit;
1866 igraph_vector_t *my_vids_old2new = &vids_old2new,
1867 *my_vids_new2old = &vids_new2old;
1868
1869 /* The order of initialization is important here, they will be destroyed in the
1870 * opposite order */
1871 IGRAPH_VECTOR_INIT_FINALLY(&eids_new2old, 0);
1872 if (invmap) {
1873 my_vids_new2old = invmap;
1874 igraph_vector_clear(my_vids_new2old);
1875 } else {
1876 IGRAPH_VECTOR_INIT_FINALLY(&vids_new2old, 0);
1877 }
1878 IGRAPH_VECTOR_INIT_FINALLY(&new_edges, 0);
1879 IGRAPH_VECTOR_INIT_FINALLY(&nei_edges, 0);
1880 if (map) {
1881 my_vids_old2new = map;
1882 IGRAPH_CHECK(igraph_vector_resize(map, no_of_nodes));
1883 igraph_vector_null(map);
1884 } else {
1885 IGRAPH_VECTOR_INIT_FINALLY(&vids_old2new, no_of_nodes);
1886 }
1887
1888 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
1889 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
1890
1891 /* Calculate the mapping from the old node IDs to the new ones. The other
1892 * igraph_simplify implementation in igraph_i_simplify_copy_and_delete
1893 * ensures that the order of vertex IDs is kept during remapping (i.e.
1894 * if the old ID of vertex A is less than the old ID of vertex B, then
1895 * the same will also be true for the new IDs). To ensure compatibility
1896 * with the other implementation, we have to fetch the vertex IDs into
1897 * a vector first and then sort it. We temporarily use new_edges for that.
1898 */
1899 IGRAPH_CHECK(igraph_vit_as_vector(&vit, &nei_edges));
1900 igraph_vit_destroy(&vit);
1901 IGRAPH_FINALLY_CLEAN(1);
1902
1903 igraph_vector_sort(&nei_edges);
1904 n = igraph_vector_size(&nei_edges);
1905 for (i = 0; i < n; i++) {
1906 long int vid = (long int) VECTOR(nei_edges)[i];
1907 if (VECTOR(*my_vids_old2new)[vid] == 0) {
1908 IGRAPH_CHECK(igraph_vector_push_back(my_vids_new2old, vid));
1909 no_of_new_nodes++;
1910 VECTOR(*my_vids_old2new)[vid] = no_of_new_nodes;
1911 }
1912 }
1913
1914 /* Create the new edge list */
1915 for (i = 0; i < no_of_new_nodes; i++) {
1916 long int old_vid = (long int) VECTOR(*my_vids_new2old)[i];
1917 long int new_vid = i;
1918 igraph_bool_t skip_loop_edge;
1919
1920 IGRAPH_CHECK(igraph_incident(graph, &nei_edges, old_vid, IGRAPH_OUT));
1921 n = igraph_vector_size(&nei_edges);
1922
1923 if (directed) {
1924 /* directed graph; this is easier */
1925 for (j = 0; j < n; j++) {
1926 eid = (igraph_integer_t) VECTOR(nei_edges)[j];
1927
1928 to = (long int) VECTOR(*my_vids_old2new)[ (long int)IGRAPH_TO(graph, eid) ];
1929 if (!to) {
1930 continue;
1931 }
1932
1933 IGRAPH_CHECK(igraph_vector_push_back(&new_edges, new_vid));
1934 IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to - 1));
1935 IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));
1936 }
1937 } else {
1938 /* undirected graph. We need to be careful with loop edges as each
1939 * loop edge will appear twice. We use a boolean flag to skip every
1940 * second loop edge */
1941 skip_loop_edge = 0;
1942 for (j = 0; j < n; j++) {
1943 eid = (igraph_integer_t) VECTOR(nei_edges)[j];
1944
1945 if (IGRAPH_FROM(graph, eid) != old_vid) {
1946 /* avoid processing edges twice */
1947 continue;
1948 }
1949
1950 to = (long int) VECTOR(*my_vids_old2new)[ (long int)IGRAPH_TO(graph, eid) ];
1951 if (!to) {
1952 continue;
1953 }
1954 to -= 1;
1955
1956 if (new_vid == to) {
1957 /* this is a loop edge; check whether we need to skip it */
1958 skip_loop_edge = !skip_loop_edge;
1959 if (skip_loop_edge) {
1960 continue;
1961 }
1962 }
1963
1964 IGRAPH_CHECK(igraph_vector_push_back(&new_edges, new_vid));
1965 IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to));
1966 IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));
1967 }
1968 }
1969 }
1970
1971 /* Get rid of some vectors that are not needed anymore */
1972 if (!map) {
1973 igraph_vector_destroy(&vids_old2new);
1974 IGRAPH_FINALLY_CLEAN(1);
1975 }
1976 igraph_vector_destroy(&nei_edges);
1977 IGRAPH_FINALLY_CLEAN(1);
1978
1979 /* Create the new graph */
1980 IGRAPH_CHECK(igraph_create(res, &new_edges, (igraph_integer_t)
1981 no_of_new_nodes, directed));
1982 IGRAPH_I_ATTRIBUTE_DESTROY(res);
1983
1984 /* Now we can also get rid of the new_edges vector */
1985 igraph_vector_destroy(&new_edges);
1986 IGRAPH_FINALLY_CLEAN(1);
1987
1988 /* Make sure that the newly created graph is destroyed if something happens from
1989 * now on */
1990 IGRAPH_FINALLY(igraph_destroy, res);
1991
1992 /* Copy the graph attributes */
1993 IGRAPH_CHECK(igraph_i_attribute_copy(res, graph,
1994 /* ga = */ 1, /* va = */ 0, /* ea = */ 0));
1995
1996 /* Copy the vertex attributes */
1997 IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, res,
1998 my_vids_new2old));
1999
2000 /* Copy the edge attributes */
2001 IGRAPH_CHECK(igraph_i_attribute_permute_edges(graph, res, &eids_new2old));
2002
2003 if (!invmap) {
2004 igraph_vector_destroy(my_vids_new2old);
2005 IGRAPH_FINALLY_CLEAN(1);
2006 }
2007 igraph_vector_destroy(&eids_new2old);
2008 IGRAPH_FINALLY_CLEAN(2); /* 1 + 1 since we don't need to destroy res */
2009
2010 return 0;
2011 }
2012
2013 /**
2014 * \ingroup structural
2015 * \function igraph_subgraph
2016 * \brief Creates a subgraph induced by the specified vertices.
2017 *
2018 * </para><para>
2019 * This function is an alias to \ref igraph_induced_subgraph(), it is
2020 * left here to ensure API compatibility with igraph versions prior to 0.6.
2021 *
2022 * </para><para>
2023 * This function collects the specified vertices and all edges between
2024 * them to a new graph.
2025 * As the vertex ids in a graph always start with zero, this function
2026 * very likely needs to reassign ids to the vertices.
2027 * \param graph The graph object.
2028 * \param res The subgraph, another graph object will be stored here,
2029 * do \em not initialize this object before calling this
2030 * function, and call \ref igraph_destroy() on it if you don't need
2031 * it any more.
2032 * \param vids A vertex selector describing which vertices to keep.
2033 * \return Error code:
2034 * \c IGRAPH_ENOMEM, not enough memory for
2035 * temporary data.
2036 * \c IGRAPH_EINVVID, invalid vertex id in
2037 * \p vids.
2038 *
2039 * Time complexity: O(|V|+|E|),
2040 * |V| and
2041 * |E| are the number of vertices and
2042 * edges in the original graph.
2043 *
2044 * \sa \ref igraph_delete_vertices() to delete the specified set of
2045 * vertices from a graph, the opposite of this function.
2046 */
2047
igraph_subgraph(const igraph_t * graph,igraph_t * res,const igraph_vs_t vids)2048 int igraph_subgraph(const igraph_t *graph, igraph_t *res,
2049 const igraph_vs_t vids) {
2050 IGRAPH_WARNING("igraph_subgraph is deprecated from igraph 0.6, "
2051 "use igraph_induced_subgraph instead");
2052 return igraph_induced_subgraph(graph, res, vids, IGRAPH_SUBGRAPH_AUTO);
2053 }
2054
2055 /**
2056 * \ingroup structural
2057 * \function igraph_induced_subgraph
2058 * \brief Creates a subgraph induced by the specified vertices.
2059 *
2060 * </para><para>
2061 * This function collects the specified vertices and all edges between
2062 * them to a new graph.
2063 * As the vertex ids in a graph always start with zero, this function
2064 * very likely needs to reassign ids to the vertices.
2065 * \param graph The graph object.
2066 * \param res The subgraph, another graph object will be stored here,
2067 * do \em not initialize this object before calling this
2068 * function, and call \ref igraph_destroy() on it if you don't need
2069 * it any more.
2070 * \param vids A vertex selector describing which vertices to keep.
2071 * \param impl This parameter selects which implementation should we
2072 * use when constructing the new graph. Basically there are two
2073 * possibilities: \c IGRAPH_SUBGRAPH_COPY_AND_DELETE copies the
2074 * existing graph and deletes the vertices that are not needed
2075 * in the new graph, while \c IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH
2076 * constructs the new graph from scratch without copying the old
2077 * one. The latter is more efficient if you are extracting a
2078 * relatively small subpart of a very large graph, while the
2079 * former is better if you want to extract a subgraph whose size
2080 * is comparable to the size of the whole graph. There is a third
2081 * possibility: \c IGRAPH_SUBGRAPH_AUTO will select one of the
2082 * two methods automatically based on the ratio of the number
2083 * of vertices in the new and the old graph.
2084 *
2085 * \return Error code:
2086 * \c IGRAPH_ENOMEM, not enough memory for
2087 * temporary data.
2088 * \c IGRAPH_EINVVID, invalid vertex id in
2089 * \p vids.
2090 *
2091 * Time complexity: O(|V|+|E|),
2092 * |V| and
2093 * |E| are the number of vertices and
2094 * edges in the original graph.
2095 *
2096 * \sa \ref igraph_delete_vertices() to delete the specified set of
2097 * vertices from a graph, the opposite of this function.
2098 */
igraph_induced_subgraph(const igraph_t * graph,igraph_t * res,const igraph_vs_t vids,igraph_subgraph_implementation_t impl)2099 int igraph_induced_subgraph(const igraph_t *graph, igraph_t *res,
2100 const igraph_vs_t vids, igraph_subgraph_implementation_t impl) {
2101 return igraph_induced_subgraph_map(graph, res, vids, impl, /* map= */ 0,
2102 /* invmap= */ 0);
2103 }
2104
igraph_i_induced_subgraph_suggest_implementation(const igraph_t * graph,const igraph_vs_t vids,igraph_subgraph_implementation_t * result)2105 int igraph_i_induced_subgraph_suggest_implementation(
2106 const igraph_t *graph, const igraph_vs_t vids,
2107 igraph_subgraph_implementation_t *result) {
2108 double ratio;
2109 igraph_integer_t num_vs;
2110
2111 if (igraph_vs_is_all(&vids)) {
2112 ratio = 1.0;
2113 } else {
2114 IGRAPH_CHECK(igraph_vs_size(graph, &vids, &num_vs));
2115 ratio = (igraph_real_t) num_vs / igraph_vcount(graph);
2116 }
2117
2118 /* TODO: needs benchmarking; threshold was chosen totally arbitrarily */
2119 if (ratio > 0.5) {
2120 *result = IGRAPH_SUBGRAPH_COPY_AND_DELETE;
2121 } else {
2122 *result = IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH;
2123 }
2124
2125 return 0;
2126 }
2127
igraph_induced_subgraph_map(const igraph_t * graph,igraph_t * res,const igraph_vs_t vids,igraph_subgraph_implementation_t impl,igraph_vector_t * map,igraph_vector_t * invmap)2128 int igraph_induced_subgraph_map(const igraph_t *graph, igraph_t *res,
2129 const igraph_vs_t vids,
2130 igraph_subgraph_implementation_t impl,
2131 igraph_vector_t *map,
2132 igraph_vector_t *invmap) {
2133
2134 if (impl == IGRAPH_SUBGRAPH_AUTO) {
2135 IGRAPH_CHECK(igraph_i_induced_subgraph_suggest_implementation(graph, vids, &impl));
2136 }
2137
2138 switch (impl) {
2139 case IGRAPH_SUBGRAPH_COPY_AND_DELETE:
2140 return igraph_i_subgraph_copy_and_delete(graph, res, vids, map, invmap);
2141
2142 case IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH:
2143 return igraph_i_subgraph_create_from_scratch(graph, res, vids, map,
2144 invmap);
2145
2146 default:
2147 IGRAPH_ERROR("unknown subgraph implementation type", IGRAPH_EINVAL);
2148 }
2149 return 0;
2150 }
2151
2152 /**
2153 * \ingroup structural
2154 * \function igraph_subgraph_edges
2155 * \brief Creates a subgraph with the specified edges and their endpoints.
2156 *
2157 * </para><para>
2158 * This function collects the specified edges and their endpoints to a new
2159 * graph.
2160 * As the vertex ids in a graph always start with zero, this function
2161 * very likely needs to reassign ids to the vertices.
2162 * \param graph The graph object.
2163 * \param res The subgraph, another graph object will be stored here,
2164 * do \em not initialize this object before calling this
2165 * function, and call \ref igraph_destroy() on it if you don't need
2166 * it any more.
2167 * \param eids An edge selector describing which edges to keep.
2168 * \param delete_vertices Whether to delete the vertices not incident on any
2169 * of the specified edges as well. If \c FALSE, the number of vertices
2170 * in the result graph will always be equal to the number of vertices
2171 * in the input graph.
2172 * \return Error code:
2173 * \c IGRAPH_ENOMEM, not enough memory for
2174 * temporary data.
2175 * \c IGRAPH_EINVEID, invalid edge id in
2176 * \p eids.
2177 *
2178 * Time complexity: O(|V|+|E|),
2179 * |V| and
2180 * |E| are the number of vertices and
2181 * edges in the original graph.
2182 *
2183 * \sa \ref igraph_delete_edges() to delete the specified set of
2184 * edges from a graph, the opposite of this function.
2185 */
2186
igraph_subgraph_edges(const igraph_t * graph,igraph_t * res,const igraph_es_t eids,igraph_bool_t delete_vertices)2187 int igraph_subgraph_edges(const igraph_t *graph, igraph_t *res,
2188 const igraph_es_t eids, igraph_bool_t delete_vertices) {
2189
2190 long int no_of_nodes = igraph_vcount(graph);
2191 long int no_of_edges = igraph_ecount(graph);
2192 igraph_vector_t delete = IGRAPH_VECTOR_NULL;
2193 char *vremain, *eremain;
2194 long int i;
2195 igraph_eit_t eit;
2196
2197 IGRAPH_CHECK(igraph_eit_create(graph, eids, &eit));
2198 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
2199
2200 IGRAPH_VECTOR_INIT_FINALLY(&delete, 0);
2201 vremain = igraph_Calloc(no_of_nodes, char);
2202 if (vremain == 0) {
2203 IGRAPH_ERROR("subgraph_edges failed", IGRAPH_ENOMEM);
2204 }
2205 eremain = igraph_Calloc(no_of_edges, char);
2206 if (eremain == 0) {
2207 IGRAPH_ERROR("subgraph_edges failed", IGRAPH_ENOMEM);
2208 }
2209 IGRAPH_FINALLY(free, vremain); /* TODO: hack */
2210 IGRAPH_FINALLY(free, eremain); /* TODO: hack */
2211 IGRAPH_CHECK(igraph_vector_reserve(&delete, no_of_edges - IGRAPH_EIT_SIZE(eit)));
2212
2213 /* Collect the vertex and edge IDs that will remain */
2214 for (IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
2215 igraph_integer_t from, to;
2216 long int eid = (long int) IGRAPH_EIT_GET(eit);
2217 IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) eid, &from, &to));
2218 eremain[eid] = vremain[(long int)from] = vremain[(long int)to] = 1;
2219 }
2220
2221 /* Collect the edge IDs to be deleted */
2222 for (i = 0; i < no_of_edges; i++) {
2223 IGRAPH_ALLOW_INTERRUPTION();
2224 if (eremain[i] == 0) {
2225 IGRAPH_CHECK(igraph_vector_push_back(&delete, i));
2226 }
2227 }
2228
2229 igraph_Free(eremain);
2230 IGRAPH_FINALLY_CLEAN(1);
2231
2232 /* Delete the unnecessary edges */
2233 /* must set res->attr to 0 before calling igraph_copy */
2234 res->attr = 0; /* Why is this needed? TODO */
2235 IGRAPH_CHECK(igraph_copy(res, graph));
2236 IGRAPH_FINALLY(igraph_destroy, res);
2237 IGRAPH_CHECK(igraph_delete_edges(res, igraph_ess_vector(&delete)));
2238
2239 if (delete_vertices) {
2240 /* Collect the vertex IDs to be deleted */
2241 igraph_vector_clear(&delete);
2242 for (i = 0; i < no_of_nodes; i++) {
2243 IGRAPH_ALLOW_INTERRUPTION();
2244 if (vremain[i] == 0) {
2245 IGRAPH_CHECK(igraph_vector_push_back(&delete, i));
2246 }
2247 }
2248 }
2249
2250 igraph_Free(vremain);
2251 IGRAPH_FINALLY_CLEAN(1);
2252
2253 /* Delete the unnecessary vertices */
2254 if (delete_vertices) {
2255 IGRAPH_CHECK(igraph_delete_vertices(res, igraph_vss_vector(&delete)));
2256 }
2257
2258 igraph_vector_destroy(&delete);
2259 igraph_eit_destroy(&eit);
2260 IGRAPH_FINALLY_CLEAN(3);
2261 return 0;
2262 }
2263
2264 void igraph_i_simplify_free(igraph_vector_ptr_t *p);
2265
igraph_i_simplify_free(igraph_vector_ptr_t * p)2266 void igraph_i_simplify_free(igraph_vector_ptr_t *p) {
2267 long int i, n = igraph_vector_ptr_size(p);
2268 for (i = 0; i < n; i++) {
2269 igraph_vector_t *v = VECTOR(*p)[i];
2270 if (v) {
2271 igraph_vector_destroy(v);
2272 }
2273 }
2274 igraph_vector_ptr_destroy(p);
2275 }
2276
2277 /**
2278 * \ingroup structural
2279 * \function igraph_simplify
2280 * \brief Removes loop and/or multiple edges from the graph.
2281 *
2282 * \param graph The graph object.
2283 * \param multiple Logical, if true, multiple edges will be removed.
2284 * \param loops Logical, if true, loops (self edges) will be removed.
2285 * \param edge_comb What to do with the edge attributes. See the igraph
2286 * manual section about attributes for details.
2287 * \return Error code:
2288 * \c IGRAPH_ENOMEM if we are out of memory.
2289 *
2290 * Time complexity: O(|V|+|E|).
2291 *
2292 * \example examples/simple/igraph_simplify.c
2293 */
2294
igraph_simplify(igraph_t * graph,igraph_bool_t multiple,igraph_bool_t loops,const igraph_attribute_combination_t * edge_comb)2295 int igraph_simplify(igraph_t *graph, igraph_bool_t multiple,
2296 igraph_bool_t loops,
2297 const igraph_attribute_combination_t *edge_comb) {
2298
2299 igraph_vector_t edges = IGRAPH_VECTOR_NULL;
2300 long int no_of_nodes = igraph_vcount(graph);
2301 long int no_of_edges = igraph_ecount(graph);
2302 long int edge;
2303 igraph_bool_t attr = edge_comb && igraph_has_attribute_table();
2304 long int from, to, pfrom = -1, pto = -2;
2305 igraph_t res;
2306 igraph_es_t es;
2307 igraph_eit_t eit;
2308 igraph_vector_t mergeinto;
2309 long int actedge;
2310
2311 if (!multiple && !loops)
2312 /* nothing to do */
2313 {
2314 return IGRAPH_SUCCESS;
2315 }
2316
2317 if (!multiple) {
2318 /* removing loop edges only, this is simple. No need to combine anything
2319 * and the whole process can be done in-place */
2320 IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
2321 IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID));
2322 IGRAPH_FINALLY(igraph_es_destroy, &es);
2323 IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
2324 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
2325
2326 while (!IGRAPH_EIT_END(eit)) {
2327 edge = IGRAPH_EIT_GET(eit);
2328 from = IGRAPH_FROM(graph, edge);
2329 to = IGRAPH_TO(graph, edge);
2330 if (from == to) {
2331 IGRAPH_CHECK(igraph_vector_push_back(&edges, edge));
2332 }
2333 IGRAPH_EIT_NEXT(eit);
2334 }
2335
2336 igraph_eit_destroy(&eit);
2337 igraph_es_destroy(&es);
2338 IGRAPH_FINALLY_CLEAN(2);
2339
2340 if (igraph_vector_size(&edges) > 0) {
2341 IGRAPH_CHECK(igraph_delete_edges(graph, igraph_ess_vector(&edges)));
2342 }
2343
2344 igraph_vector_destroy(&edges);
2345 IGRAPH_FINALLY_CLEAN(1);
2346
2347 return IGRAPH_SUCCESS;
2348 }
2349
2350 if (attr) {
2351 IGRAPH_VECTOR_INIT_FINALLY(&mergeinto, no_of_edges);
2352 }
2353 IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
2354 IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges * 2));
2355
2356 IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_FROM));
2357 IGRAPH_FINALLY(igraph_es_destroy, &es);
2358 IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
2359 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
2360
2361 for (actedge = -1; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
2362 edge = IGRAPH_EIT_GET(eit);
2363 from = IGRAPH_FROM(graph, edge);
2364 to = IGRAPH_TO(graph, edge);
2365
2366 if (loops && from == to) {
2367 /* Loop edge to be removed */
2368 if (attr) {
2369 VECTOR(mergeinto)[edge] = -1;
2370 }
2371 } else if (multiple && from == pfrom && to == pto) {
2372 /* Multiple edge to be contracted */
2373 if (attr) {
2374 VECTOR(mergeinto)[edge] = actedge;
2375 }
2376 } else {
2377 /* Edge to be kept */
2378 igraph_vector_push_back(&edges, from);
2379 igraph_vector_push_back(&edges, to);
2380 if (attr) {
2381 actedge++;
2382 VECTOR(mergeinto)[edge] = actedge;
2383 }
2384 }
2385 pfrom = from; pto = to;
2386 }
2387
2388 igraph_eit_destroy(&eit);
2389 igraph_es_destroy(&es);
2390 IGRAPH_FINALLY_CLEAN(2);
2391
2392 IGRAPH_CHECK(igraph_create(&res, &edges, (igraph_integer_t) no_of_nodes,
2393 igraph_is_directed(graph)));
2394
2395 igraph_vector_destroy(&edges);
2396 IGRAPH_FINALLY_CLEAN(1);
2397
2398 IGRAPH_FINALLY(igraph_destroy, &res);
2399
2400 IGRAPH_I_ATTRIBUTE_DESTROY(&res);
2401 IGRAPH_I_ATTRIBUTE_COPY(&res, graph, /*graph=*/ 1,
2402 /*vertex=*/ 1, /*edge=*/ 0);
2403
2404 if (attr) {
2405 igraph_fixed_vectorlist_t vl;
2406 IGRAPH_CHECK(igraph_fixed_vectorlist_convert(&vl, &mergeinto,
2407 actedge + 1));
2408 IGRAPH_FINALLY(igraph_fixed_vectorlist_destroy, &vl);
2409
2410 IGRAPH_CHECK(igraph_i_attribute_combine_edges(graph, &res, &vl.v,
2411 edge_comb));
2412
2413 igraph_fixed_vectorlist_destroy(&vl);
2414 igraph_vector_destroy(&mergeinto);
2415 IGRAPH_FINALLY_CLEAN(2);
2416 }
2417
2418 IGRAPH_FINALLY_CLEAN(1);
2419 igraph_destroy(graph);
2420 *graph = res;
2421
2422 return 0;
2423 }
2424
2425 /**
2426 * \ingroup structural
2427 * \function igraph_reciprocity
2428 * \brief Calculates the reciprocity of a directed graph.
2429 *
2430 * </para><para>
2431 * The measure of reciprocity defines the proportion of mutual
2432 * connections, in a directed graph. It is most commonly defined as
2433 * the probability that the opposite counterpart of a directed edge is
2434 * also included in the graph. In adjacency matrix notation:
2435 * <code>sum(i, j, (A.*A')ij) / sum(i, j, Aij)</code>, where
2436 * <code>A.*A'</code> is the element-wise product of matrix
2437 * <code>A</code> and its transpose. This measure is
2438 * calculated if the \p mode argument is \c
2439 * IGRAPH_RECIPROCITY_DEFAULT.
2440 *
2441 * </para><para>
2442 * Prior to igraph version 0.6, another measure was implemented,
2443 * defined as the probability of mutual connection between a vertex
2444 * pair if we know that there is a (possibly non-mutual) connection
2445 * between them. In other words, (unordered) vertex pairs are
2446 * classified into three groups: (1) disconnected, (2)
2447 * non-reciprocally connected, (3) reciprocally connected.
2448 * The result is the size of group (3), divided by the sum of group
2449 * sizes (2)+(3). This measure is calculated if \p mode is \c
2450 * IGRAPH_RECIPROCITY_RATIO.
2451 *
2452 * \param graph The graph object.
2453 * \param res Pointer to an \c igraph_real_t which will contain the result.
2454 * \param ignore_loops Whether to ignore loop edges.
2455 * \param mode Type of reciprocity to calculate, possible values are
2456 * \c IGRAPH_RECIPROCITY_DEFAULT and \c IGRAPH_RECIPROCITY_RATIO,
2457 * please see their description above.
2458 * \return Error code:
2459 * \c IGRAPH_EINVAL: graph has no edges
2460 * \c IGRAPH_ENOMEM: not enough memory for
2461 * temporary data.
2462 *
2463 * Time complexity: O(|V|+|E|), |V| is the number of vertices,
2464 * |E| is the number of edges.
2465 *
2466 * \example examples/simple/igraph_reciprocity.c
2467 */
2468
igraph_reciprocity(const igraph_t * graph,igraph_real_t * res,igraph_bool_t ignore_loops,igraph_reciprocity_t mode)2469 int igraph_reciprocity(const igraph_t *graph, igraph_real_t *res,
2470 igraph_bool_t ignore_loops,
2471 igraph_reciprocity_t mode) {
2472
2473 igraph_integer_t nonrec = 0, rec = 0, loops = 0;
2474 igraph_vector_t inneis, outneis;
2475 long int i;
2476 long int no_of_nodes = igraph_vcount(graph);
2477
2478 if (mode != IGRAPH_RECIPROCITY_DEFAULT &&
2479 mode != IGRAPH_RECIPROCITY_RATIO) {
2480 IGRAPH_ERROR("Invalid reciprocity type", IGRAPH_EINVAL);
2481 }
2482
2483 /* THIS IS AN EXIT HERE !!!!!!!!!!!!!! */
2484 if (!igraph_is_directed(graph)) {
2485 *res = 1.0;
2486 return 0;
2487 }
2488
2489 IGRAPH_VECTOR_INIT_FINALLY(&inneis, 0);
2490 IGRAPH_VECTOR_INIT_FINALLY(&outneis, 0);
2491
2492 for (i = 0; i < no_of_nodes; i++) {
2493 long int ip, op;
2494 igraph_neighbors(graph, &inneis, (igraph_integer_t) i, IGRAPH_IN);
2495 igraph_neighbors(graph, &outneis, (igraph_integer_t) i, IGRAPH_OUT);
2496
2497 ip = op = 0;
2498 while (ip < igraph_vector_size(&inneis) &&
2499 op < igraph_vector_size(&outneis)) {
2500 if (VECTOR(inneis)[ip] < VECTOR(outneis)[op]) {
2501 nonrec += 1;
2502 ip++;
2503 } else if (VECTOR(inneis)[ip] > VECTOR(outneis)[op]) {
2504 nonrec += 1;
2505 op++;
2506 } else {
2507
2508 /* loop edge? */
2509 if (VECTOR(inneis)[ip] == i) {
2510 loops += 1;
2511 if (!ignore_loops) {
2512 rec += 1;
2513 }
2514 } else {
2515 rec += 1;
2516 }
2517
2518 ip++;
2519 op++;
2520 }
2521 }
2522 nonrec += (igraph_vector_size(&inneis) - ip) +
2523 (igraph_vector_size(&outneis) - op);
2524 }
2525
2526 if (mode == IGRAPH_RECIPROCITY_DEFAULT) {
2527 if (ignore_loops) {
2528 *res = (igraph_real_t) rec / (igraph_ecount(graph) - loops);
2529 } else {
2530 *res = (igraph_real_t) rec / (igraph_ecount(graph));
2531 }
2532 } else if (mode == IGRAPH_RECIPROCITY_RATIO) {
2533 *res = (igraph_real_t) rec / (rec + nonrec);
2534 }
2535
2536 igraph_vector_destroy(&inneis);
2537 igraph_vector_destroy(&outneis);
2538 IGRAPH_FINALLY_CLEAN(2);
2539 return 0;
2540 }
2541
2542 /**
2543 * \function igraph_constraint
2544 * \brief Burt's constraint scores.
2545 *
2546 * </para><para>
2547 * This function calculates Burt's constraint scores for the given
2548 * vertices, also known as structural holes.
2549 *
2550 * </para><para>
2551 * Burt's constraint is higher if ego has less, or mutually stronger
2552 * related (i.e. more redundant) contacts. Burt's measure of
2553 * constraint, C[i], of vertex i's ego network V[i], is defined for
2554 * directed and valued graphs,
2555 * <blockquote><para>
2556 * C[i] = sum( sum( (p[i,q] p[q,j])^2, q in V[i], q != i,j ), j in
2557 * V[], j != i)
2558 * </para></blockquote>
2559 * for a graph of order (i.e. number of vertices) N, where proportional
2560 * tie strengths are defined as
2561 * <blockquote><para>
2562 * p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),
2563 * </para></blockquote>
2564 * a[i,j] are elements of A and
2565 * the latter being the graph adjacency matrix. For isolated vertices,
2566 * constraint is undefined.
2567 *
2568 * </para><para>
2569 * Burt, R.S. (2004). Structural holes and good ideas. American
2570 * Journal of Sociology 110, 349-399.
2571 *
2572 * </para><para>
2573 * The first R version of this function was contributed by Jeroen
2574 * Bruggeman.
2575 * \param graph A graph object.
2576 * \param res Pointer to an initialized vector, the result will be
2577 * stored here. The vector will be resized to have the
2578 * appropriate size for holding the result.
2579 * \param vids Vertex selector containing the vertices for which the
2580 * constraint should be calculated.
2581 * \param weights Vector giving the weights of the edges. If it is
2582 * \c NULL then each edge is supposed to have the same weight.
2583 * \return Error code.
2584 *
2585 * Time complexity: O(|V|+E|+n*d^2), n is the number of vertices for
2586 * which the constraint is calculated and d is the average degree, |V|
2587 * is the number of vertices, |E| the number of edges in the
2588 * graph. If the weights argument is \c NULL then the time complexity
2589 * is O(|V|+n*d^2).
2590 */
2591
igraph_constraint(const igraph_t * graph,igraph_vector_t * res,igraph_vs_t vids,const igraph_vector_t * weights)2592 int igraph_constraint(const igraph_t *graph, igraph_vector_t *res,
2593 igraph_vs_t vids, const igraph_vector_t *weights) {
2594
2595 long int no_of_nodes = igraph_vcount(graph);
2596 long int no_of_edges = igraph_ecount(graph);
2597 igraph_vit_t vit;
2598 long int nodes_to_calc;
2599 long int a, b, c, i, j, q;
2600 igraph_integer_t edge, from, to, edge2, from2, to2;
2601
2602 igraph_vector_t contrib;
2603 igraph_vector_t degree;
2604 igraph_vector_t ineis_in, ineis_out, jneis_in, jneis_out;
2605
2606 if (weights != 0 && igraph_vector_size(weights) != no_of_edges) {
2607 IGRAPH_ERROR("Invalid length of weight vector", IGRAPH_EINVAL);
2608 }
2609
2610 IGRAPH_VECTOR_INIT_FINALLY(&contrib, no_of_nodes);
2611 IGRAPH_VECTOR_INIT_FINALLY(°ree, no_of_nodes);
2612 IGRAPH_VECTOR_INIT_FINALLY(&ineis_in, 0);
2613 IGRAPH_VECTOR_INIT_FINALLY(&ineis_out, 0);
2614 IGRAPH_VECTOR_INIT_FINALLY(&jneis_in, 0);
2615 IGRAPH_VECTOR_INIT_FINALLY(&jneis_out, 0);
2616
2617 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
2618 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
2619 nodes_to_calc = IGRAPH_VIT_SIZE(vit);
2620
2621 if (weights == 0) {
2622 IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(),
2623 IGRAPH_ALL, IGRAPH_NO_LOOPS));
2624 } else {
2625 for (a = 0; a < no_of_edges; a++) {
2626 igraph_edge(graph, (igraph_integer_t) a, &from, &to);
2627 if (from != to) {
2628 VECTOR(degree)[(long int) from] += VECTOR(*weights)[a];
2629 VECTOR(degree)[(long int) to ] += VECTOR(*weights)[a];
2630 }
2631 }
2632 }
2633
2634 IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
2635 igraph_vector_null(res);
2636
2637 for (a = 0; a < nodes_to_calc; a++, IGRAPH_VIT_NEXT(vit)) {
2638 i = IGRAPH_VIT_GET(vit);
2639
2640 /* get neighbors of i */
2641 IGRAPH_CHECK(igraph_incident(graph, &ineis_in, (igraph_integer_t) i,
2642 IGRAPH_IN));
2643 IGRAPH_CHECK(igraph_incident(graph, &ineis_out, (igraph_integer_t) i,
2644 IGRAPH_OUT));
2645
2646 /* NaN for isolates */
2647 if (igraph_vector_size(&ineis_in) == 0 &&
2648 igraph_vector_size(&ineis_out) == 0) {
2649 VECTOR(*res)[a] = IGRAPH_NAN;
2650 }
2651
2652 /* zero their contribution */
2653 for (b = 0; b < igraph_vector_size(&ineis_in); b++) {
2654 edge = (igraph_integer_t) VECTOR(ineis_in)[b];
2655 igraph_edge(graph, edge, &from, &to);
2656 if (to == i) {
2657 to = from;
2658 }
2659 j = to;
2660 VECTOR(contrib)[j] = 0.0;
2661 }
2662 for (b = 0; b < igraph_vector_size(&ineis_out); b++) {
2663 edge = (igraph_integer_t) VECTOR(ineis_out)[b];
2664 igraph_edge(graph, edge, &from, &to);
2665 if (to == i) {
2666 to = from;
2667 }
2668 j = to;
2669 VECTOR(contrib)[j] = 0.0;
2670 }
2671
2672 /* add the direct contributions, in-neighbors and out-neighbors */
2673 for (b = 0; b < igraph_vector_size(&ineis_in); b++) {
2674 edge = (igraph_integer_t) VECTOR(ineis_in)[b];
2675 igraph_edge(graph, edge, &from, &to);
2676 if (to == i) {
2677 to = from;
2678 }
2679 j = to;
2680 if (i != j) { /* excluding loops */
2681 if (weights) {
2682 VECTOR(contrib)[j] +=
2683 VECTOR(*weights)[(long int)edge] / VECTOR(degree)[i];
2684 } else {
2685 VECTOR(contrib)[j] += 1.0 / VECTOR(degree)[i];
2686 }
2687 }
2688 }
2689 if (igraph_is_directed(graph)) {
2690 for (b = 0; b < igraph_vector_size(&ineis_out); b++) {
2691 edge = (igraph_integer_t) VECTOR(ineis_out)[b];
2692 igraph_edge(graph, edge, &from, &to);
2693 if (to == i) {
2694 to = from;
2695 }
2696 j = to;
2697 if (i != j) {
2698 if (weights) {
2699 VECTOR(contrib)[j] +=
2700 VECTOR(*weights)[(long int)edge] / VECTOR(degree)[i];
2701 } else {
2702 VECTOR(contrib)[j] += 1.0 / VECTOR(degree)[i];
2703 }
2704 }
2705 }
2706 }
2707
2708 /* add the indirect contributions, in-in, in-out, out-in, out-out */
2709 for (b = 0; b < igraph_vector_size(&ineis_in); b++) {
2710 edge = (igraph_integer_t) VECTOR(ineis_in)[b];
2711 igraph_edge(graph, edge, &from, &to);
2712 if (to == i) {
2713 to = from;
2714 }
2715 j = to;
2716 if (i == j) {
2717 continue;
2718 }
2719 IGRAPH_CHECK(igraph_incident(graph, &jneis_in, (igraph_integer_t) j,
2720 IGRAPH_IN));
2721 IGRAPH_CHECK(igraph_incident(graph, &jneis_out, (igraph_integer_t) j,
2722 IGRAPH_OUT));
2723 for (c = 0; c < igraph_vector_size(&jneis_in); c++) {
2724 edge2 = (igraph_integer_t) VECTOR(jneis_in)[c];
2725 igraph_edge(graph, edge2, &from2, &to2);
2726 if (to2 == j) {
2727 to2 = from2;
2728 }
2729 q = to2;
2730 if (j != q) {
2731 if (weights) {
2732 VECTOR(contrib)[q] +=
2733 VECTOR(*weights)[(long int)edge] *
2734 VECTOR(*weights)[(long int)edge2] /
2735 VECTOR(degree)[i] / VECTOR(degree)[j];
2736 } else {
2737 VECTOR(contrib)[q] += 1 / VECTOR(degree)[i] / VECTOR(degree)[j];
2738 }
2739 }
2740 }
2741 if (igraph_is_directed(graph)) {
2742 for (c = 0; c < igraph_vector_size(&jneis_out); c++) {
2743 edge2 = (igraph_integer_t) VECTOR(jneis_out)[c];
2744 igraph_edge(graph, edge2, &from2, &to2);
2745 if (to2 == j) {
2746 to2 = from2;
2747 }
2748 q = to2;
2749 if (j != q) {
2750 if (weights) {
2751 VECTOR(contrib)[q] +=
2752 VECTOR(*weights)[(long int)edge] *
2753 VECTOR(*weights)[(long int)edge2] /
2754 VECTOR(degree)[i] / VECTOR(degree)[j];
2755 } else {
2756 VECTOR(contrib)[q] += 1 / VECTOR(degree)[i] / VECTOR(degree)[j];
2757 }
2758 }
2759 }
2760 }
2761 }
2762 if (igraph_is_directed(graph)) {
2763 for (b = 0; b < igraph_vector_size(&ineis_out); b++) {
2764 edge = (igraph_integer_t) VECTOR(ineis_out)[b];
2765 igraph_edge(graph, edge, &from, &to);
2766 if (to == i) {
2767 to = from;
2768 }
2769 j = to;
2770 if (i == j) {
2771 continue;
2772 }
2773 IGRAPH_CHECK(igraph_incident(graph, &jneis_in, (igraph_integer_t) j,
2774 IGRAPH_IN));
2775 IGRAPH_CHECK(igraph_incident(graph, &jneis_out, (igraph_integer_t) j,
2776 IGRAPH_OUT));
2777 for (c = 0; c < igraph_vector_size(&jneis_in); c++) {
2778 edge2 = (igraph_integer_t) VECTOR(jneis_in)[c];
2779 igraph_edge(graph, edge2, &from2, &to2);
2780 if (to2 == j) {
2781 to2 = from2;
2782 }
2783 q = to2;
2784 if (j != q) {
2785 if (weights) {
2786 VECTOR(contrib)[q] +=
2787 VECTOR(*weights)[(long int)edge] *
2788 VECTOR(*weights)[(long int)edge2] /
2789 VECTOR(degree)[i] / VECTOR(degree)[j];
2790 } else {
2791 VECTOR(contrib)[q] += 1 / VECTOR(degree)[i] / VECTOR(degree)[j];
2792 }
2793 }
2794 }
2795 for (c = 0; c < igraph_vector_size(&jneis_out); c++) {
2796 edge2 = (igraph_integer_t) VECTOR(jneis_out)[c];
2797 igraph_edge(graph, edge2, &from2, &to2);
2798 if (to2 == j) {
2799 to2 = from2;
2800 }
2801 q = to2;
2802 if (j != q) {
2803 if (weights) {
2804 VECTOR(contrib)[q] +=
2805 VECTOR(*weights)[(long int)edge] *
2806 VECTOR(*weights)[(long int)edge2] /
2807 VECTOR(degree)[i] / VECTOR(degree)[j];
2808 } else {
2809 VECTOR(contrib)[q] += 1 / VECTOR(degree)[i] / VECTOR(degree)[j];
2810 }
2811 }
2812 }
2813 }
2814 }
2815
2816 /* squared sum of the contributions */
2817 for (b = 0; b < igraph_vector_size(&ineis_in); b++) {
2818 edge = (igraph_integer_t) VECTOR(ineis_in)[b];
2819 igraph_edge(graph, edge, &from, &to);
2820 if (to == i) {
2821 to = from;
2822 }
2823 j = to;
2824 if (i == j) {
2825 continue;
2826 }
2827 VECTOR(*res)[a] += VECTOR(contrib)[j] * VECTOR(contrib)[j];
2828 VECTOR(contrib)[j] = 0.0;
2829 }
2830 if (igraph_is_directed(graph)) {
2831 for (b = 0; b < igraph_vector_size(&ineis_out); b++) {
2832 edge = (igraph_integer_t) VECTOR(ineis_out)[b];
2833 igraph_edge(graph, edge, &from, &to);
2834 if (to == i) {
2835 to = from;
2836 }
2837 j = to;
2838 if (i == j) {
2839 continue;
2840 }
2841 VECTOR(*res)[a] += VECTOR(contrib)[j] * VECTOR(contrib)[j];
2842 VECTOR(contrib)[j] = 0.0;
2843 }
2844 }
2845 }
2846
2847 igraph_vit_destroy(&vit);
2848 igraph_vector_destroy(&jneis_out);
2849 igraph_vector_destroy(&jneis_in);
2850 igraph_vector_destroy(&ineis_out);
2851 igraph_vector_destroy(&ineis_in);
2852 igraph_vector_destroy(°ree);
2853 igraph_vector_destroy(&contrib);
2854 IGRAPH_FINALLY_CLEAN(7);
2855
2856 return 0;
2857 }
2858
2859 /**
2860 * \function igraph_maxdegree
2861 * \brief Calculate the maximum degree in a graph (or set of vertices).
2862 *
2863 * </para><para>
2864 * The largest in-, out- or total degree of the specified vertices is
2865 * calculated.
2866 * \param graph The input graph.
2867 * \param res Pointer to an integer (\c igraph_integer_t), the result
2868 * will be stored here.
2869 * \param vids Vector giving the vertex IDs for which the maximum degree will
2870 * be calculated.
2871 * \param mode Defines the type of the degree.
2872 * \c IGRAPH_OUT, out-degree,
2873 * \c IGRAPH_IN, in-degree,
2874 * \c IGRAPH_ALL, total degree (sum of the
2875 * in- and out-degree).
2876 * This parameter is ignored for undirected graphs.
2877 * \param loops Boolean, gives whether the self-loops should be
2878 * counted.
2879 * \return Error code:
2880 * \c IGRAPH_EINVVID: invalid vertex id.
2881 * \c IGRAPH_EINVMODE: invalid mode argument.
2882 *
2883 * Time complexity: O(v) if
2884 * loops is
2885 * TRUE, and
2886 * O(v*d)
2887 * otherwise. v is the number
2888 * vertices for which the degree will be calculated, and
2889 * d is their (average) degree.
2890 */
2891
igraph_maxdegree(const igraph_t * graph,igraph_integer_t * res,igraph_vs_t vids,igraph_neimode_t mode,igraph_bool_t loops)2892 int igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res,
2893 igraph_vs_t vids, igraph_neimode_t mode,
2894 igraph_bool_t loops) {
2895
2896 igraph_vector_t tmp;
2897
2898 IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
2899
2900 igraph_degree(graph, &tmp, vids, mode, loops);
2901 *res = (igraph_integer_t) igraph_vector_max(&tmp);
2902
2903 igraph_vector_destroy(&tmp);
2904 IGRAPH_FINALLY_CLEAN(1);
2905 return 0;
2906 }
2907
2908 /**
2909 * \function igraph_density
2910 * Calculate the density of a graph.
2911 *
2912 * </para><para>The density of a graph is simply the ratio number of
2913 * edges and the number of possible edges. Note that density is
2914 * ill-defined for graphs with multiple and/or loop edges, so consider
2915 * calling \ref igraph_simplify() on the graph if you know that it
2916 * contains multiple or loop edges.
2917 * \param graph The input graph object.
2918 * \param res Pointer to a real number, the result will be stored
2919 * here.
2920 * \param loops Logical constant, whether to include loops in the
2921 * calculation. If this constant is TRUE then
2922 * loop edges are thought to be possible in the graph (this does not
2923 * necessarily mean that the graph really contains any loops). If
2924 * this is FALSE then the result is only correct if the graph does not
2925 * contain loops.
2926 * \return Error code.
2927 *
2928 * Time complexity: O(1).
2929 */
2930
igraph_density(const igraph_t * graph,igraph_real_t * res,igraph_bool_t loops)2931 int igraph_density(const igraph_t *graph, igraph_real_t *res,
2932 igraph_bool_t loops) {
2933
2934 igraph_integer_t no_of_nodes = igraph_vcount(graph);
2935 igraph_real_t no_of_edges = igraph_ecount(graph);
2936 igraph_bool_t directed = igraph_is_directed(graph);
2937
2938 if (no_of_nodes == 0) {
2939 *res = IGRAPH_NAN;
2940 return 0;
2941 }
2942
2943 if (!loops) {
2944 if (no_of_nodes == 1) {
2945 *res = IGRAPH_NAN;
2946 } else if (directed) {
2947 *res = no_of_edges / no_of_nodes / (no_of_nodes - 1);
2948 } else {
2949 *res = no_of_edges / no_of_nodes * 2.0 / (no_of_nodes - 1);
2950 }
2951 } else {
2952 if (directed) {
2953 *res = no_of_edges / no_of_nodes / no_of_nodes;
2954 } else {
2955 *res = no_of_edges / no_of_nodes * 2.0 / (no_of_nodes + 1);
2956 }
2957 }
2958
2959 return 0;
2960 }
2961
2962 /**
2963 * \function igraph_neighborhood_size
2964 * \brief Calculates the size of the neighborhood of a given vertex.
2965 *
2966 * The neighborhood of a given order of a vertex includes all vertices
2967 * which are closer to the vertex than the order. I.e., order 0 is
2968 * always the vertex itself, order 1 is the vertex plus its immediate
2969 * neighbors, order 2 is order 1 plus the immediate neighbors of the
2970 * vertices in order 1, etc.
2971 *
2972 * </para><para> This function calculates the size of the neighborhood
2973 * of the given order for the given vertices.
2974 * \param graph The input graph.
2975 * \param res Pointer to an initialized vector, the result will be
2976 * stored here. It will be resized as needed.
2977 * \param vids The vertices for which the calculation is performed.
2978 * \param order Integer giving the order of the neighborhood.
2979 * \param mode Specifies how to use the direction of the edges if a
2980 * directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
2981 * edges are followed, so all vertices reachable from the source
2982 * vertex in at most \c order steps are counted. For \c IGRAPH_IN
2983 * all vertices from which the source vertex is reachable in at most
2984 * \c order steps are counted. \c IGRAPH_ALL ignores the direction
2985 * of the edges. This argument is ignored for undirected graphs.
2986 * \param mindist The minimum distance to include a vertex in the counting.
2987 * If this is one, then the starting vertex is not counted. If this is
2988 * two, then its neighbors are not counted, either, etc.
2989 * \return Error code.
2990 *
2991 * \sa \ref igraph_neighborhood() for calculating the actual neighborhood,
2992 * \ref igraph_neighborhood_graphs() for creating separate graphs from
2993 * the neighborhoods.
2994 *
2995 * Time complexity: O(n*d*o), where n is the number vertices for which
2996 * the calculation is performed, d is the average degree, o is the order.
2997 */
2998
igraph_neighborhood_size(const igraph_t * graph,igraph_vector_t * res,igraph_vs_t vids,igraph_integer_t order,igraph_neimode_t mode,igraph_integer_t mindist)2999 int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
3000 igraph_vs_t vids, igraph_integer_t order,
3001 igraph_neimode_t mode,
3002 igraph_integer_t mindist) {
3003
3004 long int no_of_nodes = igraph_vcount(graph);
3005 igraph_dqueue_t q;
3006 igraph_vit_t vit;
3007 long int i, j;
3008 long int *added;
3009 igraph_vector_t neis;
3010
3011 if (order < 0) {
3012 IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
3013 }
3014
3015 if (mindist < 0 || mindist > order) {
3016 IGRAPH_ERROR("Minimum distance should be between zero and order",
3017 IGRAPH_EINVAL);
3018 }
3019
3020 added = igraph_Calloc(no_of_nodes, long int);
3021 if (added == 0) {
3022 IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
3023 }
3024 IGRAPH_FINALLY(igraph_free, added);
3025 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
3026 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
3027 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
3028 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3029 IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
3030
3031 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
3032 long int node = IGRAPH_VIT_GET(vit);
3033 long int size = mindist == 0 ? 1 : 0;
3034 added[node] = i + 1;
3035 igraph_dqueue_clear(&q);
3036 if (order > 0) {
3037 igraph_dqueue_push(&q, node);
3038 igraph_dqueue_push(&q, 0);
3039 }
3040
3041 while (!igraph_dqueue_empty(&q)) {
3042 long int actnode = (long int) igraph_dqueue_pop(&q);
3043 long int actdist = (long int) igraph_dqueue_pop(&q);
3044 long int n;
3045 igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
3046 n = igraph_vector_size(&neis);
3047
3048 if (actdist < order - 1) {
3049 /* we add them to the q */
3050 for (j = 0; j < n; j++) {
3051 long int nei = (long int) VECTOR(neis)[j];
3052 if (added[nei] != i + 1) {
3053 added[nei] = i + 1;
3054 IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
3055 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
3056 if (actdist + 1 >= mindist) {
3057 size++;
3058 }
3059 }
3060 }
3061 } else {
3062 /* we just count them, but don't add them */
3063 for (j = 0; j < n; j++) {
3064 long int nei = (long int) VECTOR(neis)[j];
3065 if (added[nei] != i + 1) {
3066 added[nei] = i + 1;
3067 if (actdist + 1 >= mindist) {
3068 size++;
3069 }
3070 }
3071 }
3072 }
3073
3074 } /* while q not empty */
3075
3076 VECTOR(*res)[i] = size;
3077 } /* for VIT, i */
3078
3079 igraph_vector_destroy(&neis);
3080 igraph_vit_destroy(&vit);
3081 igraph_dqueue_destroy(&q);
3082 igraph_Free(added);
3083 IGRAPH_FINALLY_CLEAN(4);
3084
3085 return 0;
3086 }
3087
3088 /**
3089 * \function igraph_neighborhood
3090 * Calculate the neighborhood of vertices.
3091 *
3092 * The neighborhood of a given order of a vertex includes all vertices
3093 * which are closer to the vertex than the order. I.e., order 0 is
3094 * always the vertex itself, order 1 is the vertex plus its immediate
3095 * neighbors, order 2 is order 1 plus the immediate neighbors of the
3096 * vertices in order 1, etc.
3097 *
3098 * </para><para> This function calculates the vertices within the
3099 * neighborhood of the specified vertices.
3100 * \param graph The input graph.
3101 * \param res An initialized pointer vector. Note that the objects
3102 * (pointers) in the vector will \em not be freed, but the pointer
3103 * vector will be resized as needed. The result of the calculation
3104 * will be stored here in \ref igraph_vector_t objects.
3105 * \param vids The vertices for which the calculation is performed.
3106 * \param order Integer giving the order of the neighborhood.
3107 * \param mode Specifies how to use the direction of the edges if a
3108 * directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
3109 * edges are followed, so all vertices reachable from the source
3110 * vertex in at most \p order steps are included. For \c IGRAPH_IN
3111 * all vertices from which the source vertex is reachable in at most
3112 * \p order steps are included. \c IGRAPH_ALL ignores the direction
3113 * of the edges. This argument is ignored for undirected graphs.
3114 * \param mindist The minimum distance to include a vertex in the counting.
3115 * If this is one, then the starting vertex is not counted. If this is
3116 * two, then its neighbors are not counted, either, etc.
3117 * \return Error code.
3118 *
3119 * \sa \ref igraph_neighborhood_size() to calculate the size of the
3120 * neighborhood, \ref igraph_neighborhood_graphs() for creating
3121 * graphs from the neighborhoods.
3122 *
3123 * Time complexity: O(n*d*o), n is the number of vertices for which
3124 * the calculation is performed, d is the average degree, o is the
3125 * order.
3126 */
3127
igraph_neighborhood(const igraph_t * graph,igraph_vector_ptr_t * res,igraph_vs_t vids,igraph_integer_t order,igraph_neimode_t mode,igraph_integer_t mindist)3128 int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
3129 igraph_vs_t vids, igraph_integer_t order,
3130 igraph_neimode_t mode, igraph_integer_t mindist) {
3131
3132 long int no_of_nodes = igraph_vcount(graph);
3133 igraph_dqueue_t q;
3134 igraph_vit_t vit;
3135 long int i, j;
3136 long int *added;
3137 igraph_vector_t neis;
3138 igraph_vector_t tmp;
3139 igraph_vector_t *newv;
3140
3141 if (order < 0) {
3142 IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
3143 }
3144
3145 if (mindist < 0 || mindist > order) {
3146 IGRAPH_ERROR("Minimum distance should be between zero and order",
3147 IGRAPH_EINVAL);
3148 }
3149
3150 added = igraph_Calloc(no_of_nodes, long int);
3151 if (added == 0) {
3152 IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
3153 }
3154 IGRAPH_FINALLY(igraph_free, added);
3155 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
3156 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
3157 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
3158 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3159 IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
3160 IGRAPH_CHECK(igraph_vector_ptr_resize(res, IGRAPH_VIT_SIZE(vit)));
3161
3162 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
3163 long int node = IGRAPH_VIT_GET(vit);
3164 added[node] = i + 1;
3165 igraph_vector_clear(&tmp);
3166 if (mindist == 0) {
3167 IGRAPH_CHECK(igraph_vector_push_back(&tmp, node));
3168 }
3169 if (order > 0) {
3170 igraph_dqueue_push(&q, node);
3171 igraph_dqueue_push(&q, 0);
3172 }
3173
3174 while (!igraph_dqueue_empty(&q)) {
3175 long int actnode = (long int) igraph_dqueue_pop(&q);
3176 long int actdist = (long int) igraph_dqueue_pop(&q);
3177 long int n;
3178 igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
3179 n = igraph_vector_size(&neis);
3180
3181 if (actdist < order - 1) {
3182 /* we add them to the q */
3183 for (j = 0; j < n; j++) {
3184 long int nei = (long int) VECTOR(neis)[j];
3185 if (added[nei] != i + 1) {
3186 added[nei] = i + 1;
3187 IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
3188 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
3189 if (actdist + 1 >= mindist) {
3190 IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
3191 }
3192 }
3193 }
3194 } else {
3195 /* we just count them but don't add them to q */
3196 for (j = 0; j < n; j++) {
3197 long int nei = (long int) VECTOR(neis)[j];
3198 if (added[nei] != i + 1) {
3199 added[nei] = i + 1;
3200 if (actdist + 1 >= mindist) {
3201 IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
3202 }
3203 }
3204 }
3205 }
3206
3207 } /* while q not empty */
3208
3209 newv = igraph_Calloc(1, igraph_vector_t);
3210 if (newv == 0) {
3211 IGRAPH_ERROR("Cannot calculate neighborhood", IGRAPH_ENOMEM);
3212 }
3213 IGRAPH_FINALLY(igraph_free, newv);
3214 IGRAPH_CHECK(igraph_vector_copy(newv, &tmp));
3215 VECTOR(*res)[i] = newv;
3216 IGRAPH_FINALLY_CLEAN(1);
3217 }
3218
3219 igraph_vector_destroy(&tmp);
3220 igraph_vector_destroy(&neis);
3221 igraph_vit_destroy(&vit);
3222 igraph_dqueue_destroy(&q);
3223 igraph_Free(added);
3224 IGRAPH_FINALLY_CLEAN(5);
3225
3226 return 0;
3227 }
3228
3229 /**
3230 * \function igraph_neighborhood_graphs
3231 * Create graphs from the neighborhood(s) of some vertex/vertices.
3232 *
3233 * The neighborhood of a given order of a vertex includes all vertices
3234 * which are closer to the vertex than the order. Ie. order 0 is
3235 * always the vertex itself, order 1 is the vertex plus its immediate
3236 * neighbors, order 2 is order 1 plus the immediate neighbors of the
3237 * vertices in order 1, etc.
3238 *
3239 * </para><para> This function finds every vertex in the neighborhood
3240 * of a given parameter vertex and creates a graph from these
3241 * vertices.
3242 *
3243 * </para><para> The first version of this function was written by
3244 * Vincent Matossian, thanks Vincent.
3245 * \param graph The input graph.
3246 * \param res Pointer to a pointer vector, the result will be stored
3247 * here, ie. \p res will contain pointers to \c igraph_t
3248 * objects. It will be resized if needed but note that the
3249 * objects in the pointer vector will not be freed.
3250 * \param vids The vertices for which the calculation is performed.
3251 * \param order Integer giving the order of the neighborhood.
3252 * \param mode Specifies how to use the direction of the edges if a
3253 * directed graph is analyzed. For \c IGRAPH_OUT only the outgoing
3254 * edges are followed, so all vertices reachable from the source
3255 * vertex in at most \p order steps are counted. For \c IGRAPH_IN
3256 * all vertices from which the source vertex is reachable in at most
3257 * \p order steps are counted. \c IGRAPH_ALL ignores the direction
3258 * of the edges. This argument is ignored for undirected graphs.
3259 * \param mindist The minimum distance to include a vertex in the counting.
3260 * If this is one, then the starting vertex is not counted. If this is
3261 * two, then its neighbors are not counted, either, etc.
3262 * \return Error code.
3263 *
3264 * \sa \ref igraph_neighborhood_size() for calculating the neighborhood
3265 * sizes only, \ref igraph_neighborhood() for calculating the
3266 * neighborhoods (but not creating graphs).
3267 *
3268 * Time complexity: O(n*(|V|+|E|)), where n is the number vertices for
3269 * which the calculation is performed, |V| and |E| are the number of
3270 * vertices and edges in the original input graph.
3271 */
3272
igraph_neighborhood_graphs(const igraph_t * graph,igraph_vector_ptr_t * res,igraph_vs_t vids,igraph_integer_t order,igraph_neimode_t mode,igraph_integer_t mindist)3273 int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
3274 igraph_vs_t vids, igraph_integer_t order,
3275 igraph_neimode_t mode,
3276 igraph_integer_t mindist) {
3277 long int no_of_nodes = igraph_vcount(graph);
3278 igraph_dqueue_t q;
3279 igraph_vit_t vit;
3280 long int i, j;
3281 long int *added;
3282 igraph_vector_t neis;
3283 igraph_vector_t tmp;
3284 igraph_t *newg;
3285
3286 if (order < 0) {
3287 IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
3288 }
3289
3290 if (mindist < 0 || mindist > order) {
3291 IGRAPH_ERROR("Minimum distance should be between zero and order",
3292 IGRAPH_EINVAL);
3293 }
3294
3295 added = igraph_Calloc(no_of_nodes, long int);
3296 if (added == 0) {
3297 IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
3298 }
3299 IGRAPH_FINALLY(igraph_free, added);
3300 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
3301 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
3302 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
3303 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3304 IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
3305 IGRAPH_CHECK(igraph_vector_ptr_resize(res, IGRAPH_VIT_SIZE(vit)));
3306
3307 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
3308 long int node = IGRAPH_VIT_GET(vit);
3309 added[node] = i + 1;
3310 igraph_vector_clear(&tmp);
3311 if (mindist == 0) {
3312 IGRAPH_CHECK(igraph_vector_push_back(&tmp, node));
3313 }
3314 if (order > 0) {
3315 igraph_dqueue_push(&q, node);
3316 igraph_dqueue_push(&q, 0);
3317 }
3318
3319 while (!igraph_dqueue_empty(&q)) {
3320 long int actnode = (long int) igraph_dqueue_pop(&q);
3321 long int actdist = (long int) igraph_dqueue_pop(&q);
3322 long int n;
3323 igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
3324 n = igraph_vector_size(&neis);
3325
3326 if (actdist < order - 1) {
3327 /* we add them to the q */
3328 for (j = 0; j < n; j++) {
3329 long int nei = (long int) VECTOR(neis)[j];
3330 if (added[nei] != i + 1) {
3331 added[nei] = i + 1;
3332 IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
3333 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
3334 if (actdist + 1 >= mindist) {
3335 IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
3336 }
3337 }
3338 }
3339 } else {
3340 /* we just count them but don't add them to q */
3341 for (j = 0; j < n; j++) {
3342 long int nei = (long int) VECTOR(neis)[j];
3343 if (added[nei] != i + 1) {
3344 added[nei] = i + 1;
3345 if (actdist + 1 >= mindist) {
3346 IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
3347 }
3348 }
3349 }
3350 }
3351
3352 } /* while q not empty */
3353
3354 newg = igraph_Calloc(1, igraph_t);
3355 if (newg == 0) {
3356 IGRAPH_ERROR("Cannot create neighborhood graph", IGRAPH_ENOMEM);
3357 }
3358 IGRAPH_FINALLY(igraph_free, newg);
3359 if (igraph_vector_size(&tmp) < no_of_nodes) {
3360 IGRAPH_CHECK(igraph_induced_subgraph(graph, newg,
3361 igraph_vss_vector(&tmp),
3362 IGRAPH_SUBGRAPH_AUTO));
3363 } else {
3364 IGRAPH_CHECK(igraph_copy(newg, graph));
3365 }
3366 VECTOR(*res)[i] = newg;
3367 IGRAPH_FINALLY_CLEAN(1);
3368 }
3369
3370 igraph_vector_destroy(&tmp);
3371 igraph_vector_destroy(&neis);
3372 igraph_vit_destroy(&vit);
3373 igraph_dqueue_destroy(&q);
3374 igraph_Free(added);
3375 IGRAPH_FINALLY_CLEAN(5);
3376
3377 return 0;
3378 }
3379
3380 /**
3381 * \function igraph_topological_sorting
3382 * \brief Calculate a possible topological sorting of the graph.
3383 *
3384 * </para><para>
3385 * A topological sorting of a directed acyclic graph is a linear ordering
3386 * of its nodes where each node comes before all nodes to which it has
3387 * edges. Every DAG has at least one topological sort, and may have many.
3388 * This function returns a possible topological sort among them. If the
3389 * graph is not acyclic (it has at least one cycle), a partial topological
3390 * sort is returned and a warning is issued.
3391 *
3392 * \param graph The input graph.
3393 * \param res Pointer to a vector, the result will be stored here.
3394 * It will be resized if needed.
3395 * \param mode Specifies how to use the direction of the edges.
3396 * For \c IGRAPH_OUT, the sorting order ensures that each node comes
3397 * before all nodes to which it has edges, so nodes with no incoming
3398 * edges go first. For \c IGRAPH_IN, it is quite the opposite: each
3399 * node comes before all nodes from which it receives edges. Nodes
3400 * with no outgoing edges go first.
3401 * \return Error code.
3402 *
3403 * Time complexity: O(|V|+|E|), where |V| and |E| are the number of
3404 * vertices and edges in the original input graph.
3405 *
3406 * \sa \ref igraph_is_dag() if you are only interested in whether a given
3407 * graph is a DAG or not, or \ref igraph_feedback_arc_set() to find a
3408 * set of edges whose removal makes the graph a DAG.
3409 *
3410 * \example examples/simple/igraph_topological_sorting.c
3411 */
igraph_topological_sorting(const igraph_t * graph,igraph_vector_t * res,igraph_neimode_t mode)3412 int igraph_topological_sorting(const igraph_t* graph, igraph_vector_t *res,
3413 igraph_neimode_t mode) {
3414 long int no_of_nodes = igraph_vcount(graph);
3415 igraph_vector_t degrees, neis;
3416 igraph_dqueue_t sources;
3417 igraph_neimode_t deg_mode;
3418 long int node, i, j;
3419
3420 if (mode == IGRAPH_ALL || !igraph_is_directed(graph)) {
3421 IGRAPH_ERROR("topological sorting does not make sense for undirected graphs", IGRAPH_EINVAL);
3422 } else if (mode == IGRAPH_OUT) {
3423 deg_mode = IGRAPH_IN;
3424 } else if (mode == IGRAPH_IN) {
3425 deg_mode = IGRAPH_OUT;
3426 } else {
3427 IGRAPH_ERROR("invalid mode", IGRAPH_EINVAL);
3428 }
3429
3430 IGRAPH_VECTOR_INIT_FINALLY(°rees, no_of_nodes);
3431 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3432 IGRAPH_CHECK(igraph_dqueue_init(&sources, 0));
3433 IGRAPH_FINALLY(igraph_dqueue_destroy, &sources);
3434 IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), deg_mode, 0));
3435
3436 igraph_vector_clear(res);
3437
3438 /* Do we have nodes with no incoming vertices? */
3439 for (i = 0; i < no_of_nodes; i++) {
3440 if (VECTOR(degrees)[i] == 0) {
3441 IGRAPH_CHECK(igraph_dqueue_push(&sources, i));
3442 }
3443 }
3444
3445 /* Take all nodes with no incoming vertices and remove them */
3446 while (!igraph_dqueue_empty(&sources)) {
3447 igraph_real_t tmp = igraph_dqueue_pop(&sources); node = (long) tmp;
3448 /* Add the node to the result vector */
3449 igraph_vector_push_back(res, node);
3450 /* Exclude the node from further source searches */
3451 VECTOR(degrees)[node] = -1;
3452 /* Get the neighbors and decrease their degrees by one */
3453 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, mode));
3454 j = igraph_vector_size(&neis);
3455 for (i = 0; i < j; i++) {
3456 VECTOR(degrees)[(long)VECTOR(neis)[i]]--;
3457 if (VECTOR(degrees)[(long)VECTOR(neis)[i]] == 0) {
3458 IGRAPH_CHECK(igraph_dqueue_push(&sources, VECTOR(neis)[i]));
3459 }
3460 }
3461 }
3462
3463 if (igraph_vector_size(res) < no_of_nodes) {
3464 IGRAPH_WARNING("graph contains a cycle, partial result is returned");
3465 }
3466
3467 igraph_vector_destroy(°rees);
3468 igraph_vector_destroy(&neis);
3469 igraph_dqueue_destroy(&sources);
3470 IGRAPH_FINALLY_CLEAN(3);
3471
3472 return 0;
3473 }
3474
3475 /**
3476 * \function igraph_is_dag
3477 * Checks whether a graph is a directed acyclic graph (DAG) or not.
3478 *
3479 * </para><para>
3480 * A directed acyclic graph (DAG) is a directed graph with no cycles.
3481 *
3482 * \param graph The input graph.
3483 * \param res Pointer to a boolean constant, the result
3484 * is stored here.
3485 * \return Error code.
3486 *
3487 * Time complexity: O(|V|+|E|), where |V| and |E| are the number of
3488 * vertices and edges in the original input graph.
3489 *
3490 * \sa \ref igraph_topological_sorting() to get a possible topological
3491 * sorting of a DAG.
3492 */
igraph_is_dag(const igraph_t * graph,igraph_bool_t * res)3493 int igraph_is_dag(const igraph_t* graph, igraph_bool_t *res) {
3494 long int no_of_nodes = igraph_vcount(graph);
3495 igraph_vector_t degrees, neis;
3496 igraph_dqueue_t sources;
3497 long int node, i, j, nei, vertices_left;
3498
3499 if (!igraph_is_directed(graph)) {
3500 *res = 0;
3501 return IGRAPH_SUCCESS;
3502 }
3503
3504 IGRAPH_VECTOR_INIT_FINALLY(°rees, no_of_nodes);
3505 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3506 IGRAPH_CHECK(igraph_dqueue_init(&sources, 0));
3507 IGRAPH_FINALLY(igraph_dqueue_destroy, &sources);
3508 IGRAPH_CHECK(igraph_degree(graph, °rees, igraph_vss_all(), IGRAPH_OUT, 1));
3509
3510 vertices_left = no_of_nodes;
3511
3512 /* Do we have nodes with no incoming edges? */
3513 for (i = 0; i < no_of_nodes; i++) {
3514 if (VECTOR(degrees)[i] == 0) {
3515 IGRAPH_CHECK(igraph_dqueue_push(&sources, i));
3516 }
3517 }
3518
3519 /* Take all nodes with no incoming edges and remove them */
3520 while (!igraph_dqueue_empty(&sources)) {
3521 igraph_real_t tmp = igraph_dqueue_pop(&sources); node = (long) tmp;
3522 /* Exclude the node from further source searches */
3523 VECTOR(degrees)[node] = -1;
3524 vertices_left--;
3525 /* Get the neighbors and decrease their degrees by one */
3526 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
3527 IGRAPH_IN));
3528 j = igraph_vector_size(&neis);
3529 for (i = 0; i < j; i++) {
3530 nei = (long)VECTOR(neis)[i];
3531 if (nei == node) {
3532 continue;
3533 }
3534 VECTOR(degrees)[nei]--;
3535 if (VECTOR(degrees)[nei] == 0) {
3536 IGRAPH_CHECK(igraph_dqueue_push(&sources, nei));
3537 }
3538 }
3539 }
3540
3541 *res = (vertices_left == 0);
3542 if (vertices_left < 0) {
3543 IGRAPH_WARNING("vertices_left < 0 in igraph_is_dag, possible bug");
3544 }
3545
3546 igraph_vector_destroy(°rees);
3547 igraph_vector_destroy(&neis);
3548 igraph_dqueue_destroy(&sources);
3549 IGRAPH_FINALLY_CLEAN(3);
3550
3551 return IGRAPH_SUCCESS;
3552 }
3553
3554 /**
3555 * \function igraph_is_simple
3556 * \brief Decides whether the input graph is a simple graph.
3557 *
3558 * </para><para>
3559 * A graph is a simple graph if it does not contain loop edges and
3560 * multiple edges.
3561 *
3562 * \param graph The input graph.
3563 * \param res Pointer to a boolean constant, the result
3564 * is stored here.
3565 * \return Error code.
3566 *
3567 * \sa \ref igraph_is_loop() and \ref igraph_is_multiple() to
3568 * find the loops and multiple edges, \ref igraph_simplify() to
3569 * get rid of them, or \ref igraph_has_multiple() to decide whether
3570 * there is at least one multiple edge.
3571 *
3572 * Time complexity: O(|V|+|E|).
3573 */
3574
igraph_is_simple(const igraph_t * graph,igraph_bool_t * res)3575 int igraph_is_simple(const igraph_t *graph, igraph_bool_t *res) {
3576 long int vc = igraph_vcount(graph);
3577 long int ec = igraph_ecount(graph);
3578
3579 if (vc == 0 || ec == 0) {
3580 *res = 1;
3581 } else {
3582 igraph_vector_t neis;
3583 long int i, j, n;
3584 igraph_bool_t found = 0;
3585 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3586 for (i = 0; i < vc; i++) {
3587 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, IGRAPH_OUT));
3588 n = igraph_vector_size(&neis);
3589 for (j = 0; j < n; j++) {
3590 if (VECTOR(neis)[j] == i) {
3591 found = 1; break;
3592 }
3593 if (j > 0 && VECTOR(neis)[j - 1] == VECTOR(neis)[j]) {
3594 found = 1; break;
3595 }
3596 }
3597 }
3598 *res = !found;
3599 igraph_vector_destroy(&neis);
3600 IGRAPH_FINALLY_CLEAN(1);
3601 }
3602
3603 return 0;
3604 }
3605
3606 /**
3607 * \function igraph_has_loop
3608 * \brief Returns whether the graph has at least one loop edge.
3609 *
3610 * </para><para>
3611 * A loop edge is an edge from a vertex to itself.
3612 * \param graph The input graph.
3613 * \param res Pointer to an initialized boolean vector for storing the result.
3614 *
3615 * \sa \ref igraph_simplify() to get rid of loop edges.
3616 *
3617 * Time complexity: O(e), the number of edges to check.
3618 *
3619 * \example examples/simple/igraph_has_loop.c
3620 */
3621
igraph_has_loop(const igraph_t * graph,igraph_bool_t * res)3622 int igraph_has_loop(const igraph_t *graph, igraph_bool_t *res) {
3623 long int i, m = igraph_ecount(graph);
3624
3625 *res = 0;
3626
3627 for (i = 0; i < m; i++) {
3628 if (IGRAPH_FROM(graph, i) == IGRAPH_TO(graph, i)) {
3629 *res = 1;
3630 break;
3631 }
3632 }
3633
3634 return 0;
3635 }
3636
3637 /**
3638 * \function igraph_is_loop
3639 * \brief Find the loop edges in a graph.
3640 *
3641 * </para><para>
3642 * A loop edge is an edge from a vertex to itself.
3643 * \param graph The input graph.
3644 * \param res Pointer to an initialized boolean vector for storing the result,
3645 * it will be resized as needed.
3646 * \param es The edges to check, for all edges supply \ref igraph_ess_all() here.
3647 * \return Error code.
3648 *
3649 * \sa \ref igraph_simplify() to get rid of loop edges.
3650 *
3651 * Time complexity: O(e), the number of edges to check.
3652 *
3653 * \example examples/simple/igraph_is_loop.c
3654 */
3655
igraph_is_loop(const igraph_t * graph,igraph_vector_bool_t * res,igraph_es_t es)3656 int igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res,
3657 igraph_es_t es) {
3658 igraph_eit_t eit;
3659 long int i;
3660 IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
3661 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
3662
3663 IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit)));
3664
3665 for (i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
3666 long int e = IGRAPH_EIT_GET(eit);
3667 VECTOR(*res)[i] = (IGRAPH_FROM(graph, e) == IGRAPH_TO(graph, e)) ? 1 : 0;
3668 }
3669
3670 igraph_eit_destroy(&eit);
3671 IGRAPH_FINALLY_CLEAN(1);
3672 return 0;
3673 }
3674
3675 /**
3676 * \function igraph_has_multiple
3677 * \brief Check whether the graph has at least one multiple edge.
3678 *
3679 * </para><para>
3680 * An edge is a multiple edge if there is another
3681 * edge with the same head and tail vertices in the graph.
3682 *
3683 * \param graph The input graph.
3684 * \param res Pointer to a boolean variable, the result will be stored here.
3685 * \return Error code.
3686 *
3687 * \sa \ref igraph_count_multiple(), \ref igraph_is_multiple() and \ref igraph_simplify().
3688 *
3689 * Time complexity: O(e*d), e is the number of edges to check and d is the
3690 * average degree (out-degree in directed graphs) of the vertices at the
3691 * tail of the edges.
3692 *
3693 * \example examples/simple/igraph_has_multiple.c
3694 */
3695
igraph_has_multiple(const igraph_t * graph,igraph_bool_t * res)3696 int igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) {
3697 long int vc = igraph_vcount(graph);
3698 long int ec = igraph_ecount(graph);
3699 igraph_bool_t directed = igraph_is_directed(graph);
3700
3701 if (vc == 0 || ec == 0) {
3702 *res = 0;
3703 } else {
3704 igraph_vector_t neis;
3705 long int i, j, n;
3706 igraph_bool_t found = 0;
3707 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
3708 for (i = 0; i < vc && !found; i++) {
3709 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i,
3710 IGRAPH_OUT));
3711 n = igraph_vector_size(&neis);
3712 for (j = 1; j < n; j++) {
3713 if (VECTOR(neis)[j - 1] == VECTOR(neis)[j]) {
3714 /* If the graph is undirected, loop edges appear twice in the neighbor
3715 * list, so check the next item as well */
3716 if (directed) {
3717 /* Directed, so this is a real multiple edge */
3718 found = 1; break;
3719 } else if (VECTOR(neis)[j - 1] != i) {
3720 /* Undirected, but not a loop edge */
3721 found = 1; break;
3722 } else if (j < n - 1 && VECTOR(neis)[j] == VECTOR(neis)[j + 1]) {
3723 /* Undirected, loop edge, multiple times */
3724 found = 1; break;
3725 }
3726 }
3727 }
3728 }
3729 *res = found;
3730 igraph_vector_destroy(&neis);
3731 IGRAPH_FINALLY_CLEAN(1);
3732 }
3733
3734 return 0;
3735 }
3736
3737 /**
3738 * \function igraph_is_multiple
3739 * \brief Find the multiple edges in a graph.
3740 *
3741 * </para><para>
3742 * An edge is a multiple edge if there is another
3743 * edge with the same head and tail vertices in the graph.
3744 *
3745 * </para><para>
3746 * Note that this function returns true only for the second or more
3747 * appearances of the multiple edges.
3748 * \param graph The input graph.
3749 * \param res Pointer to a boolean vector, the result will be stored
3750 * here. It will be resized as needed.
3751 * \param es The edges to check. Supply \ref igraph_ess_all() if you want
3752 * to check all edges.
3753 * \return Error code.
3754 *
3755 * \sa \ref igraph_count_multiple(), \ref igraph_has_multiple() and \ref igraph_simplify().
3756 *
3757 * Time complexity: O(e*d), e is the number of edges to check and d is the
3758 * average degree (out-degree in directed graphs) of the vertices at the
3759 * tail of the edges.
3760 *
3761 * \example examples/simple/igraph_is_multiple.c
3762 */
3763
igraph_is_multiple(const igraph_t * graph,igraph_vector_bool_t * res,igraph_es_t es)3764 int igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res,
3765 igraph_es_t es) {
3766 igraph_eit_t eit;
3767 long int i;
3768 igraph_lazy_inclist_t inclist;
3769
3770 IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
3771 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
3772 IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_OUT));
3773 IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
3774
3775 IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit)));
3776
3777 for (i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
3778 long int e = IGRAPH_EIT_GET(eit);
3779 long int from = IGRAPH_FROM(graph, e);
3780 long int to = IGRAPH_TO(graph, e);
3781 igraph_vector_t *neis = igraph_lazy_inclist_get(&inclist,
3782 (igraph_integer_t) from);
3783 long int j, n = igraph_vector_size(neis);
3784 VECTOR(*res)[i] = 0;
3785 for (j = 0; j < n; j++) {
3786 long int e2 = (long int) VECTOR(*neis)[j];
3787 long int to2 = IGRAPH_OTHER(graph, e2, from);
3788 if (to2 == to && e2 < e) {
3789 VECTOR(*res)[i] = 1;
3790 }
3791 }
3792 }
3793
3794 igraph_lazy_inclist_destroy(&inclist);
3795 igraph_eit_destroy(&eit);
3796 IGRAPH_FINALLY_CLEAN(2);
3797 return 0;
3798 }
3799
3800
3801 /**
3802 * \function igraph_count_multiple
3803 * \brief Count the number of appearances of the edges in a graph.
3804 *
3805 * </para><para>
3806 * If the graph has no multiple edges then the result vector will be
3807 * filled with ones.
3808 * (An edge is a multiple edge if there is another
3809 * edge with the same head and tail vertices in the graph.)
3810 *
3811 * </para><para>
3812 * \param graph The input graph.
3813 * \param res Pointer to a vector, the result will be stored
3814 * here. It will be resized as needed.
3815 * \param es The edges to check. Supply \ref igraph_ess_all() if you want
3816 * to check all edges.
3817 * \return Error code.
3818 *
3819 * \sa \ref igraph_is_multiple() and \ref igraph_simplify().
3820 *
3821 * Time complexity: O(E d), E is the number of edges to check and d is the
3822 * average degree (out-degree in directed graphs) of the vertices at the
3823 * tail of the edges.
3824 */
3825
igraph_count_multiple(const igraph_t * graph,igraph_vector_t * res,igraph_es_t es)3826 int igraph_count_multiple(const igraph_t *graph, igraph_vector_t *res, igraph_es_t es) {
3827 igraph_eit_t eit;
3828 long int i;
3829 igraph_bool_t directed = igraph_is_directed(graph);
3830 igraph_lazy_inclist_t inclist;
3831
3832 IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
3833 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
3834 IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_OUT));
3835 IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
3836
3837 IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_EIT_SIZE(eit)));
3838
3839 for (i = 0; !IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
3840 long int e = IGRAPH_EIT_GET(eit);
3841 long int from = IGRAPH_FROM(graph, e);
3842 long int to = IGRAPH_TO(graph, e);
3843 igraph_vector_t *neis = igraph_lazy_inclist_get(&inclist,
3844 (igraph_integer_t) from);
3845 long int j, n = igraph_vector_size(neis);
3846 VECTOR(*res)[i] = 0;
3847 for (j = 0; j < n; j++) {
3848 long int e2 = (long int) VECTOR(*neis)[j];
3849 long int to2 = IGRAPH_OTHER(graph, e2, from);
3850 if (to2 == to) {
3851 VECTOR(*res)[i] += 1;
3852 }
3853 }
3854 /* for loop edges, divide the result by two */
3855 if (!directed && to == from) {
3856 VECTOR(*res)[i] /= 2;
3857 }
3858 }
3859
3860 igraph_lazy_inclist_destroy(&inclist);
3861 igraph_eit_destroy(&eit);
3862 IGRAPH_FINALLY_CLEAN(2);
3863
3864 return IGRAPH_SUCCESS;
3865 }
3866
3867
3868 /**
3869 * \function igraph_girth
3870 * \brief The girth of a graph is the length of the shortest circle in it.
3871 *
3872 * </para><para>
3873 * The current implementation works for undirected graphs only,
3874 * directed graphs are treated as undirected graphs. Loop edges and
3875 * multiple edges are ignored.
3876 * </para><para>
3877 * If the graph is a forest (ie. acyclic), then zero is returned.
3878 * </para><para>
3879 * This implementation is based on Alon Itai and Michael Rodeh:
3880 * Finding a minimum circuit in a graph
3881 * \emb Proceedings of the ninth annual ACM symposium on Theory of
3882 * computing \eme, 1-10, 1977. The first implementation of this
3883 * function was done by Keith Briggs, thanks Keith.
3884 * \param graph The input graph.
3885 * \param girth Pointer to an integer, if not \c NULL then the result
3886 * will be stored here.
3887 * \param circle Pointer to an initialized vector, the vertex ids in
3888 * the shortest circle will be stored here. If \c NULL then it is
3889 * ignored.
3890 * \return Error code.
3891 *
3892 * Time complexity: O((|V|+|E|)^2), |V| is the number of vertices, |E|
3893 * is the number of edges in the general case. If the graph has no
3894 * circles at all then the function needs O(|V|+|E|) time to realize
3895 * this and then it stops.
3896 *
3897 * \example examples/simple/igraph_girth.c
3898 */
3899
igraph_girth(const igraph_t * graph,igraph_integer_t * girth,igraph_vector_t * circle)3900 int igraph_girth(const igraph_t *graph, igraph_integer_t *girth,
3901 igraph_vector_t *circle) {
3902
3903 long int no_of_nodes = igraph_vcount(graph);
3904 igraph_dqueue_t q;
3905 igraph_lazy_adjlist_t adjlist;
3906 long int mincirc = LONG_MAX, minvertex = 0;
3907 long int node;
3908 igraph_bool_t triangle = 0;
3909 igraph_vector_t *neis;
3910 igraph_vector_long_t level;
3911 long int stoplevel = no_of_nodes + 1;
3912 igraph_bool_t anycircle = 0;
3913 long int t1 = 0, t2 = 0;
3914
3915 IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_ALL,
3916 IGRAPH_SIMPLIFY));
3917 IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
3918 IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
3919 IGRAPH_CHECK(igraph_vector_long_init(&level, no_of_nodes));
3920 IGRAPH_FINALLY(igraph_vector_long_destroy, &level);
3921
3922 for (node = 0; !triangle && node < no_of_nodes; node++) {
3923
3924 /* Are there circles in this graph at all? */
3925 if (node == 1 && anycircle == 0) {
3926 igraph_bool_t conn;
3927 IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK));
3928 if (conn) {
3929 /* No, there are none */
3930 break;
3931 }
3932 }
3933
3934 anycircle = 0;
3935 igraph_dqueue_clear(&q);
3936 igraph_vector_long_null(&level);
3937 IGRAPH_CHECK(igraph_dqueue_push(&q, node));
3938 VECTOR(level)[node] = 1;
3939
3940 IGRAPH_ALLOW_INTERRUPTION();
3941
3942 while (!igraph_dqueue_empty(&q)) {
3943 long int actnode = (long int) igraph_dqueue_pop(&q);
3944 long int actlevel = VECTOR(level)[actnode];
3945 long int i, n;
3946
3947 if (actlevel >= stoplevel) {
3948 break;
3949 }
3950
3951 neis = igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) actnode);
3952 n = igraph_vector_size(neis);
3953 for (i = 0; i < n; i++) {
3954 long int nei = (long int) VECTOR(*neis)[i];
3955 long int neilevel = VECTOR(level)[nei];
3956 if (neilevel != 0) {
3957 if (neilevel == actlevel - 1) {
3958 continue;
3959 } else {
3960 /* found circle */
3961 stoplevel = neilevel;
3962 anycircle = 1;
3963 if (actlevel < mincirc) {
3964 /* Is it a minimum circle? */
3965 mincirc = actlevel + neilevel - 1;
3966 minvertex = node;
3967 t1 = actnode; t2 = nei;
3968 if (neilevel == 2) {
3969 /* Is it a triangle? */
3970 triangle = 1;
3971 }
3972 }
3973 if (neilevel == actlevel) {
3974 break;
3975 }
3976 }
3977 } else {
3978 igraph_dqueue_push(&q, nei);
3979 VECTOR(level)[nei] = actlevel + 1;
3980 }
3981 }
3982
3983 } /* while q !empty */
3984 } /* node */
3985
3986 if (girth) {
3987 if (mincirc == LONG_MAX) {
3988 *girth = mincirc = 0;
3989 } else {
3990 *girth = (igraph_integer_t) mincirc;
3991 }
3992 }
3993
3994 /* Store the actual circle, if needed */
3995 if (circle) {
3996 IGRAPH_CHECK(igraph_vector_resize(circle, mincirc));
3997 if (mincirc != 0) {
3998 long int i, n, idx = 0;
3999 igraph_dqueue_clear(&q);
4000 igraph_vector_long_null(&level); /* used for father pointers */
4001 #define FATHER(x) (VECTOR(level)[(x)])
4002 IGRAPH_CHECK(igraph_dqueue_push(&q, minvertex));
4003 FATHER(minvertex) = minvertex;
4004 while (FATHER(t1) == 0 || FATHER(t2) == 0) {
4005 long int actnode = (long int) igraph_dqueue_pop(&q);
4006 neis = igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) actnode);
4007 n = igraph_vector_size(neis);
4008 for (i = 0; i < n; i++) {
4009 long int nei = (long int) VECTOR(*neis)[i];
4010 if (FATHER(nei) == 0) {
4011 FATHER(nei) = actnode + 1;
4012 igraph_dqueue_push(&q, nei);
4013 }
4014 }
4015 } /* while q !empty */
4016 /* Ok, now use FATHER to create the path */
4017 while (t1 != minvertex) {
4018 VECTOR(*circle)[idx++] = t1;
4019 t1 = FATHER(t1) - 1;
4020 }
4021 VECTOR(*circle)[idx] = minvertex;
4022 idx = mincirc - 1;
4023 while (t2 != minvertex) {
4024 VECTOR(*circle)[idx--] = t2;
4025 t2 = FATHER(t2) - 1;
4026 }
4027 } /* anycircle */
4028 } /* circle */
4029 #undef FATHER
4030
4031 igraph_vector_long_destroy(&level);
4032 igraph_dqueue_destroy(&q);
4033 igraph_lazy_adjlist_destroy(&adjlist);
4034 IGRAPH_FINALLY_CLEAN(3);
4035
4036 return 0;
4037 }
4038
4039 int igraph_i_linegraph_undirected(const igraph_t *graph, igraph_t *linegraph);
4040
4041 int igraph_i_linegraph_directed(const igraph_t *graph, igraph_t *linegraph);
4042
4043 /* Note to self: tried using adjacency lists instead of igraph_incident queries,
4044 * with minimal performance improvements on a graph with 70K vertices and 360K
4045 * edges. (1.09s instead of 1.10s). I think it's not worth the fuss. */
igraph_i_linegraph_undirected(const igraph_t * graph,igraph_t * linegraph)4046 int igraph_i_linegraph_undirected(const igraph_t *graph, igraph_t *linegraph) {
4047 long int no_of_edges = igraph_ecount(graph);
4048 long int i, j, n;
4049 igraph_vector_t adjedges, adjedges2;
4050 igraph_vector_t edges;
4051 long int prev = -1;
4052
4053 IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
4054 IGRAPH_VECTOR_INIT_FINALLY(&adjedges, 0);
4055 IGRAPH_VECTOR_INIT_FINALLY(&adjedges2, 0);
4056
4057 for (i = 0; i < no_of_edges; i++) {
4058 long int from = IGRAPH_FROM(graph, i);
4059 long int to = IGRAPH_TO(graph, i);
4060
4061 IGRAPH_ALLOW_INTERRUPTION();
4062
4063 if (from != prev) {
4064 IGRAPH_CHECK(igraph_incident(graph, &adjedges, (igraph_integer_t) from,
4065 IGRAPH_ALL));
4066 }
4067 n = igraph_vector_size(&adjedges);
4068 for (j = 0; j < n; j++) {
4069 long int e = (long int) VECTOR(adjedges)[j];
4070 if (e < i) {
4071 IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
4072 IGRAPH_CHECK(igraph_vector_push_back(&edges, e));
4073 }
4074 }
4075
4076 IGRAPH_CHECK(igraph_incident(graph, &adjedges2, (igraph_integer_t) to,
4077 IGRAPH_ALL));
4078 n = igraph_vector_size(&adjedges2);
4079 for (j = 0; j < n; j++) {
4080 long int e = (long int) VECTOR(adjedges2)[j];
4081 if (e < i) {
4082 IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
4083 IGRAPH_CHECK(igraph_vector_push_back(&edges, e));
4084 }
4085 }
4086
4087 prev = from;
4088 }
4089
4090 igraph_vector_destroy(&adjedges);
4091 igraph_vector_destroy(&adjedges2);
4092 IGRAPH_FINALLY_CLEAN(2);
4093
4094 igraph_create(linegraph, &edges, (igraph_integer_t) no_of_edges,
4095 igraph_is_directed(graph));
4096 igraph_vector_destroy(&edges);
4097 IGRAPH_FINALLY_CLEAN(1);
4098
4099 return 0;
4100 }
4101
igraph_i_linegraph_directed(const igraph_t * graph,igraph_t * linegraph)4102 int igraph_i_linegraph_directed(const igraph_t *graph, igraph_t *linegraph) {
4103 long int no_of_edges = igraph_ecount(graph);
4104 long int i, j, n;
4105 igraph_vector_t adjedges;
4106 igraph_vector_t edges;
4107 long int prev = -1;
4108
4109 IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
4110 IGRAPH_VECTOR_INIT_FINALLY(&adjedges, 0);
4111
4112 for (i = 0; i < no_of_edges; i++) {
4113 long int from = IGRAPH_FROM(graph, i);
4114
4115 IGRAPH_ALLOW_INTERRUPTION();
4116
4117 if (from != prev) {
4118 IGRAPH_CHECK(igraph_incident(graph, &adjedges, (igraph_integer_t) from,
4119 IGRAPH_IN));
4120 }
4121 n = igraph_vector_size(&adjedges);
4122 for (j = 0; j < n; j++) {
4123 long int e = (long int) VECTOR(adjedges)[j];
4124 IGRAPH_CHECK(igraph_vector_push_back(&edges, e));
4125 IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
4126 }
4127
4128 prev = from;
4129 }
4130
4131 igraph_vector_destroy(&adjedges);
4132 IGRAPH_FINALLY_CLEAN(1);
4133 igraph_create(linegraph, &edges, (igraph_integer_t) no_of_edges, igraph_is_directed(graph));
4134 igraph_vector_destroy(&edges);
4135 IGRAPH_FINALLY_CLEAN(1);
4136
4137 return 0;
4138 }
4139
4140 /**
4141 * \function igraph_linegraph
4142 * \brief Create the line graph of a graph.
4143 *
4144 * The line graph L(G) of a G undirected graph is defined as follows.
4145 * L(G) has one vertex for each edge in G and two vertices in L(G) are connected
4146 * by an edge if their corresponding edges share an end point.
4147 *
4148 * </para><para>
4149 * The line graph L(G) of a G directed graph is slightly different,
4150 * L(G) has one vertex for each edge in G and two vertices in L(G) are connected
4151 * by a directed edge if the target of the first vertex's corresponding edge
4152 * is the same as the source of the second vertex's corresponding edge.
4153 *
4154 * </para><para>
4155 * Edge \em i in the original graph will correspond to vertex \em i
4156 * in the line graph.
4157 *
4158 * </para><para>
4159 * The first version of this function was contributed by Vincent Matossian,
4160 * thanks.
4161 * \param graph The input graph, may be directed or undirected.
4162 * \param linegraph Pointer to an uninitialized graph object, the
4163 * result is stored here.
4164 * \return Error code.
4165 *
4166 * Time complexity: O(|V|+|E|), the number of edges plus the number of vertices.
4167 */
4168
igraph_linegraph(const igraph_t * graph,igraph_t * linegraph)4169 int igraph_linegraph(const igraph_t *graph, igraph_t *linegraph) {
4170
4171 if (igraph_is_directed(graph)) {
4172 return igraph_i_linegraph_directed(graph, linegraph);
4173 } else {
4174 return igraph_i_linegraph_undirected(graph, linegraph);
4175 }
4176 }
4177
4178 /**
4179 * \function igraph_add_edge
4180 * \brief Adds a single edge to a graph.
4181 *
4182 * </para><para>
4183 * For directed graphs the edge points from \p from to \p to.
4184 *
4185 * </para><para>
4186 * Note that if you want to add many edges to a big graph, then it is
4187 * inefficient to add them one by one, it is better to collect them into
4188 * a vector and add all of them via a single \ref igraph_add_edges() call.
4189 * \param igraph The graph.
4190 * \param from The id of the first vertex of the edge.
4191 * \param to The id of the second vertex of the edge.
4192 * \return Error code.
4193 *
4194 * \sa \ref igraph_add_edges() to add many edges, \ref
4195 * igraph_delete_edges() to remove edges and \ref
4196 * igraph_add_vertices() to add vertices.
4197 *
4198 * Time complexity: O(|V|+|E|), the number of edges plus the number of
4199 * vertices.
4200 */
4201
igraph_add_edge(igraph_t * graph,igraph_integer_t from,igraph_integer_t to)4202 int igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to) {
4203
4204 igraph_vector_t edges;
4205 int ret;
4206
4207 IGRAPH_VECTOR_INIT_FINALLY(&edges, 2);
4208
4209 VECTOR(edges)[0] = from;
4210 VECTOR(edges)[1] = to;
4211 IGRAPH_CHECK(ret = igraph_add_edges(graph, &edges, 0));
4212
4213 igraph_vector_destroy(&edges);
4214 IGRAPH_FINALLY_CLEAN(1);
4215 return ret;
4216 }
4217
4218 /*
4219 * \example examples/simple/graph_convergence_degree.c
4220 */
4221
igraph_convergence_degree(const igraph_t * graph,igraph_vector_t * result,igraph_vector_t * ins,igraph_vector_t * outs)4222 int igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result,
4223 igraph_vector_t *ins, igraph_vector_t *outs) {
4224 long int no_of_nodes = igraph_vcount(graph);
4225 long int no_of_edges = igraph_ecount(graph);
4226 long int i, j, k, n;
4227 long int *geodist;
4228 igraph_vector_int_t *eids;
4229 igraph_vector_t *ins_p, *outs_p, ins_v, outs_v;
4230 igraph_dqueue_t q;
4231 igraph_inclist_t inclist;
4232 igraph_bool_t directed = igraph_is_directed(graph);
4233
4234 if (result != 0) {
4235 IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));
4236 }
4237 IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
4238 IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
4239
4240 if (ins == 0) {
4241 ins_p = &ins_v;
4242 IGRAPH_VECTOR_INIT_FINALLY(ins_p, no_of_edges);
4243 } else {
4244 ins_p = ins;
4245 IGRAPH_CHECK(igraph_vector_resize(ins_p, no_of_edges));
4246 igraph_vector_null(ins_p);
4247 }
4248
4249 if (outs == 0) {
4250 outs_p = &outs_v;
4251 IGRAPH_VECTOR_INIT_FINALLY(outs_p, no_of_edges);
4252 } else {
4253 outs_p = outs;
4254 IGRAPH_CHECK(igraph_vector_resize(outs_p, no_of_edges));
4255 igraph_vector_null(outs_p);
4256 }
4257
4258 geodist = igraph_Calloc(no_of_nodes, long int);
4259 if (geodist == 0) {
4260 IGRAPH_ERROR("Cannot calculate convergence degrees", IGRAPH_ENOMEM);
4261 }
4262 IGRAPH_FINALLY(igraph_free, geodist);
4263
4264 /* Collect shortest paths originating from/to every node to correctly
4265 * determine input field sizes */
4266 for (k = 0; k < (directed ? 2 : 1); k++) {
4267 igraph_neimode_t neimode = (k == 0) ? IGRAPH_OUT : IGRAPH_IN;
4268 igraph_real_t *vec;
4269 IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, neimode));
4270 IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
4271 vec = (k == 0) ? VECTOR(*ins_p) : VECTOR(*outs_p);
4272 for (i = 0; i < no_of_nodes; i++) {
4273 igraph_dqueue_clear(&q);
4274 memset(geodist, 0, sizeof(long int) * (size_t) no_of_nodes);
4275 geodist[i] = 1;
4276 IGRAPH_CHECK(igraph_dqueue_push(&q, i));
4277 IGRAPH_CHECK(igraph_dqueue_push(&q, 0.0));
4278 while (!igraph_dqueue_empty(&q)) {
4279 long int actnode = (long int) igraph_dqueue_pop(&q);
4280 long int actdist = (long int) igraph_dqueue_pop(&q);
4281 IGRAPH_ALLOW_INTERRUPTION();
4282 eids = igraph_inclist_get(&inclist, actnode);
4283 n = igraph_vector_int_size(eids);
4284 for (j = 0; j < n; j++) {
4285 long int neighbor = IGRAPH_OTHER(graph, VECTOR(*eids)[j], actnode);
4286 if (geodist[neighbor] != 0) {
4287 /* we've already seen this node, another shortest path? */
4288 if (geodist[neighbor] - 1 == actdist + 1) {
4289 /* Since this edge is in the BFS tree rooted at i, we must
4290 * increase either the size of the infield or the outfield */
4291 if (!directed) {
4292 if (actnode < neighbor) {
4293 VECTOR(*ins_p)[(long int)VECTOR(*eids)[j]] += 1;
4294 } else {
4295 VECTOR(*outs_p)[(long int)VECTOR(*eids)[j]] += 1;
4296 }
4297 } else {
4298 vec[(long int)VECTOR(*eids)[j]] += 1;
4299 }
4300 } else if (geodist[neighbor] - 1 < actdist + 1) {
4301 continue;
4302 }
4303 } else {
4304 /* we haven't seen this node yet */
4305 IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
4306 IGRAPH_CHECK(igraph_dqueue_push(&q, actdist + 1));
4307 /* Since this edge is in the BFS tree rooted at i, we must
4308 * increase either the size of the infield or the outfield */
4309 if (!directed) {
4310 if (actnode < neighbor) {
4311 VECTOR(*ins_p)[(long int)VECTOR(*eids)[j]] += 1;
4312 } else {
4313 VECTOR(*outs_p)[(long int)VECTOR(*eids)[j]] += 1;
4314 }
4315 } else {
4316 vec[(long int)VECTOR(*eids)[j]] += 1;
4317 }
4318 geodist[neighbor] = actdist + 2;
4319 }
4320 }
4321 }
4322 }
4323
4324 igraph_inclist_destroy(&inclist);
4325 IGRAPH_FINALLY_CLEAN(1);
4326 }
4327
4328 if (result != 0) {
4329 for (i = 0; i < no_of_edges; i++)
4330 VECTOR(*result)[i] = (VECTOR(*ins_p)[i] - VECTOR(*outs_p)[i]) /
4331 (VECTOR(*ins_p)[i] + VECTOR(*outs_p)[i]);
4332 if (!directed) {
4333 for (i = 0; i < no_of_edges; i++)
4334 if (VECTOR(*result)[i] < 0) {
4335 VECTOR(*result)[i] = -VECTOR(*result)[i];
4336 }
4337 }
4338 }
4339
4340 if (ins == 0) {
4341 igraph_vector_destroy(ins_p);
4342 IGRAPH_FINALLY_CLEAN(1);
4343 }
4344 if (outs == 0) {
4345 igraph_vector_destroy(outs_p);
4346 IGRAPH_FINALLY_CLEAN(1);
4347 }
4348
4349 igraph_free(geodist);
4350 igraph_dqueue_destroy(&q);
4351 IGRAPH_FINALLY_CLEAN(2);
4352
4353 return 0;
4354 }
4355
4356 /**
4357 * \function igraph_shortest_paths_dijkstra
4358 * Weighted shortest paths from some sources.
4359 *
4360 * This function is Dijkstra's algorithm to find the weighted
4361 * shortest paths to all vertices from a single source. (It is run
4362 * independently for the given sources.) It uses a binary heap for
4363 * efficient implementation.
4364 *
4365 * \param graph The input graph, can be directed.
4366 * \param res The result, a matrix. A pointer to an initialized matrix
4367 * should be passed here. The matrix will be resized as needed.
4368 * Each row contains the distances from a single source, to the
4369 * vertices given in the \c to argument.
4370 * Unreachable vertices has distance
4371 * \c IGRAPH_INFINITY.
4372 * \param from The source vertices.
4373 * \param to The target vertices. It is not allowed to include a
4374 * vertex twice or more.
4375 * \param weights The edge weights. They must be all non-negative for
4376 * Dijkstra's algorithm to work. An error code is returned if there
4377 * is a negative edge weight in the weight vector. If this is a null
4378 * pointer, then the
4379 * unweighted version, \ref igraph_shortest_paths() is called.
4380 * \param mode For directed graphs; whether to follow paths along edge
4381 * directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
4382 * ignore edge directions completely (\c IGRAPH_ALL). It is ignored
4383 * for undirected graphs.
4384 * \return Error code.
4385 *
4386 * Time complexity: O(s*|E|log|E|+|V|), where |V| is the number of
4387 * vertices, |E| the number of edges and s the number of sources.
4388 *
4389 * \sa \ref igraph_shortest_paths() for a (slightly) faster unweighted
4390 * version or \ref igraph_shortest_paths_bellman_ford() for a weighted
4391 * variant that works in the presence of negative edge weights (but no
4392 * negative loops).
4393 *
4394 * \example examples/simple/dijkstra.c
4395 */
4396
igraph_shortest_paths_dijkstra(const igraph_t * graph,igraph_matrix_t * res,const igraph_vs_t from,const igraph_vs_t to,const igraph_vector_t * weights,igraph_neimode_t mode)4397 int igraph_shortest_paths_dijkstra(const igraph_t *graph,
4398 igraph_matrix_t *res,
4399 const igraph_vs_t from,
4400 const igraph_vs_t to,
4401 const igraph_vector_t *weights,
4402 igraph_neimode_t mode) {
4403
4404 /* Implementation details. This is the basic Dijkstra algorithm,
4405 with a binary heap. The heap is indexed, i.e. it stores not only
4406 the distances, but also which vertex they belong to.
4407
4408 From now on we use a 2-way heap, so the distances can be queried
4409 directly from the heap.
4410
4411 Dirty tricks:
4412 - the opposite of the distance is stored in the heap, as it is a
4413 maximum heap and we need a minimum heap.
4414 - we don't use IGRAPH_INFINITY in the res matrix during the
4415 computation, as IGRAPH_FINITE() might involve a function call
4416 and we want to spare that. -1 will denote infinity instead.
4417 */
4418
4419 long int no_of_nodes = igraph_vcount(graph);
4420 long int no_of_edges = igraph_ecount(graph);
4421 igraph_2wheap_t Q;
4422 igraph_vit_t fromvit, tovit;
4423 long int no_of_from, no_of_to;
4424 igraph_lazy_inclist_t inclist;
4425 long int i, j;
4426 igraph_real_t my_infinity = IGRAPH_INFINITY;
4427 igraph_bool_t all_to;
4428 igraph_vector_t indexv;
4429
4430 if (!weights) {
4431 return igraph_shortest_paths(graph, res, from, to, mode);
4432 }
4433
4434 if (igraph_vector_size(weights) != no_of_edges) {
4435 IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
4436 }
4437 if (igraph_vector_min(weights) < 0) {
4438 IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
4439 }
4440
4441 IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
4442 IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
4443 no_of_from = IGRAPH_VIT_SIZE(fromvit);
4444
4445 IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
4446 IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
4447 IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
4448 IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
4449
4450 if ( (all_to = igraph_vs_is_all(&to)) ) {
4451 no_of_to = no_of_nodes;
4452 } else {
4453 IGRAPH_VECTOR_INIT_FINALLY(&indexv, no_of_nodes);
4454 IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
4455 IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
4456 no_of_to = IGRAPH_VIT_SIZE(tovit);
4457 for (i = 0; !IGRAPH_VIT_END(tovit); IGRAPH_VIT_NEXT(tovit)) {
4458 long int v = IGRAPH_VIT_GET(tovit);
4459 if (VECTOR(indexv)[v]) {
4460 IGRAPH_ERROR("Duplicate vertices in `to', this is not allowed",
4461 IGRAPH_EINVAL);
4462 }
4463 VECTOR(indexv)[v] = ++i;
4464 }
4465 }
4466
4467 IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
4468 igraph_matrix_fill(res, my_infinity);
4469
4470 for (IGRAPH_VIT_RESET(fromvit), i = 0;
4471 !IGRAPH_VIT_END(fromvit);
4472 IGRAPH_VIT_NEXT(fromvit), i++) {
4473
4474 long int reached = 0;
4475 long int source = IGRAPH_VIT_GET(fromvit);
4476 igraph_2wheap_clear(&Q);
4477 igraph_2wheap_push_with_index(&Q, source, -1.0);
4478
4479 while (!igraph_2wheap_empty(&Q)) {
4480 long int minnei = igraph_2wheap_max_index(&Q);
4481 igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q);
4482 igraph_vector_t *neis;
4483 long int nlen;
4484
4485 if (all_to) {
4486 MATRIX(*res, i, minnei) = mindist - 1.0;
4487 } else {
4488 if (VECTOR(indexv)[minnei]) {
4489 MATRIX(*res, i, (long int)(VECTOR(indexv)[minnei] - 1)) = mindist - 1.0;
4490 reached++;
4491 if (reached == no_of_to) {
4492 igraph_2wheap_clear(&Q);
4493 break;
4494 }
4495 }
4496 }
4497
4498 /* Now check all neighbors of 'minnei' for a shorter path */
4499 neis = igraph_lazy_inclist_get(&inclist, (igraph_integer_t) minnei);
4500 nlen = igraph_vector_size(neis);
4501 for (j = 0; j < nlen; j++) {
4502 long int edge = (long int) VECTOR(*neis)[j];
4503 long int tto = IGRAPH_OTHER(graph, edge, minnei);
4504 igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
4505 igraph_bool_t active = igraph_2wheap_has_active(&Q, tto);
4506 igraph_bool_t has = igraph_2wheap_has_elem(&Q, tto);
4507 igraph_real_t curdist = active ? -igraph_2wheap_get(&Q, tto) : 0.0;
4508 if (!has) {
4509 /* This is the first non-infinite distance */
4510 IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
4511 } else if (altdist < curdist) {
4512 /* This is a shorter path */
4513 IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
4514 }
4515 }
4516
4517 } /* !igraph_2wheap_empty(&Q) */
4518
4519 } /* !IGRAPH_VIT_END(fromvit) */
4520
4521 if (!all_to) {
4522 igraph_vit_destroy(&tovit);
4523 igraph_vector_destroy(&indexv);
4524 IGRAPH_FINALLY_CLEAN(2);
4525 }
4526
4527 igraph_lazy_inclist_destroy(&inclist);
4528 igraph_2wheap_destroy(&Q);
4529 igraph_vit_destroy(&fromvit);
4530 IGRAPH_FINALLY_CLEAN(3);
4531
4532 return 0;
4533 }
4534
4535 /**
4536 * \ingroup structural
4537 * \function igraph_get_shortest_paths_dijkstra
4538 * \brief Calculates the weighted shortest paths from/to one vertex.
4539 *
4540 * </para><para>
4541 * If there is more than one path with the smallest weight between two vertices, this
4542 * function gives only one of them.
4543 * \param graph The graph object.
4544 * \param vertices The result, the ids of the vertices along the paths.
4545 * This is a pointer vector, each element points to a vector
4546 * object. These should be initialized before passing them to
4547 * the function, which will properly clear and/or resize them
4548 * and fill the ids of the vertices along the geodesics from/to
4549 * the vertices. Supply a null pointer here if you don't need
4550 * these vectors. Normally, either this argument, or the \c
4551 * edges should be non-null, but no error or warning is given
4552 * if they are both null pointers.
4553 * \param edges The result, the ids of the edges along the paths.
4554 * This is a pointer vector, each element points to a vector
4555 * object. These should be initialized before passing them to
4556 * the function, which will properly clear and/or resize them
4557 * and fill the ids of the vertices along the geodesics from/to
4558 * the vertices. Supply a null pointer here if you don't need
4559 * these vectors. Normally, either this argument, or the \c
4560 * vertices should be non-null, but no error or warning is given
4561 * if they are both null pointers.
4562 * \param from The id of the vertex from/to which the geodesics are
4563 * calculated.
4564 * \param to Vertex sequence with the ids of the vertices to/from which the
4565 * shortest paths will be calculated. A vertex might be given multiple
4566 * times.
4567 * \param weights a vector holding the edge weights. All weights must be
4568 * positive.
4569 * \param mode The type of shortest paths to be use for the
4570 * calculation in directed graphs. Possible values:
4571 * \clist
4572 * \cli IGRAPH_OUT
4573 * the outgoing paths are calculated.
4574 * \cli IGRAPH_IN
4575 * the incoming paths are calculated.
4576 * \cli IGRAPH_ALL
4577 * the directed graph is considered as an
4578 * undirected one for the computation.
4579 * \endclist
4580 * \param predecessors A pointer to an initialized igraph vector or null.
4581 * If not null, a vector containing the predecessor of each vertex in
4582 * the single source shortest path tree is returned here. The
4583 * predecessor of vertex i in the tree is the vertex from which vertex i
4584 * was reached. The predecessor of the start vertex (in the \c from
4585 * argument) is itself by definition. If the predecessor is -1, it means
4586 * that the given vertex was not reached from the source during the
4587 * search. Note that the search terminates if all the vertices in
4588 * \c to are reached.
4589 * \param inbound_edges A pointer to an initialized igraph vector or null.
4590 * If not null, a vector containing the inbound edge of each vertex in
4591 * the single source shortest path tree is returned here. The
4592 * inbound edge of vertex i in the tree is the edge via which vertex i
4593 * was reached. The start vertex and vertices that were not reached
4594 * during the search will have -1 in the corresponding entry of the
4595 * vector. Note that the search terminates if all the vertices in
4596 * \c to are reached.
4597 * \return Error code:
4598 * \clist
4599 * \cli IGRAPH_ENOMEM
4600 * not enough memory for temporary data.
4601 * \cli IGRAPH_EINVVID
4602 * \p from is invalid vertex id, or the length of \p to is
4603 * not the same as the length of \p res.
4604 * \cli IGRAPH_EINVMODE
4605 * invalid mode argument.
4606 * \endclist
4607 *
4608 * Time complexity: O(|E|log|E|+|V|), where |V| is the number of
4609 * vertices and |E| is the number of edges
4610 *
4611 * \sa \ref igraph_shortest_paths_dijkstra() if you only need the path length but
4612 * not the paths themselves, \ref igraph_get_shortest_paths() if all edge
4613 * weights are equal.
4614 *
4615 * \example examples/simple/igraph_get_shortest_paths_dijkstra.c
4616 */
igraph_get_shortest_paths_dijkstra(const igraph_t * graph,igraph_vector_ptr_t * vertices,igraph_vector_ptr_t * edges,igraph_integer_t from,igraph_vs_t to,const igraph_vector_t * weights,igraph_neimode_t mode,igraph_vector_long_t * predecessors,igraph_vector_long_t * inbound_edges)4617 int igraph_get_shortest_paths_dijkstra(const igraph_t *graph,
4618 igraph_vector_ptr_t *vertices,
4619 igraph_vector_ptr_t *edges,
4620 igraph_integer_t from,
4621 igraph_vs_t to,
4622 const igraph_vector_t *weights,
4623 igraph_neimode_t mode,
4624 igraph_vector_long_t *predecessors,
4625 igraph_vector_long_t *inbound_edges) {
4626 /* Implementation details. This is the basic Dijkstra algorithm,
4627 with a binary heap. The heap is indexed, i.e. it stores not only
4628 the distances, but also which vertex they belong to. The other
4629 mapping, i.e. getting the distance for a vertex is not in the
4630 heap (that would by the double-indexed heap), but in the result
4631 matrix.
4632
4633 Dirty tricks:
4634 - the opposite of the distance is stored in the heap, as it is a
4635 maximum heap and we need a minimum heap.
4636 - we don't use IGRAPH_INFINITY in the distance vector during the
4637 computation, as IGRAPH_FINITE() might involve a function call
4638 and we want to spare that. So we store distance+1.0 instead of
4639 distance, and zero denotes infinity.
4640 - `parents' assigns the inbound edge IDs of all vertices in the
4641 shortest path tree to the vertices. In this implementation, the
4642 edge ID + 1 is stored, zero means unreachable vertices.
4643 */
4644
4645 long int no_of_nodes = igraph_vcount(graph);
4646 long int no_of_edges = igraph_ecount(graph);
4647 igraph_vit_t vit;
4648 igraph_2wheap_t Q;
4649 igraph_lazy_inclist_t inclist;
4650 igraph_vector_t dists;
4651 long int *parents;
4652 igraph_bool_t *is_target;
4653 long int i, to_reach;
4654
4655 if (!weights) {
4656 return igraph_get_shortest_paths(graph, vertices, edges, from, to, mode,
4657 predecessors, inbound_edges);
4658 }
4659
4660 if (igraph_vector_size(weights) != no_of_edges) {
4661 IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
4662 }
4663 if (igraph_vector_min(weights) < 0) {
4664 IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
4665 }
4666
4667 IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
4668 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
4669
4670 if (vertices && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(vertices)) {
4671 IGRAPH_ERROR("Size of `vertices' and `to' should match", IGRAPH_EINVAL);
4672 }
4673 if (edges && IGRAPH_VIT_SIZE(vit) != igraph_vector_ptr_size(edges)) {
4674 IGRAPH_ERROR("Size of `edges' and `to' should match", IGRAPH_EINVAL);
4675 }
4676
4677 IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
4678 IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
4679 IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
4680 IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
4681
4682 IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes);
4683 igraph_vector_fill(&dists, -1.0);
4684
4685 parents = igraph_Calloc(no_of_nodes, long int);
4686 if (parents == 0) {
4687 IGRAPH_ERROR("Can't calculate shortest paths", IGRAPH_ENOMEM);
4688 }
4689 IGRAPH_FINALLY(igraph_free, parents);
4690 is_target = igraph_Calloc(no_of_nodes, igraph_bool_t);
4691 if (is_target == 0) {
4692 IGRAPH_ERROR("Can't calculate shortest paths", IGRAPH_ENOMEM);
4693 }
4694 IGRAPH_FINALLY(igraph_free, is_target);
4695
4696 /* Mark the vertices we need to reach */
4697 to_reach = IGRAPH_VIT_SIZE(vit);
4698 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
4699 if (!is_target[ (long int) IGRAPH_VIT_GET(vit) ]) {
4700 is_target[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
4701 } else {
4702 to_reach--; /* this node was given multiple times */
4703 }
4704 }
4705
4706 VECTOR(dists)[(long int)from] = 0.0; /* zero distance */
4707 parents[(long int)from] = 0;
4708 igraph_2wheap_push_with_index(&Q, from, 0);
4709
4710 while (!igraph_2wheap_empty(&Q) && to_reach > 0) {
4711 long int nlen, minnei = igraph_2wheap_max_index(&Q);
4712 igraph_real_t mindist = -igraph_2wheap_delete_max(&Q);
4713 igraph_vector_t *neis;
4714
4715 IGRAPH_ALLOW_INTERRUPTION();
4716
4717 if (is_target[minnei]) {
4718 is_target[minnei] = 0;
4719 to_reach--;
4720 }
4721
4722 /* Now check all neighbors of 'minnei' for a shorter path */
4723 neis = igraph_lazy_inclist_get(&inclist, (igraph_integer_t) minnei);
4724 nlen = igraph_vector_size(neis);
4725 for (i = 0; i < nlen; i++) {
4726 long int edge = (long int) VECTOR(*neis)[i];
4727 long int tto = IGRAPH_OTHER(graph, edge, minnei);
4728 igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
4729 igraph_real_t curdist = VECTOR(dists)[tto];
4730 if (curdist < 0) {
4731 /* This is the first finite distance */
4732 VECTOR(dists)[tto] = altdist;
4733 parents[tto] = edge + 1;
4734 IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
4735 } else if (altdist < curdist) {
4736 /* This is a shorter path */
4737 VECTOR(dists)[tto] = altdist;
4738 parents[tto] = edge + 1;
4739 IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
4740 }
4741 }
4742 } /* !igraph_2wheap_empty(&Q) */
4743
4744 if (to_reach > 0) {
4745 IGRAPH_WARNING("Couldn't reach some vertices");
4746 }
4747
4748 /* Create `predecessors' if needed */
4749 if (predecessors) {
4750 IGRAPH_CHECK(igraph_vector_long_resize(predecessors, no_of_nodes));
4751
4752 for (i = 0; i < no_of_nodes; i++) {
4753 if (i == from) {
4754 /* i is the start vertex */
4755 VECTOR(*predecessors)[i] = i;
4756 } else if (parents[i] <= 0) {
4757 /* i was not reached */
4758 VECTOR(*predecessors)[i] = -1;
4759 } else {
4760 /* i was reached via the edge with ID = parents[i] - 1 */
4761 VECTOR(*predecessors)[i] = IGRAPH_OTHER(graph, parents[i] - 1, i);
4762 }
4763 }
4764 }
4765
4766 /* Create `inbound_edges' if needed */
4767 if (inbound_edges) {
4768 IGRAPH_CHECK(igraph_vector_long_resize(inbound_edges, no_of_nodes));
4769
4770 for (i = 0; i < no_of_nodes; i++) {
4771 if (parents[i] <= 0) {
4772 /* i was not reached */
4773 VECTOR(*inbound_edges)[i] = -1;
4774 } else {
4775 /* i was reached via the edge with ID = parents[i] - 1 */
4776 VECTOR(*inbound_edges)[i] = parents[i] - 1;
4777 }
4778 }
4779 }
4780
4781 /* Reconstruct the shortest paths based on vertex and/or edge IDs */
4782 if (vertices || edges) {
4783 for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
4784 long int node = IGRAPH_VIT_GET(vit);
4785 long int size, act, edge;
4786 igraph_vector_t *vvec = 0, *evec = 0;
4787 if (vertices) {
4788 vvec = VECTOR(*vertices)[i];
4789 igraph_vector_clear(vvec);
4790 }
4791 if (edges) {
4792 evec = VECTOR(*edges)[i];
4793 igraph_vector_clear(evec);
4794 }
4795
4796 IGRAPH_ALLOW_INTERRUPTION();
4797
4798 size = 0;
4799 act = node;
4800 while (parents[act]) {
4801 size++;
4802 edge = parents[act] - 1;
4803 act = IGRAPH_OTHER(graph, edge, act);
4804 }
4805 if (vvec) {
4806 IGRAPH_CHECK(igraph_vector_resize(vvec, size + 1));
4807 VECTOR(*vvec)[size] = node;
4808 }
4809 if (evec) {
4810 IGRAPH_CHECK(igraph_vector_resize(evec, size));
4811 }
4812 act = node;
4813 while (parents[act]) {
4814 edge = parents[act] - 1;
4815 act = IGRAPH_OTHER(graph, edge, act);
4816 size--;
4817 if (vvec) {
4818 VECTOR(*vvec)[size] = act;
4819 }
4820 if (evec) {
4821 VECTOR(*evec)[size] = edge;
4822 }
4823 }
4824 }
4825 }
4826
4827 igraph_lazy_inclist_destroy(&inclist);
4828 igraph_2wheap_destroy(&Q);
4829 igraph_vector_destroy(&dists);
4830 igraph_Free(is_target);
4831 igraph_Free(parents);
4832 igraph_vit_destroy(&vit);
4833 IGRAPH_FINALLY_CLEAN(6);
4834
4835 return 0;
4836 }
4837
4838 /**
4839 * \function igraph_get_shortest_path_dijkstra
4840 * Weighted shortest path from one vertex to another one.
4841 *
4842 * Calculates a single (positively) weighted shortest path from
4843 * a single vertex to another one, using Dijkstra's algorithm.
4844 *
4845 * </para><para>This function is a special case (and a wrapper) to
4846 * \ref igraph_get_shortest_paths_dijkstra().
4847 *
4848 * \param graph The input graph, it can be directed or undirected.
4849 * \param vertices Pointer to an initialized vector or a null
4850 * pointer. If not a null pointer, then the vertex ids along
4851 * the path are stored here, including the source and target
4852 * vertices.
4853 * \param edges Pointer to an uninitialized vector or a null
4854 * pointer. If not a null pointer, then the edge ids along the
4855 * path are stored here.
4856 * \param from The id of the source vertex.
4857 * \param to The id of the target vertex.
4858 * \param weights Vector of edge weights, in the order of edge
4859 * ids. They must be non-negative, otherwise the algorithm does
4860 * not work.
4861 * \param mode A constant specifying how edge directions are
4862 * considered in directed graphs. \c IGRAPH_OUT follows edge
4863 * directions, \c IGRAPH_IN follows the opposite directions,
4864 * and \c IGRAPH_ALL ignores edge directions. This argument is
4865 * ignored for undirected graphs.
4866 * \return Error code.
4867 *
4868 * Time complexity: O(|E|log|E|+|V|), |V| is the number of vertices,
4869 * |E| is the number of edges in the graph.
4870 *
4871 * \sa \ref igraph_get_shortest_paths_dijkstra() for the version with
4872 * more target vertices.
4873 */
4874
igraph_get_shortest_path_dijkstra(const igraph_t * graph,igraph_vector_t * vertices,igraph_vector_t * edges,igraph_integer_t from,igraph_integer_t to,const igraph_vector_t * weights,igraph_neimode_t mode)4875 int igraph_get_shortest_path_dijkstra(const igraph_t *graph,
4876 igraph_vector_t *vertices,
4877 igraph_vector_t *edges,
4878 igraph_integer_t from,
4879 igraph_integer_t to,
4880 const igraph_vector_t *weights,
4881 igraph_neimode_t mode) {
4882
4883 igraph_vector_ptr_t vertices2, *vp = &vertices2;
4884 igraph_vector_ptr_t edges2, *ep = &edges2;
4885
4886 if (vertices) {
4887 IGRAPH_CHECK(igraph_vector_ptr_init(&vertices2, 1));
4888 IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vertices2);
4889 VECTOR(vertices2)[0] = vertices;
4890 } else {
4891 vp = 0;
4892 }
4893 if (edges) {
4894 IGRAPH_CHECK(igraph_vector_ptr_init(&edges2, 1));
4895 IGRAPH_FINALLY(igraph_vector_ptr_destroy, &edges2);
4896 VECTOR(edges2)[0] = edges;
4897 } else {
4898 ep = 0;
4899 }
4900
4901 IGRAPH_CHECK(igraph_get_shortest_paths_dijkstra(graph, vp, ep,
4902 from, igraph_vss_1(to),
4903 weights, mode, 0, 0));
4904
4905 if (edges) {
4906 igraph_vector_ptr_destroy(&edges2);
4907 IGRAPH_FINALLY_CLEAN(1);
4908 }
4909 if (vertices) {
4910 igraph_vector_ptr_destroy(&vertices2);
4911 IGRAPH_FINALLY_CLEAN(1);
4912 }
4913
4914 return 0;
4915 }
4916
4917 int igraph_i_vector_tail_cmp(const void* path1, const void* path2);
4918
4919 /* Compares two paths based on their last elements. Required by
4920 * igraph_get_all_shortest_paths_dijkstra to put the final result
4921 * in order. Assumes that both paths are pointers to igraph_vector_t
4922 * objects and that they are not empty
4923 */
igraph_i_vector_tail_cmp(const void * path1,const void * path2)4924 int igraph_i_vector_tail_cmp(const void* path1, const void* path2) {
4925 return (int) (igraph_vector_tail(*(const igraph_vector_t**)path1) -
4926 igraph_vector_tail(*(const igraph_vector_t**)path2));
4927 }
4928
4929 /**
4930 * \ingroup structural
4931 * \function igraph_get_all_shortest_paths_dijkstra
4932 * \brief Finds all shortest paths (geodesics) from a vertex to all other vertices.
4933 *
4934 * \param graph The graph object.
4935 * \param res Pointer to an initialized pointer vector, the result
4936 * will be stored here in igraph_vector_t objects. Each vector
4937 * object contains the vertices along a shortest path from \p from
4938 * to another vertex. The vectors are ordered according to their
4939 * target vertex: first the shortest paths to vertex 0, then to
4940 * vertex 1, etc. No data is included for unreachable vertices.
4941 * \param nrgeo Pointer to an initialized igraph_vector_t object or
4942 * NULL. If not NULL the number of shortest paths from \p from are
4943 * stored here for every vertex in the graph. Note that the values
4944 * will be accurate only for those vertices that are in the target
4945 * vertex sequence (see \p to), since the search terminates as soon
4946 * as all the target vertices have been found.
4947 * \param from The id of the vertex from/to which the geodesics are
4948 * calculated.
4949 * \param to Vertex sequence with the ids of the vertices to/from which the
4950 * shortest paths will be calculated. A vertex might be given multiple
4951 * times.
4952 * \param weights a vector holding the edge weights. All weights must be
4953 * non-negative.
4954 * \param mode The type of shortest paths to be use for the
4955 * calculation in directed graphs. Possible values:
4956 * \clist
4957 * \cli IGRAPH_OUT
4958 * the outgoing paths are calculated.
4959 * \cli IGRAPH_IN
4960 * the incoming paths are calculated.
4961 * \cli IGRAPH_ALL
4962 * the directed graph is considered as an
4963 * undirected one for the computation.
4964 * \endclist
4965 * \return Error code:
4966 * \clist
4967 * \cli IGRAPH_ENOMEM
4968 * not enough memory for temporary data.
4969 * \cli IGRAPH_EINVVID
4970 * \p from is invalid vertex id, or the length of \p to is
4971 * not the same as the length of \p res.
4972 * \cli IGRAPH_EINVMODE
4973 * invalid mode argument.
4974 * \endclist
4975 *
4976 * Time complexity: O(|E|log|E|+|V|), where |V| is the number of
4977 * vertices and |E| is the number of edges
4978 *
4979 * \sa \ref igraph_shortest_paths_dijkstra() if you only need the path
4980 * length but not the paths themselves, \ref igraph_get_all_shortest_paths()
4981 * if all edge weights are equal.
4982 *
4983 * \example examples/simple/igraph_get_all_shortest_paths_dijkstra.c
4984 */
igraph_get_all_shortest_paths_dijkstra(const igraph_t * graph,igraph_vector_ptr_t * res,igraph_vector_t * nrgeo,igraph_integer_t from,igraph_vs_t to,const igraph_vector_t * weights,igraph_neimode_t mode)4985 int igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph,
4986 igraph_vector_ptr_t *res,
4987 igraph_vector_t *nrgeo,
4988 igraph_integer_t from, igraph_vs_t to,
4989 const igraph_vector_t *weights,
4990 igraph_neimode_t mode) {
4991 /* Implementation details: see igraph_get_shortest_paths_dijkstra,
4992 it's basically the same.
4993 */
4994
4995 long int no_of_nodes = igraph_vcount(graph);
4996 long int no_of_edges = igraph_ecount(graph);
4997 igraph_vit_t vit;
4998 igraph_2wheap_t Q;
4999 igraph_lazy_inclist_t inclist;
5000 igraph_vector_t dists, order;
5001 igraph_vector_ptr_t parents;
5002 unsigned char *is_target;
5003 long int i, n, to_reach;
5004
5005 if (!weights) {
5006 return igraph_get_all_shortest_paths(graph, res, nrgeo, from, to, mode);
5007 }
5008
5009 if (res == 0 && nrgeo == 0) {
5010 return IGRAPH_SUCCESS;
5011 }
5012
5013 if (igraph_vector_size(weights) != no_of_edges) {
5014 IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
5015 }
5016 if (igraph_vector_min(weights) < 0) {
5017 IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
5018 }
5019
5020 /* parents stores a vector for each vertex, listing the parent vertices
5021 * of each vertex in the traversal */
5022 IGRAPH_CHECK(igraph_vector_ptr_init(&parents, no_of_nodes));
5023 IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &parents);
5024 igraph_vector_ptr_set_item_destructor(&parents, (igraph_finally_func_t*)igraph_vector_destroy);
5025 for (i = 0; i < no_of_nodes; i++) {
5026 igraph_vector_t* parent_vec;
5027 parent_vec = igraph_Calloc(1, igraph_vector_t);
5028 if (parent_vec == 0) {
5029 IGRAPH_ERROR("cannot run igraph_get_all_shortest_paths", IGRAPH_ENOMEM);
5030 }
5031 IGRAPH_CHECK(igraph_vector_init(parent_vec, 0));
5032 VECTOR(parents)[i] = parent_vec;
5033 }
5034
5035 /* distance of each vertex from the root */
5036 IGRAPH_VECTOR_INIT_FINALLY(&dists, no_of_nodes);
5037 igraph_vector_fill(&dists, -1.0);
5038
5039 /* order lists the order of vertices in which they were found during
5040 * the traversal */
5041 IGRAPH_VECTOR_INIT_FINALLY(&order, 0);
5042
5043 /* boolean array to mark whether a given vertex is a target or not */
5044 is_target = igraph_Calloc(no_of_nodes, unsigned char);
5045 if (is_target == 0) {
5046 IGRAPH_ERROR("Can't calculate shortest paths", IGRAPH_ENOMEM);
5047 }
5048 IGRAPH_FINALLY(igraph_free, is_target);
5049
5050 /* two-way heap storing vertices and distances */
5051 IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
5052 IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
5053
5054 /* lazy adjacency edge list to query neighbours efficiently */
5055 IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
5056 IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
5057
5058 /* Mark the vertices we need to reach */
5059 IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
5060 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
5061 to_reach = IGRAPH_VIT_SIZE(vit);
5062 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
5063 if (!is_target[ (long int) IGRAPH_VIT_GET(vit) ]) {
5064 is_target[ (long int) IGRAPH_VIT_GET(vit) ] = 1;
5065 } else {
5066 to_reach--; /* this node was given multiple times */
5067 }
5068 }
5069 igraph_vit_destroy(&vit);
5070 IGRAPH_FINALLY_CLEAN(1);
5071
5072 VECTOR(dists)[(long int)from] = 0.0; /* zero distance */
5073 igraph_2wheap_push_with_index(&Q, from, 0);
5074
5075 while (!igraph_2wheap_empty(&Q) && to_reach > 0) {
5076 long int nlen, minnei = igraph_2wheap_max_index(&Q);
5077 igraph_real_t mindist = -igraph_2wheap_delete_max(&Q);
5078 igraph_vector_t *neis;
5079
5080 IGRAPH_ALLOW_INTERRUPTION();
5081
5082 /*
5083 printf("Reached vertex %ld, is_target[%ld] = %d, %ld to go\n",
5084 minnei, minnei, (int)is_target[minnei], to_reach - is_target[minnei]);
5085 */
5086
5087 if (is_target[minnei]) {
5088 is_target[minnei] = 0;
5089 to_reach--;
5090 }
5091
5092 /* Mark that we have reached this vertex */
5093 IGRAPH_CHECK(igraph_vector_push_back(&order, minnei));
5094
5095 /* Now check all neighbors of 'minnei' for a shorter path */
5096 neis = igraph_lazy_inclist_get(&inclist, (igraph_integer_t) minnei);
5097 nlen = igraph_vector_size(neis);
5098 for (i = 0; i < nlen; i++) {
5099 long int edge = (long int) VECTOR(*neis)[i];
5100 long int tto = IGRAPH_OTHER(graph, edge, minnei);
5101 igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
5102 igraph_real_t curdist = VECTOR(dists)[tto];
5103 igraph_vector_t *parent_vec;
5104
5105 if (curdist < 0) {
5106 /* This is the first non-infinite distance */
5107 VECTOR(dists)[tto] = altdist;
5108 parent_vec = (igraph_vector_t*)VECTOR(parents)[tto];
5109 IGRAPH_CHECK(igraph_vector_push_back(parent_vec, minnei));
5110 IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
5111 } else if (altdist == curdist && VECTOR(*weights)[edge] > 0) {
5112 /* This is an alternative path with exactly the same length.
5113 * Note that we consider this case only if the edge via which we
5114 * reached the node has a nonzero weight; otherwise we could create
5115 * infinite loops in undirected graphs by traversing zero-weight edges
5116 * back-and-forth */
5117 parent_vec = (igraph_vector_t*)VECTOR(parents)[tto];
5118 IGRAPH_CHECK(igraph_vector_push_back(parent_vec, minnei));
5119 } else if (altdist < curdist) {
5120 /* This is a shorter path */
5121 VECTOR(dists)[tto] = altdist;
5122 parent_vec = (igraph_vector_t*)VECTOR(parents)[tto];
5123 igraph_vector_clear(parent_vec);
5124 IGRAPH_CHECK(igraph_vector_push_back(parent_vec, minnei));
5125 IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
5126 }
5127 }
5128 } /* !igraph_2wheap_empty(&Q) */
5129
5130 if (to_reach > 0) {
5131 IGRAPH_WARNING("Couldn't reach some vertices");
5132 }
5133
5134 /* we don't need these anymore */
5135 igraph_lazy_inclist_destroy(&inclist);
5136 igraph_2wheap_destroy(&Q);
5137 IGRAPH_FINALLY_CLEAN(2);
5138
5139 /*
5140 printf("Order:\n");
5141 igraph_vector_print(&order);
5142
5143 printf("Parent vertices:\n");
5144 for (i = 0; i < no_of_nodes; i++) {
5145 if (igraph_vector_size(VECTOR(parents)[i]) > 0) {
5146 printf("[%ld]: ", (long int)i);
5147 igraph_vector_print(VECTOR(parents)[i]);
5148 }
5149 }
5150 */
5151
5152 if (nrgeo) {
5153 IGRAPH_CHECK(igraph_vector_resize(nrgeo, no_of_nodes));
5154 igraph_vector_null(nrgeo);
5155
5156 /* Theoretically, we could calculate nrgeo in parallel with the traversal.
5157 * However, that way we would have to check whether nrgeo is null or not
5158 * every time we want to update some element in nrgeo. Since we need the
5159 * order vector anyway for building the final result, we could just as well
5160 * build nrgeo here.
5161 */
5162 VECTOR(*nrgeo)[(long int)from] = 1;
5163 n = igraph_vector_size(&order);
5164 for (i = 1; i < n; i++) {
5165 long int node, j, k;
5166 igraph_vector_t *parent_vec;
5167
5168 node = (long int)VECTOR(order)[i];
5169 /* now, take the parent vertices */
5170 parent_vec = (igraph_vector_t*)VECTOR(parents)[node];
5171 k = igraph_vector_size(parent_vec);
5172 for (j = 0; j < k; j++) {
5173 VECTOR(*nrgeo)[node] += VECTOR(*nrgeo)[(long int)VECTOR(*parent_vec)[j]];
5174 }
5175 }
5176 }
5177
5178 if (res) {
5179 igraph_vector_t *path, *paths_index, *parent_vec;
5180 igraph_stack_t stack;
5181 long int j, node;
5182
5183 /* a shortest path from the starting vertex to vertex i can be
5184 * obtained by calculating the shortest paths from the "parents"
5185 * of vertex i in the traversal. Knowing which of the vertices
5186 * are "targets" (see is_target), we can collect for which other
5187 * vertices do we need to calculate the shortest paths. We reuse
5188 * is_target for that; is_target = 0 means that we don't need the
5189 * vertex, is_target = 1 means that the vertex is a target (hence
5190 * we need it), is_target = 2 means that the vertex is not a target
5191 * but it stands between a shortest path between the root and one
5192 * of the targets
5193 */
5194 if (igraph_vs_is_all(&to)) {
5195 memset(is_target, 1, sizeof(unsigned char) * (size_t) no_of_nodes);
5196 } else {
5197 memset(is_target, 0, sizeof(unsigned char) * (size_t) no_of_nodes);
5198
5199 IGRAPH_CHECK(igraph_stack_init(&stack, 0));
5200 IGRAPH_FINALLY(igraph_stack_destroy, &stack);
5201
5202 /* Add the target vertices to the queue */
5203 IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
5204 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
5205 for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
5206 i = (long int) IGRAPH_VIT_GET(vit);
5207 if (!is_target[i]) {
5208 is_target[i] = 1;
5209 IGRAPH_CHECK(igraph_stack_push(&stack, i));
5210 }
5211 }
5212 igraph_vit_destroy(&vit);
5213 IGRAPH_FINALLY_CLEAN(1);
5214
5215 while (!igraph_stack_empty(&stack)) {
5216 /* For each parent of node i, get its parents */
5217 igraph_real_t el = igraph_stack_pop(&stack);
5218 parent_vec = (igraph_vector_t*)VECTOR(parents)[(long int) el];
5219 i = igraph_vector_size(parent_vec);
5220
5221 for (j = 0; j < i; j++) {
5222 /* For each parent, check if it's already in the stack.
5223 * If not, push it and mark it in is_target */
5224 n = (long int) VECTOR(*parent_vec)[j];
5225 if (!is_target[n]) {
5226 is_target[n] = 2;
5227 IGRAPH_CHECK(igraph_stack_push(&stack, n));
5228 }
5229 }
5230 }
5231 igraph_stack_destroy(&stack);
5232 IGRAPH_FINALLY_CLEAN(1);
5233 }
5234
5235 /* now, reconstruct the shortest paths from the parent list in the
5236 * order we've found the nodes during the traversal.
5237 * dists is being re-used as a vector where element i tells the
5238 * index in res where the shortest paths leading to vertex i
5239 * start, plus one (so that zero means that there are no paths
5240 * for a given vertex).
5241 */
5242 paths_index = &dists;
5243 n = igraph_vector_size(&order);
5244 igraph_vector_null(paths_index);
5245
5246 /* clear the paths vector */
5247 igraph_vector_ptr_clear(res);
5248 igraph_vector_ptr_set_item_destructor(res,
5249 (igraph_finally_func_t*)igraph_vector_destroy);
5250
5251 /* by definition, the shortest path leading to the starting vertex
5252 * consists of the vertex itself only */
5253 path = igraph_Calloc(1, igraph_vector_t);
5254 if (path == 0)
5255 IGRAPH_ERROR("cannot run igraph_get_all_shortest_paths_dijkstra",
5256 IGRAPH_ENOMEM);
5257 IGRAPH_FINALLY(igraph_free, path);
5258 IGRAPH_CHECK(igraph_vector_init(path, 1));
5259 IGRAPH_CHECK(igraph_vector_ptr_push_back(res, path));
5260 IGRAPH_FINALLY_CLEAN(1); /* ownership of path passed to res */
5261 VECTOR(*path)[0] = from;
5262 VECTOR(*paths_index)[(long int)from] = 1;
5263
5264 for (i = 1; i < n; i++) {
5265 long int m, path_count;
5266 igraph_vector_t *parent_path;
5267
5268 node = (long int) VECTOR(order)[i];
5269
5270 /* if we don't need the shortest paths for this node (because
5271 * it is not standing in a shortest path between the source
5272 * node and any of the target nodes), skip it */
5273 if (!is_target[node]) {
5274 continue;
5275 }
5276
5277 IGRAPH_ALLOW_INTERRUPTION();
5278
5279 /* we are calculating the shortest paths of node now. */
5280 /* first, we update the paths_index */
5281 path_count = igraph_vector_ptr_size(res);
5282 VECTOR(*paths_index)[node] = path_count + 1;
5283 /* res_end = (igraph_vector_t*)&(VECTOR(*res)[path_count]); */
5284
5285 /* now, take the parent vertices */
5286 parent_vec = (igraph_vector_t*)VECTOR(parents)[node];
5287 m = igraph_vector_size(parent_vec);
5288
5289 /*
5290 printf("Calculating shortest paths to vertex %ld\n", node);
5291 printf("Parents are: ");
5292 igraph_vector_print(parent_vec);
5293 */
5294
5295 for (j = 0; j < m; j++) {
5296 /* for each parent, copy the shortest paths leading to that parent
5297 * and add the current vertex in the end */
5298 long int parent_node = (long int) VECTOR(*parent_vec)[j];
5299 long int parent_path_idx = (long int) VECTOR(*paths_index)[parent_node] - 1;
5300 /*
5301 printf(" Considering parent: %ld\n", parent_node);
5302 printf(" Paths to parent start at index %ld in res\n", parent_path_idx);
5303 */
5304 assert(parent_path_idx >= 0);
5305 for (; parent_path_idx < path_count; parent_path_idx++) {
5306 parent_path = (igraph_vector_t*)VECTOR(*res)[parent_path_idx];
5307 if (igraph_vector_tail(parent_path) != parent_node) {
5308 break;
5309 }
5310
5311 path = igraph_Calloc(1, igraph_vector_t);
5312 if (path == 0)
5313 IGRAPH_ERROR("cannot run igraph_get_all_shortest_paths_dijkstra",
5314 IGRAPH_ENOMEM);
5315 IGRAPH_FINALLY(igraph_free, path);
5316 IGRAPH_CHECK(igraph_vector_copy(path, parent_path));
5317 IGRAPH_CHECK(igraph_vector_ptr_push_back(res, path));
5318 IGRAPH_FINALLY_CLEAN(1); /* ownership of path passed to res */
5319 IGRAPH_CHECK(igraph_vector_push_back(path, node));
5320 }
5321 }
5322 }
5323
5324 /* remove the destructor from the path vector */
5325 igraph_vector_ptr_set_item_destructor(res, 0);
5326
5327 /* free those paths from the result vector which we won't need */
5328 n = igraph_vector_ptr_size(res);
5329 j = 0;
5330 for (i = 0; i < n; i++) {
5331 igraph_real_t tmp;
5332 path = (igraph_vector_t*)VECTOR(*res)[i];
5333 tmp = igraph_vector_tail(path);
5334 if (is_target[(long int)tmp] == 1) {
5335 /* we need this path, keep it */
5336 VECTOR(*res)[j] = path;
5337 j++;
5338 } else {
5339 /* we don't need this path, free it */
5340 igraph_vector_destroy(path); free(path);
5341 }
5342 }
5343 IGRAPH_CHECK(igraph_vector_ptr_resize(res, j));
5344
5345 /* sort the paths by the target vertices */
5346 igraph_vector_ptr_sort(res, igraph_i_vector_tail_cmp);
5347 }
5348
5349 /* free the allocated memory */
5350 igraph_vector_destroy(&order);
5351 igraph_Free(is_target);
5352 igraph_vector_destroy(&dists);
5353 igraph_vector_ptr_destroy_all(&parents);
5354 IGRAPH_FINALLY_CLEAN(4);
5355
5356 return 0;
5357 }
5358
5359 /**
5360 * \function igraph_shortest_paths_bellman_ford
5361 * Weighted shortest paths from some sources allowing negative weights.
5362 *
5363 * This function is the Bellman-Ford algorithm to find the weighted
5364 * shortest paths to all vertices from a single source. (It is run
5365 * independently for the given sources.). If there are no negative
5366 * weights, you are better off with \ref igraph_shortest_paths_dijkstra() .
5367 *
5368 * \param graph The input graph, can be directed.
5369 * \param res The result, a matrix. A pointer to an initialized matrix
5370 * should be passed here, the matrix will be resized if needed.
5371 * Each row contains the distances from a single source, to all
5372 * vertices in the graph, in the order of vertex ids. For unreachable
5373 * vertices the matrix contains \c IGRAPH_INFINITY.
5374 * \param from The source vertices.
5375 * \param weights The edge weights. There mustn't be any closed loop in
5376 * the graph that has a negative total weight (since this would allow
5377 * us to decrease the weight of any path containing at least a single
5378 * vertex of this loop infinitely). If this is a null pointer, then the
5379 * unweighted version, \ref igraph_shortest_paths() is called.
5380 * \param mode For directed graphs; whether to follow paths along edge
5381 * directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
5382 * ignore edge directions completely (\c IGRAPH_ALL). It is ignored
5383 * for undirected graphs.
5384 * \return Error code.
5385 *
5386 * Time complexity: O(s*|E|*|V|), where |V| is the number of
5387 * vertices, |E| the number of edges and s the number of sources.
5388 *
5389 * \sa \ref igraph_shortest_paths() for a faster unweighted version
5390 * or \ref igraph_shortest_paths_dijkstra() if you do not have negative
5391 * edge weights.
5392 *
5393 * \example examples/simple/bellman_ford.c
5394 */
5395
igraph_shortest_paths_bellman_ford(const igraph_t * graph,igraph_matrix_t * res,const igraph_vs_t from,const igraph_vs_t to,const igraph_vector_t * weights,igraph_neimode_t mode)5396 int igraph_shortest_paths_bellman_ford(const igraph_t *graph,
5397 igraph_matrix_t *res,
5398 const igraph_vs_t from,
5399 const igraph_vs_t to,
5400 const igraph_vector_t *weights,
5401 igraph_neimode_t mode) {
5402 long int no_of_nodes = igraph_vcount(graph);
5403 long int no_of_edges = igraph_ecount(graph);
5404 igraph_lazy_inclist_t inclist;
5405 long int i, j, k;
5406 long int no_of_from, no_of_to;
5407 igraph_dqueue_t Q;
5408 igraph_vector_t clean_vertices;
5409 igraph_vector_t num_queued;
5410 igraph_vit_t fromvit, tovit;
5411 igraph_real_t my_infinity = IGRAPH_INFINITY;
5412 igraph_bool_t all_to;
5413 igraph_vector_t dist;
5414
5415 /*
5416 - speedup: a vertex is marked clean if its distance from the source
5417 did not change during the last phase. Neighbors of a clean vertex
5418 are not relaxed again, since it would mean no change in the
5419 shortest path values. Dirty vertices are queued. Negative loops can
5420 be detected by checking whether a vertex has been queued at least
5421 n times.
5422 */
5423 if (!weights) {
5424 return igraph_shortest_paths(graph, res, from, to, mode);
5425 }
5426
5427 if (igraph_vector_size(weights) != no_of_edges) {
5428 IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
5429 }
5430
5431 IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
5432 IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
5433 no_of_from = IGRAPH_VIT_SIZE(fromvit);
5434
5435 IGRAPH_DQUEUE_INIT_FINALLY(&Q, no_of_nodes);
5436 IGRAPH_VECTOR_INIT_FINALLY(&clean_vertices, no_of_nodes);
5437 IGRAPH_VECTOR_INIT_FINALLY(&num_queued, no_of_nodes);
5438 IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, mode));
5439 IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
5440
5441 if ( (all_to = igraph_vs_is_all(&to)) ) {
5442 no_of_to = no_of_nodes;
5443 } else {
5444 IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
5445 IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
5446 no_of_to = IGRAPH_VIT_SIZE(tovit);
5447 }
5448
5449 IGRAPH_VECTOR_INIT_FINALLY(&dist, no_of_nodes);
5450 IGRAPH_CHECK(igraph_matrix_resize(res, no_of_from, no_of_to));
5451
5452 for (IGRAPH_VIT_RESET(fromvit), i = 0;
5453 !IGRAPH_VIT_END(fromvit);
5454 IGRAPH_VIT_NEXT(fromvit), i++) {
5455 long int source = IGRAPH_VIT_GET(fromvit);
5456
5457 igraph_vector_fill(&dist, my_infinity);
5458 VECTOR(dist)[source] = 0;
5459 igraph_vector_null(&clean_vertices);
5460 igraph_vector_null(&num_queued);
5461
5462 /* Fill the queue with vertices to be checked */
5463 for (j = 0; j < no_of_nodes; j++) {
5464 IGRAPH_CHECK(igraph_dqueue_push(&Q, j));
5465 }
5466
5467 while (!igraph_dqueue_empty(&Q)) {
5468 igraph_vector_t *neis;
5469 long int nlen;
5470
5471 j = (long int) igraph_dqueue_pop(&Q);
5472 VECTOR(clean_vertices)[j] = 1;
5473 VECTOR(num_queued)[j] += 1;
5474 if (VECTOR(num_queued)[j] > no_of_nodes) {
5475 IGRAPH_ERROR("cannot run Bellman-Ford algorithm", IGRAPH_ENEGLOOP);
5476 }
5477
5478 /* If we cannot get to j in finite time yet, there is no need to relax
5479 * its edges */
5480 if (!IGRAPH_FINITE(VECTOR(dist)[j])) {
5481 continue;
5482 }
5483
5484 neis = igraph_lazy_inclist_get(&inclist, (igraph_integer_t) j);
5485 nlen = igraph_vector_size(neis);
5486
5487 for (k = 0; k < nlen; k++) {
5488 long int nei = (long int) VECTOR(*neis)[k];
5489 long int target = IGRAPH_OTHER(graph, nei, j);
5490 if (VECTOR(dist)[target] > VECTOR(dist)[j] + VECTOR(*weights)[nei]) {
5491 /* relax the edge */
5492 VECTOR(dist)[target] = VECTOR(dist)[j] + VECTOR(*weights)[nei];
5493 if (VECTOR(clean_vertices)[target]) {
5494 VECTOR(clean_vertices)[target] = 0;
5495 IGRAPH_CHECK(igraph_dqueue_push(&Q, target));
5496 }
5497 }
5498 }
5499 }
5500
5501 /* Copy it to the result */
5502 if (all_to) {
5503 igraph_matrix_set_row(res, &dist, i);
5504 } else {
5505 for (IGRAPH_VIT_RESET(tovit), j = 0; !IGRAPH_VIT_END(tovit);
5506 IGRAPH_VIT_NEXT(tovit), j++) {
5507 long int v = IGRAPH_VIT_GET(tovit);
5508 MATRIX(*res, i, j) = VECTOR(dist)[v];
5509 }
5510 }
5511 }
5512
5513 igraph_vector_destroy(&dist);
5514 IGRAPH_FINALLY_CLEAN(1);
5515
5516 if (!all_to) {
5517 igraph_vit_destroy(&tovit);
5518 IGRAPH_FINALLY_CLEAN(1);
5519 }
5520
5521 igraph_vit_destroy(&fromvit);
5522 igraph_dqueue_destroy(&Q);
5523 igraph_vector_destroy(&clean_vertices);
5524 igraph_vector_destroy(&num_queued);
5525 igraph_lazy_inclist_destroy(&inclist);
5526 IGRAPH_FINALLY_CLEAN(5);
5527
5528 return 0;
5529 }
5530
5531 /**
5532 * \function igraph_shortest_paths_johnson
5533 * Calculate shortest paths from some sources using Johnson's algorithm.
5534 *
5535 * See Wikipedia at http://en.wikipedia.org/wiki/Johnson's_algorithm
5536 * for Johnson's algorithm. This algorithm works even if the graph
5537 * contains negative edge weights, and it is worth using it if we
5538 * calculate the shortest paths from many sources.
5539 *
5540 * </para><para> If no edge weights are supplied, then the unweighted
5541 * version, \ref igraph_shortest_paths() is called.
5542 *
5543 * </para><para> If all the supplied edge weights are non-negative,
5544 * then Dijkstra's algorithm is used by calling
5545 * \ref igraph_shortest_paths_dijkstra().
5546 *
5547 * \param graph The input graph, typically it is directed.
5548 * \param res Pointer to an initialized matrix, the result will be
5549 * stored here, one line for each source vertex, one column for each
5550 * target vertex.
5551 * \param from The source vertices.
5552 * \param to The target vertices. It is not allowed to include a
5553 * vertex twice or more.
5554 * \param weights Optional edge weights. If it is a null-pointer, then
5555 * the unweighted breadth-first search based \ref
5556 * igraph_shortest_paths() will be called.
5557 * \return Error code.
5558 *
5559 * Time complexity: O(s|V|log|V|+|V||E|), |V| and |E| are the number
5560 * of vertices and edges, s is the number of source vertices.
5561 *
5562 * \sa \ref igraph_shortest_paths() for a faster unweighted version
5563 * or \ref igraph_shortest_paths_dijkstra() if you do not have negative
5564 * edge weights, \ref igraph_shortest_paths_bellman_ford() if you only
5565 * need to calculate shortest paths from a couple of sources.
5566 */
5567
igraph_shortest_paths_johnson(const igraph_t * graph,igraph_matrix_t * res,const igraph_vs_t from,const igraph_vs_t to,const igraph_vector_t * weights)5568 int igraph_shortest_paths_johnson(const igraph_t *graph,
5569 igraph_matrix_t *res,
5570 const igraph_vs_t from,
5571 const igraph_vs_t to,
5572 const igraph_vector_t *weights) {
5573
5574 long int no_of_nodes = igraph_vcount(graph);
5575 long int no_of_edges = igraph_ecount(graph);
5576 igraph_t newgraph;
5577 igraph_vector_t edges, newweights;
5578 igraph_matrix_t bfres;
5579 long int i, ptr;
5580 long int nr, nc;
5581 igraph_vit_t fromvit;
5582
5583 /* If no weights, then we can just run the unweighted version */
5584 if (!weights) {
5585 return igraph_shortest_paths(graph, res, from, to, IGRAPH_OUT);
5586 }
5587
5588 if (igraph_vector_size(weights) != no_of_edges) {
5589 IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);
5590 }
5591
5592 /* If no negative weights, then we can run Dijkstra's algorithm */
5593 if (igraph_vector_min(weights) >= 0) {
5594 return igraph_shortest_paths_dijkstra(graph, res, from, to,
5595 weights, IGRAPH_OUT);
5596 }
5597
5598 if (!igraph_is_directed(graph)) {
5599 IGRAPH_ERROR("Johnson's shortest path: undirected graph and negative weight",
5600 IGRAPH_EINVAL);
5601 }
5602
5603 /* ------------------------------------------------------------ */
5604 /* -------------------- Otherwise proceed --------------------- */
5605
5606 IGRAPH_MATRIX_INIT_FINALLY(&bfres, 0, 0);
5607 IGRAPH_VECTOR_INIT_FINALLY(&newweights, 0);
5608
5609 IGRAPH_CHECK(igraph_empty(&newgraph, (igraph_integer_t) no_of_nodes + 1,
5610 igraph_is_directed(graph)));
5611 IGRAPH_FINALLY(igraph_destroy, &newgraph);
5612
5613 /* Add a new node to the graph, plus edges from it to all the others. */
5614 IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2 + no_of_nodes * 2);
5615 igraph_get_edgelist(graph, &edges, /*bycol=*/ 0);
5616 igraph_vector_resize(&edges, no_of_edges * 2 + no_of_nodes * 2);
5617 for (i = 0, ptr = no_of_edges * 2; i < no_of_nodes; i++) {
5618 VECTOR(edges)[ptr++] = no_of_nodes;
5619 VECTOR(edges)[ptr++] = i;
5620 }
5621 IGRAPH_CHECK(igraph_add_edges(&newgraph, &edges, 0));
5622 igraph_vector_destroy(&edges);
5623 IGRAPH_FINALLY_CLEAN(1);
5624
5625 IGRAPH_CHECK(igraph_vector_reserve(&newweights, no_of_edges + no_of_nodes));
5626 igraph_vector_update(&newweights, weights);
5627 igraph_vector_resize(&newweights, no_of_edges + no_of_nodes);
5628 for (i = no_of_edges; i < no_of_edges + no_of_nodes; i++) {
5629 VECTOR(newweights)[i] = 0;
5630 }
5631
5632 /* Run Bellmann-Ford algorithm on the new graph, starting from the
5633 new vertex. */
5634
5635 IGRAPH_CHECK(igraph_shortest_paths_bellman_ford(&newgraph, &bfres,
5636 igraph_vss_1((igraph_integer_t) no_of_nodes),
5637 igraph_vss_all(), &newweights, IGRAPH_OUT));
5638
5639 igraph_destroy(&newgraph);
5640 IGRAPH_FINALLY_CLEAN(1);
5641
5642 /* Now the edges of the original graph are reweighted, using the
5643 values from the BF algorithm. Instead of w(u,v) we will have
5644 w(u,v) + h(u) - h(v) */
5645
5646 igraph_vector_resize(&newweights, no_of_edges);
5647 for (i = 0; i < no_of_edges; i++) {
5648 long int ffrom = IGRAPH_FROM(graph, i);
5649 long int tto = IGRAPH_TO(graph, i);
5650 VECTOR(newweights)[i] += MATRIX(bfres, 0, ffrom) - MATRIX(bfres, 0, tto);
5651 }
5652
5653 /* Run Dijkstra's algorithm on the new weights */
5654 IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, res, from,
5655 to, &newweights,
5656 IGRAPH_OUT));
5657
5658 igraph_vector_destroy(&newweights);
5659 IGRAPH_FINALLY_CLEAN(1);
5660
5661 /* Reweight the shortest paths */
5662 nr = igraph_matrix_nrow(res);
5663 nc = igraph_matrix_ncol(res);
5664
5665 IGRAPH_CHECK(igraph_vit_create(graph, from, &fromvit));
5666 IGRAPH_FINALLY(igraph_vit_destroy, &fromvit);
5667
5668 for (i = 0; i < nr; i++, IGRAPH_VIT_NEXT(fromvit)) {
5669 long int v1 = IGRAPH_VIT_GET(fromvit);
5670 if (igraph_vs_is_all(&to)) {
5671 long int v2;
5672 for (v2 = 0; v2 < nc; v2++) {
5673 igraph_real_t sub = MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2);
5674 MATRIX(*res, i, v2) -= sub;
5675 }
5676 } else {
5677 long int j;
5678 igraph_vit_t tovit;
5679 IGRAPH_CHECK(igraph_vit_create(graph, to, &tovit));
5680 IGRAPH_FINALLY(igraph_vit_destroy, &tovit);
5681 for (j = 0, IGRAPH_VIT_RESET(tovit); j < nc; j++, IGRAPH_VIT_NEXT(tovit)) {
5682 long int v2 = IGRAPH_VIT_GET(tovit);
5683 igraph_real_t sub = MATRIX(bfres, 0, v1) - MATRIX(bfres, 0, v2);
5684 MATRIX(*res, i, v2) -= sub;
5685 }
5686 igraph_vit_destroy(&tovit);
5687 IGRAPH_FINALLY_CLEAN(1);
5688 }
5689 }
5690
5691 igraph_vit_destroy(&fromvit);
5692 igraph_matrix_destroy(&bfres);
5693 IGRAPH_FINALLY_CLEAN(2);
5694
5695 return 0;
5696 }
5697
5698 /**
5699 * \function igraph_unfold_tree
5700 * Unfolding a graph into a tree, by possibly multiplicating its vertices.
5701 *
5702 * A graph is converted into a tree (or forest, if it is unconnected),
5703 * by performing a breadth-first search on it, and replicating
5704 * vertices that were found a second, third, etc. time.
5705 * \param graph The input graph, it can be either directed or
5706 * undirected.
5707 * \param tree Pointer to an uninitialized graph object, the result is
5708 * stored here.
5709 * \param mode For directed graphs; whether to follow paths along edge
5710 * directions (\c IGRAPH_OUT), or the opposite (\c IGRAPH_IN), or
5711 * ignore edge directions completely (\c IGRAPH_ALL). It is ignored
5712 * for undirected graphs.
5713 * \param roots A numeric vector giving the root vertex, or vertices
5714 * (if the graph is not connected), to start from.
5715 * \param vertex_index Pointer to an initialized vector, or a null
5716 * pointer. If not a null pointer, then a mapping from the vertices
5717 * in the new graph to the ones in the original is created here.
5718 * \return Error code.
5719 *
5720 * Time complexity: O(n+m), linear in the number vertices and edges.
5721 *
5722 */
5723
igraph_unfold_tree(const igraph_t * graph,igraph_t * tree,igraph_neimode_t mode,const igraph_vector_t * roots,igraph_vector_t * vertex_index)5724 int igraph_unfold_tree(const igraph_t *graph, igraph_t *tree,
5725 igraph_neimode_t mode, const igraph_vector_t *roots,
5726 igraph_vector_t *vertex_index) {
5727
5728 long int no_of_nodes = igraph_vcount(graph);
5729 long int no_of_edges = igraph_ecount(graph);
5730 long int no_of_roots = igraph_vector_size(roots);
5731 long int tree_vertex_count = no_of_nodes;
5732
5733 igraph_vector_t edges;
5734 igraph_vector_bool_t seen_vertices;
5735 igraph_vector_bool_t seen_edges;
5736
5737 igraph_dqueue_t Q;
5738 igraph_vector_t neis;
5739
5740 long int i, n, r, v_ptr = no_of_nodes;
5741
5742 /* TODO: handle not-connected graphs, multiple root vertices */
5743
5744 IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
5745 igraph_vector_reserve(&edges, no_of_edges * 2);
5746 IGRAPH_DQUEUE_INIT_FINALLY(&Q, 100);
5747 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
5748 IGRAPH_VECTOR_BOOL_INIT_FINALLY(&seen_vertices, no_of_nodes);
5749 IGRAPH_VECTOR_BOOL_INIT_FINALLY(&seen_edges, no_of_edges);
5750
5751 if (vertex_index) {
5752 IGRAPH_CHECK(igraph_vector_resize(vertex_index, no_of_nodes));
5753 for (i = 0; i < no_of_nodes; i++) {
5754 VECTOR(*vertex_index)[i] = i;
5755 }
5756 }
5757
5758 for (r = 0; r < no_of_roots; r++) {
5759
5760 long int root = (long int) VECTOR(*roots)[r];
5761 VECTOR(seen_vertices)[root] = 1;
5762 igraph_dqueue_push(&Q, root);
5763
5764 while (!igraph_dqueue_empty(&Q)) {
5765 long int actnode = (long int) igraph_dqueue_pop(&Q);
5766
5767 IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) actnode, mode));
5768 n = igraph_vector_size(&neis);
5769 for (i = 0; i < n; i++) {
5770
5771 long int edge = (long int) VECTOR(neis)[i];
5772 long int from = IGRAPH_FROM(graph, edge);
5773 long int to = IGRAPH_TO(graph, edge);
5774 long int nei = IGRAPH_OTHER(graph, edge, actnode);
5775
5776 if (! VECTOR(seen_edges)[edge]) {
5777
5778 VECTOR(seen_edges)[edge] = 1;
5779
5780 if (! VECTOR(seen_vertices)[nei]) {
5781
5782 igraph_vector_push_back(&edges, from);
5783 igraph_vector_push_back(&edges, to);
5784
5785 VECTOR(seen_vertices)[nei] = 1;
5786 IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));
5787
5788 } else {
5789
5790 tree_vertex_count++;
5791 if (vertex_index) {
5792 IGRAPH_CHECK(igraph_vector_push_back(vertex_index, nei));
5793 }
5794
5795 if (from == nei) {
5796 igraph_vector_push_back(&edges, v_ptr++);
5797 igraph_vector_push_back(&edges, to);
5798 } else {
5799 igraph_vector_push_back(&edges, from);
5800 igraph_vector_push_back(&edges, v_ptr++);
5801 }
5802 }
5803 }
5804
5805 } /* for i<n */
5806
5807 } /* ! igraph_dqueue_empty(&Q) */
5808
5809 } /* r < igraph_vector_size(roots) */
5810
5811 igraph_vector_bool_destroy(&seen_edges);
5812 igraph_vector_bool_destroy(&seen_vertices);
5813 igraph_vector_destroy(&neis);
5814 igraph_dqueue_destroy(&Q);
5815 IGRAPH_FINALLY_CLEAN(4);
5816
5817 IGRAPH_CHECK(igraph_create(tree, &edges, tree_vertex_count, igraph_is_directed(graph)));
5818 igraph_vector_destroy(&edges);
5819 IGRAPH_FINALLY_CLEAN(1);
5820
5821 return 0;
5822 }
5823
5824 /**
5825 * \function igraph_is_mutual
5826 * Check whether the edges of a directed graph are mutual.
5827 *
5828 * An (A,B) edge is mutual if the graph contains the (B,A) edge, too.
5829 * </para>
5830 *
5831 * <para>An undirected graph only has mutual edges, by definition.
5832 * </para>
5833 *
5834 * <para>Edge multiplicity is not considered here, e.g. if there are two
5835 * (A,B) edges and one (B,A) edge, then all three are considered to be
5836 * mutual.
5837 *
5838 * \param graph The input graph.
5839 * \param res Pointer to an initialized vector, the result is stored
5840 * here.
5841 * \param es The sequence of edges to check. Supply
5842 * <code>igraph_ess_all()</code> for all edges, see \ref
5843 * igraph_ess_all().
5844 * \return Error code.
5845 *
5846 * Time complexity: O(n log(d)), n is the number of edges supplied, d
5847 * is the maximum in-degree of the vertices that are targets of the
5848 * supplied edges. An upper limit of the time complexity is O(n log(|E|)),
5849 * |E| is the number of edges in the graph.
5850 */
5851
igraph_is_mutual(igraph_t * graph,igraph_vector_bool_t * res,igraph_es_t es)5852 int igraph_is_mutual(igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es) {
5853
5854 igraph_eit_t eit;
5855 igraph_lazy_adjlist_t adjlist;
5856 long int i;
5857
5858 /* How many edges do we have? */
5859 IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
5860 IGRAPH_FINALLY(igraph_eit_destroy, &eit);
5861 IGRAPH_CHECK(igraph_vector_bool_resize(res, IGRAPH_EIT_SIZE(eit)));
5862
5863 /* An undirected graph has mutual edges by definition,
5864 res is already properly resized */
5865 if (! igraph_is_directed(graph)) {
5866 igraph_vector_bool_fill(res, 1);
5867 igraph_eit_destroy(&eit);
5868 IGRAPH_FINALLY_CLEAN(1);
5869 return 0;
5870 }
5871
5872 IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, IGRAPH_OUT, IGRAPH_DONT_SIMPLIFY));
5873 IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
5874
5875 for (i = 0; ! IGRAPH_EIT_END(eit); i++, IGRAPH_EIT_NEXT(eit)) {
5876 long int edge = IGRAPH_EIT_GET(eit);
5877 long int from = IGRAPH_FROM(graph, edge);
5878 long int to = IGRAPH_TO(graph, edge);
5879
5880 /* Check whether there is a to->from edge, search for from in the
5881 out-list of to. We don't search an empty vector, because
5882 vector_binsearch seems to have a bug with this. */
5883 igraph_vector_t *neis = igraph_lazy_adjlist_get(&adjlist,
5884 (igraph_integer_t) to);
5885 if (igraph_vector_empty(neis)) {
5886 VECTOR(*res)[i] = 0;
5887 } else {
5888 VECTOR(*res)[i] = igraph_vector_binsearch2(neis, from);
5889 }
5890 }
5891
5892 igraph_lazy_adjlist_destroy(&adjlist);
5893 igraph_eit_destroy(&eit);
5894 IGRAPH_FINALLY_CLEAN(2);
5895
5896 return 0;
5897 }
5898
5899 int igraph_i_avg_nearest_neighbor_degree_weighted(const igraph_t *graph,
5900 igraph_vs_t vids,
5901 igraph_neimode_t mode,
5902 igraph_neimode_t neighbor_degree_mode,
5903 igraph_vector_t *knn,
5904 igraph_vector_t *knnk,
5905 const igraph_vector_t *weights);
5906
igraph_i_avg_nearest_neighbor_degree_weighted(const igraph_t * graph,igraph_vs_t vids,igraph_neimode_t mode,igraph_neimode_t neighbor_degree_mode,igraph_vector_t * knn,igraph_vector_t * knnk,const igraph_vector_t * weights)5907 int igraph_i_avg_nearest_neighbor_degree_weighted(const igraph_t *graph,
5908 igraph_vs_t vids,
5909 igraph_neimode_t mode,
5910 igraph_neimode_t neighbor_degree_mode,
5911 igraph_vector_t *knn,
5912 igraph_vector_t *knnk,
5913 const igraph_vector_t *weights) {
5914
5915 long int no_of_nodes = igraph_vcount(graph);
5916 igraph_vector_t neis, edge_neis;
5917 long int i, j, no_vids;
5918 igraph_vit_t vit;
5919 igraph_vector_t my_knn_v, *my_knn = knn;
5920 igraph_vector_t strength, deg;
5921 igraph_integer_t maxdeg;
5922 igraph_vector_t deghist;
5923 igraph_real_t mynan = IGRAPH_NAN;
5924
5925 if (igraph_vector_size(weights) != igraph_ecount(graph)) {
5926 IGRAPH_ERROR("Invalid weight vector size", IGRAPH_EINVAL);
5927 }
5928
5929 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
5930 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
5931 no_vids = IGRAPH_VIT_SIZE(vit);
5932
5933 if (!knn) {
5934 IGRAPH_VECTOR_INIT_FINALLY(&my_knn_v, no_vids);
5935 my_knn = &my_knn_v;
5936 } else {
5937 IGRAPH_CHECK(igraph_vector_resize(knn, no_vids));
5938 }
5939
5940 // Get degree of neighbours
5941 IGRAPH_VECTOR_INIT_FINALLY(°, no_of_nodes);
5942 IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(),
5943 neighbor_degree_mode, IGRAPH_LOOPS));
5944 IGRAPH_VECTOR_INIT_FINALLY(&strength, no_of_nodes);
5945
5946 // Get strength of all nodes
5947 IGRAPH_CHECK(igraph_strength(graph, &strength, igraph_vss_all(),
5948 mode, IGRAPH_LOOPS, weights));
5949
5950 // Get maximum degree for initialization
5951 IGRAPH_CHECK(igraph_maxdegree(graph, &maxdeg, igraph_vss_all(),
5952 mode, IGRAPH_LOOPS));
5953 IGRAPH_VECTOR_INIT_FINALLY(&neis, (long int)maxdeg);
5954 IGRAPH_VECTOR_INIT_FINALLY(&edge_neis, (long int)maxdeg);
5955 igraph_vector_resize(&neis, 0);
5956 igraph_vector_resize(&edge_neis, 0);
5957
5958 if (knnk) {
5959 IGRAPH_CHECK(igraph_vector_resize(knnk, (long int)maxdeg));
5960 igraph_vector_null(knnk);
5961 IGRAPH_VECTOR_INIT_FINALLY(°hist, (long int)maxdeg);
5962 }
5963
5964 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
5965 igraph_real_t sum = 0.0;
5966 long int v = IGRAPH_VIT_GET(vit);
5967 long int nv;
5968 igraph_real_t str = VECTOR(strength)[v];
5969 // Get neighbours and incident edges
5970 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, mode));
5971 IGRAPH_CHECK(igraph_incident(graph, &edge_neis, (igraph_integer_t) v, mode));
5972 nv = igraph_vector_size(&neis);
5973 for (j = 0; j < nv; j++) {
5974 long int nei = (long int) VECTOR(neis)[j];
5975 long int e = (long int) VECTOR(edge_neis)[j];
5976 double w = VECTOR(*weights)[e];
5977 sum += w * VECTOR(deg)[nei];
5978 }
5979 if (str != 0.0) {
5980 VECTOR(*my_knn)[i] = sum / str;
5981 } else {
5982 VECTOR(*my_knn)[i] = mynan;
5983 }
5984 if (knnk && nv > 0) {
5985 VECTOR(*knnk)[nv - 1] += VECTOR(*my_knn)[i];
5986 VECTOR(deghist)[nv - 1] += 1;
5987 }
5988 }
5989
5990 igraph_vector_destroy(&edge_neis);
5991 igraph_vector_destroy(&neis);
5992 IGRAPH_FINALLY_CLEAN(2);
5993
5994 if (knnk) {
5995 for (i = 0; i < maxdeg; i++) {
5996 igraph_real_t dh = VECTOR(deghist)[i];
5997 if (dh != 0) {
5998 VECTOR(*knnk)[i] /= dh;
5999 } else {
6000 VECTOR(*knnk)[i] = mynan;
6001 }
6002 }
6003
6004 igraph_vector_destroy(°hist);
6005 IGRAPH_FINALLY_CLEAN(1);
6006 }
6007
6008 igraph_vector_destroy(&strength);
6009 igraph_vector_destroy(°);
6010 IGRAPH_FINALLY_CLEAN(2);
6011
6012 if (!knn) {
6013 igraph_vector_destroy(&my_knn_v);
6014 IGRAPH_FINALLY_CLEAN(1);
6015 }
6016
6017 igraph_vit_destroy(&vit);
6018 IGRAPH_FINALLY_CLEAN(1);
6019
6020 return 0;
6021 }
6022
6023 /**
6024 * \function igraph_avg_nearest_neighbor_degree
6025 * Average neighbor degree.
6026 *
6027 * Calculates the average degree of the neighbors for each vertex (\p knn), and
6028 * optionally, the same quantity as a function of the vertex degree (\p knnk).
6029 *
6030 * </para><para>
6031 * For isolated vertices \p knn is set to NaN.
6032 * The same is done in \p knnk for vertex degrees that
6033 * don't appear in the graph.
6034 *
6035 * </para><para>
6036 * The weighted version computes a weighted average of the neighbor degrees as
6037 *
6038 * <code>k_nn_u = 1/s_u sum_v w_uv k_v</code>,
6039 *
6040 * where <code>s_u = sum_v w_uv</code> is the sum of the incident edge weights
6041 * of vertex \c u, i.e. its strength.
6042 * The sum runs over the neighbors \c v of vertex \c u
6043 * as indicated by \p mode. <code>w_uv</code> denotes the weighted adjacency matrix
6044 * and <code>k_v</code> is the neighbors' degree, specified by \p neighbor_degree_mode.
6045 *
6046 * </para><para>
6047 * Reference:
6048 * A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani,
6049 * The architecture of complex weighted networks,
6050 * Proc. Natl. Acad. Sci. USA 101, 3747 (2004).
6051 * https://dx.doi.org/10.1073/pnas.0400087101
6052 *
6053 * \param graph The input graph. It may be directed.
6054 * \param vids The vertices for which the calculation is performed.
6055 * \param mode The type of neighbors to consider in directed graphs.
6056 * \c IGRAPH_OUT considers out-neighbors, \c IGRAPH_IN in-neighbors
6057 * and \c IGRAPH_ALL ignores edge directions.
6058 * \param neighbor_degree_mode The type of degree to average in directed graphs.
6059 * \c IGRAPH_OUT averages out-degrees, \c IGRAPH_IN averages in-degrees
6060 * and \c IGRAPH_ALL ignores edge directions for the degree calculation.
6061 * \param vids The vertices for which the calculation is performed.
6062 * \param knn Pointer to an initialized vector, the result will be
6063 * stored here. It will be resized as needed. Supply a \c NULL pointer
6064 * here, if you only want to calculate \c knnk.
6065 * \param knnk Pointer to an initialized vector, the average
6066 * neighbor degree as a function of the vertex degree is stored
6067 * here. The first (zeroth) element is for degree one vertices,
6068 * etc. Supply a \c NULL pointer here if you don't want to calculate
6069 * this.
6070 * \param weights Optional edge weights. Supply a null pointer here
6071 * for the non-weighted version.
6072 *
6073 * \return Error code.
6074 *
6075 * Time complexity: O(|V|+|E|), linear in the number of vertices and
6076 * edges.
6077 *
6078 * \example examples/simple/igraph_knn.c
6079 */
6080
igraph_avg_nearest_neighbor_degree(const igraph_t * graph,igraph_vs_t vids,igraph_neimode_t mode,igraph_neimode_t neighbor_degree_mode,igraph_vector_t * knn,igraph_vector_t * knnk,const igraph_vector_t * weights)6081 int igraph_avg_nearest_neighbor_degree(const igraph_t *graph,
6082 igraph_vs_t vids,
6083 igraph_neimode_t mode,
6084 igraph_neimode_t neighbor_degree_mode,
6085 igraph_vector_t *knn,
6086 igraph_vector_t *knnk,
6087 const igraph_vector_t *weights) {
6088
6089 long int no_of_nodes = igraph_vcount(graph);
6090 igraph_vector_t neis;
6091 long int i, j, no_vids;
6092 igraph_vit_t vit;
6093 igraph_vector_t my_knn_v, *my_knn = knn;
6094 igraph_vector_t deg;
6095 igraph_integer_t maxdeg;
6096 igraph_vector_t deghist;
6097 igraph_real_t mynan = IGRAPH_NAN;
6098 igraph_bool_t simple;
6099
6100 IGRAPH_CHECK(igraph_is_simple(graph, &simple));
6101 if (!simple) {
6102 IGRAPH_ERROR("Average nearest neighbor degree works only with "
6103 "simple graphs", IGRAPH_EINVAL);
6104 }
6105
6106 if (weights) {
6107 return igraph_i_avg_nearest_neighbor_degree_weighted(graph, vids,
6108 mode, neighbor_degree_mode, knn, knnk, weights);
6109 }
6110
6111 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
6112 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
6113 no_vids = IGRAPH_VIT_SIZE(vit);
6114
6115 if (!knn) {
6116 IGRAPH_VECTOR_INIT_FINALLY(&my_knn_v, no_vids);
6117 my_knn = &my_knn_v;
6118 } else {
6119 IGRAPH_CHECK(igraph_vector_resize(knn, no_vids));
6120 }
6121
6122 IGRAPH_VECTOR_INIT_FINALLY(°, no_of_nodes);
6123 IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(),
6124 neighbor_degree_mode, IGRAPH_LOOPS));
6125 igraph_maxdegree(graph, &maxdeg, igraph_vss_all(), mode, IGRAPH_LOOPS);
6126 IGRAPH_VECTOR_INIT_FINALLY(&neis, maxdeg);
6127 igraph_vector_resize(&neis, 0);
6128
6129 if (knnk) {
6130 IGRAPH_CHECK(igraph_vector_resize(knnk, (long int)maxdeg));
6131 igraph_vector_null(knnk);
6132 IGRAPH_VECTOR_INIT_FINALLY(°hist, (long int)maxdeg);
6133 }
6134
6135 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
6136 igraph_real_t sum = 0.0;
6137 long int v = IGRAPH_VIT_GET(vit);
6138 long int nv;
6139 IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, mode));
6140 nv = igraph_vector_size(&neis);
6141 for (j = 0; j < nv; j++) {
6142 long int nei = (long int) VECTOR(neis)[j];
6143 sum += VECTOR(deg)[nei];
6144 }
6145 if (nv != 0) {
6146 VECTOR(*my_knn)[i] = sum / nv;
6147 } else {
6148 VECTOR(*my_knn)[i] = mynan;
6149 }
6150 if (knnk && nv > 0) {
6151 VECTOR(*knnk)[nv - 1] += VECTOR(*my_knn)[i];
6152 VECTOR(deghist)[nv - 1] += 1;
6153 }
6154 }
6155
6156 if (knnk) {
6157 for (i = 0; i < maxdeg; i++) {
6158 long int dh = (long int) VECTOR(deghist)[i];
6159 if (dh != 0) {
6160 VECTOR(*knnk)[i] /= dh;
6161 } else {
6162 VECTOR(*knnk)[i] = mynan;
6163 }
6164 }
6165 igraph_vector_destroy(°hist);
6166 IGRAPH_FINALLY_CLEAN(1);
6167 }
6168
6169 igraph_vector_destroy(&neis);
6170 igraph_vector_destroy(°);
6171 igraph_vit_destroy(&vit);
6172 IGRAPH_FINALLY_CLEAN(3);
6173
6174 if (!knn) {
6175 igraph_vector_destroy(&my_knn_v);
6176 IGRAPH_FINALLY_CLEAN(1);
6177 }
6178
6179 return 0;
6180 }
6181
6182 /**
6183 * \function igraph_strength
6184 * Strength of the vertices, weighted vertex degree in other words.
6185 *
6186 * In a weighted network the strength of a vertex is the sum of the
6187 * weights of all incident edges. In a non-weighted network this is
6188 * exactly the vertex degree.
6189 * \param graph The input graph.
6190 * \param res Pointer to an initialized vector, the result is stored
6191 * here. It will be resized as needed.
6192 * \param vids The vertices for which the calculation is performed.
6193 * \param mode Gives whether to count only outgoing (\c IGRAPH_OUT),
6194 * incoming (\c IGRAPH_IN) edges or both (\c IGRAPH_ALL).
6195 * \param loops A logical scalar, whether to count loop edges as well.
6196 * \param weights A vector giving the edge weights. If this is a NULL
6197 * pointer, then \ref igraph_degree() is called to perform the
6198 * calculation.
6199 * \return Error code.
6200 *
6201 * Time complexity: O(|V|+|E|), linear in the number vertices and
6202 * edges.
6203 *
6204 * \sa \ref igraph_degree() for the traditional, non-weighted version.
6205 */
6206
igraph_strength(const igraph_t * graph,igraph_vector_t * res,const igraph_vs_t vids,igraph_neimode_t mode,igraph_bool_t loops,const igraph_vector_t * weights)6207 int igraph_strength(const igraph_t *graph, igraph_vector_t *res,
6208 const igraph_vs_t vids, igraph_neimode_t mode,
6209 igraph_bool_t loops, const igraph_vector_t *weights) {
6210
6211 long int no_of_nodes = igraph_vcount(graph);
6212 igraph_vit_t vit;
6213 long int no_vids;
6214 igraph_vector_t neis;
6215 long int i;
6216
6217 if (!weights) {
6218 return igraph_degree(graph, res, vids, mode, loops);
6219 }
6220
6221 if (igraph_vector_size(weights) != igraph_ecount(graph)) {
6222 IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
6223 }
6224
6225 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
6226 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
6227 no_vids = IGRAPH_VIT_SIZE(vit);
6228
6229 IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
6230 IGRAPH_CHECK(igraph_vector_reserve(&neis, no_of_nodes));
6231 IGRAPH_CHECK(igraph_vector_resize(res, no_vids));
6232 igraph_vector_null(res);
6233
6234 if (loops) {
6235 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
6236 long int vid = IGRAPH_VIT_GET(vit);
6237 long int j, n;
6238 IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) vid, mode));
6239 n = igraph_vector_size(&neis);
6240 for (j = 0; j < n; j++) {
6241 long int edge = (long int) VECTOR(neis)[j];
6242 VECTOR(*res)[i] += VECTOR(*weights)[edge];
6243 }
6244 }
6245 } else {
6246 for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
6247 long int vid = IGRAPH_VIT_GET(vit);
6248 long int j, n;
6249 IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) vid, mode));
6250 n = igraph_vector_size(&neis);
6251 for (j = 0; j < n; j++) {
6252 long int edge = (long int) VECTOR(neis)[j];
6253 long int from = IGRAPH_FROM(graph, edge);
6254 long int to = IGRAPH_TO(graph, edge);
6255 if (from != to) {
6256 VECTOR(*res)[i] += VECTOR(*weights)[edge];
6257 }
6258 }
6259 }
6260 }
6261
6262 igraph_vit_destroy(&vit);
6263 igraph_vector_destroy(&neis);
6264 IGRAPH_FINALLY_CLEAN(2);
6265
6266 return 0;
6267 }
6268
6269 /**
6270 * \function igraph_diameter_dijkstra
6271 * Weighted diameter using Dijkstra's algorithm, non-negative weights only.
6272 *
6273 * The diameter of a graph is its longest geodesic. I.e. the
6274 * (weighted) shortest path is calculated for all pairs of vertices
6275 * and the longest one is the diameter.
6276 * \param graph The input graph, can be directed or undirected.
6277 * \param pres Pointer to a real number, if not \c NULL then it will contain
6278 * the diameter (the actual distance).
6279 * \param pfrom Pointer to an integer, if not \c NULL it will be set to the
6280 * source vertex of the diameter path.
6281 * \param pto Pointer to an integer, if not \c NULL it will be set to the
6282 * target vertex of the diameter path.
6283 * \param path Pointer to an initialized vector. If not \c NULL the actual
6284 * longest geodesic path will be stored here. The vector will be
6285 * resized as needed.
6286 * \param directed Boolean, whether to consider directed
6287 * paths. Ignored for undirected graphs.
6288 * \param unconn What to do if the graph is not connected. If
6289 * \c TRUE the longest geodesic within a component
6290 * will be returned, otherwise \c IGRAPH_INFINITY is
6291 * returned.
6292 * \return Error code.
6293 *
6294 * Time complexity: O(|V||E|*log|E|), |V| is the number of vertices,
6295 * |E| is the number of edges.
6296 */
6297
igraph_diameter_dijkstra(const igraph_t * graph,const igraph_vector_t * weights,igraph_real_t * pres,igraph_integer_t * pfrom,igraph_integer_t * pto,igraph_vector_t * path,igraph_bool_t directed,igraph_bool_t unconn)6298 int igraph_diameter_dijkstra(const igraph_t *graph,
6299 const igraph_vector_t *weights,
6300 igraph_real_t *pres,
6301 igraph_integer_t *pfrom,
6302 igraph_integer_t *pto,
6303 igraph_vector_t *path,
6304 igraph_bool_t directed,
6305 igraph_bool_t unconn) {
6306
6307 /* Implementation details. This is the basic Dijkstra algorithm,
6308 with a binary heap. The heap is indexed, i.e. it stores not only
6309 the distances, but also which vertex they belong to.
6310
6311 From now on we use a 2-way heap, so the distances can be queried
6312 directly from the heap.
6313
6314 Dirty tricks:
6315 - the opposite of the distance is stored in the heap, as it is a
6316 maximum heap and we need a minimum heap.
6317 - we don't use IGRAPH_INFINITY during the computation, as IGRAPH_FINITE()
6318 might involve a function call and we want to spare that. -1 will denote
6319 infinity instead.
6320 */
6321
6322 long int no_of_nodes = igraph_vcount(graph);
6323 long int no_of_edges = igraph_ecount(graph);
6324
6325 igraph_2wheap_t Q;
6326 igraph_inclist_t inclist;
6327 long int source, j;
6328 igraph_neimode_t dirmode = directed ? IGRAPH_OUT : IGRAPH_ALL;
6329
6330 long int from = -1, to = -1;
6331 igraph_real_t res = 0;
6332 long int nodes_reached = 0;
6333
6334 if (!weights) {
6335 igraph_integer_t diameter;
6336 IGRAPH_CHECK(igraph_diameter(graph, &diameter, pfrom, pto, path, directed, unconn));
6337 if (pres) {
6338 *pres = diameter;
6339 }
6340 return IGRAPH_SUCCESS;
6341 }
6342
6343 if (weights && igraph_vector_size(weights) != no_of_edges) {
6344 IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
6345 }
6346
6347 if (igraph_vector_min(weights) < 0) {
6348 IGRAPH_ERROR("Weight vector must be non-negative", IGRAPH_EINVAL);
6349 }
6350
6351 IGRAPH_CHECK(igraph_2wheap_init(&Q, no_of_nodes));
6352 IGRAPH_FINALLY(igraph_2wheap_destroy, &Q);
6353 IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, dirmode));
6354 IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);
6355
6356 for (source = 0; source < no_of_nodes; source++) {
6357
6358 IGRAPH_PROGRESS("Weighted diameter: ", source * 100.0 / no_of_nodes, NULL);
6359 IGRAPH_ALLOW_INTERRUPTION();
6360
6361 igraph_2wheap_clear(&Q);
6362 igraph_2wheap_push_with_index(&Q, source, -1.0);
6363
6364 nodes_reached = 0.0;
6365
6366 while (!igraph_2wheap_empty(&Q)) {
6367 long int minnei = igraph_2wheap_max_index(&Q);
6368 igraph_real_t mindist = -igraph_2wheap_deactivate_max(&Q);
6369 igraph_vector_int_t *neis;
6370 long int nlen;
6371
6372 if (mindist > res) {
6373 res = mindist; from = source; to = minnei;
6374 }
6375 nodes_reached++;
6376
6377 /* Now check all neighbors of 'minnei' for a shorter path */
6378 neis = igraph_inclist_get(&inclist, minnei);
6379 nlen = igraph_vector_int_size(neis);
6380 for (j = 0; j < nlen; j++) {
6381 long int edge = (long int) VECTOR(*neis)[j];
6382 long int tto = IGRAPH_OTHER(graph, edge, minnei);
6383 igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
6384 igraph_bool_t active = igraph_2wheap_has_active(&Q, tto);
6385 igraph_bool_t has = igraph_2wheap_has_elem(&Q, tto);
6386 igraph_real_t curdist = active ? -igraph_2wheap_get(&Q, tto) : 0.0;
6387
6388 if (!has) {
6389 /* First finite distance */
6390 IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));
6391 } else if (altdist < curdist) {
6392 /* A shorter path */
6393 IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));
6394 }
6395 }
6396
6397 } /* !igraph_2wheap_empty(&Q) */
6398
6399 /* not connected, return infinity */
6400 if (nodes_reached != no_of_nodes && !unconn) {
6401 res = IGRAPH_INFINITY;
6402 from = to = -1;
6403 break;
6404 }
6405
6406 } /* source < no_of_nodes */
6407
6408 /* Compensate for the +1 that we have added to distances */
6409 res -= 1;
6410
6411 igraph_inclist_destroy(&inclist);
6412 igraph_2wheap_destroy(&Q);
6413 IGRAPH_FINALLY_CLEAN(2);
6414
6415 IGRAPH_PROGRESS("Weighted diameter: ", 100.0, NULL);
6416
6417 if (pres) {
6418 *pres = res;
6419 }
6420 if (pfrom) {
6421 *pfrom = (igraph_integer_t) from;
6422 }
6423 if (pto) {
6424 *pto = (igraph_integer_t) to;
6425 }
6426 if (path) {
6427 if (!igraph_finite(res)) {
6428 igraph_vector_clear(path);
6429 } else {
6430 igraph_vector_ptr_t tmpptr;
6431 igraph_vector_ptr_init(&tmpptr, 1);
6432 IGRAPH_FINALLY(igraph_vector_ptr_destroy, &tmpptr);
6433 VECTOR(tmpptr)[0] = path;
6434 IGRAPH_CHECK(igraph_get_shortest_paths_dijkstra(graph,
6435 /*vertices=*/ &tmpptr, /*edges=*/ 0,
6436 (igraph_integer_t) from,
6437 igraph_vss_1((igraph_integer_t) to),
6438 weights, dirmode, /*predecessors=*/ 0,
6439 /*inbound_edges=*/ 0));
6440 igraph_vector_ptr_destroy(&tmpptr);
6441 IGRAPH_FINALLY_CLEAN(1);
6442 }
6443 }
6444
6445 return 0;
6446 }
6447
6448 /**
6449 * \function igraph_sort_vertex_ids_by_degree
6450 * \brief Calculate a list of vertex ids sorted by degree of the corresponding vertex.
6451 *
6452 * The list of vertex ids is returned in a vector that is sorted
6453 * in ascending or descending order of vertex degree.
6454 *
6455 * \param graph The input graph.
6456 * \param outvids Pointer to an initialized vector that will be
6457 * resized and will contain the ordered vertex ids.
6458 * \param vids Input vertex selector of vertex ids to include in
6459 * calculation.
6460 * \param mode Defines the type of the degree.
6461 * \c IGRAPH_OUT, out-degree,
6462 * \c IGRAPH_IN, in-degree,
6463 * \c IGRAPH_ALL, total degree (sum of the
6464 * in- and out-degree).
6465 * This parameter is ignored for undirected graphs.
6466 * \param loops Boolean, gives whether the self-loops should be
6467 * counted.
6468 * \param order Specifies whether the ordering should be ascending
6469 * (\c IGRAPH_ASCENDING) or descending (\c IGRAPH_DESCENDING).
6470 * \param only_indices If true, then return a sorted list of indices
6471 * into a vector corresponding to \c vids, rather than a list
6472 * of vertex ids. This parameter is ignored if \c vids is set
6473 * to all vertices via igraph_vs_all() or igraph_vss_all(),
6474 * because in this case the indices and vertex ids are the
6475 * same.
6476 * \return Error code:
6477 * \c IGRAPH_EINVVID: invalid vertex id.
6478 * \c IGRAPH_EINVMODE: invalid mode argument.
6479 *
6480 */
6481
igraph_sort_vertex_ids_by_degree(const igraph_t * graph,igraph_vector_t * outvids,igraph_vs_t vids,igraph_neimode_t mode,igraph_bool_t loops,igraph_order_t order,igraph_bool_t only_indices)6482 int igraph_sort_vertex_ids_by_degree(const igraph_t *graph,
6483 igraph_vector_t *outvids,
6484 igraph_vs_t vids,
6485 igraph_neimode_t mode,
6486 igraph_bool_t loops,
6487 igraph_order_t order,
6488 igraph_bool_t only_indices) {
6489 long int i;
6490 igraph_vector_t degrees, vs_vec;
6491 IGRAPH_VECTOR_INIT_FINALLY(°rees, 0);
6492 IGRAPH_CHECK(igraph_degree(graph, °rees, vids, mode, loops));
6493 IGRAPH_CHECK((int) igraph_vector_qsort_ind(°rees, outvids,
6494 order == IGRAPH_DESCENDING));
6495 if (only_indices || igraph_vs_is_all(&vids) ) {
6496 igraph_vector_destroy(°rees);
6497 IGRAPH_FINALLY_CLEAN(1);
6498 } else {
6499 IGRAPH_VECTOR_INIT_FINALLY(&vs_vec, 0);
6500 IGRAPH_CHECK(igraph_vs_as_vector(graph, vids, &vs_vec));
6501 for (i = 0; i < igraph_vector_size(outvids); i++) {
6502 VECTOR(*outvids)[i] = VECTOR(vs_vec)[(long int)VECTOR(*outvids)[i]];
6503 }
6504 igraph_vector_destroy(&vs_vec);
6505 igraph_vector_destroy(°rees);
6506 IGRAPH_FINALLY_CLEAN(2);
6507 }
6508 return 0;
6509 }
6510
6511 /**
6512 * \function igraph_contract_vertices
6513 * Replace multiple vertices with a single one.
6514 *
6515 * This function creates a new graph, by merging several
6516 * vertices into one. The vertices in the new graph correspond
6517 * to sets of vertices in the input graph.
6518 * \param graph The input graph, it can be directed or
6519 * undirected.
6520 * \param mapping A vector giving the mapping. For each
6521 * vertex in the original graph, it should contain
6522 * its id in the new graph.
6523 * \param vertex_comb What to do with the vertex attributes.
6524 * See the igraph manual section about attributes for
6525 * details.
6526 * \return Error code.
6527 *
6528 * Time complexity: O(|V|+|E|), linear in the number
6529 * or vertices plus edges.
6530 */
6531
igraph_contract_vertices(igraph_t * graph,const igraph_vector_t * mapping,const igraph_attribute_combination_t * vertex_comb)6532 int igraph_contract_vertices(igraph_t *graph,
6533 const igraph_vector_t *mapping,
6534 const igraph_attribute_combination_t *vertex_comb) {
6535 igraph_vector_t edges;
6536 long int no_of_nodes = igraph_vcount(graph);
6537 long int no_of_edges = igraph_ecount(graph);
6538 igraph_bool_t vattr = vertex_comb && igraph_has_attribute_table();
6539 igraph_t res;
6540 long int e, last = -1;
6541 long int no_new_vertices;
6542
6543 if (igraph_vector_size(mapping) != no_of_nodes) {
6544 IGRAPH_ERROR("Invalid mapping vector length",
6545 IGRAPH_EINVAL);
6546 }
6547
6548 IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
6549 IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges * 2));
6550
6551 if (no_of_nodes > 0) {
6552 last = (long int) igraph_vector_max(mapping);
6553 }
6554
6555 for (e = 0; e < no_of_edges; e++) {
6556 long int from = IGRAPH_FROM(graph, e);
6557 long int to = IGRAPH_TO(graph, e);
6558
6559 long int nfrom = (long int) VECTOR(*mapping)[from];
6560 long int nto = (long int) VECTOR(*mapping)[to];
6561
6562 igraph_vector_push_back(&edges, nfrom);
6563 igraph_vector_push_back(&edges, nto);
6564
6565 if (nfrom > last) {
6566 last = nfrom;
6567 }
6568 if (nto > last) {
6569 last = nto;
6570 }
6571 }
6572
6573 no_new_vertices = last + 1;
6574
6575 IGRAPH_CHECK(igraph_create(&res, &edges, (igraph_integer_t) no_new_vertices,
6576 igraph_is_directed(graph)));
6577
6578 igraph_vector_destroy(&edges);
6579 IGRAPH_FINALLY_CLEAN(1);
6580
6581 IGRAPH_FINALLY(igraph_destroy, &res);
6582
6583 IGRAPH_I_ATTRIBUTE_DESTROY(&res);
6584 IGRAPH_I_ATTRIBUTE_COPY(&res, graph, /*graph=*/ 1,
6585 /*vertex=*/ 0, /*edge=*/ 1);
6586
6587 if (vattr) {
6588 long int i;
6589 igraph_vector_ptr_t merges;
6590 igraph_vector_t sizes;
6591 igraph_vector_t *vecs;
6592
6593 vecs = igraph_Calloc(no_new_vertices, igraph_vector_t);
6594 if (!vecs) {
6595 IGRAPH_ERROR("Cannot combine attributes while contracting"
6596 " vertices", IGRAPH_ENOMEM);
6597 }
6598 IGRAPH_FINALLY(igraph_free, vecs);
6599 IGRAPH_CHECK(igraph_vector_ptr_init(&merges, no_new_vertices));
6600 IGRAPH_FINALLY(igraph_i_simplify_free, &merges);
6601 IGRAPH_VECTOR_INIT_FINALLY(&sizes, no_new_vertices);
6602
6603 for (i = 0; i < no_of_nodes; i++) {
6604 long int to = (long int) VECTOR(*mapping)[i];
6605 VECTOR(sizes)[to] += 1;
6606 }
6607 for (i = 0; i < no_new_vertices; i++) {
6608 igraph_vector_t *v = &vecs[i];
6609 IGRAPH_CHECK(igraph_vector_init(v, (long int) VECTOR(sizes)[i]));
6610 igraph_vector_clear(v);
6611 VECTOR(merges)[i] = v;
6612 }
6613 for (i = 0; i < no_of_nodes; i++) {
6614 long int to = (long int) VECTOR(*mapping)[i];
6615 igraph_vector_t *v = &vecs[to];
6616 igraph_vector_push_back(v, i);
6617 }
6618
6619 IGRAPH_CHECK(igraph_i_attribute_combine_vertices(graph, &res,
6620 &merges,
6621 vertex_comb));
6622
6623 igraph_vector_destroy(&sizes);
6624 igraph_i_simplify_free(&merges);
6625 igraph_free(vecs);
6626 IGRAPH_FINALLY_CLEAN(3);
6627 }
6628
6629 IGRAPH_FINALLY_CLEAN(1);
6630 igraph_destroy(graph);
6631 *graph = res;
6632
6633 return 0;
6634 }
6635
6636 /* Create the transitive closure of a tree graph.
6637 This is fairly simple, we just collect all ancestors of a vertex
6638 using a depth-first search.
6639 */
6640
igraph_transitive_closure_dag(const igraph_t * graph,igraph_t * closure)6641 int igraph_transitive_closure_dag(const igraph_t *graph,
6642 igraph_t *closure) {
6643
6644 long int no_of_nodes = igraph_vcount(graph);
6645 igraph_vector_t deg;
6646 igraph_vector_t new_edges;
6647 igraph_vector_t ancestors;
6648 long int root;
6649 igraph_vector_t neighbors;
6650 igraph_stack_t path;
6651 igraph_vector_bool_t done;
6652
6653 if (!igraph_is_directed(graph)) {
6654 IGRAPH_ERROR("Tree transitive closure of a directed graph",
6655 IGRAPH_EINVAL);
6656 }
6657
6658 IGRAPH_VECTOR_INIT_FINALLY(&new_edges, 0);
6659 IGRAPH_VECTOR_INIT_FINALLY(°, no_of_nodes);
6660 IGRAPH_VECTOR_INIT_FINALLY(&ancestors, 0);
6661 IGRAPH_VECTOR_INIT_FINALLY(&neighbors, 0);
6662 IGRAPH_CHECK(igraph_stack_init(&path, 0));
6663 IGRAPH_FINALLY(igraph_stack_destroy, &path);
6664 IGRAPH_CHECK(igraph_vector_bool_init(&done, no_of_nodes));
6665 IGRAPH_FINALLY(igraph_vector_bool_destroy, &done);
6666
6667 IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(),
6668 IGRAPH_OUT, IGRAPH_LOOPS));
6669
6670 #define STAR (-1)
6671
6672 for (root = 0; root < no_of_nodes; root++) {
6673 if (VECTOR(deg)[root] != 0) {
6674 continue;
6675 }
6676 IGRAPH_CHECK(igraph_stack_push(&path, root));
6677
6678 while (!igraph_stack_empty(&path)) {
6679 long int node = (long int) igraph_stack_top(&path);
6680 if (node == STAR) {
6681 /* Leaving a node */
6682 long int j, n;
6683 igraph_stack_pop(&path);
6684 node = (long int) igraph_stack_pop(&path);
6685 if (!VECTOR(done)[node]) {
6686 igraph_vector_pop_back(&ancestors);
6687 VECTOR(done)[node] = 1;
6688 }
6689 n = igraph_vector_size(&ancestors);
6690 for (j = 0; j < n; j++) {
6691 IGRAPH_CHECK(igraph_vector_push_back(&new_edges, node));
6692 IGRAPH_CHECK(igraph_vector_push_back(&new_edges,
6693 VECTOR(ancestors)[j]));
6694 }
6695 } else {
6696 /* Getting into a node */
6697 long int n, j;
6698 if (!VECTOR(done)[node]) {
6699 IGRAPH_CHECK(igraph_vector_push_back(&ancestors, node));
6700 }
6701 IGRAPH_CHECK(igraph_neighbors(graph, &neighbors,
6702 (igraph_integer_t) node, IGRAPH_IN));
6703 n = igraph_vector_size(&neighbors);
6704 IGRAPH_CHECK(igraph_stack_push(&path, STAR));
6705 for (j = 0; j < n; j++) {
6706 long int nei = (long int) VECTOR(neighbors)[j];
6707 IGRAPH_CHECK(igraph_stack_push(&path, nei));
6708 }
6709 }
6710 }
6711 }
6712
6713 #undef STAR
6714
6715 igraph_vector_bool_destroy(&done);
6716 igraph_stack_destroy(&path);
6717 igraph_vector_destroy(&neighbors);
6718 igraph_vector_destroy(&ancestors);
6719 igraph_vector_destroy(°);
6720 IGRAPH_FINALLY_CLEAN(5);
6721
6722 IGRAPH_CHECK(igraph_create(closure, &new_edges, (igraph_integer_t)no_of_nodes,
6723 IGRAPH_DIRECTED));
6724
6725 igraph_vector_destroy(&new_edges);
6726 IGRAPH_FINALLY_CLEAN(1);
6727
6728 return 0;
6729 }
6730
6731 /**
6732 * \function igraph_diversity
6733 * Structural diversity index of the vertices
6734 *
6735 * This measure was defined in Nathan Eagle, Michael Macy and Rob
6736 * Claxton: Network Diversity and Economic Development, Science 328,
6737 * 1029--1031, 2010.
6738 *
6739 * </para><para>
6740 * It is simply the (normalized) Shannon entropy of the
6741 * incident edges' weights. D(i)=H(i)/log(k[i]), and
6742 * H(i) = -sum(p[i,j] log(p[i,j]), j=1..k[i]),
6743 * where p[i,j]=w[i,j]/sum(w[i,l], l=1..k[i]), k[i] is the (total)
6744 * degree of vertex i, and w[i,j] is the weight of the edge(s) between
6745 * vertex i and j.
6746 * \param graph The input graph, edge directions are ignored.
6747 * \param weights The edge weights, in the order of the edge ids, must
6748 * have appropriate length.
6749 * \param res An initialized vector, the results are stored here.
6750 * \param vids Vector with the vertex ids for which to calculate the
6751 * measure.
6752 * \return Error code.
6753 *
6754 * Time complexity: O(|V|+|E|), linear.
6755 *
6756 */
6757
igraph_diversity(igraph_t * graph,const igraph_vector_t * weights,igraph_vector_t * res,const igraph_vs_t vids)6758 int igraph_diversity(igraph_t *graph, const igraph_vector_t *weights,
6759 igraph_vector_t *res, const igraph_vs_t vids) {
6760
6761 int no_of_nodes = igraph_vcount(graph);
6762 int no_of_edges = igraph_ecount(graph);
6763 igraph_vector_t incident;
6764 igraph_vit_t vit;
6765 igraph_real_t s, ent, w;
6766 int i, j, k;
6767
6768 if (!weights) {
6769 IGRAPH_ERROR("Edge weights must be given", IGRAPH_EINVAL);
6770 }
6771
6772 if (igraph_vector_size(weights) != no_of_edges) {
6773 IGRAPH_ERROR("Invalid edge weight vector length", IGRAPH_EINVAL);
6774 }
6775
6776 IGRAPH_VECTOR_INIT_FINALLY(&incident, 10);
6777
6778 if (igraph_vs_is_all(&vids)) {
6779 IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
6780 for (i = 0; i < no_of_nodes; i++) {
6781 s = ent = 0.0;
6782 IGRAPH_CHECK(igraph_incident(graph, &incident, i, /*mode=*/ IGRAPH_ALL));
6783 for (j = 0, k = (int) igraph_vector_size(&incident); j < k; j++) {
6784 w = VECTOR(*weights)[(long int)VECTOR(incident)[j]];
6785 s += w;
6786 ent += (w * log(w));
6787 }
6788 VECTOR(*res)[i] = (log(s) - ent / s) / log(k);
6789 }
6790 } else {
6791 IGRAPH_CHECK(igraph_vector_resize(res, 0));
6792 IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
6793 IGRAPH_FINALLY(igraph_vit_destroy, &vit);
6794
6795 for (IGRAPH_VIT_RESET(vit), i = 0;
6796 !IGRAPH_VIT_END(vit);
6797 IGRAPH_VIT_NEXT(vit), i++) {
6798 long int v = IGRAPH_VIT_GET(vit);
6799 s = ent = 0.0;
6800 IGRAPH_CHECK(igraph_incident(graph, &incident, (igraph_integer_t) v,
6801 /*mode=*/ IGRAPH_ALL));
6802 for (j = 0, k = (int) igraph_vector_size(&incident); j < k; j++) {
6803 w = VECTOR(*weights)[(long int)VECTOR(incident)[j]];
6804 s += w;
6805 ent += (w * log(w));
6806 }
6807 IGRAPH_CHECK(igraph_vector_push_back(res, (log(s) - ent / s) / log(k)));
6808 }
6809
6810 igraph_vit_destroy(&vit);
6811 IGRAPH_FINALLY_CLEAN(1);
6812 }
6813
6814 igraph_vector_destroy(&incident);
6815 IGRAPH_FINALLY_CLEAN(1);
6816
6817 return 0;
6818 }
6819
6820 #define SUCCEED { \
6821 if (res) { \
6822 *res = 1; \
6823 } \
6824 return IGRAPH_SUCCESS; \
6825 }
6826
6827 #define FAIL { \
6828 if (res) { \
6829 *res = 0; \
6830 } \
6831 return IGRAPH_SUCCESS; \
6832 }
6833
6834 /**
6835 * \function igraph_is_degree_sequence
6836 * Determines whether a degree sequence is valid.
6837 *
6838 * A sequence of n integers is a valid degree sequence if there exists some
6839 * graph where the degree of the i-th vertex is equal to the i-th element of the
6840 * sequence. Note that the graph may contain multiple or loop edges; if you are
6841 * interested in whether the degrees of some \em simple graph may realize the
6842 * given sequence, use \ref igraph_is_graphical_degree_sequence.
6843 *
6844 * </para><para>
6845 * In particular, the function checks whether all the degrees are non-negative.
6846 * For undirected graphs, it also checks whether the sum of degrees is even.
6847 * For directed graphs, the function checks whether the lengths of the two
6848 * degree vectors are equal and whether their sums are also equal. These are
6849 * known sufficient and necessary conditions for a degree sequence to be
6850 * valid.
6851 *
6852 * \param out_degrees an integer vector specifying the degree sequence for
6853 * undirected graphs or the out-degree sequence for directed graphs.
6854 * \param in_degrees an integer vector specifying the in-degrees of the
6855 * vertices for directed graphs. For undirected graphs, this must be null.
6856 * \param res pointer to a boolean variable, the result will be stored here
6857 * \return Error code.
6858 *
6859 * Time complexity: O(n), where n is the length of the degree sequence.
6860 */
igraph_is_degree_sequence(const igraph_vector_t * out_degrees,const igraph_vector_t * in_degrees,igraph_bool_t * res)6861 int igraph_is_degree_sequence(const igraph_vector_t *out_degrees,
6862 const igraph_vector_t *in_degrees, igraph_bool_t *res) {
6863 /* degrees must be non-negative */
6864 if (igraph_vector_any_smaller(out_degrees, 0)) {
6865 FAIL;
6866 }
6867 if (in_degrees && igraph_vector_any_smaller(in_degrees, 0)) {
6868 FAIL;
6869 }
6870
6871 if (in_degrees == 0) {
6872 /* sum of degrees must be even */
6873 if (((long int)igraph_vector_sum(out_degrees) % 2) != 0) {
6874 FAIL;
6875 }
6876 } else {
6877 /* length of the two degree vectors must be equal */
6878 if (igraph_vector_size(out_degrees) != igraph_vector_size(in_degrees)) {
6879 FAIL;
6880 }
6881 /* sum of in-degrees must be equal to sum of out-degrees */
6882 if (igraph_vector_sum(out_degrees) != igraph_vector_sum(in_degrees)) {
6883 FAIL;
6884 }
6885 }
6886
6887 SUCCEED;
6888 return 0;
6889 }
6890
6891 int igraph_i_is_graphical_degree_sequence_undirected(
6892 const igraph_vector_t *degrees, igraph_bool_t *res);
6893 int igraph_i_is_graphical_degree_sequence_directed(
6894 const igraph_vector_t *out_degrees, const igraph_vector_t *in_degrees,
6895 igraph_bool_t *res);
6896
6897 /**
6898 * \function igraph_is_graphical_degree_sequence
6899 * Determines whether a sequence of integers can be a degree sequence of some
6900 * simple graph.
6901 *
6902 * </para><para>
6903 * References:
6904 *
6905 * </para><para>
6906 * Hakimi SL: On the realizability of a set of integers as degrees of the
6907 * vertices of a simple graph. J SIAM Appl Math 10:496-506, 1962.
6908 *
6909 * </para><para>
6910 * PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm
6911 * to realize graphical degree sequences of directed graphs. The Electronic
6912 * Journal of Combinatorics 17(1):R66, 2010.
6913 *
6914 * </para><para>
6915 * Z Kiraly: Recognizing graphic degree sequences and generating all
6916 * realizations. TR-2011-11, Egervary Research Group, H-1117, Budapest,
6917 * Hungary. ISSN 1587-4451, 2012.
6918 *
6919 * \param out_degrees an integer vector specifying the degree sequence for
6920 * undirected graphs or the out-degree sequence for directed graphs.
6921 * \param in_degrees an integer vector specifying the in-degrees of the
6922 * vertices for directed graphs. For undirected graphs, this must be null.
6923 * \param res pointer to a boolean variable, the result will be stored here
6924 * \return Error code.
6925 *
6926 * Time complexity: O(n log n) for undirected graphs, O(n^2) for directed
6927 * graphs, where n is the length of the degree sequence.
6928 */
igraph_is_graphical_degree_sequence(const igraph_vector_t * out_degrees,const igraph_vector_t * in_degrees,igraph_bool_t * res)6929 int igraph_is_graphical_degree_sequence(const igraph_vector_t *out_degrees,
6930 const igraph_vector_t *in_degrees, igraph_bool_t *res) {
6931 IGRAPH_CHECK(igraph_is_degree_sequence(out_degrees, in_degrees, res));
6932 if (!*res) {
6933 FAIL;
6934 }
6935
6936 if (igraph_vector_size(out_degrees) == 0) {
6937 SUCCEED;
6938 }
6939
6940 if (in_degrees == 0) {
6941 return igraph_i_is_graphical_degree_sequence_undirected(out_degrees, res);
6942 } else {
6943 return igraph_i_is_graphical_degree_sequence_directed(out_degrees, in_degrees, res);
6944 }
6945 }
6946
igraph_i_is_graphical_degree_sequence_undirected(const igraph_vector_t * degrees,igraph_bool_t * res)6947 int igraph_i_is_graphical_degree_sequence_undirected(const igraph_vector_t *degrees, igraph_bool_t *res) {
6948 igraph_vector_t work;
6949 long int w, b, s, c, n, k;
6950
6951 n = igraph_vector_size(degrees);
6952
6953 /* zero-length sequences are considered graphical */
6954 if (n == 0) {
6955 *res = 1;
6956 return IGRAPH_SUCCESS;
6957 }
6958
6959 IGRAPH_CHECK(igraph_vector_copy(&work, degrees));
6960 IGRAPH_FINALLY(igraph_vector_destroy, &work);
6961
6962 igraph_vector_reverse_sort(&work);
6963
6964 /* This algorithm is outlined in TR-2011-11 of the Egervary Research Group,
6965 * ISSN 1587-4451. The main loop of the algorithm is O(n) but it is dominated
6966 * by an O(n log n) quicksort; this could in theory be brought down to
6967 * O(n) with binsort but it's probably not worth the fuss.
6968 *
6969 * Variables names are mostly according to the technical report, apart from
6970 * the degrees themselves. w and k are zero-based here; in the technical
6971 * report they are 1-based */
6972 *res = 1;
6973 w = n - 1; b = 0; s = 0; c = 0;
6974 for (k = 0; k < n; k++) {
6975 b += VECTOR(work)[k];
6976 c += w;
6977 while (w > k && VECTOR(work)[w] <= k + 1) {
6978 s += VECTOR(work)[w];
6979 c -= (k + 1);
6980 w--;
6981 }
6982 if (b > c + s) {
6983 *res = 0;
6984 break;
6985 }
6986 if (w == k) {
6987 break;
6988 }
6989 }
6990
6991 igraph_vector_destroy(&work);
6992 IGRAPH_FINALLY_CLEAN(1);
6993
6994 return IGRAPH_SUCCESS;
6995 }
6996
6997 typedef struct {
6998 const igraph_vector_t* first;
6999 const igraph_vector_t* second;
7000 } igraph_i_qsort_dual_vector_cmp_data_t;
7001
igraph_i_qsort_dual_vector_cmp_desc(void * data,const void * p1,const void * p2)7002 int igraph_i_qsort_dual_vector_cmp_desc(void* data, const void *p1, const void *p2) {
7003 igraph_i_qsort_dual_vector_cmp_data_t* sort_data =
7004 (igraph_i_qsort_dual_vector_cmp_data_t*)data;
7005 long int index1 = *((long int*)p1);
7006 long int index2 = *((long int*)p2);
7007 if (VECTOR(*sort_data->first)[index1] < VECTOR(*sort_data->first)[index2]) {
7008 return 1;
7009 }
7010 if (VECTOR(*sort_data->first)[index1] > VECTOR(*sort_data->first)[index2]) {
7011 return -1;
7012 }
7013 if (VECTOR(*sort_data->second)[index1] < VECTOR(*sort_data->second)[index2]) {
7014 return 1;
7015 }
7016 if (VECTOR(*sort_data->second)[index1] > VECTOR(*sort_data->second)[index2]) {
7017 return -1;
7018 }
7019 return 0;
7020 }
7021
igraph_i_is_graphical_degree_sequence_directed(const igraph_vector_t * out_degrees,const igraph_vector_t * in_degrees,igraph_bool_t * res)7022 int igraph_i_is_graphical_degree_sequence_directed(
7023 const igraph_vector_t *out_degrees, const igraph_vector_t *in_degrees,
7024 igraph_bool_t *res) {
7025 igraph_vector_long_t index_array;
7026 long int i, j, vcount, lhs, rhs;
7027 igraph_i_qsort_dual_vector_cmp_data_t sort_data;
7028
7029 /* Create an index vector that sorts the vertices by decreasing in-degree */
7030 vcount = igraph_vector_size(out_degrees);
7031 IGRAPH_CHECK(igraph_vector_long_init_seq(&index_array, 0, vcount - 1));
7032 IGRAPH_FINALLY(igraph_vector_long_destroy, &index_array);
7033
7034 /* Set up the auxiliary struct for sorting */
7035 sort_data.first = in_degrees;
7036 sort_data.second = out_degrees;
7037
7038 /* Sort the index vector */
7039 igraph_qsort_r(VECTOR(index_array), vcount, sizeof(long int), &sort_data,
7040 igraph_i_qsort_dual_vector_cmp_desc);
7041
7042 /* Be optimistic, then check whether the Fulkerson–Chen–Anstee condition
7043 * holds for every k. In particular, for every k in [0; n), it must be true
7044 * that:
7045 *
7046 * \sum_{i=0}^k indegree[i] <=
7047 * \sum_{i=0}^k min(outdegree[i], k) +
7048 * \sum_{i=k+1}^{n-1} min(outdegree[i], k + 1)
7049 */
7050
7051 #define INDEGREE(x) (VECTOR(*in_degrees)[VECTOR(index_array)[x]])
7052 #define OUTDEGREE(x) (VECTOR(*out_degrees)[VECTOR(index_array)[x]])
7053
7054 *res = 1;
7055 lhs = 0;
7056 for (i = 0; i < vcount; i++) {
7057 lhs += INDEGREE(i);
7058
7059 /* It is enough to check for indexes where the in-degree is about to
7060 * decrease in the next step; see "Stronger condition" in the Wikipedia
7061 * entry for the Fulkerson-Chen-Anstee condition */
7062 if (i != vcount - 1 && INDEGREE(i) == INDEGREE(i + 1)) {
7063 continue;
7064 }
7065
7066 rhs = 0;
7067 for (j = 0; j <= i; j++) {
7068 rhs += OUTDEGREE(j) < i ? OUTDEGREE(j) : i;
7069 }
7070 for (j = i + 1; j < vcount; j++) {
7071 rhs += OUTDEGREE(j) < (i + 1) ? OUTDEGREE(j) : (i + 1);
7072 }
7073
7074 if (lhs > rhs) {
7075 *res = 0;
7076 break;
7077 }
7078 }
7079
7080 #undef INDEGREE
7081 #undef OUTDEGREE
7082
7083 igraph_vector_long_destroy(&index_array);
7084 IGRAPH_FINALLY_CLEAN(1);
7085
7086 return IGRAPH_SUCCESS;
7087 }
7088
7089 #undef SUCCEED
7090 #undef FAIL
7091
7092
7093 /* igraph_is_tree -- check if a graph is a tree */
7094
7095 /* count the number of vertices reachable from the root */
igraph_i_is_tree_visitor(igraph_integer_t root,const igraph_adjlist_t * al,igraph_integer_t * visited_count)7096 static int igraph_i_is_tree_visitor(igraph_integer_t root, const igraph_adjlist_t *al, igraph_integer_t *visited_count) {
7097 igraph_stack_int_t stack;
7098 igraph_vector_bool_t visited;
7099 long i;
7100
7101 IGRAPH_CHECK(igraph_vector_bool_init(&visited, igraph_adjlist_size(al)));
7102 IGRAPH_FINALLY(igraph_vector_bool_destroy, &visited);
7103
7104 IGRAPH_CHECK(igraph_stack_int_init(&stack, 0));
7105 IGRAPH_FINALLY(igraph_stack_int_destroy, &stack);
7106
7107 *visited_count = 0;
7108
7109 /* push the root into the stack */
7110 IGRAPH_CHECK(igraph_stack_int_push(&stack, root));
7111
7112 while (! igraph_stack_int_empty(&stack)) {
7113 igraph_integer_t u;
7114 igraph_vector_int_t *neighbors;
7115 long ncount;
7116
7117 /* take a vertex from the stack, mark it as visited */
7118 u = igraph_stack_int_pop(&stack);
7119 if (IGRAPH_LIKELY(! VECTOR(visited)[u])) {
7120 VECTOR(visited)[u] = 1;
7121 *visited_count += 1;
7122 }
7123
7124 /* register all its yet-unvisited neighbours for future processing */
7125 neighbors = igraph_adjlist_get(al, u);
7126 ncount = igraph_vector_int_size(neighbors);
7127 for (i = 0; i < ncount; ++i) {
7128 igraph_integer_t v = VECTOR(*neighbors)[i];
7129 if (! VECTOR(visited)[v]) {
7130 IGRAPH_CHECK(igraph_stack_int_push(&stack, v));
7131 }
7132 }
7133 }
7134
7135 igraph_stack_int_destroy(&stack);
7136 igraph_vector_bool_destroy(&visited);
7137 IGRAPH_FINALLY_CLEAN(2);
7138
7139 return IGRAPH_SUCCESS;
7140 }
7141
7142
7143 /**
7144 * \ingroup structural
7145 * \function igraph_is_tree
7146 * \brief Decides whether the graph is a tree.
7147 *
7148 * An undirected graph is a tree if it is connected and has no cycles.
7149 * </para><para>
7150 *
7151 * In the directed case, a possible additional requirement is that all
7152 * edges are oriented away from a root (out-tree or arborescence) or all edges
7153 * are oriented towards a root (in-tree or anti-arborescence).
7154 * This test can be controlled using the \p mode parameter.
7155 * </para><para>
7156 *
7157 * By convention, the null graph (i.e. the graph with no vertices) is considered not to be a tree.
7158 *
7159 * \param graph The graph object to analyze.
7160 * \param res Pointer to a logical variable, the result will be stored
7161 * here.
7162 * \param root If not \c NULL, the root node will be stored here. When \p mode
7163 * is \c IGRAPH_ALL or the graph is undirected, any vertex can be the root
7164 * and \p root is set to 0 (the first vertex). When \p mode is \c IGRAPH_OUT
7165 * or \c IGRAPH_IN, the root is set to the vertex with zero in- or out-degree,
7166 * respectively.
7167 * \param mode For a directed graph this specifies whether to test for an
7168 * out-tree, an in-tree or ignore edge directions. The respective
7169 * possible values are:
7170 * \c IGRAPH_OUT, \c IGRAPH_IN, \c IGRAPH_ALL. This argument is
7171 * ignored for undirected graphs.
7172 * \return Error code:
7173 * \c IGRAPH_EINVAL: invalid mode argument.
7174 *
7175 * Time complexity: At most O(|V|+|E|), the
7176 * number of vertices plus the number of edges in the graph.
7177 *
7178 * \sa igraph_is_weakly_connected()
7179 *
7180 * \example examples/simple/igraph_tree.c
7181 */
7182
igraph_is_tree(const igraph_t * graph,igraph_bool_t * res,igraph_integer_t * root,igraph_neimode_t mode)7183 int igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_integer_t *root, igraph_neimode_t mode) {
7184 igraph_adjlist_t al;
7185 igraph_integer_t iroot = 0;
7186 igraph_integer_t visited_count;
7187 igraph_integer_t vcount, ecount;
7188
7189 vcount = igraph_vcount(graph);
7190 ecount = igraph_ecount(graph);
7191
7192 /* A tree must have precisely vcount-1 edges. */
7193 /* By convention, the zero-vertex graph will not be considered a tree. */
7194 if (ecount != vcount - 1) {
7195 *res = 0;
7196 return IGRAPH_SUCCESS;
7197 }
7198
7199 /* The single-vertex graph is a tree, provided it has no edges (checked in the previous if (..)) */
7200 if (vcount == 1) {
7201 *res = 1;
7202 if (root) {
7203 *root = 0;
7204 }
7205 return IGRAPH_SUCCESS;
7206 }
7207
7208 /* For higher vertex counts we cannot short-circuit due to the possibility
7209 * of loops or multi-edges even when the edge count is correct. */
7210
7211 /* Ignore mode for undirected graphs. */
7212 if (! igraph_is_directed(graph)) {
7213 mode = IGRAPH_ALL;
7214 }
7215
7216 IGRAPH_CHECK(igraph_adjlist_init(graph, &al, mode));
7217 IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
7218
7219 /* The main algorithm:
7220 * We find a root and check that all other vertices are reachable from it.
7221 * We have already checked the number of edges, so with the additional
7222 * reachability condition we can verify if the graph is a tree.
7223 *
7224 * For directed graphs, the root is the node with no incoming/outgoing
7225 * connections, depending on 'mode'. For undirected, it is arbitrary, so
7226 * we choose 0.
7227 */
7228
7229 *res = 1; /* assume success */
7230
7231 switch (mode) {
7232 case IGRAPH_ALL:
7233 iroot = 0;
7234 break;
7235
7236 case IGRAPH_IN:
7237 case IGRAPH_OUT: {
7238 igraph_vector_t degree;
7239 igraph_integer_t i;
7240
7241 IGRAPH_CHECK(igraph_vector_init(°ree, 0));
7242 IGRAPH_FINALLY(igraph_vector_destroy, °ree);
7243
7244 IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), mode == IGRAPH_IN ? IGRAPH_OUT : IGRAPH_IN, /* loops = */ 1));
7245
7246 for (i = 0; i < vcount; ++i)
7247 if (VECTOR(degree)[i] == 0) {
7248 break;
7249 }
7250
7251 /* if no suitable root is found, the graph is not a tree */
7252 if (i == vcount) {
7253 *res = 0;
7254 } else {
7255 iroot = i;
7256 }
7257
7258 igraph_vector_destroy(°ree);
7259 IGRAPH_FINALLY_CLEAN(1);
7260 }
7261
7262 break;
7263 default:
7264 IGRAPH_ERROR("Invalid mode", IGRAPH_EINVMODE);
7265 }
7266
7267 /* if no suitable root was found, skip visting vertices */
7268 if (*res) {
7269 IGRAPH_CHECK(igraph_i_is_tree_visitor(iroot, &al, &visited_count));
7270 *res = visited_count == vcount;
7271 }
7272
7273 if (root) {
7274 *root = iroot;
7275 }
7276
7277 igraph_adjlist_destroy(&al);
7278 IGRAPH_FINALLY_CLEAN(1);
7279
7280 return IGRAPH_SUCCESS;
7281 }
7282