Commit bc4b3707 authored by Tiago Peixoto's avatar Tiago Peixoto

Implement fully random moves in blockmodel.py

parent 3af0783d
...@@ -370,13 +370,14 @@ struct move_sweep_dispatch ...@@ -370,13 +370,14 @@ struct move_sweep_dispatch
move_sweep_dispatch(Eprop eweight, Vprop vweight, boost::any egroups, move_sweep_dispatch(Eprop eweight, Vprop vweight, boost::any egroups,
VEprop esrcpos, VEprop etgtpos, Vprop label, size_t L, VEprop esrcpos, VEprop etgtpos, Vprop label, size_t L,
vector<int>& vlist, bool deg_corr, double beta, vector<int>& vlist, bool deg_corr, double beta,
bool sequential, bool verbose, size_t max_edge_index, bool sequential, bool random_move, bool verbose,
rng_t& rng, double& S, size_t& nmoves, size_t max_edge_index, rng_t& rng, double& S,
GraphInterface& bgi) size_t& nmoves, GraphInterface& bgi)
: eweight(eweight), vweight(vweight), oegroups(egroups), esrcpos(esrcpos), : eweight(eweight), vweight(vweight), oegroups(egroups), esrcpos(esrcpos),
etgtpos(etgtpos), label(label), L(L), vlist(vlist), etgtpos(etgtpos), label(label), L(L), vlist(vlist),
deg_corr(deg_corr), beta(beta), sequential(sequential), verbose(verbose), deg_corr(deg_corr), beta(beta), sequential(sequential),
random_move(random_move), verbose(verbose),
max_edge_index(max_edge_index), rng(rng), S(S), nmoves(nmoves), bgi(bgi) max_edge_index(max_edge_index), rng(rng), S(S), nmoves(nmoves), bgi(bgi)
{} {}
...@@ -392,6 +393,7 @@ struct move_sweep_dispatch ...@@ -392,6 +393,7 @@ struct move_sweep_dispatch
bool deg_corr; bool deg_corr;
double beta; double beta;
bool sequential; bool sequential;
bool random_move;
bool verbose; bool verbose;
size_t max_edge_index; size_t max_edge_index;
rng_t& rng; rng_t& rng;
...@@ -441,7 +443,8 @@ struct move_sweep_dispatch ...@@ -441,7 +443,8 @@ struct move_sweep_dispatch
egroups.get_unchecked(num_vertices(bg)), egroups.get_unchecked(num_vertices(bg)),
esrcpos.get_unchecked(max_edge_index + 1), esrcpos.get_unchecked(max_edge_index + 1),
etgtpos.get_unchecked(max_edge_index + 1), etgtpos.get_unchecked(max_edge_index + 1),
g, bg, emat, sequential, verbose, rng, S, nmoves); g, bg, emat, sequential, random_move, verbose,
rng, S, nmoves);
} }
}; };
...@@ -454,8 +457,8 @@ python::object do_move_sweep(GraphInterface& gi, GraphInterface& bgi, ...@@ -454,8 +457,8 @@ python::object do_move_sweep(GraphInterface& gi, GraphInterface& bgi,
bool deg_corr, boost::any oeweight, bool deg_corr, boost::any oeweight,
boost::any ovweight, boost::any oegroups, boost::any ovweight, boost::any oegroups,
boost::any oesrcpos, boost::any oetgtpos, boost::any oesrcpos, boost::any oetgtpos,
double beta, bool sequential, bool verbose, double beta, bool sequential, bool random_move,
rng_t& rng) bool verbose, rng_t& rng)
{ {
typedef property_map_type::apply<int32_t, typedef property_map_type::apply<int32_t,
GraphInterface::vertex_index_map_t>::type GraphInterface::vertex_index_map_t>::type
...@@ -484,8 +487,8 @@ python::object do_move_sweep(GraphInterface& gi, GraphInterface& bgi, ...@@ -484,8 +487,8 @@ python::object do_move_sweep(GraphInterface& gi, GraphInterface& bgi,
(gi, boost::bind<void>(move_sweep_dispatch<emap_t, vmap_t, vemap_t> (gi, boost::bind<void>(move_sweep_dispatch<emap_t, vmap_t, vemap_t>
(eweight, vweight, oegroups, esrcpos, etgtpos, (eweight, vweight, oegroups, esrcpos, etgtpos,
label, L, vlist, deg_corr, beta, label, L, vlist, deg_corr, beta,
sequential, verbose, gi.GetMaxEdgeIndex(), sequential, random_move, verbose,
rng, S, nmoves, bgi), gi.GetMaxEdgeIndex(), rng, S, nmoves, bgi),
mrs, mrp, mrm, wr, b, _1, ref(emat)))(); mrs, mrp, mrm, wr, b, _1, ref(emat)))();
return python::make_tuple(S, nmoves); return python::make_tuple(S, nmoves);
} }
......
...@@ -799,8 +799,8 @@ void move_sweep(Eprop mrs, Vprop mrp, Vprop mrm, Vprop wr, Vprop b, Vprop label, ...@@ -799,8 +799,8 @@ void move_sweep(Eprop mrs, Vprop mrp, Vprop mrm, Vprop wr, Vprop b, Vprop label,
size_t L, vector<int>& vlist, bool deg_corr, double beta, size_t L, vector<int>& vlist, bool deg_corr, double beta,
Eprop eweight, Vprop vweight, EVprop egroups, VEprop esrcpos, Eprop eweight, Vprop vweight, EVprop egroups, VEprop esrcpos,
VEprop etgtpos, Graph& g, BGraph& bg, EMat& emat, VEprop etgtpos, Graph& g, BGraph& bg, EMat& emat,
bool sequential, bool verbose, RNG& rng, double& S, bool sequential, bool random_move, bool verbose, RNG& rng,
size_t& nmoves) double& S, size_t& nmoves)
{ {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t; typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
nmoves = 0; nmoves = 0;
...@@ -841,7 +841,7 @@ void move_sweep(Eprop mrs, Vprop mrp, Vprop mrm, Vprop wr, Vprop b, Vprop label, ...@@ -841,7 +841,7 @@ void move_sweep(Eprop mrs, Vprop mrp, Vprop mrm, Vprop wr, Vprop b, Vprop label,
else else
p_rand = B / double(mrp[t] + B); p_rand = B / double(mrp[t] + B);
if (rand_real() >= p_rand) if (rand_real() >= p_rand && !random_move)
{ {
std::tr1::uniform_int<size_t> urand(0, egroups[t].size() - 1); std::tr1::uniform_int<size_t> urand(0, egroups[t].size() - 1);
...@@ -857,12 +857,12 @@ void move_sweep(Eprop mrs, Vprop mrp, Vprop mrm, Vprop wr, Vprop b, Vprop label, ...@@ -857,12 +857,12 @@ void move_sweep(Eprop mrs, Vprop mrp, Vprop mrm, Vprop wr, Vprop b, Vprop label,
if (s == r) if (s == r)
continue; continue;
double pf = isinf(beta) ? 1 : get_move_prob(v, s, b, mrs, mrp, mrm, emat, g, B); double pf = (isinf(beta) || random_move) ? 1 : get_move_prob(v, s, b, mrs, mrp, mrm, emat, g, B);
double dS = move_vertex(v, s, mrs, mrp, mrm, wr, b, deg_corr, eweight, double dS = move_vertex(v, s, mrs, mrp, mrm, wr, b, deg_corr, eweight,
vweight, g, bg, emat, true); vweight, g, bg, emat, true);
double pb = isinf(beta) ? 1 : get_move_prob(v, r, b, mrs, mrp, mrm, emat, g, B); double pb = (isinf(beta) || random_move) ? 1 : get_move_prob(v, r, b, mrs, mrp, mrm, emat, g, B);
double a = isinf(beta) ? -dS : -beta * dS + log(pb) - log(pf); double a = isinf(beta) ? -dS : -beta * dS + log(pb) - log(pf);
......
...@@ -716,7 +716,7 @@ def min_dist(state, n=0): ...@@ -716,7 +716,7 @@ def min_dist(state, n=0):
return min_d, r, s return min_d, r, s
def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None): def mcmc_sweep(state, beta=1., sequential=True, vertices=None, random_move=False, verbose=False):
r"""Performs a Monte Carlo Markov chain sweep on the network, to sample the block partition according to a probability :math:`\propto e^{-\beta \mathcal{S}_{t/c}}`, where :math:`\mathcal{S}_{t/c}` is the blockmodel entropy. r"""Performs a Monte Carlo Markov chain sweep on the network, to sample the block partition according to a probability :math:`\propto e^{-\beta \mathcal{S}_{t/c}}`, where :math:`\mathcal{S}_{t/c}` is the blockmodel entropy.
Parameters Parameters
...@@ -730,6 +730,14 @@ def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None): ...@@ -730,6 +730,14 @@ def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None):
random order. Otherwise a total of `N` moves attempts are made, where random order. Otherwise a total of `N` moves attempts are made, where
`N` is the number of vertices, where each vertex can be selected with `N` is the number of vertices, where each vertex can be selected with
equal probability. equal probability.
random_move : ``bool`` (optional, default: ``False``)
If ``True``, the proposed moves will attempt to place the vertices in
fully randomly-chosen blocks. If ``False``, the proposed moves will be
chosen with a probability depending on the membership of the neighbours
and the currently-inferred block structure.
vertices: ``list of ints`` (optional, default: ``None``)
A list of vertices which will be attempted to be moved. If ``None``, all
vertices will be attempted.
verbose : ``bool`` (optional, default: ``False``) verbose : ``bool`` (optional, default: ``False``)
If ``True``, verbose information is displayed. If ``True``, verbose information is displayed.
...@@ -838,6 +846,10 @@ def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None): ...@@ -838,6 +846,10 @@ def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None):
if vertices is None: if vertices is None:
vertices = libcommunity.get_vector(state.g.num_vertices()) vertices = libcommunity.get_vector(state.g.num_vertices())
vertices.a = state.g.vertex_index.copy("int").fa vertices.a = state.g.vertex_index.copy("int").fa
else:
vlist = libcommunity.get_vector(len(vertices))
vlist.a = vertices
vertices = vlist
dS, nmoves = libcommunity.move_sweep(state.g._Graph__graph, dS, nmoves = libcommunity.move_sweep(state.g._Graph__graph,
state.bg._Graph__graph, state.bg._Graph__graph,
...@@ -856,62 +868,66 @@ def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None): ...@@ -856,62 +868,66 @@ def mcmc_sweep(state, beta=1., sequential=True, verbose=False, vertices=None):
state.egroups, state.egroups,
_prop("e", state.g, state.esrcpos), _prop("e", state.g, state.esrcpos),
_prop("e", state.g, state.etgtpos), _prop("e", state.g, state.etgtpos),
float(beta), sequential, float(beta), sequential, random_move,
verbose, _get_rng()) verbose, _get_rng())
return dS / state.E, nmoves return dS / state.E, nmoves
def mc_get_dl(state, nsweep, greedy, rng, checkpoint=None, anneal=1, def mc_get_dl(state, nsweep, greedy, rng, checkpoint, checkpoint_state,
verbose=False): anneal=1, verbose=False):
if len(state.vertices) == 1: if len(state.vertices) == 1:
return state._BlockState__min_dl() return state._BlockState__min_dl()
S = state._BlockState__min_dl() B = len(state.vertices)
if checkpoint_state is None:
checkpoint_state = defaultdict(dict)
if "S" in checkpoint_state[B]:
S = checkpoint_state[B]["S"]
niter = checkpoint_state[B]["niter"]
else:
S = state._BlockState__min_dl()
checkpoint_state[B]["S"] = S
niter = 0
checkpoint_state[B]["niter"] = niter
if nsweep >= 0: if nsweep >= 0:
for i in range(nsweep): ntotal = nsweep if not greedy else 2 * nsweep
delta, nmoves = mcmc_sweep(state, beta=1, rng=rng) for i in range(ntotal):
if checkpoint is not None: if i < niter:
checkpoint(state, S, delta, nmoves) continue
if i < nsweep:
beta = 1
else:
beta = float("inf") # greedy
delta, nmoves = mcmc_sweep(state, beta=beta, rng=rng)
S += delta S += delta
if greedy: niter += 1
for i in range(nsweep): checkpoint_state[B]["S"] = S
delta, nmoves = mcmc_sweep(state, beta=float("inf")) checkpoint_state[B]["niter"] = niter
if checkpoint is not None: if checkpoint is not None:
checkpoint(state, S, delta, nmoves) checkpoint(state, S, delta, nmoves, checkpoint_state)
S += delta
else: else:
# adaptive mode # adaptive mode
min_dl = S min_dl = checkpoint_state[B].get("min_dl", S)
max_dl = S max_dl = checkpoint_state[B].get("max_dl", S)
count = 0 count = checkpoint_state[B].get("count", 0)
time = 0 time = checkpoint_state[B].get("time", 0)
bump = False bump = checkpoint_state[B].get("bump", False)
beta = 1. beta = checkpoint_state[B].get("beta", 1.)
last_min = min_dl last_min = checkpoint_state[B].get("last_min", min_dl)
greedy = checkpoint_state[B].get("greedy", False)
if verbose: if verbose:
print("beta = %g" % beta) print("beta = %g" % beta)
while True: while True:
delta, nmoves = mcmc_sweep(state, beta=beta) if greedy:
if checkpoint is not None: break
checkpoint(state, S, delta, nmoves)
S += delta
if S < min_dl:
min_dl = S
count = 0
elif S > max_dl:
max_dl = S
count = 0
else:
count += 1
if count > abs(nsweep): if count > abs(nsweep):
if not bump: if not bump:
min_dl = max_dl = S min_dl = max_dl = S
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment