Commit f7a38bba authored by Tiago Peixoto's avatar Tiago Peixoto

Implement latent triadic closure

parent 31428695
......@@ -31,6 +31,7 @@ libgraph_tool_generation_la_SOURCES = \
graph_price.cc \
graph_rewiring.cc \
graph_sbm.cc \
graph_triadic_closure.cc \
graph_triangulation.cc \
graph_union.cc \
graph_union_eprop.cc \
......@@ -50,6 +51,7 @@ libgraph_tool_generation_la_include_HEADERS = \
graph_price.hh \
graph_rewiring.hh \
graph_sbm.hh \
graph_triadic_closure.hh \
graph_triangulation.hh \
graph_union.hh \
sampler.hh \
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
//
// 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.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GRAPH_SBM_HH
#define GRAPH_SBM_HH
#include <tuple>
#include <iostream>
#include <boost/functional/hash.hpp>
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_util.hh"
#include "sampler.hh"
#include "urn_sampler.hh"
#include "random.hh"
#include "hash_map_wrap.hh"
namespace graph_tool
{
using namespace std;
using namespace boost;
template <bool micro_deg, class Graph, class VProp, class IVec, class FVec,
class VDProp, class RNG>
void gen_sbm(Graph& g, VProp b, IVec& rs, IVec& ss, FVec probs, VDProp in_deg,
VDProp out_deg, bool micro_ers, RNG& rng)
{
typedef typename std::conditional_t<micro_deg,size_t,double> dtype;
vector<vector<size_t>> rvs;
vector<vector<dtype>> v_in_probs, v_out_probs;
for (auto v : vertices_range(g))
{
size_t r = b[v];
if (r >= v_out_probs.size())
{
if (graph_tool::is_directed(g))
v_in_probs.resize(r+1);
v_out_probs.resize(r+1);
rvs.resize(r+1);
}
rvs[r].push_back(v);
if (graph_tool::is_directed(g))
v_in_probs[r].push_back(in_deg[v]);
v_out_probs[r].push_back(out_deg[v]);
}
typedef std::conditional_t<micro_deg,
UrnSampler<size_t, false>,
Sampler<size_t>> vsampler_t;
vector<vsampler_t> v_in_sampler_, v_out_sampler;
for (size_t r = 0; r < rvs.size(); ++r)
{
if (graph_tool::is_directed(g))
v_in_sampler_.emplace_back(rvs[r], v_in_probs[r]);
v_out_sampler.emplace_back(rvs[r], v_out_probs[r]);
}
auto& v_in_sampler = (graph_tool::is_directed(g)) ? v_in_sampler_ : v_out_sampler;
for (size_t i = 0; i < rs.shape()[0]; ++i)
{
size_t r = rs[i];
size_t s = ss[i];
auto p = probs[i];
if (p == 0)
continue;
if (!graph_tool::is_directed(g) && r == s)
p /= 2;
auto& r_sampler = v_out_sampler[r];
auto& s_sampler = v_in_sampler[s];
size_t mrs;
if (micro_ers)
{
mrs = p;
}
else
{
std::poisson_distribution<> poi(p);
mrs = poi(rng);
}
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)
{
size_t u = r_sampler.sample(rng);
size_t v = s_sampler.sample(rng);
add_edge(u, v, g);
}
}
}
} // graph_tool namespace
#endif // GRAPH_SBM_HH
......@@ -86,6 +86,10 @@ void generate_knn(GraphInterface& gi, boost::python::object om, size_t k,
void generate_knn_exact(GraphInterface& gi, boost::python::object om, size_t k,
boost::any aw);
void generate_triadic_closure(GraphInterface& gi, boost::any acurr,
boost::any aego, boost::any oEs, bool probs,
rng_t& rng);
size_t random_rewire(GraphInterface& gi, string strat, size_t niter,
bool no_sweep, bool self_loops, bool parallel_edges,
bool configuration, bool traditional, bool micro,
......@@ -144,6 +148,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_generation)
def("gen_sbm", &generate_sbm);
def("gen_knn", &generate_knn);
def("gen_knn_exact", &generate_knn_exact);
def("gen_triadic_closure", &generate_triadic_closure);
def("random_rewire", &random_rewire);
def("predecessor_graph", &predecessor_graph);
def("line_graph", &line_graph);
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
//
// 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.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph_triadic_closure.hh"
#include "numpy_bind.hh"
using namespace std;
using namespace boost;
using namespace graph_tool;
void generate_triadic_closure(GraphInterface& gi,
boost::any acurr,
boost::any aego,
boost::any aEs,
bool probs, rng_t& rng)
{
typedef eprop_map_t<uint8_t>::type emap_t;
auto curr = any_cast<emap_t>(acurr).get_unchecked();
typedef eprop_map_t<int64_t>::type eemap_t;
auto ego = any_cast<eemap_t>(aego);
run_action<>()(gi,
[&](auto& g, auto Es) { gen_triadic_closure(g, curr, ego, Es,
probs, rng); },
vertex_scalar_properties())(aEs);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
//
// 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.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GRAPH_TRIADIC_CLOSURE_HH
#define GRAPH_TRIADIC_CLOSURE_HH
#include <tuple>
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_util.hh"
#include "hash_map_wrap.hh"
#include "sampler.hh"
namespace graph_tool
{
using namespace std;
using namespace boost;
template <class Graph, class EMap, class ETMap, class EV, class RNG>
void gen_triadic_closure(Graph& g, EMap curr, ETMap ego, EV& Es, bool probs,
RNG& rng)
{
std::vector<uint8_t> mark(num_vertices(g));
std::vector<std::vector<std::tuple<size_t, size_t>>> edges(num_vertices(g));
#pragma omp parallel if (num_vertices(g) > OPENMP_MIN_THRESH) \
firstprivate(mark)
parallel_vertex_loop_no_spawn
(g,
[&](auto v)
{
if (Es[v] == 0)
return;
for (auto e1 : out_edges_range(v, g))
{
auto w = target(e1, g);
if (w == v)
continue;
for (auto e2 : out_edges_range(w, g))
mark[target(e2, g)] = 1;
for (auto e2 : out_edges_range(v, g))
{
if (!curr[e1] && !curr[e2])
continue;
auto u = target(e2, g);
if (u >= w || mark[u] > 0)
continue;
edges[v].emplace_back(u, w);
}
for (auto e2 : out_edges_range(w, g))
mark[target(e2, g)] = 0;
}
});
for (auto v : vertices_range(g))
{
auto x = Es[v];
if (x == 0)
continue;
size_t E;
if (probs)
{
std::binomial_distribution<size_t> sample(edges[v].size(), x);
E = sample(rng);
}
else
{
E = x;
}
for (const auto& e : random_permutation_range(edges[v], rng))
{
if (E == 0)
break;
auto ne = add_edge(get<0>(e), get<1>(e), g);
ego[ne.first] = v;
E--;
}
}
}
} // graph_tool namespace
#endif // GRAPH_TRIADIC_CLOSURE_HH
......@@ -84,6 +84,8 @@ libgraph_tool_inference_la_SOURCES = \
uncertain/graph_blockmodel_dynamics_pseudo_ising.cc \
uncertain/graph_blockmodel_dynamics_pseudo_ising_mcmc.cc \
uncertain/graph_blockmodel_dynamics_pseudo_ising_mcmc_h.cc \
uncertain/graph_blockmodel_latent_closure.cc \
uncertain/graph_blockmodel_latent_closure_mcmc.cc \
uncertain/graph_blockmodel_measured.cc \
uncertain/graph_blockmodel_measured_mcmc.cc \
uncertain/graph_blockmodel_uncertain.cc \
......@@ -131,6 +133,8 @@ nobase_libgraph_tool_inference_la_include_HEADERS = \
uncertain/graph_blockmodel_dynamics_epidemics_mcmc_h.hh \
uncertain/graph_blockmodel_dynamics_mcmc.hh \
uncertain/graph_blockmodel_dynamics_pseudo_ising_mcmc_h.hh \
uncertain/graph_blockmodel_latent_closure.hh \
uncertain/graph_blockmodel_latent_layers.hh \
uncertain/graph_blockmodel_measured.hh \
uncertain/graph_blockmodel_uncertain.hh \
uncertain/graph_blockmodel_uncertain_marginal.hh \
......
......@@ -126,6 +126,8 @@ class EntrySet
public:
typedef typename graph_traits<BGraph>::edge_descriptor bedge_t;
EntrySet() {};
EntrySet(size_t B)
: _dummy(_null)
{
......
......@@ -140,6 +140,8 @@ extern void export_pp_multiflip_mcmc();
extern void export_modularity_state();
extern void export_modularity_mcmc();
extern void export_modularity_multiflip_mcmc();
extern void export_latent_closure_state();
extern void export_latent_closure_mcmc();
BOOST_PYTHON_MODULE(libgraph_tool_inference)
{
......@@ -216,6 +218,8 @@ BOOST_PYTHON_MODULE(libgraph_tool_inference)
export_modularity_state();
export_modularity_mcmc();
export_modularity_multiflip_mcmc();
export_latent_closure_state();
export_latent_closure_mcmc();
def("vector_map", vector_map<int32_t>);
def("vector_map64", vector_map<int64_t>);
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
//
// 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.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BOOST_PYTHON_MAX_ARITY 40
#include <boost/python.hpp>
#include "graph_tool.hh"
#include "random.hh"
#include "../blockmodel/graph_blockmodel.hh"
#define BASE_STATE_params BLOCK_STATE_params
#include "graph_blockmodel_latent_closure.hh"
#include "graph_blockmodel_latent_layers.hh"
#include "../support/graph_state.hh"
using namespace boost;
using namespace graph_tool;
GEN_DISPATCH(block_state, BlockState, BLOCK_STATE_params)
template <class BaseState>
GEN_DISPATCH(latent_layers_state, LatentLayers<BaseState>::template LatentLayersState,
LATENT_LAYERS_STATE_params)
template <class BaseState>
GEN_DISPATCH(latent_closure_state, LatentClosure<BaseState>::template LatentClosureState,
LATENT_CLOSURE_STATE_params)
python::object make_latent_closure_state(boost::python::object oeblock_state,
boost::python::object opblock_state,
boost::python::object olatent_layers_state,
size_t L)
{
python::list state;
auto dispatch = [&](auto& eblock_state)
{
typedef typename std::remove_reference<decltype(eblock_state)>::type
state_t;
state_t& pblock_state = python::extract<state_t&>(opblock_state);
for (size_t l = 0; l < L; ++l)
{
latent_closure_state<state_t>::make_dispatch
(olatent_layers_state,
[&](auto& s)
{
state.append(python::object(s));
},
eblock_state, pblock_state, l);
}
latent_closure_state<state_t>::dispatch
([&](auto* cs)
{
typedef typename std::remove_reference<decltype(*cs)>::type c_state_t;
std::vector<c_state_t*> cstates;
for (size_t l = 0; l < L; ++l)
cstates.push_back(&python::extract<c_state_t&>(state[l])());
for (size_t l = 0; l < L; ++l)
cstates[l]->set_cstates(cstates);
std::vector<std::reference_wrapper<c_state_t>> layers;
for (size_t l = 0; l < L; ++l)
layers.push_back(*cstates[l]);
latent_layers_state<c_state_t>::make_dispatch
(olatent_layers_state,
[&](auto& s)
{
state.append(python::object(s));
},
layers);
});
};
block_state::dispatch(oeblock_state, dispatch);
return state;
}
void export_latent_closure_state()
{
using namespace boost::python;
def("make_latent_closure_state", &make_latent_closure_state);
block_state::dispatch
([&](auto* bs)
{
typedef typename std::remove_reference<decltype(*bs)>::type block_state_t;
latent_closure_state<block_state_t>::dispatch
([&](auto* cs)
{
typedef typename std::remove_reference<decltype(*cs)>::type c_state_t;
class_<c_state_t>
c(name_demangle(typeid(c_state_t).name()).c_str(),
no_init);
c.def("entropy", &c_state_t::entropy);
latent_layers_state<c_state_t>::dispatch
([&](auto* s)
{
typedef typename std::remove_reference<decltype(*s)>::type state_t;
class_<state_t>
c(name_demangle(typeid(state_t).name()).c_str(),
no_init);
c.def("remove_edge", &state_t::remove_edge)
.def("add_edge", &state_t::add_edge)
.def("remove_edge_dS", &state_t::remove_edge_dS)
.def("add_edge_dS", &state_t::add_edge_dS)
.def("entropy", &state_t::entropy)
.def("set_hparams", &state_t::set_hparams)
.def("get_N", &state_t::get_N)
.def("get_X", &state_t::get_X)
.def("get_T", &state_t::get_T)
.def("get_M", &state_t::get_M);
});
});
});
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
//
// 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.
//
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph_tool.hh"
#include "random.hh"
#include <boost/python.hpp>
#include "../blockmodel/graph_blockmodel.hh"
#define BASE_STATE_params BLOCK_STATE_params
#include "graph_blockmodel_latent_layers.hh"
#include "graph_blockmodel_latent_layers_mcmc.hh"
#include "graph_blockmodel_latent_closure.hh"
#include "../support/graph_state.hh"
#include "../loops/mcmc_loop.hh"
using namespace boost;
using namespace graph_tool;
GEN_DISPATCH(block_state, BlockState, BLOCK_STATE_params)
template <class BaseState>
GEN_DISPATCH(latent_layers_state, LatentLayers<BaseState>::template LatentLayersState,
LATENT_LAYERS_STATE_params)
template <class BaseState>
GEN_DISPATCH(latent_closure_state, LatentClosure<BaseState>::template LatentClosureState,
LATENT_CLOSURE_STATE_params)
template <class State>
GEN_DISPATCH(mcmc_latent_layers_state, MCMC<State>::template MCMCLatentLayersState,
MCMC_LATENT_LAYERS_STATE_params(State))
python::object mcmc_latent_closure_sweep(python::object omcmc_state,
python::object olatent_layers_state,
rng_t& rng)
{
python::object ret;
auto dispatch = [&](auto* block_state)
{
typedef typename std::remove_pointer<decltype(block_state)>::type
block_state_t;
latent_closure_state<block_state_t>::dispatch
([&](auto* cs)
{
typedef typename std::remove_reference<decltype(*cs)>::type c_state_t;
latent_layers_state<c_state_t>::dispatch
(olatent_layers_state,
[&](auto& ls)
{
typedef typename std::remove_reference<decltype(ls)>::type
latent_layers_state_t;
mcmc_latent_layers_state<latent_layers_state_t>::make_dispatch
(omcmc_state,
[&](auto& s)
{
auto ret_ = mcmc_sweep(s, rng);
ret = tuple_apply([&](auto&... args){ return python::make_tuple(args...); }, ret_);
});
},
false);
});
};
block_state::dispatch(dispatch);
return ret;
}
void export_latent_closure_mcmc()
{
using namespace boost::python;
def("mcmc_latent_closure_sweep", &mcmc_latent_closure_sweep);
}
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2020 Tiago de Paula Peixoto <tiago@skewed.de>
//
// 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.
//