Coverage Report

Created: 2025-12-14 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/src/misc/bipartite.c
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor@gmail.com>
4
   334 Harvard street, Cambridge, MA 02139 USA
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 2 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
   02110-1301 USA
20
21
*/
22
23
#include "igraph_bipartite.h"
24
25
#include "igraph_adjlist.h"
26
#include "igraph_interface.h"
27
#include "igraph_constructors.h"
28
#include "igraph_dqueue.h"
29
#include "igraph_random.h"
30
31
#include "core/interruption.h"
32
#include "graph/attributes.h"
33
#include "internal/utils.h"
34
#include "math/safe_intop.h"
35
#include "misc/graphicality.h"
36
#include "random/random_internal.h"
37
38
/**
39
 * \section about_bipartite Bipartite networks in igraph
40
 *
41
 * <para>
42
 * A bipartite network contains two kinds of vertices and connections
43
 * are only possible between two vertices of different kinds. There are
44
 * many natural examples, e.g. movies and actors as vertices and a
45
 * movie is connected to all participating actors, etc.
46
 *
47
 * </para><para>
48
 * igraph does not have direct support for bipartite networks, at
49
 * least not at the C language level. In other words the igraph_t
50
 * structure does not contain information about the vertex types.
51
 * The C functions for bipartite networks usually have an additional
52
 * input argument to graph, called \c types, a boolean vector giving
53
 * the vertex types.
54
 *
55
 * </para><para>
56
 * Most functions creating bipartite networks are able to create this
57
 * extra vector, you just need to supply an initialized boolean vector
58
 * to them.</para>
59
 */
60
61
/**
62
 * \function igraph_bipartite_projection_size
63
 * \brief Calculate the number of vertices and edges in the bipartite projections.
64
 *
65
 * This function calculates the number of vertices and edges in the
66
 * two projections of a bipartite network. This is useful if you have
67
 * a big bipartite network and you want to estimate the amount of
68
 * memory you would need to calculate the projections themselves.
69
 *
70
 * \param graph The input graph.
71
 * \param types Boolean vector giving the vertex types of the graph.
72
 * \param vcount1 Pointer to an \c igraph_int_t, the number of
73
 *     vertices in the first projection is stored here. May be \c NULL
74
 *     if not needed.
75
 * \param ecount1 Pointer to an \c igraph_int_t, the number of
76
 *     edges in the first projection is stored here. May be \c NULL
77
 *     if not needed.
78
 * \param vcount2 Pointer to an \c igraph_int_t, the number of
79
 *     vertices in the second projection is stored here. May be \c NULL
80
 *     if not needed.
81
 * \param ecount2 Pointer to an \c igraph_int_t, the number of
82
 *     edges in the second projection is stored here. May be \c NULL
83
 *     if not needed.
84
 * \return Error code.
85
 *
86
 * \sa \ref igraph_bipartite_projection() to calculate the actual
87
 * projection.
88
 *
89
 * Time complexity: O(|V|*d^2+|E|), |V| is the number of vertices, |E|
90
 * is the number of edges, d is the average (total) degree of the
91
 * graphs.
92
 */
93
94
igraph_error_t igraph_bipartite_projection_size(const igraph_t *graph,
95
                                     const igraph_vector_bool_t *types,
96
                                     igraph_int_t *vcount1,
97
                                     igraph_int_t *ecount1,
98
                                     igraph_int_t *vcount2,
99
0
                                     igraph_int_t *ecount2) {
100
101
0
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
102
0
    igraph_int_t vc1 = 0, ec1 = 0, vc2 = 0, ec2 = 0;
103
0
    igraph_adjlist_t adjlist;
104
0
    igraph_vector_int_t added;
105
106
0
    if (igraph_vector_bool_size(types) != no_of_nodes) {
107
0
        IGRAPH_ERROR("Invalid bipartite type vector length.", IGRAPH_EINVAL);
108
0
    }
109
110
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&added, no_of_nodes);
111
112
0
    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL, IGRAPH_LOOPS_TWICE, IGRAPH_MULTIPLE));
113
0
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
114
115
0
    for (igraph_int_t i = 0; i < no_of_nodes; i++) {
116
0
        igraph_vector_int_t *neis1;
117
0
        igraph_int_t neilen1;
118
0
        igraph_int_t *ecptr;
119
0
        if (VECTOR(*types)[i]) {
120
0
            vc2++;
121
0
            ecptr = &ec2;
122
0
        } else {
123
0
            vc1++;
124
0
            ecptr = &ec1;
125
0
        }
126
0
        neis1 = igraph_adjlist_get(&adjlist, i);
127
0
        neilen1 = igraph_vector_int_size(neis1);
128
0
        for (igraph_int_t j = 0; j < neilen1; j++) {
129
0
            igraph_int_t neilen2, nei = VECTOR(*neis1)[j];
130
0
            const igraph_vector_int_t *neis2 = igraph_adjlist_get(&adjlist, nei);
131
0
            if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
132
0
                IGRAPH_ERROR("Non-bipartite edge found in bipartite projection.",
133
0
                             IGRAPH_EINVAL);
134
0
            }
135
0
            neilen2 = igraph_vector_int_size(neis2);
136
0
            for (igraph_int_t k = 0; k < neilen2; k++) {
137
0
                igraph_int_t nei2 = VECTOR(*neis2)[k];
138
0
                if (nei2 <= i) {
139
0
                    continue;
140
0
                }
141
0
                if (VECTOR(added)[nei2] == i + 1) {
142
0
                    continue;
143
0
                }
144
0
                VECTOR(added)[nei2] = i + 1;
145
0
                (*ecptr)++;
146
0
            }
147
0
        }
148
0
    }
149
150
0
    if (vcount1) {
151
0
        *vcount1 = vc1;
152
0
    }
153
154
0
    if (ecount1) {
155
0
        *ecount1 = ec1;
156
0
    }
157
158
0
    if (vcount2) {
159
0
        *vcount2 = vc2;
160
0
    }
161
162
0
    if (ecount2) {
163
0
        *ecount2 = ec2;
164
0
    }
165
166
0
    igraph_adjlist_destroy(&adjlist);
167
0
    igraph_vector_int_destroy(&added);
168
0
    IGRAPH_FINALLY_CLEAN(2);
169
170
0
    return IGRAPH_SUCCESS;
171
0
}
172
173
static igraph_error_t igraph_i_bipartite_projection(const igraph_t *graph,
174
                                         const igraph_vector_bool_t *types,
175
                                         igraph_t *proj,
176
                                         int which,
177
0
                                         igraph_vector_int_t *multiplicity) {
178
179
0
    igraph_int_t no_of_nodes = igraph_vcount(graph);
180
0
    igraph_int_t remaining_nodes = 0;
181
0
    igraph_vector_int_t vertex_perm, vertex_index;
182
0
    igraph_vector_int_t edges;
183
0
    igraph_adjlist_t adjlist;
184
0
    const igraph_vector_int_t *neis1, *neis2;
185
0
    igraph_int_t neilen1, neilen2;
186
0
    igraph_vector_int_t added;
187
0
    igraph_vector_int_t mult;
188
189
0
    if (which < 0) {
190
0
        return IGRAPH_SUCCESS;
191
0
    }
192
193
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_perm, 0);
194
0
    IGRAPH_CHECK(igraph_vector_int_reserve(&vertex_perm, no_of_nodes));
195
196
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
197
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_index, no_of_nodes);
198
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&added, no_of_nodes);
199
200
0
    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL, IGRAPH_LOOPS_TWICE, IGRAPH_MULTIPLE));
201
0
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
202
203
    /* we won't need the 'mult' vector if 'multiplicity' is NULL, but MSVC will
204
     * throw warnings in the compiler output if we initialize it conditionally */
205
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&mult, multiplicity ? no_of_nodes : 1);
206
0
    if (multiplicity) {
207
0
        igraph_vector_int_clear(multiplicity);
208
0
    }
209
210
0
    for (igraph_int_t i = 0; i < no_of_nodes; i++) {
211
0
        if (VECTOR(*types)[i] == which) {
212
0
            VECTOR(vertex_index)[i] = remaining_nodes++;
213
0
            igraph_vector_int_push_back(&vertex_perm, i); /* reserved */
214
0
        }
215
0
    }
216
217
0
    for (igraph_int_t i = 0; i < no_of_nodes; i++) {
218
0
        if (VECTOR(*types)[i] == which) {
219
0
            igraph_int_t new_i = VECTOR(vertex_index)[i];
220
0
            igraph_int_t iedges = 0;
221
0
            neis1 = igraph_adjlist_get(&adjlist, i);
222
0
            neilen1 = igraph_vector_int_size(neis1);
223
0
            for (igraph_int_t j = 0; j < neilen1; j++) {
224
0
                igraph_int_t nei = VECTOR(*neis1)[j];
225
0
                if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
226
0
                    IGRAPH_ERROR("Non-bipartite edge found in bipartite projection.", IGRAPH_EINVAL);
227
0
                }
228
0
                neis2 = igraph_adjlist_get(&adjlist, nei);
229
0
                neilen2 = igraph_vector_int_size(neis2);
230
0
                for (igraph_int_t k = 0; k < neilen2; k++) {
231
0
                    igraph_int_t nei2 = VECTOR(*neis2)[k], new_nei2;
232
0
                    if (nei2 <= i) {
233
0
                        continue;
234
0
                    }
235
0
                    if (VECTOR(added)[nei2] == i + 1) {
236
0
                        if (multiplicity) {
237
0
                            VECTOR(mult)[nei2] += 1;
238
0
                        }
239
0
                        continue;
240
0
                    }
241
0
                    VECTOR(added)[nei2] = i + 1;
242
0
                    if (multiplicity) {
243
0
                        VECTOR(mult)[nei2] = 1;
244
0
                    }
245
0
                    iedges++;
246
247
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, new_i));
248
0
                    if (multiplicity) {
249
                        /* If we need the multiplicity as well, then we put in the
250
                           old vertex IDs here and rewrite it later */
251
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, nei2));
252
0
                    } else {
253
0
                        new_nei2 = VECTOR(vertex_index)[nei2];
254
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, new_nei2));
255
0
                    }
256
0
                }
257
0
            }
258
0
            if (multiplicity) {
259
                /* OK, we need to go through all the edges added for vertex new_i
260
                   and check their multiplicity */
261
0
                igraph_int_t now = igraph_vector_int_size(&edges);
262
0
                igraph_int_t from = now - iedges * 2;
263
0
                for (igraph_int_t j = from; j < now; j += 2) {
264
0
                    igraph_int_t nei2 = VECTOR(edges)[j + 1];
265
0
                    igraph_int_t new_nei2 = VECTOR(vertex_index)[nei2];
266
0
                    igraph_int_t m = VECTOR(mult)[nei2];
267
0
                    VECTOR(edges)[j + 1] = new_nei2;
268
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(multiplicity, m));
269
0
                }
270
0
            }
271
0
        } /* if VECTOR(*type)[i] == which */
272
0
    }
273
274
0
    igraph_vector_int_destroy(&mult);
275
0
    igraph_adjlist_destroy(&adjlist);
276
0
    igraph_vector_int_destroy(&added);
277
0
    igraph_vector_int_destroy(&vertex_index);
278
0
    IGRAPH_FINALLY_CLEAN(4);
279
280
0
    IGRAPH_CHECK(igraph_create(proj, &edges, remaining_nodes, IGRAPH_UNDIRECTED));
281
282
0
    igraph_vector_int_destroy(&edges);
283
0
    IGRAPH_FINALLY_CLEAN(1);
284
285
0
    IGRAPH_FINALLY(igraph_destroy, proj);
286
287
    /* copy graph attributes */
288
0
    IGRAPH_CHECK(igraph_i_attribute_copy(proj, graph, true, /* vertex= */ false, /* edge= */ false));
289
290
    /* copy vertex attributes */
291
0
    IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm));
292
293
0
    igraph_vector_int_destroy(&vertex_perm);
294
0
    IGRAPH_FINALLY_CLEAN(2); /* +1 for proj1 */
295
296
0
    return IGRAPH_SUCCESS;
297
0
}
298
299
/**
300
 * \function igraph_bipartite_projection
301
 * \brief Create one or both projections of a bipartite (two-mode) network.
302
 *
303
 * Creates one or both projections of a bipartite graph.
304
 *
305
 * </para><para>
306
 * A graph is called bipartite if its vertices can be partitioned into
307
 * two sets, V1 and V2, so that connections only run between V1 and V2,
308
 * but not within V1 or within V2. The \p types parameter specifies
309
 * which vertex should be considered a member of one or the other
310
 * partition. The projection to V1 has vertex set V1, and two vertices
311
 * are connected if they have at least one common neighbour in V2.
312
 * The number of common neighbours is returned in \p multiplicity1,
313
 * if requested.
314
 *
315
 * \param graph The bipartite input graph. Directedness of the edges
316
 *   is ignored.
317
 * \param types Boolean vector giving the vertex types of the graph.
318
 * \param proj1 Pointer to an uninitialized graph object, the first
319
 *   projection will be created here. It a null pointer, then it is
320
 *   ignored, see also the \p probe1 argument.
321
 * \param proj2 Pointer to an uninitialized graph object, the second
322
 *   projection is created here, if it is not a null pointer. See also
323
 *   the \p probe1 argument.
324
 * \param multiplicity1 Pointer to a vector, or a null pointer. If not
325
 *   the latter, then the multiplicity of the edges is stored
326
 *   here. E.g. if there is an A-C-B and also an A-D-B triple in the
327
 *   bipartite graph (but no more X, such that A-X-B is also in the
328
 *   graph), then the multiplicity of the A-B edge in the projection
329
 *   will be 2.
330
 * \param multiplicity2 The same as \c multiplicity1, but for the
331
 *   other projection.
332
 * \param probe1 This argument can be used to specify the order of the
333
 *   projections in the resulting list. When it is non-negative, then
334
 *   it is considered as a vertex ID and the projection containing
335
 *   this vertex will be the first one in the result. Setting this
336
 *   argument to a non-negative value implies that \c proj1 must be
337
 *   a non-null pointer. If you don't care about the ordering of the
338
 *   projections, pass -1 here.
339
 * \return Error code.
340
 *
341
 * \sa \ref igraph_bipartite_projection_size() to calculate the number
342
 * of vertices and edges in the projections, without creating the
343
 * projection graphs themselves.
344
 *
345
 * Time complexity: O(|V|*d^2+|E|), |V| is the number of vertices, |E|
346
 * is the number of edges, d is the average (total) degree of the
347
 * graphs.
348
 */
349
350
igraph_error_t igraph_bipartite_projection(const igraph_t *graph,
351
                                const igraph_vector_bool_t *types,
352
                                igraph_t *proj1,
353
                                igraph_t *proj2,
354
                                igraph_vector_int_t *multiplicity1,
355
                                igraph_vector_int_t *multiplicity2,
356
0
                                igraph_int_t probe1) {
357
358
0
    const igraph_int_t no_of_nodes = igraph_vcount(graph);
359
360
    /* t1 is -1 if proj1 is omitted, it is 0 if it belongs to type zero,
361
       it is 1 if it belongs to type one. The same for t2 */
362
0
    int t1, t2;
363
364
0
    if (igraph_vector_bool_size(types) != no_of_nodes) {
365
0
        IGRAPH_ERROR("Invalid bipartite type vector length.", IGRAPH_EINVAL);
366
0
    }
367
368
0
    if (probe1 >= no_of_nodes) {
369
0
        IGRAPH_ERROR("No such vertex to probe.", IGRAPH_EINVAL);
370
0
    }
371
372
0
    if (probe1 >= 0 && !proj1) {
373
0
        IGRAPH_ERROR("`probe1' given, but `proj1' is a null pointer.", IGRAPH_EINVAL);
374
0
    }
375
376
0
    if (probe1 >= 0) {
377
0
        t1 = VECTOR(*types)[probe1];
378
0
        if (proj2) {
379
0
            t2 = 1 - t1;
380
0
        } else {
381
0
            t2 = -1;
382
0
        }
383
0
    } else {
384
0
        t1 = proj1 ? 0 : -1;
385
0
        t2 = proj2 ? 1 : -1;
386
0
    }
387
388
0
    if (proj1) {
389
0
        IGRAPH_CHECK(igraph_i_bipartite_projection(graph, types, proj1, t1, multiplicity1));
390
0
        IGRAPH_FINALLY(igraph_destroy, proj1);
391
0
    }
392
393
0
    if (proj2) {
394
0
        IGRAPH_CHECK(igraph_i_bipartite_projection(graph, types, proj2, t2, multiplicity2));
395
0
    }
396
397
0
    if (proj1) {
398
0
        IGRAPH_FINALLY_CLEAN(1); /* proj1 ownership change */
399
0
    }
400
401
0
    return IGRAPH_SUCCESS;
402
0
}
403
404
405
/**
406
 * \function igraph_full_bipartite
407
 * \brief Creates a complete bipartite graph.
408
 *
409
 * A bipartite network contains two kinds of vertices and connections
410
 * are only possible between two vertices of different kind. There are
411
 * many natural examples, e.g. movies and actors as vertices and a
412
 * movie is connected to all participating actors, etc.
413
 *
414
 * </para><para>
415
 * igraph does not have direct support for bipartite networks, at
416
 * least not at the C language level. In other words the \type igraph_t
417
 * structure does not contain information about the vertex types.
418
 * The C functions for bipartite networks usually have an additional
419
 * input argument to graph, called \p types, a boolean vector giving
420
 * the vertex types.
421
 *
422
 * </para><para>
423
 * Most functions creating bipartite networks are able to create this
424
 * extra vector, you just need to supply an initialized boolean vector
425
 * to them.
426
 *
427
 * \param graph Pointer to an uninitialized graph object, the graph will be
428
 *   created here.
429
 * \param types Pointer to a boolean vector. If not a null pointer,
430
 *   then the vertex types will be stored here.
431
 * \param n1 Integer, the number of vertices of the first kind.
432
 * \param n2 Integer, the number of vertices of the second kind.
433
 * \param directed Boolean, whether to create a directed graph.
434
 * \param mode A constant that gives the type of connections for
435
 *   directed graphs. If \c IGRAPH_OUT, then edges point from vertices
436
 *   of the first kind to vertices of the second kind; if \c
437
 *   IGRAPH_IN, then the opposite direction is realized; if \c
438
 *   IGRAPH_ALL, then mutual edges will be created.
439
 * \return Error code.
440
 *
441
 * Time complexity: O(|V|+|E|), linear in the number of vertices and
442
 * edges.
443
 *
444
 * \sa \ref igraph_full() for non-bipartite complete graphs,
445
 * \ref igraph_full_multipartite() for complete multipartite graphs.
446
 */
447
448
igraph_error_t igraph_full_bipartite(igraph_t *graph,
449
                          igraph_vector_bool_t *types,
450
                          igraph_int_t n1, igraph_int_t n2,
451
                          igraph_bool_t directed,
452
0
                          igraph_neimode_t mode) {
453
454
0
    igraph_int_t no_of_nodes, no_of_edges;
455
0
    igraph_vector_int_t edges;
456
0
    igraph_int_t ptr;
457
458
0
    if (n1 < 0 || n2 < 0) {
459
0
        IGRAPH_ERROR("Invalid number of vertices for bipartite graph.", IGRAPH_EINVAL);
460
0
    }
461
462
0
    IGRAPH_SAFE_ADD(n1, n2, &no_of_nodes);
463
464
0
    if (!directed) {
465
0
        IGRAPH_SAFE_MULT(n1, n2, &no_of_edges);
466
0
    } else if (mode == IGRAPH_OUT || mode == IGRAPH_IN) {
467
0
        IGRAPH_SAFE_MULT(n1, n2, &no_of_edges);
468
0
    } else { /* mode==IGRAPH_ALL */
469
0
        IGRAPH_SAFE_MULT(n1, n2, &no_of_edges);
470
0
        IGRAPH_SAFE_MULT(no_of_edges, 2, &no_of_edges);
471
0
    }
472
473
    /* To ensure the size of the edges vector will not overflow. */
474
0
    if (no_of_edges > IGRAPH_ECOUNT_MAX) {
475
0
        IGRAPH_ERROR("Overflow in number of edges.", IGRAPH_EOVERFLOW);
476
0
    }
477
478
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, no_of_edges * 2);
479
480
0
    ptr = 0;
481
482
0
    if (!directed || mode == IGRAPH_OUT) {
483
484
0
        for (igraph_int_t i = 0; i < n1; i++) {
485
0
            for (igraph_int_t j = 0; j < n2; j++) {
486
0
                VECTOR(edges)[ptr++] = i;
487
0
                VECTOR(edges)[ptr++] = n1 + j;
488
0
            }
489
0
        }
490
491
0
    } else if (mode == IGRAPH_IN) {
492
493
0
        for (igraph_int_t i = 0; i < n1; i++) {
494
0
            for (igraph_int_t j = 0; j < n2; j++) {
495
0
                VECTOR(edges)[ptr++] = n1 + j;
496
0
                VECTOR(edges)[ptr++] = i;
497
0
            }
498
0
        }
499
500
0
    } else {
501
502
0
        for (igraph_int_t i = 0; i < n1; i++) {
503
0
            for (igraph_int_t j = 0; j < n2; j++) {
504
0
                VECTOR(edges)[ptr++] = i;
505
0
                VECTOR(edges)[ptr++] = n1 + j;
506
0
                VECTOR(edges)[ptr++] = n1 + j;
507
0
                VECTOR(edges)[ptr++] = i;
508
0
            }
509
0
        }
510
0
    }
511
512
0
    IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed));
513
0
    igraph_vector_int_destroy(&edges);
514
0
    IGRAPH_FINALLY_CLEAN(1);
515
0
    IGRAPH_FINALLY(igraph_destroy, graph);
516
517
0
    if (types) {
518
0
        IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes));
519
0
        igraph_vector_bool_null(types);
520
0
        for (igraph_int_t i = n1; i < no_of_nodes; i++) {
521
0
            VECTOR(*types)[i] = true;
522
0
        }
523
0
    }
524
525
0
    IGRAPH_FINALLY_CLEAN(1);
526
527
0
    return IGRAPH_SUCCESS;
528
0
}
529
530
/**
531
 * \function igraph_create_bipartite
532
 * \brief Create a bipartite graph.
533
 *
534
 * This is a simple wrapper function to create a bipartite graph. It
535
 * does a little more than \ref igraph_create(), e.g. it checks that
536
 * the graph is indeed bipartite with respect to the given \p types
537
 * vector. If there is an edge connecting two vertices of the same
538
 * kind, then an error is reported.
539
 *
540
 * \param graph Pointer to an uninitialized graph object, the result is
541
 *   created here.
542
 * \param types Boolean vector giving the vertex types. The length of
543
 *   the vector defines the number of vertices in the graph.
544
 * \param edges Vector giving the edges of the graph. The highest
545
 *   vertex ID in this vector must be smaller than the length of the
546
 *   \p types vector.
547
 * \param directed Boolean, whether to create a directed graph.
548
 * \return Error code.
549
 *
550
 * Time complexity: O(|V|+|E|), linear in the number of vertices and
551
 * edges.
552
 *
553
 * \example examples/simple/igraph_bipartite_create.c
554
 */
555
556
igraph_error_t igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool_t *types,
557
                            const igraph_vector_int_t *edges,
558
0
                            igraph_bool_t directed) {
559
560
0
    igraph_int_t no_of_nodes = igraph_vector_bool_size(types);
561
0
    igraph_int_t no_of_edges = igraph_vector_int_size(edges);
562
0
    igraph_int_t i;
563
564
0
    if (no_of_edges % 2 != 0) {
565
0
        IGRAPH_ERROR("Invalid (odd length) edges vector.", IGRAPH_EINVAL);
566
0
    }
567
0
    no_of_edges /= 2;
568
569
0
    if (! igraph_vector_int_isininterval(edges, 0, no_of_nodes-1)) {
570
0
        IGRAPH_ERRORF("Invalid vertex ID for a graph with %" IGRAPH_PRId " vertices.",
571
0
                     IGRAPH_EINVVID,
572
0
                     no_of_nodes);
573
0
    }
574
575
    /* Check bipartiteness */
576
0
    for (i = 0; i < no_of_edges * 2; i += 2) {
577
0
        igraph_int_t from = VECTOR(*edges)[i];
578
0
        igraph_int_t to = VECTOR(*edges)[i + 1];
579
0
        igraph_bool_t t1 = VECTOR(*types)[from];
580
0
        igraph_bool_t t2 = VECTOR(*types)[to];
581
0
        if ( (t1 && t2) || (!t1 && !t2) ) {
582
0
            IGRAPH_ERROR("Invalid edges, not a bipartite graph.", IGRAPH_EINVAL);
583
0
        }
584
0
    }
585
586
0
    IGRAPH_CHECK(igraph_empty(graph, no_of_nodes, directed));
587
0
    IGRAPH_FINALLY(igraph_destroy, graph);
588
0
    IGRAPH_CHECK(igraph_add_edges(graph, edges, 0));
589
590
0
    IGRAPH_FINALLY_CLEAN(1);
591
0
    return IGRAPH_SUCCESS;
592
0
}
593
594
/**
595
 * \function igraph_biadjacency
596
 * \brief Creates a bipartite graph from a bipartite adjacency matrix.
597
 *
598
 * A bipartite (or two-mode) graph contains two types of vertices and
599
 * edges always connect vertices of different types. A bipartite adjacency
600
 * matrix is an \em n x \em m matrix, \em n and \em m are the number of vertices
601
 * of the two types, respectively. Nonzero elements in the matrix denote
602
 * edges between the two corresponding vertices.
603
 *
604
 * </para><para>
605
 * This function can operate in two modes, depending on the
606
 * \p multiple argument. If it is \c false, then a single edge is
607
 * created for every non-zero element in the bipartite adjacency matrix. If
608
 * \p multiple is \c true, then as many edges are created between two
609
 * vertices as the corresponding matrix element. When \p multiple
610
 * is set to \c true, matrix elements should be whole numbers.
611
 * Otherwise their fractional part will be discarded.
612
 *
613
 * \param graph Pointer to an uninitialized graph object.
614
 * \param types Pointer to an initialized boolean vector, or a null
615
 *   pointer. If not a null pointer, then the vertex types are stored
616
 *   here. It is resized as needed.
617
 * \param biadjmatrix The bipartite adjacency matrix that serves as an input
618
 *   to this function.
619
 * \param directed Specifies whether to create an undirected or a directed
620
 *   graph.
621
 * \param mode Specifies the direction of the edges in a directed
622
 *   graph. If \c IGRAPH_OUT, then edges point from vertices
623
 *   of the first kind (corresponding to rows) to vertices of the
624
 *   second kind (corresponding to columns); if \c IGRAPH_IN,
625
 *   then the opposite direction is realized; if \c IGRAPH_ALL,
626
 *   then mutual edges will be created.
627
 * \param multiple Whether to interpret matrix entries as edge multiplicities,
628
 *   see details above.
629
 * \return Error code.
630
 *
631
 * Time complexity: O(n*m), the size of the bipartite adjacency matrix.
632
 */
633
634
igraph_error_t igraph_biadjacency(
635
        igraph_t *graph,
636
        igraph_vector_bool_t *types,
637
        const igraph_matrix_t *biadjmatrix,
638
        igraph_bool_t directed,
639
        igraph_neimode_t mode,
640
0
        igraph_bool_t multiple) {
641
642
0
    const igraph_int_t n1 = igraph_matrix_nrow(biadjmatrix);
643
0
    const igraph_int_t n2 = igraph_matrix_ncol(biadjmatrix);
644
0
    const igraph_int_t no_of_nodes = n1 + n2;
645
0
    igraph_vector_int_t edges;
646
647
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
648
649
0
    if (multiple) {
650
651
0
        if (n1 > 0 && n2 > 0 && igraph_matrix_min(biadjmatrix) < 0) {
652
0
            IGRAPH_ERRORF(
653
0
                "Bipartite adjacency matrix elements should be non-negative, found %g.",
654
0
                IGRAPH_EINVAL, igraph_matrix_min(biadjmatrix)
655
0
            );
656
0
        }
657
658
0
        for (igraph_int_t j = 0; j < n2; j++) {
659
0
            for (igraph_int_t i = 0; i < n1; i++) {
660
0
                igraph_int_t elem = MATRIX(*biadjmatrix, i, j);
661
0
                igraph_int_t from, to;
662
663
0
                if (elem == 0) {
664
0
                    continue;
665
0
                }
666
667
0
                if (mode == IGRAPH_IN) {
668
0
                    from = n1 + j;
669
0
                    to = i;
670
0
                } else {
671
0
                    from = i;
672
0
                    to = n1 + j;
673
0
                }
674
675
0
                if (mode != IGRAPH_ALL || !directed) {
676
0
                    for (igraph_int_t k = 0; k < elem; k++) {
677
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
678
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
679
0
                    }
680
0
                } else {
681
0
                    for (igraph_int_t k = 0; k < elem; k++) {
682
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
683
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
684
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
685
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
686
0
                    }
687
0
                }
688
0
            }
689
0
        }
690
691
0
    } else {
692
693
0
        for (igraph_int_t j = 0; j < n2; j++) {
694
0
            for (igraph_int_t i = 0; i < n1; i++) {
695
0
                igraph_int_t from, to;
696
697
0
                if (MATRIX(*biadjmatrix, i, j) != 0) {
698
0
                    if (mode == IGRAPH_IN) {
699
0
                        from = n1 + j;
700
0
                        to = i;
701
0
                    } else {
702
0
                        from = i;
703
0
                        to = n1 + j;
704
0
                    }
705
0
                    if (mode != IGRAPH_ALL || !directed) {
706
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
707
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
708
0
                    } else {
709
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
710
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
711
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
712
0
                        IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
713
0
                    }
714
0
                }
715
0
            }
716
0
        }
717
718
0
    }
719
720
0
    IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed));
721
0
    igraph_vector_int_destroy(&edges);
722
0
    IGRAPH_FINALLY_CLEAN(1);
723
724
0
    IGRAPH_FINALLY(igraph_destroy, graph);
725
726
0
    if (types) {
727
0
        IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes));
728
0
        igraph_vector_bool_null(types);
729
0
        for (igraph_int_t i = n1; i < no_of_nodes; i++) {
730
0
            VECTOR(*types)[i] = true;
731
0
        }
732
0
    }
733
734
0
    IGRAPH_FINALLY_CLEAN(1);
735
736
0
    return IGRAPH_SUCCESS;
737
0
}
738
739
740
/**
741
 * \function igraph_weighted_biadjacency
742
 * \brief Creates a bipartite graph from a weighted bipartite adjacency matrix.
743
 *
744
 * A bipartite (or two-mode) graph contains two types of vertices and
745
 * edges always connect vertices of different types. A bipartite adjacency
746
 * matrix is an \em n x \em m matrix, \em n and \em m are the number of vertices
747
 * of the two types, respectively. Nonzero elements in the matrix denote
748
 * edges between the two corresponding vertices.
749
 *
750
 * \param graph Pointer to an uninitialized graph object.
751
 * \param types Pointer to an initialized boolean vector, or a null
752
 *   pointer. If not a null pointer, then the vertex types are stored
753
 *   here. It is resized as needed.
754
 * \param weights Pointer to an initialized vector, the weights will be stored here.
755
 * \param biadjmatrix The bipartite adjacency matrix that serves as an input
756
 *   to this function.
757
 * \param directed Specifies whether to create an undirected or a directed
758
 *   graph.
759
 * \param mode Specifies the direction of the edges in a directed
760
 *   graph. If \c IGRAPH_OUT, then edges point from vertices
761
 *   of the first kind (corresponding to rows) to vertices of the
762
 *   second kind (corresponding to columns); if \c IGRAPH_IN,
763
 *   then the opposite direction is realized; if \c IGRAPH_ALL,
764
 *   then mutual edges will be created.
765
 * \return Error code.
766
 *
767
 * Time complexity: O(n*m), the size of the bipartite adjacency matrix.
768
 */
769
770
igraph_error_t igraph_weighted_biadjacency(
771
        igraph_t *graph,
772
        igraph_vector_bool_t *types,
773
        igraph_vector_t *weights,
774
        const igraph_matrix_t *biadjmatrix,
775
        igraph_bool_t directed,
776
0
        igraph_neimode_t mode) {
777
778
0
    const igraph_int_t n1 = igraph_matrix_nrow(biadjmatrix);
779
0
    const igraph_int_t n2 = igraph_matrix_ncol(biadjmatrix);
780
0
    const igraph_int_t no_of_nodes = n1 + n2;
781
0
    igraph_vector_int_t edges;
782
783
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
784
0
    igraph_vector_clear(weights);
785
786
0
    for (igraph_int_t j = 0; j < n2; j++) {
787
0
        for (igraph_int_t i = 0; i < n1; i++) {
788
0
            igraph_real_t weight = MATRIX(*biadjmatrix, i, j);
789
0
            igraph_int_t from, to;
790
791
0
            if (weight != 0) {
792
0
                if (mode == IGRAPH_IN) {
793
0
                    from = n1 + j;
794
0
                    to = i;
795
0
                } else {
796
0
                    from = i;
797
0
                    to = n1 + j;
798
0
                }
799
0
                if (mode != IGRAPH_ALL || !directed) {
800
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
801
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
802
0
                    IGRAPH_CHECK(igraph_vector_push_back(weights, weight));
803
0
                } else {
804
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
805
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
806
0
                    IGRAPH_CHECK(igraph_vector_push_back(weights, weight));
807
808
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, to));
809
0
                    IGRAPH_CHECK(igraph_vector_int_push_back(&edges, from));
810
0
                    IGRAPH_CHECK(igraph_vector_push_back(weights, weight));
811
0
                }
812
0
            }
813
0
        }
814
0
    }
815
816
0
    IGRAPH_CHECK(igraph_create(graph, &edges, no_of_nodes, directed));
817
0
    igraph_vector_int_destroy(&edges);
818
0
    IGRAPH_FINALLY_CLEAN(1);
819
820
0
    IGRAPH_FINALLY(igraph_destroy, graph);
821
822
0
    if (types) {
823
0
        IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes));
824
0
        igraph_vector_bool_null(types);
825
0
        for (igraph_int_t i = n1; i < no_of_nodes; i++) {
826
0
            VECTOR(*types)[i] = true;
827
0
        }
828
0
    }
829
830
0
    IGRAPH_FINALLY_CLEAN(1);
831
832
0
    return IGRAPH_SUCCESS;
833
0
}
834
835
/**
836
 * \function igraph_get_biadjacency
837
 * \brief Converts a bipartite graph into a bipartite adjacency matrix.
838
 *
839
 * In a bipartite adjacency matrix \c A, element <code>A_ij</code>
840
 * gives the number of edges between the <code>i</code>th vertex of the
841
 * first partition and the <code>j</code>th vertex of the second partition.
842
 *
843
 * </para><para>
844
 * If the graph contains edges within the same partition, this function
845
 * issues a warning.
846
 *
847
 * \param graph The input graph, edge directions are ignored.
848
 * \param types Boolean vector containing the vertex types. Vertices belonging
849
 *   to the first partition have type \c false, the one in the second
850
 *   partition type \c true.
851
 * \param weights A vector specifying a weight for each edge or \c NULL.
852
 *   If \c NULL, all edges are assumed to have weight 1.
853
 * \param res Pointer to an initialized matrix, the result is stored
854
 *   here. An element of the matrix gives the number of edges
855
 *   (irrespectively of their direction), or sum of edge weights,
856
 *   between the two corresponding vertices. The rows will correspond
857
 *   to vertices with type \c false, the columns correspond to vertices
858
 *   with type \c true.
859
 * \param row_ids Pointer to an initialized vector or \c NULL.
860
 *   If not a null pointer, then the IDs of vertices with type \c false
861
 *   are stored here, with the same ordering as the rows of the
862
 *   biadjacency matrix.
863
 * \param col_ids Pointer to an initialized vector or \c NULL.
864
 *   If not a null pointer, then the IDs of vertices with type \c true
865
 *   are stored here, with the same ordering as the columns of the
866
 *   biadjacency matrix.
867
 * \return Error code.
868
 *
869
 * Time complexity: O(|E|) where |E| is the number of edges.
870
 *
871
 * \sa \ref igraph_biadjacency() for the opposite operation.
872
 */
873
874
igraph_error_t igraph_get_biadjacency(
875
    const igraph_t *graph, const igraph_vector_bool_t *types,
876
    const igraph_vector_t *weights,
877
    igraph_matrix_t *res, igraph_vector_int_t *row_ids,
878
    igraph_vector_int_t *col_ids
879
0
) {
880
881
0
    igraph_int_t no_of_nodes = igraph_vcount(graph);
882
0
    igraph_int_t no_of_edges = igraph_ecount(graph);
883
0
    igraph_int_t n1 = 0, n2 = 0;
884
0
    igraph_int_t ignored_edges = 0;
885
0
    igraph_vector_int_t perm;
886
887
0
    if (igraph_vector_bool_size(types) != no_of_nodes) {
888
0
        IGRAPH_ERRORF("Vertex type vector size (%" IGRAPH_PRId ") not equal to number of vertices (%" IGRAPH_PRId ").",
889
0
                      IGRAPH_EINVAL, igraph_vector_bool_size(types), no_of_nodes);
890
0
    }
891
892
0
    if (weights) {
893
0
        if (igraph_vector_size(weights) != no_of_edges) {
894
0
            IGRAPH_ERRORF("Edge weight vector size (%" IGRAPH_PRId ") not equal to number of edges (%" IGRAPH_PRId ").",
895
0
                          IGRAPH_EINVAL, igraph_vector_size(weights), no_of_edges);
896
0
        }
897
0
    }
898
899
0
    for (igraph_int_t i = 0; i < no_of_nodes; i++) {
900
0
        n1 += VECTOR(*types)[i] == false ? 1 : 0;
901
0
    }
902
0
    n2 = no_of_nodes - n1;
903
904
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&perm, no_of_nodes);
905
906
0
    for (igraph_int_t i = 0, p1 = 0, p2 = n1; i < no_of_nodes; i++) {
907
0
        VECTOR(perm)[i] = VECTOR(*types)[i] ? p2++ : p1++;
908
0
    }
909
910
0
    IGRAPH_CHECK(igraph_matrix_resize(res, n1, n2));
911
0
    igraph_matrix_null(res);
912
0
    for (igraph_int_t i = 0; i < no_of_edges; i++) {
913
0
        igraph_int_t from = IGRAPH_FROM(graph, i);
914
0
        igraph_int_t to = IGRAPH_TO(graph, i);
915
0
        igraph_int_t from2 = VECTOR(perm)[from];
916
0
        igraph_int_t to2 = VECTOR(perm)[to];
917
0
        if (VECTOR(*types)[from] == VECTOR(*types)[to]) {
918
0
            ignored_edges++;
919
0
        } else if (! VECTOR(*types)[from]) {
920
0
            MATRIX(*res, from2, to2 - n1) += weights ? VECTOR(*weights)[i] : 1;
921
0
        } else {
922
0
            MATRIX(*res, to2, from2 - n1) += weights ? VECTOR(*weights)[i] : 1;
923
0
        }
924
0
    }
925
926
0
    if (ignored_edges > 0) {
927
0
        IGRAPH_WARNINGF("%" IGRAPH_PRId " edges running within partitions were ignored.", ignored_edges);
928
0
    }
929
930
0
    if (row_ids) {
931
0
        IGRAPH_CHECK(igraph_vector_int_resize(row_ids, n1));
932
0
    }
933
0
    if (col_ids) {
934
0
        IGRAPH_CHECK(igraph_vector_int_resize(col_ids, n2));
935
0
    }
936
0
    if (row_ids || col_ids) {
937
0
        for (igraph_int_t i = 0; i < no_of_nodes; i++) {
938
0
            if (! VECTOR(*types)[i]) {
939
0
                if (row_ids) {
940
0
                    igraph_int_t i2 = VECTOR(perm)[i];
941
0
                    VECTOR(*row_ids)[i2] = i;
942
0
                }
943
0
            } else {
944
0
                if (col_ids) {
945
0
                    igraph_int_t i2 = VECTOR(perm)[i];
946
0
                    VECTOR(*col_ids)[i2 - n1] = i;
947
0
                }
948
0
            }
949
0
        }
950
0
    }
951
952
0
    igraph_vector_int_destroy(&perm);
953
0
    IGRAPH_FINALLY_CLEAN(1);
954
955
0
    return IGRAPH_SUCCESS;
956
0
}
957
958
/**
959
 * \function igraph_is_bipartite
960
 * \brief Check whether a graph is bipartite.
961
 *
962
 * This function checks whether a graph is bipartite. It tries
963
 * to find a mapping that gives a possible division of the vertices into two
964
 * classes, such that no two vertices of the same class are connected by an
965
 * edge.
966
 *
967
 * </para><para>
968
 * The existence of such a mapping is equivalent of having no circuits of
969
 * odd length in the graph. A graph with loop edges cannot be bipartite.
970
 *
971
 * </para><para>
972
 * Note that the mapping is not necessarily unique, e.g. if the graph has
973
 * at least two components, then the vertices in the separate components
974
 * can be mapped independently.
975
 *
976
 * \param graph The input graph.
977
 * \param res Pointer to a boolean, the result is stored here.
978
 * \param types Pointer to an initialized boolean vector, or a null
979
 *   pointer. If not a null pointer and a mapping was found, then it
980
 *   is stored here. If not a null pointer, but no mapping was found,
981
 *   the contents of this vector is invalid.
982
 * \return Error code.
983
 *
984
 * Time complexity: O(|V|+|E|), linear in the number of vertices and
985
 * edges.
986
 *
987
 * \sa igraph_is_bipartite_coloring() to determine if all edges connect
988
 * vertices of different types, given a specific type vector.
989
 */
990
991
igraph_error_t igraph_is_bipartite(const igraph_t *graph,
992
                        igraph_bool_t *res,
993
531
                        igraph_vector_bool_t *types) {
994
995
    /* We basically do a breadth first search and label the
996
       vertices along the way. We stop as soon as we can find a
997
       contradiction.
998
999
       In the 'seen' vector 0 means 'not seen yet', 1 means type 1,
1000
       2 means type 2.
1001
    */
1002
1003
531
    igraph_int_t no_of_nodes = igraph_vcount(graph);
1004
531
    igraph_vector_char_t seen;
1005
531
    igraph_dqueue_int_t Q;
1006
531
    igraph_vector_int_t neis;
1007
531
    igraph_bool_t bi = true;
1008
1009
    /* Shortcut: Graphs with self-loops are not bipartite. */
1010
531
    if (igraph_i_property_cache_has(graph, IGRAPH_PROP_HAS_LOOP) &&
1011
0
        igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_HAS_LOOP)) {
1012
0
        if (res) {
1013
0
            *res = false;
1014
0
        }
1015
0
        return IGRAPH_SUCCESS;
1016
0
    }
1017
1018
    /* Shortcut: If the type vector is not requested, and the graph is a forest
1019
     * we can immediately return with the result that the graph is bipartite. */
1020
531
    if (! types &&
1021
531
        igraph_i_property_cache_has(graph, IGRAPH_PROP_IS_FOREST) &&
1022
0
        igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_IS_FOREST)) {
1023
0
        if (res) {
1024
0
            *res = true;
1025
0
        }
1026
0
        return IGRAPH_SUCCESS;
1027
0
    }
1028
1029
531
    IGRAPH_VECTOR_CHAR_INIT_FINALLY(&seen, no_of_nodes);
1030
531
    IGRAPH_DQUEUE_INT_INIT_FINALLY(&Q, 100);
1031
531
    IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0);
1032
1033
46.9k
    for (igraph_int_t i = 0; bi && i < no_of_nodes; i++) {
1034
1035
46.4k
        if (VECTOR(seen)[i]) {
1036
5.75k
            continue;
1037
5.75k
        }
1038
1039
40.7k
        IGRAPH_CHECK(igraph_dqueue_int_push(&Q, i));
1040
40.7k
        VECTOR(seen)[i] = 1;
1041
1042
88.6k
        while (bi && !igraph_dqueue_int_empty(&Q)) {
1043
47.8k
            igraph_int_t n, j;
1044
47.8k
            igraph_int_t actnode = igraph_dqueue_int_pop(&Q);
1045
47.8k
            char acttype = VECTOR(seen)[actnode];
1046
1047
47.8k
            IGRAPH_CHECK(igraph_neighbors(
1048
47.8k
                graph, &neis, actnode, IGRAPH_ALL, IGRAPH_LOOPS, IGRAPH_MULTIPLE
1049
47.8k
            ));
1050
47.8k
            n = igraph_vector_int_size(&neis);
1051
65.1k
            for (j = 0; j < n; j++) {
1052
17.4k
                igraph_int_t nei = VECTOR(neis)[j];
1053
17.4k
                if (VECTOR(seen)[nei]) {
1054
9.95k
                    char neitype = VECTOR(seen)[nei];
1055
9.95k
                    if (neitype == acttype) {
1056
243
                        bi = false;
1057
243
                        break;
1058
243
                    }
1059
9.95k
                } else {
1060
7.54k
                    VECTOR(seen)[nei] = 3 - acttype;
1061
7.54k
                    IGRAPH_CHECK(igraph_dqueue_int_push(&Q, nei));
1062
7.54k
                }
1063
17.4k
            }
1064
47.8k
        }
1065
40.7k
    }
1066
1067
531
    igraph_vector_int_destroy(&neis);
1068
531
    igraph_dqueue_int_destroy(&Q);
1069
531
    IGRAPH_FINALLY_CLEAN(2);
1070
1071
    /* Set the cache: A graph that is not bipartite has
1072
     * an odd-length cycle, therefore it cannot be a forest. */
1073
531
    if (! bi) {
1074
243
        igraph_i_property_cache_set_bool_checked(graph, IGRAPH_PROP_IS_FOREST, false);
1075
243
    }
1076
1077
531
    if (res) {
1078
531
        *res = bi;
1079
531
    }
1080
1081
531
    if (types && bi) {
1082
0
        IGRAPH_CHECK(igraph_vector_bool_resize(types, no_of_nodes));
1083
0
        for (igraph_int_t i = 0; i < no_of_nodes; i++) {
1084
0
            VECTOR(*types)[i] = VECTOR(seen)[i] - 1;
1085
0
        }
1086
0
    }
1087
1088
531
    igraph_vector_char_destroy(&seen);
1089
531
    IGRAPH_FINALLY_CLEAN(1);
1090
1091
531
    return IGRAPH_SUCCESS;
1092
531
}
1093
1094
1095
static igraph_error_t bipartite_iea_game(
1096
        igraph_t *graph,
1097
        igraph_int_t n1, igraph_int_t n2,
1098
        igraph_int_t m,
1099
0
        igraph_bool_t directed, igraph_neimode_t mode) {
1100
1101
0
    igraph_vector_int_t edges;
1102
0
    igraph_int_t n = n1 + n2; /* overflow checked by caller */
1103
1104
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
1105
0
    IGRAPH_CHECK(igraph_vector_int_reserve(&edges, m * 2));
1106
1107
0
    for (igraph_int_t i = 0; i < m; i++) {
1108
0
        igraph_int_t to, from;
1109
1110
0
        to = RNG_INTEGER(n1, n - 1);
1111
0
        from = RNG_INTEGER(0, n1 - 1);
1112
1113
        /* flip unconditionally for IGRAPH_IN,
1114
         * or with probability 0.5 for IGRAPH_ALL */
1115
0
        if (mode == IGRAPH_IN || (mode == IGRAPH_ALL && RNG_BOOL())) {
1116
0
            igraph_vector_int_push_back(&edges, to); /* reserved */
1117
0
            igraph_vector_int_push_back(&edges, from); /* reserved */
1118
0
        } else {
1119
0
            igraph_vector_int_push_back(&edges, from); /* reserved */
1120
0
            igraph_vector_int_push_back(&edges, to); /* reserved */
1121
0
        }
1122
1123
0
    }
1124
1125
0
    IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
1126
0
    igraph_vector_int_destroy(&edges);
1127
0
    IGRAPH_FINALLY_CLEAN(1);
1128
1129
0
    return IGRAPH_SUCCESS;
1130
0
}
1131
1132
static igraph_error_t bipartite_gnm_multi(
1133
        igraph_t *graph,
1134
        igraph_int_t n1, igraph_int_t n2,
1135
        igraph_int_t m,
1136
0
        igraph_bool_t directed, igraph_neimode_t mode) {
1137
1138
    /* See igraph_erdos_renyi_game_gnm() for how the sampling works. */
1139
1140
0
    igraph_vector_int_t edges;
1141
0
    igraph_int_t nrow, ncol;
1142
0
    igraph_int_t last;
1143
0
    igraph_int_t offset1 = 0, offset2 = n1;
1144
0
    igraph_int_t n = n1 + n2; /* overflow checked by caller */
1145
1146
    /* The larger partition is associated with columns, the smaller
1147
     * with rows. This setup helps avoid integer overflow. We swap
1148
     * n1 and n2 so that n1 is smaller. */
1149
0
    if (n1 > n2) {
1150
0
        igraph_int_t tmp = n1;
1151
0
        n1 = n2;
1152
0
        n2 = tmp;
1153
1154
0
        offset1 = n2; offset2 = 0;
1155
1156
0
        mode = IGRAPH_REVERSE_MODE(mode);
1157
0
    }
1158
1159
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 2*m);
1160
1161
0
    if (!directed || mode != IGRAPH_ALL) {
1162
0
        nrow = n1;
1163
0
        ncol = n2;
1164
0
        last = ncol-1;
1165
0
        for (igraph_int_t i=0; i < m; i++) {
1166
0
            while (true) {
1167
0
                igraph_int_t r = RNG_INTEGER(0, nrow-1);
1168
0
                igraph_int_t c = RNG_INTEGER(0, ncol-1);
1169
1170
0
                if (r >= n1) {
1171
0
                    igraph_int_t j = (r - n1) * ncol + c;
1172
0
                    if (j >= i) continue; /* rejection sampling */
1173
0
                    VECTOR(edges)[2*i]   = VECTOR(edges)[2*j];
1174
0
                    VECTOR(edges)[2*i+1] = VECTOR(edges)[2*j+1];
1175
0
                } else {
1176
0
                    if (directed && mode == IGRAPH_IN) {
1177
0
                        VECTOR(edges)[2*i]   = c + offset2;
1178
0
                        VECTOR(edges)[2*i+1] = r + offset1;
1179
0
                    } else {
1180
0
                        VECTOR(edges)[2*i]   = r + offset1;
1181
0
                        VECTOR(edges)[2*i+1] = c + offset2;
1182
0
                    }
1183
0
                }
1184
1185
0
                last += 1;
1186
0
                if (last >= ncol) {
1187
0
                    last -= ncol;
1188
0
                    nrow++;
1189
0
                }
1190
1191
0
                break;
1192
0
            }
1193
0
        }
1194
0
    } else /* directed, mutual allowed */ {
1195
0
        nrow = 2*n1;
1196
0
        ncol = n2;
1197
0
        last = ncol-1;
1198
0
        for (igraph_int_t i=0; i < m; i++) {
1199
0
            while (true) {
1200
0
                igraph_int_t r = RNG_INTEGER(0, nrow-1);
1201
0
                igraph_int_t c = RNG_INTEGER(0, ncol-1);
1202
1203
0
                if (r >= 2*n1) {
1204
0
                    igraph_int_t j = (r - 2*n1) * ncol + c;
1205
0
                    if (j >= i) continue; /* rejection sampling */
1206
0
                    VECTOR(edges)[2*i]   = VECTOR(edges)[2*j];
1207
0
                    VECTOR(edges)[2*i+1] = VECTOR(edges)[2*j+1];
1208
0
                } else {
1209
0
                    if (r < n1) {
1210
0
                        VECTOR(edges)[2*i]   = r + offset1;
1211
0
                        VECTOR(edges)[2*i+1] = c + offset2;
1212
0
                    } else {
1213
0
                        VECTOR(edges)[2*i]   = c + offset2;
1214
0
                        VECTOR(edges)[2*i+1] = r - n1 + offset1;
1215
0
                    }
1216
0
                }
1217
1218
0
                last += 1;
1219
0
                if (last >= ncol) {
1220
0
                    last -= ncol;
1221
0
                    nrow++;
1222
0
                }
1223
1224
0
                break;
1225
0
            }
1226
0
        }
1227
0
    }
1228
1229
0
    IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
1230
1231
0
    igraph_vector_int_destroy(&edges);
1232
0
    IGRAPH_FINALLY_CLEAN(1);
1233
1234
0
    return IGRAPH_SUCCESS;
1235
0
}
1236
1237
static igraph_error_t bipartite_gnm_simple(
1238
        igraph_t *graph,
1239
        igraph_int_t n1, igraph_int_t n2,
1240
        igraph_int_t m,
1241
        igraph_bool_t directed, igraph_neimode_t mode,
1242
0
        igraph_bool_t edge_labeled) {
1243
1244
0
    igraph_vector_int_t edges;
1245
0
    igraph_vector_t s;
1246
0
    igraph_real_t n1_real = (igraph_real_t) n1, n2_real = (igraph_real_t) n2; /* for floating-point operations */
1247
0
    igraph_int_t n = n1 + n2; /* overflow checked by caller */
1248
0
    igraph_real_t maxedges;
1249
0
    int iter = 0;
1250
1251
0
    if (!directed || mode != IGRAPH_ALL) {
1252
0
        maxedges = n1_real * n2_real;
1253
0
    } else {
1254
0
        maxedges = 2.0 * n1_real * n2_real;
1255
0
    }
1256
1257
0
    if (m > maxedges) {
1258
0
        IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL);
1259
0
    }
1260
1261
0
    if (maxedges == m && ! edge_labeled) {
1262
        /* TODO: Cannot use igraph_full_bipartite() when edge_labeled as we must shuffle edges. */
1263
0
        IGRAPH_CHECK(igraph_full_bipartite(graph, NULL, n1, n2, directed, mode));
1264
0
    } else {
1265
0
        igraph_int_t to, from;
1266
1267
0
        IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
1268
0
        IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
1269
0
        IGRAPH_CHECK(igraph_i_random_sample_real(&s, 0, maxedges - 1, m));
1270
0
        IGRAPH_CHECK(igraph_vector_int_reserve(&edges, m * 2));
1271
1272
0
        for (igraph_int_t i = 0; i < m; i++) {
1273
0
            if (!directed || mode != IGRAPH_ALL) {
1274
0
                to = trunc(VECTOR(s)[i] / n1_real);
1275
0
                from = VECTOR(s)[i] - to * n1_real;
1276
0
                to += n1;
1277
0
            } else {
1278
0
                igraph_real_t n1n2 = n1_real * n2_real;
1279
0
                if (VECTOR(s)[i] < n1n2) {
1280
0
                    to = trunc(VECTOR(s)[i] / n1_real);
1281
0
                    from = VECTOR(s)[i] - to * n1_real;
1282
0
                    to += n1;
1283
0
                } else {
1284
0
                    to = trunc((VECTOR(s)[i] - n1n2) / n2_real);
1285
0
                    from = VECTOR(s)[i] - n1n2 - to * n2_real;
1286
0
                    from += n1;
1287
0
                }
1288
0
            }
1289
1290
0
            if (mode != IGRAPH_IN) {
1291
0
                igraph_vector_int_push_back(&edges, from); /* reserved */
1292
0
                igraph_vector_int_push_back(&edges, to); /* reserved */
1293
0
            } else {
1294
0
                igraph_vector_int_push_back(&edges, to); /* reserved */
1295
0
                igraph_vector_int_push_back(&edges, from); /* reserved */
1296
0
            }
1297
1298
0
            IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14);
1299
0
        }
1300
1301
0
        igraph_vector_destroy(&s);
1302
0
        IGRAPH_FINALLY_CLEAN(1);
1303
1304
0
        if (edge_labeled) {
1305
0
            IGRAPH_CHECK(igraph_i_vector_int_shuffle_pairs(&edges));
1306
0
        }
1307
1308
0
        IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
1309
1310
0
        igraph_vector_int_destroy(&edges);
1311
0
        IGRAPH_FINALLY_CLEAN(1);
1312
0
    }
1313
1314
0
    return IGRAPH_SUCCESS;
1315
0
}
1316
1317
/**
1318
 * \function igraph_bipartite_game_gnm
1319
 * \brief Generate a random bipartite graph with a fixed number of edges.
1320
 *
1321
 * The <code>G(n1, n2, m)</code> model uniformly samples bipartite graphs with
1322
 * \p n1 bottom vertices and \p n2 top vertices, and precisely \p m edges.
1323
 *
1324
 * \param graph Pointer to an uninitialized igraph graph, the result
1325
 *    is stored here.
1326
 * \param types Pointer to an initialized boolean vector, or a null
1327
 *    pointer. If not a null pointer, then the vertex types are stored
1328
 *    here. Bottom vertices come first, \p n1 of them, then \p n2 top
1329
 *    vertices.
1330
 * \param n1 The number of bottom vertices.
1331
 * \param n2 The number of top vertices.
1332
 * \param m The number of edges.
1333
 * \param directed Boolean, whether to generate a directed graph. See
1334
 *     also the \p mode argument.
1335
 * \param mode Specifies how to direct the edges in directed
1336
 *     graphs. If it is \c IGRAPH_OUT, then directed edges point from
1337
 *     bottom vertices to top vertices. If it is \c IGRAPH_IN, edges
1338
 *     point from top vertices to bottom vertices. \c IGRAPH_OUT and
1339
 *     \c IGRAPH_IN do not generate mutual edges. If this argument is
1340
 *     \c IGRAPH_ALL, then each edge direction is considered
1341
 *     independently and mutual edges might be generated. This
1342
 *     argument is ignored for undirected graphs.
1343
* \param allowed_edge_types The types of edges to allow in the graph.
1344
 *        \clist
1345
 *          \cli IGRAPH_SIMPLE_SW
1346
 *          simple graph (i.e. no multi-edges allowed).
1347
 *          \cli IGRAPH_MULTI_SW
1348
 *          multi-edges are allowed
1349
 *        \endclist
1350
 * \param edge_labeled If true, the sampling is done uniformly from the set
1351
 *     of ordered edge lists. See \ref igraph_bipartite_iea_game() for more
1352
 *     information. Set this to \c false to select the classic Erdős-Rényi model.
1353
 *     The constants \c IGRAPH_EDGE_UNLABELED and \c IGRAPH_EDGE_LABELED
1354
 *     may be used instead of \c false and \c true for better readability.
1355
 * \return Error code.
1356
 *
1357
 * \sa \ref igraph_erdos_renyi_game_gnm() for the unipartite version,
1358
 * \ref igraph_bipartite_game_gnp() for the <code>G(n1, n2, p)</code>
1359
 * model.
1360
 *
1361
 * Time complexity: O(|V|+|E|), linear in the number of vertices and
1362
 * edges.
1363
 */
1364
1365
igraph_error_t igraph_bipartite_game_gnm(
1366
        igraph_t *graph,
1367
        igraph_vector_bool_t *types,
1368
        igraph_int_t n1, igraph_int_t n2, igraph_int_t m,
1369
        igraph_bool_t directed, igraph_neimode_t mode,
1370
        igraph_edge_type_sw_t allowed_edge_types,
1371
0
        igraph_bool_t edge_labeled) {
1372
1373
0
    igraph_int_t n;
1374
0
    igraph_bool_t loops, multiple;
1375
1376
0
    if (n1 < 0 || n2 < 0) {
1377
0
        IGRAPH_ERROR("Invalid number of vertices for bipartite G(n,m) model.", IGRAPH_EINVAL);
1378
0
    }
1379
0
    if (m < 0 || m > IGRAPH_ECOUNT_MAX) {
1380
0
        IGRAPH_ERROR("Invalid number of edges for bipartite G(n,m) model.", IGRAPH_EINVAL);
1381
0
    }
1382
0
    if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) {
1383
0
        IGRAPH_ERROR("Invalid mode for bipartite G(n,m) model.", IGRAPH_EINVAL);
1384
0
    }
1385
1386
    /* Bipartite graphs cannot have self-loops. We ignore them. */
1387
0
    IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple));
1388
1389
0
    IGRAPH_SAFE_ADD(n1, n2, &n); /* overflow check */
1390
1391
0
    if (types) {
1392
0
        IGRAPH_CHECK(igraph_vector_bool_resize(types, n));
1393
0
        igraph_vector_bool_null(types);
1394
0
        for (igraph_int_t i = n1; i < n; i++) {
1395
0
            VECTOR(*types)[i] = true;
1396
0
        }
1397
0
    }
1398
1399
0
    if (m == 0 || n1 == 0 || n2 == 0) {
1400
0
        if (m > 0) {
1401
0
            IGRAPH_ERROR("Too many edges requested compared to the number of vertices.", IGRAPH_EINVAL);
1402
0
        }
1403
0
        return igraph_empty(graph, n, directed);
1404
0
    } else if (multiple) {
1405
0
        if (edge_labeled) {
1406
0
            return bipartite_iea_game(graph, n1, n2, m, directed, mode);
1407
0
        } else {
1408
0
            return bipartite_gnm_multi(graph, n1, n2, m, directed, mode);
1409
0
        }
1410
0
    } else {
1411
0
        return bipartite_gnm_simple(graph, n1, n2, m, directed, mode, edge_labeled);
1412
0
    }
1413
1414
0
    return IGRAPH_SUCCESS;
1415
0
}
1416
1417
/**
1418
 * \function igraph_bipartite_iea_game
1419
 * \brief Generates a random bipartite multigraph through independent edge assignment.
1420
 *
1421
 * \experimental
1422
 *
1423
 * This model generates random multigraphs with \p n1 bottom vertices,
1424
 * \p n2 top vertices and \p m edges through independent edge assignment (IEA).
1425
 * Each of the \p m edges is assigned uniformly at random to a vertex pair,
1426
 * independently of each other.
1427
 *
1428
 * </para><para>
1429
 * This model does not sample multigraphs uniformly. Undirected graphs are
1430
 * generated with probability proportional to
1431
 *
1432
 * </para><para>
1433
 * <code>(prod_(i&lt;j) A_ij !)^(-1)</code>,
1434
 *
1435
 * </para><para>
1436
 * where \c A denotes the adjacency matrix. The corresponding  expression for
1437
 * directed graphs is
1438
 *
1439
 * </para><para>
1440
 * <code>(prod_(i,j) A_ij !)^(-1)</code>.
1441
 *
1442
 * </para><para>
1443
 * Thus the probability of all simple graphs (which only have 0s and 1s in the
1444
 * adjacency matrix) is the same, while that of non-simple ones depends on
1445
 * their edge and self-loop multiplicities.
1446
 *
1447
 * \param graph Pointer to an uninitialized igraph graph, the result
1448
 *    is stored here.
1449
 * \param types Pointer to an initialized boolean vector, or a \c NULL
1450
 *    pointer. If not \c NULL, then the vertex types are stored
1451
 *    here. Bottom vertices come first, \p n1 of them, then \p n2 top
1452
 *    vertices.
1453
 * \param n1 The number of bottom vertices.
1454
 * \param n2 The number of top vertices.
1455
 * \param m The number of edges.
1456
 * \param directed Whether to generate a directed graph. See
1457
 *     also the \p mode argument.
1458
 * \param mode Specifies how to direct the edges in directed
1459
 *     graphs. If it is \c IGRAPH_OUT, then directed edges point from
1460
 *     bottom vertices to top vertices. If it is \c IGRAPH_IN, edges
1461
 *     point from top vertices to bottom vertices. \c IGRAPH_OUT and
1462
 *     \c IGRAPH_IN do not generate mutual edges. If this argument is
1463
 *     \c IGRAPH_ALL, then each edge direction is considered
1464
 *     independently and mutual edges might be generated. This
1465
 *     argument is ignored for undirected graphs.
1466
 * \return Error code.
1467
 *
1468
 * \sa \ref igraph_iea_game() for the unipartite version;
1469
 * \ref igraph_bipartite_game_gnm() to uniformly sample bipartite graphs
1470
 * with a given number of vertices and edges.
1471
 *
1472
 * Time complexity: O(|V|+|E|), linear in the number of vertices and
1473
 * edges.
1474
 */
1475
1476
igraph_error_t igraph_bipartite_iea_game(
1477
        igraph_t *graph, igraph_vector_bool_t *types,
1478
        igraph_int_t n1, igraph_int_t n2, igraph_int_t m,
1479
0
        igraph_bool_t directed, igraph_neimode_t mode) {
1480
1481
0
    return igraph_bipartite_game_gnm(
1482
0
        graph, types, n1, n2, m, directed, mode,
1483
0
        IGRAPH_MULTI_SW, IGRAPH_EDGE_UNLABELED);
1484
0
}
1485
1486
1487
static igraph_error_t bipartite_gnp_edge_labeled(
1488
        igraph_t *graph,
1489
        igraph_int_t n1, igraph_int_t n2, igraph_real_t p,
1490
        igraph_bool_t directed, igraph_neimode_t mode,
1491
0
        igraph_bool_t multiple) {
1492
1493
0
    if (multiple) {
1494
0
        igraph_real_t maxedges;
1495
1496
0
        if (!directed || mode != IGRAPH_ALL) {
1497
0
            maxedges = (igraph_real_t) n1 * (igraph_real_t) n2;
1498
0
        } else {
1499
0
            maxedges = 2.0 * (igraph_real_t) n1 * (igraph_real_t) n2;
1500
0
        }
1501
1502
0
        igraph_real_t m;
1503
0
        do {
1504
0
            m = RNG_GEOM( 1.0 / (1.0 + maxedges * p) );
1505
0
        } while (m > (igraph_real_t) IGRAPH_INTEGER_MAX);
1506
1507
0
        return bipartite_iea_game(graph, n1, n2, m, directed, mode);
1508
0
    } else {
1509
0
        IGRAPH_ERROR("The edge-labeled bipartite G(n,p) model is not yet implemented for graphs without multi-edges.",
1510
0
                     IGRAPH_UNIMPLEMENTED);
1511
0
    }
1512
0
}
1513
1514
/* This implementation is used only with very large vertex counts, when the
1515
 * default implementation would fail due to overflow. While this version
1516
 * avoids overflow and uses less memory, it is also slower than the default
1517
 * implementation.
1518
 *
1519
 * This function expects that when multiple=true, the p parameter has already
1520
 * been transformed by p = p / (1 + p). This is currently done by the caller.
1521
 */
1522
static igraph_error_t gnp_bipartite_large(
1523
        igraph_t *graph,
1524
        igraph_int_t n1, igraph_int_t n2,
1525
        igraph_real_t p,
1526
        igraph_bool_t directed, igraph_neimode_t mode,
1527
        igraph_bool_t multiple,
1528
0
        igraph_int_t ecount_estimate) {
1529
1530
0
    igraph_vector_int_t edges;
1531
0
    int iter = 0;
1532
1533
    /* Necessitated by floating point arithmetic used in the implementation. */
1534
0
    if (n1 >= IGRAPH_MAX_EXACT_REAL || n2 >= IGRAPH_MAX_EXACT_REAL) {
1535
0
        IGRAPH_ERROR("Number of vertices is too large.", IGRAPH_EOVERFLOW);
1536
0
    }
1537
1538
0
    if (ecount_estimate > IGRAPH_ECOUNT_MAX) {
1539
0
        ecount_estimate = IGRAPH_ECOUNT_MAX;
1540
0
    }
1541
1542
0
    IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
1543
0
    IGRAPH_CHECK(igraph_vector_int_reserve(&edges, 2*ecount_estimate));
1544
1545
0
    for (igraph_int_t i = 0; i < n1; i++) {
1546
0
        igraph_int_t j = 0;
1547
1548
0
        while (true) {
1549
0
            igraph_real_t gap = RNG_GEOM(p);
1550
1551
0
            if (gap >= n2 - j) {
1552
0
                break;
1553
0
            }
1554
1555
0
            j += gap;
1556
1557
0
            if (!directed) {
1558
                /* Undirected graph */
1559
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i));
1560
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, j + n1));
1561
0
            } else if (mode == IGRAPH_IN) {
1562
                /* Incoming edges */
1563
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, j + n1));
1564
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i));
1565
0
            } else if (mode == IGRAPH_OUT) {
1566
                /* Outgoing edges */
1567
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i));
1568
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, j + n1));
1569
0
            } else {
1570
                /* Both directions for IGRAPH_ALL */
1571
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i));
1572
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, j + n1));
1573
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, j + n1));
1574
0
                IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i));
1575
0
            }
1576
1577
0
            j += ! multiple; /* 1 for simple graph, 0 for multigraph */
1578
1579
0
            IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14);
1580
0
        }
1581
0
    }
1582
1583
    /* n1 + n2 has already been checked for overflow in the caller function. */
1584
0
    IGRAPH_CHECK(igraph_create(graph, &edges, n1 + n2, directed));
1585
1586
0
    igraph_vector_int_destroy(&edges);
1587
0
    IGRAPH_FINALLY_CLEAN(1);
1588
1589
0
    return IGRAPH_SUCCESS;
1590
0
}
1591
1592
/**
1593
 * \function igraph_bipartite_game_gnp
1594
 * \brief Generates a random bipartite graph with a fixed connection probability.
1595
 *
1596
 * In the <code>G(n1, n2, p)</code> model, every possible edge between the \p n1
1597
 * bottom vertices and \p n2 top vertices is realized independently with
1598
 * probability \p p. This is equivalent to a maximum entropy model with
1599
 * a constraint on the \em expected total edge count. This view allows
1600
 * a multigraph extension, in which case \p is interpreted as the expected
1601
 * number of edges between any vertex pair. See \ref igraph_erdos_renyi_game_gnp()
1602
 * for more details.
1603
 *
1604
 * \param graph Pointer to an uninitialized igraph graph, the result
1605
 *    is stored here.
1606
 * \param types Pointer to an initialized boolean vector, or a null
1607
 *    pointer. If not \c NULL, then the vertex types are stored
1608
 *    here. Bottom vertices come first, \p n1 of them, then \p n2 top
1609
 *    vertices.
1610
 * \param n1 The number of bottom vertices.
1611
 * \param n2 The number of top vertices.
1612
 * \param p The expected number of edges between any vertex pair.
1613
 *    When multi-edges are disallowed, this is equivalent to the probability
1614
 *    of having a connection between any two vertices.
1615
 * \param directed Whether to generate a directed graph. See also
1616
 *     the \p mode argument.
1617
 * \param mode Specifies how to direct the edges in directed
1618
 *     graphs. If it is \c IGRAPH_OUT, then directed edges point from
1619
 *     bottom vertices to top vertices. If it is \c IGRAPH_IN, edges
1620
 *     point from top vertices to bottom vertices. \c IGRAPH_OUT and
1621
 *     \c IGRAPH_IN do not generate mutual edges. If this argument is
1622
 *     \c IGRAPH_ALL, then each edge direction is considered
1623
 *     independently and mutual edges might be generated. This
1624
 *     argument is ignored for undirected graphs.
1625
* \param allowed_edge_types The types of edges to allow in the graph.
1626
 *        \clist
1627
 *          \cli IGRAPH_SIMPLE_SW
1628
 *          simple graph (i.e. no multi-edges allowed).
1629
 *          \cli IGRAPH_MULTI_SW
1630
 *          multi-edges are allowed
1631
 *        \endclist
1632
 * \param edge_labeled If true, the model is defined over the set of ordered
1633
 *     edge lists, i.e. over the set of edge-labeled graphs. Set it to
1634
 *     \c false to select the classic bipartite Erdős-Rényi model.
1635
 *     The constants \c IGRAPH_EDGE_UNLABELED and \c IGRAPH_EDGE_LABELED
1636
 *     may be used instead of \c false and \c true for better readability.
1637
 * \return Error code.
1638
 *
1639
 * \sa \ref igraph_erdos_renyi_game_gnp() for the unipartite version,
1640
 * \ref igraph_bipartite_game_gnm() for the <code>G(n1, n2, m)</code> model.
1641
 *
1642
 * Time complexity: O(|V|+|E|), linear in the number of vertices and
1643
 * edges.
1644
 */
1645
1646
igraph_error_t igraph_bipartite_game_gnp(
1647
        igraph_t *graph,
1648
        igraph_vector_bool_t *types,
1649
        igraph_int_t n1, igraph_int_t n2, igraph_real_t p,
1650
        igraph_bool_t directed, igraph_neimode_t mode,
1651
        igraph_edge_type_sw_t allowed_edge_types,
1652
0
        igraph_bool_t edge_labeled) {
1653
1654
0
    igraph_vector_int_t edges;
1655
0
    igraph_vector_t s;
1656
0
    igraph_int_t n;
1657
0
    igraph_real_t n1_real = (igraph_real_t) n1, n2_real = (igraph_real_t) n2; /* for floating-point operations */
1658
0
    igraph_bool_t loops, multiple;
1659
0
    int iter = 0;
1660
1661
0
    if (n1 < 0 || n2 < 0) {
1662
0
        IGRAPH_ERROR("Invalid number of vertices for bipartite G(n,p) model.", IGRAPH_EINVAL);
1663
0
    }
1664
1665
    /* Bipartite graphs cannot have self-loops. We ignore them. */
1666
0
    IGRAPH_CHECK(igraph_i_edge_type_to_loops_multiple(allowed_edge_types, &loops, &multiple));
1667
1668
0
    if (multiple) {
1669
0
        if (p < 0.0) {
1670
0
            IGRAPH_ERROR(
1671
0
                "Invalid expected edge multiplicity given for "
1672
0
                "bipartite G(n,p) multigraph model.",
1673
0
                IGRAPH_EINVAL);
1674
0
        }
1675
0
    } else {
1676
0
        if (p < 0.0 || p > 1.0) {
1677
0
            IGRAPH_ERROR(
1678
0
                "Invalid connection probability given for bipartite G(n,p) model.",
1679
0
                IGRAPH_EINVAL);
1680
0
        }
1681
0
    }
1682
1683
0
    if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) {
1684
0
        IGRAPH_ERROR("Invalid mode for bipartite G(n,p) model.", IGRAPH_EINVAL);
1685
0
    }
1686
1687
0
    IGRAPH_SAFE_ADD(n1, n2, &n);
1688
1689
0
    if (types) {
1690
0
        IGRAPH_CHECK(igraph_vector_bool_resize(types, n));
1691
0
        igraph_vector_bool_null(types);
1692
0
        for (igraph_int_t i = n1; i < n; i++) {
1693
0
            VECTOR(*types)[i] = true;
1694
0
        }
1695
0
    }
1696
1697
0
    if (edge_labeled) {
1698
0
        return bipartite_gnp_edge_labeled(graph, n1, n2, p, directed, mode, multiple);
1699
0
    }
1700
1701
0
    if (multiple) {
1702
        /* Convert the expected edge count to the appropriate probability parameter
1703
         * of the geometric distribution when sampling lengths of runs of 0s in the
1704
         * adjacency matrix. */
1705
0
        p = p / (1 + p);
1706
0
    }
1707
1708
0
    if (p == 0 || n1 == 0 || n2 == 0) {
1709
0
        IGRAPH_CHECK(igraph_empty(graph, n, directed));
1710
0
    } else if (p == 1.0) {
1711
0
        IGRAPH_CHECK(igraph_full_bipartite(graph, types, n1, n2, directed, mode));
1712
0
    } else {
1713
1714
0
        igraph_int_t to, from, slen;
1715
0
        igraph_real_t maxedges, last;
1716
0
        igraph_int_t ecount_estimate;
1717
1718
0
        if (!directed || mode != IGRAPH_ALL) {
1719
0
            maxedges = n1_real * n2_real;
1720
0
        } else {
1721
0
            maxedges = 2.0 * n1_real * n2_real;
1722
0
        }
1723
1724
0
        IGRAPH_CHECK(igraph_i_safe_floor(maxedges * p * 1.1, &ecount_estimate));
1725
1726
0
        if (maxedges > IGRAPH_MAX_EXACT_REAL) {
1727
            /* Use a slightly slower, but overflow-free implementation. */
1728
0
            return gnp_bipartite_large(graph, n1, n2, p, directed, mode, multiple, ecount_estimate);
1729
0
        }
1730
1731
0
        IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0);
1732
0
        IGRAPH_VECTOR_INIT_FINALLY(&s, 0);
1733
0
        IGRAPH_CHECK(igraph_vector_reserve(&s, ecount_estimate));
1734
1735
0
        last = RNG_GEOM(p);
1736
0
        while (last < maxedges) {
1737
0
            IGRAPH_CHECK(igraph_vector_push_back(&s, last));
1738
0
            last += RNG_GEOM(p);
1739
0
            last += ! multiple; /* 1 for simple graph, 0 for multigraph */
1740
0
            IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14);
1741
0
        }
1742
1743
0
        slen = igraph_vector_size(&s);
1744
0
        IGRAPH_CHECK(igraph_vector_int_reserve(&edges, slen * 2));
1745
1746
0
        for (igraph_int_t i = 0; i < slen; i++) {
1747
0
            if (!directed || mode != IGRAPH_ALL) {
1748
0
                to = trunc(VECTOR(s)[i] / n1_real);
1749
0
                from = VECTOR(s)[i] - to * n1_real;
1750
0
                to += n1;
1751
0
            } else {
1752
0
                igraph_real_t n1n2 = n1_real * n2_real;
1753
0
                if (VECTOR(s)[i] < n1n2) {
1754
0
                    to = trunc(VECTOR(s)[i] / n1_real);
1755
0
                    from = VECTOR(s)[i] - to * n1_real;
1756
0
                    to += n1;
1757
0
                } else {
1758
0
                    to = trunc((VECTOR(s)[i] - n1n2) / n2_real);
1759
0
                    from = VECTOR(s)[i] - n1n2 - to * n2_real;
1760
0
                    from += n1;
1761
0
                }
1762
0
            }
1763
1764
0
            if (mode != IGRAPH_IN) {
1765
0
                igraph_vector_int_push_back(&edges, from); /* reserved */
1766
0
                igraph_vector_int_push_back(&edges, to); /* reserved */
1767
0
            } else {
1768
0
                igraph_vector_int_push_back(&edges, to); /* reserved */
1769
0
                igraph_vector_int_push_back(&edges, from); /* reserved */
1770
0
            }
1771
1772
0
            IGRAPH_ALLOW_INTERRUPTION_LIMITED(iter, 1 << 14);
1773
0
        }
1774
1775
0
        igraph_vector_destroy(&s);
1776
0
        IGRAPH_FINALLY_CLEAN(1);
1777
1778
0
        IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
1779
0
        igraph_vector_int_destroy(&edges);
1780
0
        IGRAPH_FINALLY_CLEAN(1);
1781
0
    }
1782
1783
0
    return IGRAPH_SUCCESS;
1784
0
}