graph_sbm.hh 3.42 KB
Newer Older
1
2
// graph-tool -- a general graph modification and manipulation thingy
//
Tiago Peixoto's avatar
Tiago Peixoto committed
3
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
4
//
5
6
7
8
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option) any
// later version.
9
//
10
11
12
13
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
14
//
15
// You should have received a copy of the GNU Lesser General Public License
16
17
18
19
20
21
22
23
24
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#ifndef GRAPH_SBM_HH
#define GRAPH_SBM_HH

#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_util.hh"
#include "sampler.hh"
25
#include "urn_sampler.hh"
26
27
28
29
30
31
32
33
34
35

#include "random.hh"

#include "hash_map_wrap.hh"

namespace graph_tool
{
using namespace std;
using namespace boost;

36
37
template <bool micro_deg, class Graph, class VProp, class IVec, class FVec,
          class VDProp, class RNG>
38
void gen_sbm(Graph& g, VProp b, IVec& rs, IVec& ss, FVec probs, VDProp in_deg,
39
             VDProp out_deg, bool micro_ers, RNG& rng)
40
{
41
    typedef typename std::conditional_t<micro_deg,size_t,double> dtype;
42
    vector<vector<size_t>> rvs;
43
    vector<vector<dtype>> v_in_probs, v_out_probs;
44
45
46
    for (auto v : vertices_range(g))
    {
        size_t r = b[v];
47
        if (r >= v_out_probs.size())
48
        {
49
            if (graph_tool::is_directed(g))
50
                v_in_probs.resize(r+1);
51
52
53
54
            v_out_probs.resize(r+1);
            rvs.resize(r+1);
        }
        rvs[r].push_back(v);
55
        if (graph_tool::is_directed(g))
56
            v_in_probs[r].push_back(in_deg[v]);
57
58
59
        v_out_probs[r].push_back(out_deg[v]);
    }

Tiago Peixoto's avatar
Tiago Peixoto committed
60
61
62
    typedef std::conditional_t<micro_deg,
                               UrnSampler<size_t, false>,
                               Sampler<size_t>> vsampler_t;
63
    vector<vsampler_t> v_in_sampler_, v_out_sampler;
64
65
    for (size_t r = 0; r < rvs.size(); ++r)
    {
66
        if (graph_tool::is_directed(g))
67
            v_in_sampler_.emplace_back(rvs[r], v_in_probs[r]);
68
69
70
        v_out_sampler.emplace_back(rvs[r], v_out_probs[r]);
    }

71
    auto& v_in_sampler = (graph_tool::is_directed(g)) ? v_in_sampler_ : v_out_sampler;
72

73
74
75
76
    for (size_t i = 0; i < rs.shape()[0]; ++i)
    {
        size_t r = rs[i];
        size_t s = ss[i];
77
        auto p = probs[i];
78

79
80
81
        if (p == 0)
            continue;

82
        if (!graph_tool::is_directed(g) && r == s)
83
            p /= 2;
84

85
86
87
        auto& r_sampler = v_out_sampler[r];
        auto& s_sampler = v_in_sampler[s];

88
        size_t mrs;
89
90
        if (micro_ers)
        {
91
            mrs = p;
92
93
94
95
        }
        else
        {
            std::poisson_distribution<> poi(p);
96
            mrs = poi(rng);
97
98
        }

99
100
101
102
103
        size_t ers = (&r_sampler != &s_sampler) ? mrs : 2 * mrs;
        if (!r_sampler.has_n(ers) || !s_sampler.has_n(ers))
            throw GraphException("Inconsistent SBM parameters: node degrees do not agree with matrix of edge counts between groups");

        for (size_t j = 0; j < mrs; ++j)
104
        {
105
106
            size_t u = r_sampler.sample(rng);
            size_t v = s_sampler.sample(rng);
107
108
109
110
111
112
113
114
115
            add_edge(u, v, g);
        }
    }
}


} // graph_tool namespace

#endif // GRAPH_SBM_HH