1 /* -*- mode: C -*-  */
2 /* vim:set ts=4 sw=4 sts=4 et: */
3 /*
4    IGraph library.
5    Copyright (C) 2003-2021 The igraph development team
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301 USA
21 
22 */
23 
24 #include "igraph_games.h"
25 
26 #include "igraph_adjlist.h"
27 #include "igraph_constructors.h"
28 #include "igraph_conversion.h"
29 #include "igraph_graphicality.h"
30 #include "igraph_memory.h"
31 #include "igraph_random.h"
32 #include "igraph_vector_ptr.h"
33 
34 #include "core/interruption.h"
35 #include "core/set.h"
36 
igraph_i_degree_sequence_game_simple(igraph_t * graph,const igraph_vector_t * out_seq,const igraph_vector_t * in_seq)37 static int igraph_i_degree_sequence_game_simple(igraph_t *graph,
38                                        const igraph_vector_t *out_seq,
39                                        const igraph_vector_t *in_seq) {
40 
41     long int outsum = 0, insum = 0;
42     igraph_bool_t directed = (in_seq != 0 && igraph_vector_size(in_seq) != 0);
43     igraph_bool_t degseq_ok;
44     long int no_of_nodes, no_of_edges;
45     long int *bag1 = 0, *bag2 = 0;
46     long int bagp1 = 0, bagp2 = 0;
47     igraph_vector_t edges = IGRAPH_VECTOR_NULL;
48     long int i, j;
49 
50     IGRAPH_CHECK(igraph_is_graphical(out_seq, in_seq, IGRAPH_LOOPS_SW | IGRAPH_MULTI_SW, &degseq_ok));
51     if (!degseq_ok) {
52         IGRAPH_ERROR(in_seq ? "No directed graph can realize the given degree sequences" :
53                      "No undirected graph can realize the given degree sequence", IGRAPH_EINVAL);
54     }
55 
56     outsum = (long int) igraph_vector_sum(out_seq);
57     if (directed) {
58         insum = (long int) igraph_vector_sum(in_seq);
59     }
60 
61     no_of_nodes = igraph_vector_size(out_seq);
62     no_of_edges = directed ? outsum : outsum / 2;
63 
64     bag1 = IGRAPH_CALLOC(outsum, long int);
65     if (bag1 == 0) {
66         IGRAPH_ERROR("degree sequence game (simple)", IGRAPH_ENOMEM);
67     }
68     IGRAPH_FINALLY(igraph_free, bag1);
69 
70     for (i = 0; i < no_of_nodes; i++) {
71         for (j = 0; j < VECTOR(*out_seq)[i]; j++) {
72             bag1[bagp1++] = i;
73         }
74     }
75     if (directed) {
76         bag2 = IGRAPH_CALLOC(insum, long int);
77         if (bag2 == 0) {
78             IGRAPH_ERROR("degree sequence game (simple)", IGRAPH_ENOMEM);
79         }
80         IGRAPH_FINALLY(igraph_free, bag2);
81         for (i = 0; i < no_of_nodes; i++) {
82             for (j = 0; j < VECTOR(*in_seq)[i]; j++) {
83                 bag2[bagp2++] = i;
84             }
85         }
86     }
87 
88     IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
89     IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges * 2));
90 
91     RNG_BEGIN();
92 
93     if (directed) {
94         for (i = 0; i < no_of_edges; i++) {
95             long int from = RNG_INTEGER(0, bagp1 - 1);
96             long int to = RNG_INTEGER(0, bagp2 - 1);
97             igraph_vector_push_back(&edges, bag1[from]); /* safe, already reserved */
98             igraph_vector_push_back(&edges, bag2[to]);   /* ditto */
99             bag1[from] = bag1[bagp1 - 1];
100             bag2[to] = bag2[bagp2 - 1];
101             bagp1--; bagp2--;
102         }
103     } else {
104         for (i = 0; i < no_of_edges; i++) {
105             long int from = RNG_INTEGER(0, bagp1 - 1);
106             long int to;
107             igraph_vector_push_back(&edges, bag1[from]); /* safe, already reserved */
108             bag1[from] = bag1[bagp1 - 1];
109             bagp1--;
110             to = RNG_INTEGER(0, bagp1 - 1);
111             igraph_vector_push_back(&edges, bag1[to]);   /* ditto */
112             bag1[to] = bag1[bagp1 - 1];
113             bagp1--;
114         }
115     }
116 
117     RNG_END();
118 
119     IGRAPH_FREE(bag1);
120     IGRAPH_FINALLY_CLEAN(1);
121     if (directed) {
122         IGRAPH_FREE(bag2);
123         IGRAPH_FINALLY_CLEAN(1);
124     }
125 
126     IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
127                                directed));
128     igraph_vector_destroy(&edges);
129     IGRAPH_FINALLY_CLEAN(1);
130 
131     return 0;
132 }
133 
igraph_i_degree_sequence_game_no_multiple_undirected(igraph_t * graph,const igraph_vector_t * seq)134 static int igraph_i_degree_sequence_game_no_multiple_undirected(
135     igraph_t *graph, const igraph_vector_t *seq) {
136 
137     igraph_vector_t stubs = IGRAPH_VECTOR_NULL;
138     igraph_vector_int_t *neis;
139     igraph_vector_t residual_degrees = IGRAPH_VECTOR_NULL;
140     igraph_set_t incomplete_vertices;
141     igraph_adjlist_t al;
142     igraph_bool_t finished, failed;
143     igraph_integer_t from, to, dummy;
144     long int i, j, k;
145     long int no_of_nodes, outsum = 0;
146     igraph_bool_t degseq_ok;
147 
148     IGRAPH_CHECK(igraph_is_graphical(seq, 0, IGRAPH_SIMPLE_SW, &degseq_ok));
149     if (!degseq_ok) {
150         IGRAPH_ERROR("No simple undirected graph can realize the given degree sequence",
151                      IGRAPH_EINVAL);
152     }
153 
154     outsum = (long int) igraph_vector_sum(seq);
155     no_of_nodes = igraph_vector_size(seq);
156 
157     /* Allocate required data structures */
158     IGRAPH_CHECK(igraph_adjlist_init_empty(&al, (igraph_integer_t) no_of_nodes));
159     IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
160     IGRAPH_VECTOR_INIT_FINALLY(&stubs, 0);
161     IGRAPH_CHECK(igraph_vector_reserve(&stubs, outsum));
162     IGRAPH_VECTOR_INIT_FINALLY(&residual_degrees, no_of_nodes);
163     IGRAPH_CHECK(igraph_set_init(&incomplete_vertices, 0));
164     IGRAPH_FINALLY(igraph_set_destroy, &incomplete_vertices);
165 
166     /* Start the RNG */
167     RNG_BEGIN();
168 
169     /* Outer loop; this will try to construct a graph several times from scratch
170      * until it finally succeeds. */
171     finished = 0;
172     while (!finished) {
173         IGRAPH_ALLOW_INTERRUPTION();
174 
175         /* Be optimistic :) */
176         failed = 0;
177 
178         /* Clear the adjacency list to get rid of the previous attempt (if any) */
179         igraph_adjlist_clear(&al);
180 
181         /* Initialize the residual degrees from the degree sequence */
182         IGRAPH_CHECK(igraph_vector_update(&residual_degrees, seq));
183 
184         /* While there are some unconnected stubs left... */
185         while (!finished && !failed) {
186             /* Construct the initial stub vector */
187             igraph_vector_clear(&stubs);
188             for (i = 0; i < no_of_nodes; i++) {
189                 for (j = 0; j < VECTOR(residual_degrees)[i]; j++) {
190                     igraph_vector_push_back(&stubs, i);
191                 }
192             }
193 
194             /* Clear the skipped stub counters and the set of incomplete vertices */
195             igraph_vector_null(&residual_degrees);
196             igraph_set_clear(&incomplete_vertices);
197 
198             /* Shuffle the stubs in-place */
199             igraph_vector_shuffle(&stubs);
200 
201             /* Connect the stubs where possible */
202             k = igraph_vector_size(&stubs);
203             for (i = 0; i < k; ) {
204                 from = (igraph_integer_t) VECTOR(stubs)[i++];
205                 to = (igraph_integer_t) VECTOR(stubs)[i++];
206 
207                 if (from > to) {
208                     dummy = from; from = to; to = dummy;
209                 }
210 
211                 neis = igraph_adjlist_get(&al, from);
212                 if (from == to || igraph_vector_int_binsearch(neis, to, &j)) {
213                     /* Edge exists already */
214                     VECTOR(residual_degrees)[from]++;
215                     VECTOR(residual_degrees)[to]++;
216                     IGRAPH_CHECK(igraph_set_add(&incomplete_vertices, from));
217                     IGRAPH_CHECK(igraph_set_add(&incomplete_vertices, to));
218                 } else {
219                     /* Insert the edge */
220                     IGRAPH_CHECK(igraph_vector_int_insert(neis, j, to));
221                 }
222             }
223 
224             finished = igraph_set_empty(&incomplete_vertices);
225 
226             if (!finished) {
227                 /* We are not done yet; check if the remaining stubs are feasible. This
228                  * is done by enumerating all possible pairs and checking whether at
229                  * least one feasible pair is found. */
230                 i = 0;
231                 failed = 1;
232                 while (failed && igraph_set_iterate(&incomplete_vertices, &i, &from)) {
233                     j = 0;
234                     while (igraph_set_iterate(&incomplete_vertices, &j, &to)) {
235                         if (from == to) {
236                             /* This is used to ensure that each pair is checked once only */
237                             break;
238                         }
239                         if (from > to) {
240                             dummy = from; from = to; to = dummy;
241                         }
242                         neis = igraph_adjlist_get(&al, from);
243                         if (!igraph_vector_int_binsearch(neis, to, 0)) {
244                             /* Found a suitable pair, so we can continue */
245                             failed = 0;
246                             break;
247                         }
248                     }
249                 }
250             }
251         }
252     }
253 
254     /* Finish the RNG */
255     RNG_END();
256 
257     /* Clean up */
258     igraph_set_destroy(&incomplete_vertices);
259     igraph_vector_destroy(&residual_degrees);
260     igraph_vector_destroy(&stubs);
261     IGRAPH_FINALLY_CLEAN(3);
262 
263     /* Create the graph. We cannot use IGRAPH_ALL here for undirected graphs
264      * because we did not add edges in both directions in the adjacency list.
265      * We will use igraph_to_undirected in an extra step. */
266     IGRAPH_CHECK(igraph_adjlist(graph, &al, IGRAPH_OUT, 1));
267     IGRAPH_CHECK(igraph_to_undirected(graph, IGRAPH_TO_UNDIRECTED_EACH, 0));
268 
269     /* Clear the adjacency list */
270     igraph_adjlist_destroy(&al);
271     IGRAPH_FINALLY_CLEAN(1);
272 
273     return IGRAPH_SUCCESS;
274 }
275 
igraph_i_degree_sequence_game_no_multiple_directed(igraph_t * graph,const igraph_vector_t * out_seq,const igraph_vector_t * in_seq)276 static int igraph_i_degree_sequence_game_no_multiple_directed(igraph_t *graph,
277         const igraph_vector_t *out_seq, const igraph_vector_t *in_seq) {
278     igraph_adjlist_t al;
279     igraph_bool_t deg_seq_ok, failed, finished;
280     igraph_vector_t in_stubs = IGRAPH_VECTOR_NULL;
281     igraph_vector_t out_stubs = IGRAPH_VECTOR_NULL;
282     igraph_vector_int_t *neis;
283     igraph_vector_t residual_in_degrees = IGRAPH_VECTOR_NULL;
284     igraph_vector_t residual_out_degrees = IGRAPH_VECTOR_NULL;
285     igraph_set_t incomplete_in_vertices;
286     igraph_set_t incomplete_out_vertices;
287     igraph_integer_t from, to;
288     long int i, j, k;
289     long int no_of_nodes, outsum;
290 
291     IGRAPH_CHECK(igraph_is_graphical(out_seq, in_seq, IGRAPH_SIMPLE_SW, &deg_seq_ok));
292     if (!deg_seq_ok) {
293         IGRAPH_ERROR("No simple directed graph can realize the given degree sequence",
294                      IGRAPH_EINVAL);
295     }
296 
297     outsum = (long int) igraph_vector_sum(out_seq);
298     no_of_nodes = igraph_vector_size(out_seq);
299 
300     /* Allocate required data structures */
301     IGRAPH_CHECK(igraph_adjlist_init_empty(&al, (igraph_integer_t) no_of_nodes));
302     IGRAPH_FINALLY(igraph_adjlist_destroy, &al);
303     IGRAPH_VECTOR_INIT_FINALLY(&out_stubs, 0);
304     IGRAPH_CHECK(igraph_vector_reserve(&out_stubs, outsum));
305     IGRAPH_VECTOR_INIT_FINALLY(&in_stubs, 0);
306     IGRAPH_CHECK(igraph_vector_reserve(&in_stubs, outsum));
307     IGRAPH_VECTOR_INIT_FINALLY(&residual_out_degrees, no_of_nodes);
308     IGRAPH_VECTOR_INIT_FINALLY(&residual_in_degrees, no_of_nodes);
309     IGRAPH_CHECK(igraph_set_init(&incomplete_out_vertices, 0));
310     IGRAPH_FINALLY(igraph_set_destroy, &incomplete_out_vertices);
311     IGRAPH_CHECK(igraph_set_init(&incomplete_in_vertices, 0));
312     IGRAPH_FINALLY(igraph_set_destroy, &incomplete_in_vertices);
313 
314     /* Start the RNG */
315     RNG_BEGIN();
316 
317     /* Outer loop; this will try to construct a graph several times from scratch
318      * until it finally succeeds. */
319     finished = 0;
320     while (!finished) {
321         IGRAPH_ALLOW_INTERRUPTION();
322 
323         /* Be optimistic :) */
324         failed = 0;
325 
326         /* Clear the adjacency list to get rid of the previous attempt (if any) */
327         igraph_adjlist_clear(&al);
328 
329         /* Initialize the residual degrees from the degree sequences */
330         IGRAPH_CHECK(igraph_vector_update(&residual_out_degrees, out_seq));
331         IGRAPH_CHECK(igraph_vector_update(&residual_in_degrees, in_seq));
332 
333         /* While there are some unconnected stubs left... */
334         while (!finished && !failed) {
335             /* Construct the initial stub vectors */
336             igraph_vector_clear(&out_stubs);
337             igraph_vector_clear(&in_stubs);
338             for (i = 0; i < no_of_nodes; i++) {
339                 for (j = 0; j < VECTOR(residual_out_degrees)[i]; j++) {
340                     igraph_vector_push_back(&out_stubs, i);
341                 }
342                 for (j = 0; j < VECTOR(residual_in_degrees)[i]; j++) {
343                     igraph_vector_push_back(&in_stubs, i);
344                 }
345             }
346 
347             /* Clear the skipped stub counters and the set of incomplete vertices */
348             igraph_vector_null(&residual_out_degrees);
349             igraph_vector_null(&residual_in_degrees);
350             igraph_set_clear(&incomplete_out_vertices);
351             igraph_set_clear(&incomplete_in_vertices);
352 
353             /* Shuffle the out-stubs in-place */
354             igraph_vector_shuffle(&out_stubs);
355 
356             /* Connect the stubs where possible */
357             k = igraph_vector_size(&out_stubs);
358             for (i = 0; i < k; i++) {
359                 from = (igraph_integer_t) VECTOR(out_stubs)[i];
360                 to = (igraph_integer_t) VECTOR(in_stubs)[i];
361 
362                 neis = igraph_adjlist_get(&al, from);
363                 if (from == to || igraph_vector_int_binsearch(neis, to, &j)) {
364                     /* Edge exists already */
365                     VECTOR(residual_out_degrees)[from]++;
366                     VECTOR(residual_in_degrees)[to]++;
367                     IGRAPH_CHECK(igraph_set_add(&incomplete_out_vertices, from));
368                     IGRAPH_CHECK(igraph_set_add(&incomplete_in_vertices, to));
369                 } else {
370                     /* Insert the edge */
371                     IGRAPH_CHECK(igraph_vector_int_insert(neis, j, to));
372                 }
373             }
374 
375             /* Are we finished? */
376             finished = igraph_set_empty(&incomplete_out_vertices);
377 
378             if (!finished) {
379                 /* We are not done yet; check if the remaining stubs are feasible. This
380                  * is done by enumerating all possible pairs and checking whether at
381                  * least one feasible pair is found. */
382                 i = 0;
383                 failed = 1;
384                 while (failed && igraph_set_iterate(&incomplete_out_vertices, &i, &from)) {
385                     j = 0;
386                     while (igraph_set_iterate(&incomplete_in_vertices, &j, &to)) {
387                         neis = igraph_adjlist_get(&al, from);
388                         if (from != to && !igraph_vector_int_binsearch(neis, to, 0)) {
389                             /* Found a suitable pair, so we can continue */
390                             failed = 0;
391                             break;
392                         }
393                     }
394                 }
395             }
396         }
397     }
398 
399     /* Finish the RNG */
400     RNG_END();
401 
402     /* Clean up */
403     igraph_set_destroy(&incomplete_in_vertices);
404     igraph_set_destroy(&incomplete_out_vertices);
405     igraph_vector_destroy(&residual_in_degrees);
406     igraph_vector_destroy(&residual_out_degrees);
407     igraph_vector_destroy(&in_stubs);
408     igraph_vector_destroy(&out_stubs);
409     IGRAPH_FINALLY_CLEAN(6);
410 
411     /* Create the graph */
412     IGRAPH_CHECK(igraph_adjlist(graph, &al, IGRAPH_OUT, 1));
413 
414     /* Clear the adjacency list */
415     igraph_adjlist_destroy(&al);
416     IGRAPH_FINALLY_CLEAN(1);
417 
418     return IGRAPH_SUCCESS;
419 }
420 
421 /* swap two elements of a vector_int */
422 #define SWAP_INT_ELEM(vec, i, j) \
423     { \
424         igraph_integer_t temp; \
425         temp = VECTOR(vec)[i]; \
426         VECTOR(vec)[i] = VECTOR(vec)[j]; \
427         VECTOR(vec)[j] = temp; \
428     }
429 
igraph_i_degree_sequence_game_no_multiple_undirected_uniform(igraph_t * graph,const igraph_vector_t * degseq)430 static int igraph_i_degree_sequence_game_no_multiple_undirected_uniform(igraph_t *graph, const igraph_vector_t *degseq) {
431     igraph_vector_int_t stubs;
432     igraph_vector_t edges;
433     igraph_bool_t degseq_ok;
434     igraph_vector_ptr_t adjlist;
435     long i, j;
436     long vcount, ecount, stub_count;
437 
438     IGRAPH_CHECK(igraph_is_graphical(degseq, NULL, IGRAPH_SIMPLE_SW, &degseq_ok));
439     if (!degseq_ok) {
440         IGRAPH_ERROR("No simple undirected graph can realize the given degree sequence", IGRAPH_EINVAL);
441     }
442 
443     stub_count = (long) igraph_vector_sum(degseq);
444     ecount = stub_count / 2;
445     vcount = igraph_vector_size(degseq);
446 
447     IGRAPH_VECTOR_INT_INIT_FINALLY(&stubs, stub_count);
448     IGRAPH_VECTOR_INIT_FINALLY(&edges, stub_count);
449 
450     /* Fill stubs vector. */
451     {
452         long k = 0;
453         for (i = 0; i < vcount; ++i) {
454             long deg = (long) VECTOR(*degseq)[i];
455             for (j = 0; j < deg; ++j) {
456                 VECTOR(stubs)[k++] = i;
457             }
458         }
459     }
460 
461     /* Build an adjacency list in terms of sets; used to check for multi-edges. */
462     IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount));
463     IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy);
464     IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);
465     for (i = 0; i < vcount; ++i) {
466         igraph_set_t *set = IGRAPH_CALLOC(1, igraph_set_t);
467         if (! set) {
468             IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM);
469         }
470         IGRAPH_CHECK(igraph_set_init(set, 0));
471         VECTOR(adjlist)[i] = set;
472         IGRAPH_CHECK(igraph_set_reserve(set, (long) VECTOR(*degseq)[i]));
473     }
474 
475     RNG_BEGIN();
476 
477     for (;;) {
478         igraph_bool_t success = 1;
479 
480         /* Shuffle stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */
481         for (i = 0; i < ecount; ++i) {
482             long k, from, to;
483 
484             k = RNG_INTEGER(2*i, stub_count-1);
485             SWAP_INT_ELEM(stubs, 2*i, k);
486 
487             k = RNG_INTEGER(2*i+1, stub_count-1);
488             SWAP_INT_ELEM(stubs, 2*i+1, k);
489 
490             from = VECTOR(stubs)[2*i];
491             to   = VECTOR(stubs)[2*i+1];
492 
493             /* self-loop, fail */
494             if (from == to) {
495                 success = 0;
496                 break;
497             }
498 
499             /* multi-edge, fail */
500             if (igraph_set_contains((igraph_set_t *) VECTOR(adjlist)[to], from)) {
501                 success = 0;
502                 break;
503             }
504 
505             /* sets are already reserved */
506             igraph_set_add((igraph_set_t *) VECTOR(adjlist)[to], from);
507             igraph_set_add((igraph_set_t *) VECTOR(adjlist)[from], to);
508 
509             /* register edge */
510             VECTOR(edges)[2 * i]   = from;
511             VECTOR(edges)[2 * i + 1] = to;
512         }
513 
514         if (success) {
515             break;
516         }
517 
518         /* Clear adjacency list. */
519         for (j = 0; j < vcount; ++j) {
520             igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]);
521         }
522 
523         IGRAPH_ALLOW_INTERRUPTION();
524     }
525 
526     RNG_END();
527 
528     igraph_vector_ptr_destroy_all(&adjlist);
529     igraph_vector_int_destroy(&stubs);
530     IGRAPH_FINALLY_CLEAN(2);
531 
532     IGRAPH_CHECK(igraph_create(graph, &edges, vcount, /* directed = */ 0));
533 
534     igraph_vector_destroy(&edges);
535     IGRAPH_FINALLY_CLEAN(1);
536 
537     return IGRAPH_SUCCESS;
538 }
539 
540 
igraph_i_degree_sequence_game_no_multiple_directed_uniform(igraph_t * graph,const igraph_vector_t * out_deg,const igraph_vector_t * in_deg)541 static int igraph_i_degree_sequence_game_no_multiple_directed_uniform(
542     igraph_t *graph, const igraph_vector_t *out_deg, const igraph_vector_t *in_deg) {
543     igraph_vector_int_t out_stubs, in_stubs;
544     igraph_vector_t edges;
545     igraph_bool_t degseq_ok;
546     igraph_vector_ptr_t adjlist;
547     long i, j;
548     long vcount, ecount;
549 
550     IGRAPH_CHECK(igraph_is_graphical(out_deg, in_deg, IGRAPH_SIMPLE_SW, &degseq_ok));
551     if (!degseq_ok) {
552         IGRAPH_ERROR("No simple directed graph can realize the given degree sequence", IGRAPH_EINVAL);
553     }
554 
555     ecount = (long) igraph_vector_sum(out_deg);
556     vcount = igraph_vector_size(out_deg);
557 
558     IGRAPH_VECTOR_INT_INIT_FINALLY(&out_stubs, ecount);
559     IGRAPH_VECTOR_INT_INIT_FINALLY(&in_stubs, ecount);
560     IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * ecount);
561 
562     /* Fill in- and out-stubs vectors. */
563     {
564         long k = 0, l = 0;
565         for (i = 0; i < vcount; ++i) {
566             long dout, din;
567 
568             dout = (long) VECTOR(*out_deg)[i];
569             for (j = 0; j < dout; ++j) {
570                 VECTOR(out_stubs)[k++] = i;
571             }
572 
573             din  = (long) VECTOR(*in_deg)[i];
574             for (j = 0; j < din; ++j) {
575                 VECTOR(in_stubs)[l++] = i;
576             }
577         }
578     }
579 
580     /* Build an adjacency list in terms of sets; used to check for multi-edges. */
581     IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount));
582     IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy);
583     IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);
584     for (i = 0; i < vcount; ++i) {
585         igraph_set_t *set = IGRAPH_CALLOC(1, igraph_set_t);
586         if (! set) {
587             IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM);
588         }
589         IGRAPH_CHECK(igraph_set_init(set, 0));
590         VECTOR(adjlist)[i] = set;
591         IGRAPH_CHECK(igraph_set_reserve(set, (long) VECTOR(*out_deg)[i]));
592     }
593 
594     RNG_BEGIN();
595 
596     for (;;) {
597         igraph_bool_t success = 1;
598 
599         /* Shuffle out-stubs vector with Fisher-Yates and check for self-loops and multi-edges as we go. */
600         for (i = 0; i < ecount; ++i) {
601             long k, from, to;
602             igraph_set_t *set;
603 
604             k = RNG_INTEGER(i, ecount-1);
605             SWAP_INT_ELEM(out_stubs, i, k);
606 
607             from = VECTOR(out_stubs)[i];
608             to   = VECTOR(in_stubs)[i];
609 
610             /* self-loop, fail */
611             if (to == from) {
612                 success = 0;
613                 break;
614             }
615 
616             /* multi-edge, fail */
617             set = (igraph_set_t *) VECTOR(adjlist)[from];
618             if (igraph_set_contains(set, to)) {
619                 success = 0;
620                 break;
621             }
622 
623             /* sets are already reserved */
624             igraph_set_add(set, to);
625 
626             /* register edge */
627             VECTOR(edges)[2 * i]   = from;
628             VECTOR(edges)[2 * i + 1] = to;
629         }
630 
631         if (success) {
632             break;
633         }
634 
635         /* Clear adjacency list. */
636         for (j = 0; j < vcount; ++j) {
637             igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]);
638         }
639 
640         IGRAPH_ALLOW_INTERRUPTION();
641     }
642 
643     RNG_END();
644 
645     igraph_vector_ptr_destroy_all(&adjlist);
646     igraph_vector_int_destroy(&out_stubs);
647     igraph_vector_int_destroy(&in_stubs);
648     IGRAPH_FINALLY_CLEAN(3);
649 
650     IGRAPH_CHECK(igraph_create(graph, &edges, vcount, /* directed = */ 1));
651 
652     igraph_vector_destroy(&edges);
653     IGRAPH_FINALLY_CLEAN(1);
654 
655     return IGRAPH_SUCCESS;
656 }
657 
658 #undef SWAP_INT_ELEM
659 
660 
661 /* This is in gengraph_mr-connected.cpp */
662 
663 int igraph_degree_sequence_game_vl(igraph_t *graph,
664                                    const igraph_vector_t *out_seq,
665                                    const igraph_vector_t *in_seq);
666 
667 /**
668  * \ingroup generators
669  * \function igraph_degree_sequence_game
670  * \brief Generates a random graph with a given degree sequence.
671  *
672  * \param graph Pointer to an uninitialized graph object.
673  * \param out_deg The degree sequence for an undirected graph (if
674  *        \p in_seq is \c NULL or of length zero), or the out-degree
675  *        sequence of a directed graph (if \p in_deq is not
676  *        of length zero).
677  * \param in_deg It is either a zero-length vector or
678  *        \c NULL (if an undirected
679  *        graph is generated), or the in-degree sequence.
680  * \param method The method to generate the graph. Possible values:
681  *        \clist
682  *          \cli IGRAPH_DEGSEQ_SIMPLE
683  *          This method implements the configuration model.
684  *          For undirected graphs, it puts all vertex IDs in a bag
685  *          such that the multiplicity of a vertex in the bag is the same as
686  *          its degree. Then it draws pairs from the bag until the bag becomes
687  *          empty. This method may generate both loop (self) edges and multiple
688  *          edges. For directed graphs, the algorithm is basically the same,
689  *          but two separate bags are used for the in- and out-degrees.
690  *          Undirected graphs are generated with probability proportional to
691  *          <code>(\prod_{i&lt;j} A_{ij} ! \prod_i A_{ii} !!)^{-1}</code>,
692  *          where \c A denotes the adjacency matrix and <code>!!</code> denotes
693  *          the double factorial. Here \c A is assumed to have twice the number of
694  *          self-loops on its diagonal.
695  *          The corresponding  expression for directed graphs is
696  *          <code>(\prod_{i,j} A_{ij}!)^{-1}</code>.
697  *          Thus the probability of all simple graphs (which only have 0s and 1s
698  *          in the adjacency matrix) is the same, while that of
699  *          non-simple ones depends on their edge and self-loop multiplicities.
700  *          \cli IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE
701  *          This method generates simple graphs.
702  *          It is similar to \c IGRAPH_DEGSEQ_SIMPLE
703  *          but tries to avoid multiple and loop edges and restarts the
704  *          generation from scratch if it gets stuck. It can generate all simple
705  *          realizations of a degree sequence, but it is not guaranteed
706  *          to sample them uniformly. This method is relatively fast and it will
707  *          eventually succeed if the provided degree sequence is graphical,
708  *          but there is no upper bound on the number of iterations.
709  *          \cli IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE_UNIFORM
710  *          This method is identical to \c IGRAPH_DEGSEQ_SIMPLE, but if the
711  *          generated graph is not simple, it rejects it and re-starts the
712  *          generation. It generates all simple graphs with the same probability.
713  *          \cli IGRAPH_DEGSEQ_VL
714  *          This method samples undirected \em connected graphs approximately
715  *          uniformly. It is a Monte Carlo method based on degree-preserving
716  *          edge swaps.
717  *          This generator should be favoured if undirected and connected
718  *          graphs are to be generated and execution time is not a concern.
719  *          igraph uses the original implementation of Fabien Viger; for the algorithm,
720  *          see https://www-complexnetworks.lip6.fr/~latapy/FV/generation.html
721  *          and the paper https://arxiv.org/abs/cs/0502085
722  *        \endclist
723  * \return Error code:
724  *          \c IGRAPH_ENOMEM: there is not enough
725  *           memory to perform the operation.
726  *          \c IGRAPH_EINVAL: invalid method parameter, or
727  *           invalid in- and/or out-degree vectors. The degree vectors
728  *           should be non-negative, \p out_deg should sum
729  *           up to an even integer for undirected graphs; the length
730  *           and sum of \p out_deg and
731  *           \p in_deg
732  *           should match for directed graphs.
733  *
734  * Time complexity: O(|V|+|E|), the number of vertices plus the number of edges
735  *                  for \c IGRAPH_DEGSEQ_SIMPLE. The time complexity of the
736  *                  other modes is not known.
737  *
738  * \sa \ref igraph_barabasi_game(), \ref igraph_erdos_renyi_game(),
739  *     \ref igraph_is_graphical()
740  *
741  * \example examples/simple/igraph_degree_sequence_game.c
742  */
743 
igraph_degree_sequence_game(igraph_t * graph,const igraph_vector_t * out_deg,const igraph_vector_t * in_deg,igraph_degseq_t method)744 int igraph_degree_sequence_game(igraph_t *graph, const igraph_vector_t *out_deg,
745                                 const igraph_vector_t *in_deg,
746                                 igraph_degseq_t method) {
747     if (in_deg && igraph_vector_empty(in_deg) && !igraph_vector_empty(out_deg)) {
748         in_deg = 0;
749     }
750 
751     switch (method) {
752     case IGRAPH_DEGSEQ_SIMPLE:
753         return igraph_i_degree_sequence_game_simple(graph, out_deg, in_deg);
754 
755     case IGRAPH_DEGSEQ_VL:
756         return igraph_degree_sequence_game_vl(graph, out_deg, in_deg);
757 
758     case IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE:
759         if (in_deg == 0) {
760             return igraph_i_degree_sequence_game_no_multiple_undirected(graph, out_deg);
761         } else {
762             return igraph_i_degree_sequence_game_no_multiple_directed(graph, out_deg, in_deg);
763         }
764 
765     case IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE_UNIFORM:
766         if (in_deg == 0) {
767             return igraph_i_degree_sequence_game_no_multiple_undirected_uniform(graph, out_deg);
768         } else {
769             return igraph_i_degree_sequence_game_no_multiple_directed_uniform(graph, out_deg, in_deg);
770         }
771 
772     default:
773         IGRAPH_ERROR("Invalid degree sequence game method", IGRAPH_EINVAL);
774     }
775 }
776