Commit 30342d88 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

uncertain_blockmodel: improve addition/removal of multiple edges

parent 8645b67a
......@@ -628,9 +628,11 @@ public:
}
template <bool Add, bool Deplete=true>
void modify_edge(size_t u, size_t v, GraphInterface::edge_t& e,
const std::vector<double>& rec)
void modify_edge(size_t u, size_t v, GraphInterface::edge_t& e, int dw)
{
if (dw == 0)
return;
size_t r = _b[u];
size_t s = _b[v];
......@@ -658,34 +660,33 @@ public:
}
if (_coupled_state == nullptr)
_mrs[me]++;
_mrp[r]++;
_mrm[s]++;
_mrs[me] += dw;
_mrp[r] += dw;
_mrm[s] += dw;
}
else
{
assert(me != _emat.get_null_edge());
if (_coupled_state == nullptr)
_mrs[me]--;
_mrp[r]--;
_mrm[s]--;
}
// constexpr auto one = (Add) ? 1 : -1;
// for (size_t i = 0; i < _rec_types.size(); ++i)
// {
// switch (_rec_types[i])
// {
// case weight_type::REAL_NORMAL: // signed weights
// _bdrec[i][me] += one * std::pow(rec[i], 2);
// throw GraphException("Lrecdx, etc...");
// [[gnu::fallthrough]];
// default:
// _brec[i][me] += one * rec[i];
// }
// }
modify_edge<Add, Deplete>(u, v, e, _is_weighted);
{
_mrs[me] -= dw;
if (_mrs[me] == 0)
{
_emat.remove_me(me, _bg);
boost::remove_edge(me, _bg);
}
}
else
{
if (_mrs[me] == dw)
_emat.remove_me(me, _bg);
}
_mrp[r] -= dw;
_mrm[s] -= dw;
}
modify_edge<Add, Deplete>(u, v, e, dw, _is_weighted);
get_partition_stats(u).add_vertex(u, r, _deg_corr, _g,
_vweight, _eweight,
......@@ -693,20 +694,21 @@ public:
if (u != v)
get_partition_stats(v).add_vertex(v, s, _deg_corr, _g,
_vweight, _eweight,
_degs);
get_partition_stats(u).change_E(Add ? 1 : -1); // FIXME: wrong for multiple partition stats
_degs);
get_partition_stats(u).change_E(Add ? dw : -dw); // FIXME: wrong for multiple partition stats
if (_coupled_state != nullptr)
{
if constexpr (Add)
_coupled_state->add_edge(r, s, me, rec);
_coupled_state->add_edge(r, s, me, dw);
else
_coupled_state->remove_edge(r, s, me, rec);
_coupled_state->remove_edge(r, s, me, dw);
}
}
template <bool Add, bool Deplete>
void modify_edge(size_t u, size_t v, GraphInterface::edge_t& e,
void modify_edge(size_t u, size_t v, GraphInterface::edge_t& e, int,
std::false_type)
{
if constexpr (Add)
......@@ -724,7 +726,7 @@ public:
}
template <bool Add, bool Deplete>
void modify_edge(size_t u, size_t v, GraphInterface::edge_t& e,
void modify_edge(size_t u, size_t v, GraphInterface::edge_t& e, int dw,
std::true_type)
{
if constexpr (Add)
......@@ -733,25 +735,25 @@ public:
{
e = boost::add_edge(u, v, _g).first;
auto c_eweight = _eweight.get_checked();
c_eweight[e] = 1;
c_eweight[e] = dw;
}
else
{
_eweight[e]++;
_eweight[e] += dw;
}
if (_deg_corr)
{
get<1>(_degs[u])++;
get<1>(_degs[u]) += dw;
if constexpr (is_directed_::apply<g_t>::type::value)
get<0>(_degs[v])++;
get<0>(_degs[v]) += dw;
else
get<1>(_degs[v])++;
get<1>(_degs[v]) += dw;
}
}
else
{
_eweight[e]--;
_eweight[e] -= dw;
if (_eweight[e] == 0 && Deplete)
{
boost::remove_edge(e, _g);
......@@ -760,25 +762,23 @@ public:
if (_deg_corr)
{
get<1>(_degs[u])--;
get<1>(_degs[u]) -= dw;
if constexpr (is_directed_::apply<g_t>::type::value)
get<0>(_degs[v])--;
get<0>(_degs[v]) -= dw;
else
get<1>(_degs[v])--;
get<1>(_degs[v]) -= dw;
}
}
}
void add_edge(size_t u, size_t v, GraphInterface::edge_t& e,
const std::vector<double>& rec)
void add_edge(size_t u, size_t v, GraphInterface::edge_t& e, int dw)
{
modify_edge<true, false>(u, v, e, rec);
modify_edge<true, false>(u, v, e, dw);
}
void remove_edge(size_t u, size_t v, GraphInterface::edge_t& e,
const std::vector<double>& rec)
void remove_edge(size_t u, size_t v, GraphInterface::edge_t& e, int dw)
{
modify_edge<false, false>(u, v, e, rec);
modify_edge<false, false>(u, v, e, dw);
}
void set_vertex_weight(size_t v, int w)
......@@ -1922,7 +1922,8 @@ public:
}
template <bool Add>
double edge_entropy_term(size_t u, size_t v, const entropy_args_t& ea)
double edge_entropy_term(size_t u, size_t v, int dw,
const entropy_args_t& ea)
{
double S = 0, S_dl = 0;
size_t r = _b[u];
......@@ -1941,25 +1942,25 @@ public:
if (u != v)
{
if constexpr (Add)
degs[1] = {kin, kout + 1};
degs[1] = {kin, kout + dw};
else
degs[1] = {kin, kout - 1};
degs[1] = {kin, kout - dw};
}
else
{
if constexpr (!is_directed_::apply<g_t>::type::value)
{
if constexpr (Add)
degs[1] = {kin, kout + 2};
degs[1] = {kin, kout + 2 * dw};
else
degs[1] = {kin, kout - 2};
degs[1] = {kin, kout - 2 * dw};
}
else
{
if constexpr (Add)
degs[1] = {kin + 1, kout + 1};
degs[1] = {kin + dw, kout + dw};
else
degs[1] = {kin - 1, kout - 1};
degs[1] = {kin - dw, kout - dw};
}
}
......@@ -1977,16 +1978,16 @@ public:
if constexpr (!is_directed_::apply<g_t>::type::value)
{
if constexpr (Add)
degs[1] = {kin, kout + 1};
degs[1] = {kin, kout + dw};
else
degs[1] = {kin, kout - 1};
degs[1] = {kin, kout - dw};
}
else
{
if constexpr (Add)
degs[1] = {kin + 1, kout};
degs[1] = {kin + dw, kout};
else
degs[1] = {kin - 1, kout};
degs[1] = {kin - dw, kout};
}
S_dl += get_partition_stats(v).get_deg_dl(ea.degree_dl_kind,
......@@ -2003,9 +2004,9 @@ public:
degs[0] = {kin, kout};
if constexpr (Add)
degs[1] = {kin, kout + 1};
degs[1] = {kin, kout + dw};
else
degs[1] = {kin, kout - 1};
degs[1] = {kin, kout - dw};
std::tie(kin, kout) = get_deg(v, _eweight, _degs, _g);
......@@ -2014,16 +2015,16 @@ public:
if constexpr (!is_directed_::apply<g_t>::type::value)
{
if constexpr (Add)
degs[3] = {kin, kout + 1};
degs[3] = {kin, kout + dw};
else
degs[3] = {kin, kout - 1};
degs[3] = {kin, kout - dw};
}
else
{
if constexpr (Add)
degs[3] = {kin + 1, kout};
degs[3] = {kin + dw, kout};
else
degs[3] = {kin - 1, kout};
degs[3] = {kin - dw, kout};
}
for (size_t i = 0; i < 2; ++i)
......@@ -2085,7 +2086,7 @@ public:
if (_coupled_state != nullptr)
{
S_dl += _coupled_state->edge_entropy_term(r, s, _coupled_entropy_args);
S_dl += _coupled_state->edge_entropy_term(r, s, dw, _coupled_entropy_args);
}
else
{
......@@ -2102,20 +2103,23 @@ public:
return S + S_dl * ea.beta_dl;
}
double edge_entropy_term(size_t u, size_t v, const entropy_args_t& ea)
double edge_entropy_term(size_t u, size_t v, int dw, const entropy_args_t& ea)
{
return edge_entropy_term<true>(u, v, ea);
return edge_entropy_term<true>(u, v, dw, ea);
}
template <bool Add>
double modify_edge_dS(size_t u, size_t v, GraphInterface::edge_t& e,
const std::vector<double>& recs, const entropy_args_t& ea)
int dw, const entropy_args_t& ea)
{
if (dw == 0)
return 0;
double dS = 0;
dS -= edge_entropy_term<Add>(u, v, ea);
modify_edge<Add>(u, v, e, recs);
dS += edge_entropy_term<!Add>(u, v, ea);
modify_edge<!Add>(u, v, e, recs);
dS -= edge_entropy_term<Add>(u, v, dw, ea);
modify_edge<Add>(u, v, e, dw);
dS += edge_entropy_term<!Add>(u, v, dw, ea);
modify_edge<!Add>(u, v, e, dw);
return dS;
}
......
......@@ -50,11 +50,9 @@ public:
virtual void remove_edge_rec(const GraphInterface::edge_t& e) = 0;
virtual void update_edge_rec(const GraphInterface::edge_t& e,
const std::vector<double>& delta) = 0;
virtual void add_edge(size_t u, size_t v, GraphInterface::edge_t& e,
const std::vector<double>& rec) = 0;
virtual void remove_edge(size_t u, size_t v, GraphInterface::edge_t& e,
const std::vector<double>& rec) = 0;
virtual double edge_entropy_term(size_t u, size_t v, const entropy_args_t& ea) = 0;
virtual void add_edge(size_t u, size_t v, GraphInterface::edge_t& e, int dm) = 0;
virtual void remove_edge(size_t u, size_t v, GraphInterface::edge_t& e, int dm) = 0;
virtual double edge_entropy_term(size_t u, size_t v, int dm, const entropy_args_t& ea) = 0;
virtual void propagate_delta(size_t u, size_t v,
std::vector<std::tuple<size_t, size_t,
GraphInterface::edge_t, int,
......
......@@ -730,7 +730,7 @@ struct Layers
}
}
double edge_entropy_term(size_t, size_t, const entropy_args_t&) { return 0; }
double edge_entropy_term(size_t, size_t, int, const entropy_args_t&) { return 0; }
template <class MCMCState>
void init_mcmc(MCMCState& state)
......@@ -925,13 +925,11 @@ struct Layers
BaseState::update_edge_rec(e, delta);
}
void add_edge(size_t, size_t, GraphInterface::edge_t&,
const std::vector<double>&)
void add_edge(size_t, size_t, GraphInterface::edge_t&, int)
{
}
void remove_edge(size_t, size_t, GraphInterface::edge_t&,
const std::vector<double>&)
void remove_edge(size_t, size_t, GraphInterface::edge_t&, int)
{
}
......
......@@ -294,13 +294,11 @@ public:
move_vertices(vs, rs);
}
void add_edge(size_t, size_t, GraphInterface::edge_t&,
const std::vector<double>&)
void add_edge(size_t, size_t, GraphInterface::edge_t&, int)
{
}
void remove_edge(size_t, size_t, GraphInterface::edge_t&,
const std::vector<double>&)
void remove_edge(size_t, size_t, GraphInterface::edge_t&, int)
{
}
......@@ -919,7 +917,7 @@ public:
return S;
}
double edge_entropy_term(size_t, size_t, const entropy_args_t&)
double edge_entropy_term(size_t, size_t, int, const entropy_args_t&)
{
return 0;
}
......
......@@ -98,7 +98,6 @@ struct Dynamics
typename BlockState::g_t& _u = _block_state._g;
typename BlockState::eweight_t& _eweight = _block_state._eweight;
GraphInterface::edge_t _null_edge;
std::vector<double> _recs;
std::vector<gt_hash_map<size_t, GraphInterface::edge_t>> _u_edges;
......@@ -149,24 +148,27 @@ struct Dynamics
return -S;
}
double remove_edge_dS(size_t u, size_t v, const uentropy_args_t& ea)
double remove_edge_dS(size_t u, size_t v, int dw, const uentropy_args_t& ea)
{
if (dw == 0)
return 0;
auto& e = get_u_edge(u, v);
auto x = _xc[e];
double dS = _block_state.template modify_edge_dS<false>(source(e, _u),
target(e, _u),
e, _recs, ea);
e, dw, ea);
_xc[e] = x;
if (ea.density && _E_prior)
{
dS += _pe;
dS += lgamma_fast(_E) - lgamma_fast(_E + 1);
dS += _pe * dw;
dS += lgamma_fast(_E + 1 - dw) - lgamma_fast(_E + 1);
}
if (ea.latent_edges)
{
if (_eweight[e] == 1 && (_self_loops || u != v))
if (_eweight[e] == dw && (_self_loops || u != v))
{
dS += _dstate.template get_edge_dS<false>(u, v, _xc[e]);
if (u != v && !graph_tool::is_directed(_u))
......@@ -176,15 +178,17 @@ struct Dynamics
return dS;
}
double add_edge_dS(size_t u, size_t v, double x, const uentropy_args_t& ea)
double add_edge_dS(size_t u, size_t v, int dw, double x, const uentropy_args_t& ea)
{
if (dw == 0)
return 0;
auto& e = get_u_edge(u, v);
double dS = _block_state.template modify_edge_dS<true>(u, v, e,
_recs, ea);
double dS = _block_state.template modify_edge_dS<true>(u, v, e, dw, ea);
if (ea.density && _E_prior)
{
dS -= _pe;
dS += lgamma_fast(_E + 2) - lgamma_fast(_E + 1);
dS -= _pe * dw;
dS += lgamma_fast(_E + 1 + dw) - lgamma_fast(_E + 1);
}
if (ea.latent_edges)
......@@ -201,6 +205,9 @@ struct Dynamics
double update_edge_dS(size_t u, size_t v, double dx, const uentropy_args_t& ea)
{
if (dx == 0)
return 0;
double dS = 0;
if (ea.latent_edges)
{
......@@ -214,13 +221,15 @@ struct Dynamics
return dS;
}
void remove_edge(size_t u, size_t v)
void remove_edge(size_t u, size_t v, int dw)
{
if (dw == 0)
return;
auto& e = get_u_edge(u, v);
auto x = _xc[e];
_block_state.template modify_edge<false>(u, v, e,
_recs);
_block_state.template modify_edge<false>(u, v, e, dw);
if ((e == _null_edge || _eweight[e] == 0) && (_self_loops || u != v))
{
......@@ -232,13 +241,15 @@ struct Dynamics
_E--;
}
void add_edge(size_t u, size_t v, double x)
void add_edge(size_t u, size_t v, int dw, double x)
{
if (dw == 0)
return;
auto& e = get_u_edge<true>(u, v);
_block_state.template modify_edge<true>(u, v, e,
_recs);
_block_state.template modify_edge<true>(u, v, e, dw);
if (_eweight[e] == 1 && (_self_loops || u != v))
if (_eweight[e] == dw && (_self_loops || u != v))
{
_xc[e] = x;
_dstate.template update_edge<true>(u, v, x);
......@@ -250,6 +261,9 @@ struct Dynamics
void update_edge(size_t u, size_t v, double dx)
{
if (dx == 0)
return;
if (_self_loops || u != v)
{
auto& e = get_u_edge(u, v);
......
......@@ -229,31 +229,11 @@ struct MCMC
double dS = 0;
if (dm == 0)
{
dS = _state.update_edge_dS(u, v, dx, _entropy_args);
}
else if (dm < 0)
{
dS = _state.remove_edge_dS(u, v, _entropy_args);
for (int i = 0; i < -dm-1; ++i)
{
_state.remove_edge(u, v);
dS += _state.remove_edge_dS(u, v, _entropy_args);
}
for (int i = 0; i < -dm-1; ++i)
_state.add_edge(u, v, (i == 0) ? x : 0);
}
dS = _state.remove_edge_dS(u, v, -dm, _entropy_args);
else
{
dS = _state.add_edge_dS(u, v, dx, _entropy_args);
for (int i = 0; i < dm-1; ++i)
{
_state.add_edge(u, v, 0);
dS += _state.add_edge_dS(u, v, 0, _entropy_args);
}
for (int i = 0; i < dm-1; ++i)
_state.remove_edge(u, v);
}
dS = _state.add_edge_dS(u, v, dm, dx, _entropy_args);
double a = 0;
if (dm != 0)
......@@ -282,15 +262,9 @@ struct MCMC
size_t m = get<0>(node_state(u, v));
_edge_sampler.update_edge(u, v, m, dm);
if (dm < 0)
{
for (int i = 0; i < -dm; ++i)
_state.remove_edge(u, v);
}
_state.remove_edge(u, v, -dm);
else
{
for (int i = 0; i < dm; ++i)
_state.add_edge(u, v, (i == 0) ? dx : 0);
}
_state.add_edge(u, v, dm, dx);
}
}
......
......@@ -337,13 +337,12 @@ struct LatentClosure
_cstates[_l + 1]->internal_move_proposal(u, v, rng);
}
template <bool Add, class Edge, class Recs, class Eargs>
double modify_edge_dS(size_t u, size_t v, Edge& e, Recs& recs,
Eargs& ea)
template <bool Add, class Edge, class Eargs>
double modify_edge_dS(size_t u, size_t v, Edge& e, Eargs& ea)
{
double dS = 0;
if (_l == 0)
dS = _ebstate.template modify_edge_dS<Add>(u, v, e, recs, ea);
dS = _ebstate.template modify_edge_dS<Add>(u, v, e, 1, ea);
else
dS = modify_edge_g_dS<Add>(u, v);
......@@ -363,8 +362,8 @@ struct LatentClosure
return dS;
}
template <bool Add, class Edge, class Recs>
void modify_edge(size_t u, size_t v, Edge& e, Recs& recs)
template <bool Add, class Edge>
void modify_edge(size_t u, size_t v, Edge& e)
{
if (u != v)
{
......@@ -376,7 +375,7 @@ struct LatentClosure
}
if (_l == 0)
_ebstate.template modify_edge<Add>(u, v, e, recs);