Commit 62055e30 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

inference.blockmodel: simplify and speedup vertex movements

parent 74cfb8a4
...@@ -153,6 +153,8 @@ void export_blockmodel_state() ...@@ -153,6 +153,8 @@ void export_blockmodel_state()
&state_t::remove_vertex; &state_t::remove_vertex;
void (state_t::*add_vertex)(size_t, size_t) = void (state_t::*add_vertex)(size_t, size_t) =
&state_t::add_vertex; &state_t::add_vertex;
void (state_t::*move_vertex)(size_t, size_t) =
&state_t::move_vertex;
void (state_t::*remove_vertices)(python::object) = void (state_t::*remove_vertices)(python::object) =
&state_t::remove_vertices; &state_t::remove_vertices;
void (state_t::*add_vertices)(python::object, python::object) = void (state_t::*add_vertices)(python::object, python::object) =
...@@ -180,7 +182,7 @@ void export_blockmodel_state() ...@@ -180,7 +182,7 @@ void export_blockmodel_state()
.def("add_vertex", add_vertex) .def("add_vertex", add_vertex)
.def("remove_vertices", remove_vertices) .def("remove_vertices", remove_vertices)
.def("add_vertices", add_vertices) .def("add_vertices", add_vertices)
.def("move_vertex", &state_t::move_vertex) .def("move_vertex", move_vertex)
.def("move_vertices", move_vertices) .def("move_vertices", move_vertices)
.def("set_partition", set_partition) .def("set_partition", set_partition)
.def("virtual_move", virtual_move) .def("virtual_move", virtual_move)
......
...@@ -110,10 +110,11 @@ public: ...@@ -110,10 +110,11 @@ public:
_c_bdrec(_bdrec.get_checked()), _c_bdrec(_bdrec.get_checked()),
_vweight(uncheck(__avweight, typename std::add_pointer<vweight_t>::type())), _vweight(uncheck(__avweight, typename std::add_pointer<vweight_t>::type())),
_eweight(uncheck(__aeweight, typename std::add_pointer<eweight_t>::type())), _eweight(uncheck(__aeweight, typename std::add_pointer<eweight_t>::type())),
_emat(_g, _b, _bg, rng), _emat(_bg, rng),
_neighbour_sampler(get(vertex_index_t(), _g), num_vertices(_g)), _neighbour_sampler(get(vertex_index_t(), _g), num_vertices(_g)),
_m_entries(num_vertices(_bg)), _m_entries(num_vertices(_bg)),
_coupled_state(nullptr) _coupled_state(nullptr),
_gstate(this)
{ {
rebuild_neighbour_sampler(); rebuild_neighbour_sampler();
_empty_blocks.clear(); _empty_blocks.clear();
...@@ -139,158 +140,125 @@ public: ...@@ -139,158 +140,125 @@ public:
_emat(other._emat), _emat(other._emat),
_neighbour_sampler(other._neighbour_sampler), _neighbour_sampler(other._neighbour_sampler),
_m_entries(num_vertices(_bg)), _m_entries(num_vertices(_bg)),
_coupled_state(nullptr) _coupled_state(nullptr),
_gstate(other._gstate == &other ? this : other._gstate)
{ {
if (other.is_partition_stats_enabled()) if (other.is_partition_stats_enabled())
enable_partition_stats(); enable_partition_stats();
} }
template <bool Add, class BEdge, class EFilt, class EOP> // =========================================================================
void modify_vertex(size_t v, size_t r, BEdge&& bedge, EFilt&& efilt, // State modification
EOP&& eop) // =========================================================================
{
typedef typename graph_traits<g_t>::vertex_descriptor vertex_t;
for (auto e : out_edges_range(v, _g))
{
if (efilt(e) || _eweight[e] == 0)
continue;
vertex_t u = target(e, _g);
vertex_t s = _b[u];
auto& me = bedge[e];
if (Add)
{
if (me != _emat.get_null_edge())
{
assert(u == v);
continue;
}
if (u == v)
s = r;
me = _emat.get_me(r, s);
if (me == _emat.get_null_edge())
{
me = add_edge(r, s, _bg).first;
_emat.put_me(r, s, me);
_c_mrs[me] = 0;
_c_brec[me] = 0;
_c_bdrec[me] = 0;
}
assert(_emat.get_bedge(e) != _emat.get_null_edge()); template <class MEntries, class Efilt, class GetB>
} void get_move_entries(size_t v, size_t r, size_t nr, MEntries& m_entries,
else Efilt&& efilt, GetB&& get_b)
{ {
if (me == _emat.get_null_edge()) auto& gs = *_gstate;
{ auto mv_entries = [&](auto&&... args)
assert(u == v);
continue;
}
}
assert(me != _emat.get_null_edge());
assert(me == _emat.get_me(r, s));
assert(std::min(source(me, _bg), target(me, _bg)) == std::min(r, s));
assert(std::max(source(me, _bg), target(me, _bg)) == std::max(r, s));
auto ew = _eweight[e];
if (Add)
{
_mrs[me] += ew;
_mrp[r] += ew;
_mrm[s] += ew;
eop(e, me);
}
else
{ {
_mrs[me] -= ew; move_entries(v, r, nr, get_b, gs._g, gs._eweight, m_entries,
_mrp[r] -= ew; efilt, is_loop_nop(), args...);
_mrm[s] -= ew; };
eop(e, me);
assert(_mrs[me] >= 0);
if (_mrs[me] == 0)
_emat.remove_me(r, s, me, _bg);
me = _emat.get_null_edge();
}
}
for (auto e : in_edges_range(v, _g)) switch (_rec_type)
{ {
if (efilt(e)) case weight_type::POSITIVE: // positive weights
continue; mv_entries(gs._rec);
break;
vertex_t u = source(e, _g); case weight_type::SIGNED: // positive and negative weights
if (u == v) mv_entries(gs._rec, gs._drec);
continue; break;
vertex_t s = _b[u]; default: // no weights
mv_entries();
auto& me = _emat.get_bedge(e); }
}
if (Add) template <class MEntries>
{ void get_move_entries(size_t v, size_t r, size_t nr, MEntries& m_entries)
me = _emat.get_me(s, r); {
if (me == _emat.get_null_edge()) get_move_entries(v, r, nr, m_entries,
{ [](auto) { return false; },
me = add_edge(s, r, _bg).first; [&](auto u) -> auto& { return this->_b[u]; });
_emat.put_me(s, r, me); }
_c_mrs[me] = 0;
_c_brec[me] = 0;
_c_bdrec[me] = 0;
}
assert(_emat.get_bedge(e) != _emat.get_null_edge());
}
assert(me != _emat.get_null_edge());
assert(me == _emat.get_me(s, r));
assert(std::min(source(me, _bg), target(me, _bg)) == std::min(r, s));
assert(std::max(source(me, _bg), target(me, _bg)) == std::max(r, s));
auto ew = _eweight[e]; template <bool Add, class EFilt, class GetB>
void modify_vertex(size_t v, size_t r, EFilt&& efilt, GetB&& get_b)
{
_m_entries.clear();
if (Add)
get_move_entries(v, null_group, r, _m_entries, efilt, get_b);
else
get_move_entries(v, r, null_group, _m_entries, efilt, get_b);
if (Add) entries_op(_m_entries, _emat,
{ [&](auto r, auto s, auto& me, auto& delta)
_mrs[me] += ew; {
_mrp[s] += ew; if (Add && me == this->_emat.get_null_edge())
_mrm[r] += ew; {
eop(e, me); me = add_edge(r, s, this->_bg).first;
} _emat.put_me(r, s, me);
else this->_c_mrs[me] = 0;
this->_c_brec[me] = 0;
this->_c_bdrec[me] = 0;
}
this->_mrs[me] += get<0>(delta);
this->_mrp[r] += get<0>(delta);
this->_mrm[s] += get<0>(delta);
switch (this->_rec_type)
{
case weight_type::SIGNED: // signed weights
this->_bdrec[me] += get<2>(delta);
case weight_type::POSITIVE: // positive weights
this->_brec[me] += get<1>(delta);
}
});
if (_rec_type == weight_type::DELTA_T) // waiting times
{
if (_ignore_degrees[v] > 0)
{ {
_mrs[me] -= ew; double dt = out_degreeS()(v, _g, _rec);
_mrp[s] -= ew; auto r = _b[v];
_mrm[r] -= ew; if (Add)
eop(e, me); _brecsum[r] += dt;
if (_mrs[me] == 0) else
_emat.remove_me(s, r, me, _bg); _brecsum[r] -= dt;
me = _emat.get_null_edge();
} }
} }
if (Add) if (Add)
{
auto& b_v = get_b(v);
b_v = r;
add_partition_node(v, r); add_partition_node(v, r);
}
else else
{
remove_partition_node(v, r); remove_partition_node(v, r);
}
} }
void remove_partition_node(size_t v, size_t r) void remove_partition_node(size_t v, size_t r)
{ {
_wr[r] -= _vweight[v]; auto& gs = *_gstate;
_wr[r] -= gs._vweight[v];
if (!_egroups.empty()) if (!_egroups.empty())
_egroups.remove_vertex(v, r, _g); _egroups.remove_vertex(v, r, gs._g);
if (is_partition_stats_enabled()) if (is_partition_stats_enabled())
get_partition_stats(v).remove_vertex(v, r, _deg_corr, _g, get_partition_stats(v).remove_vertex(v, r, _deg_corr, gs._g,
_vweight, _eweight, _degs); gs._vweight, gs._eweight,
gs._degs);
if (_vweight[v] > 0 && _wr[r] == 0) if (gs._vweight[v] > 0 && _wr[r] == 0)
{ {
remove_element(_candidate_blocks, _candidate_pos, r); remove_element(_candidate_blocks, _candidate_pos, r);
add_element(_empty_blocks, _empty_pos, r); add_element(_empty_blocks, _empty_pos, r);
...@@ -299,64 +267,50 @@ public: ...@@ -299,64 +267,50 @@ public:
void add_partition_node(size_t v, size_t r) void add_partition_node(size_t v, size_t r)
{ {
_b[v] = r; auto& gs = *_gstate;
_wr[r] += _vweight[v];
_wr[r] += gs._vweight[v];
if (!_egroups.empty()) if (!_egroups.empty())
_egroups.add_vertex(v, r, _eweight, _g); _egroups.add_vertex(v, r, gs._eweight, gs._g);
if (is_partition_stats_enabled()) if (is_partition_stats_enabled())
get_partition_stats(v).add_vertex(v, r, _deg_corr, _g, _vweight, get_partition_stats(v).add_vertex(v, r, _deg_corr, gs._g, gs._vweight,
_eweight, _degs); gs._eweight, gs._degs);
if (_vweight[v] > 0 && _wr[r] == _vweight[v]) if (gs._vweight[v] > 0 && _wr[r] == gs._vweight[v])
{ {
remove_element(_empty_blocks, _empty_pos, r); remove_element(_empty_blocks, _empty_pos, r);
add_element(_candidate_blocks, _candidate_pos, r); add_element(_candidate_blocks, _candidate_pos, r);
} }
} }
template <class BEdge, class EFilt> template <class EFilt, class GetB>
void remove_vertex(size_t v, BEdge&& bedge, EFilt&& efilt) void remove_vertex(size_t v, size_t r, EFilt && efilt, GetB && get_b)
{ {
size_t r = _b[v]; modify_vertex<false>(v, r, efilt, get_b);
switch (_rec_type) }
{
case weight_type::POSITIVE: // positive weights template <class EFilt>
modify_vertex<false>(v, r, bedge, efilt, void remove_vertex(size_t v, size_t r, EFilt&& efilt)
[&](auto& e, auto& me) {
{ remove_vertex(v, r, efilt,
this->_brec[me] -= this->_rec[e]; [&](auto u) -> auto& { return this->_b[u]; });
}); }
break;
case weight_type::SIGNED: // positive and negative weights void remove_vertex(size_t v, size_t r)
modify_vertex<false>(v, r, bedge, efilt, {
[&](auto& e, auto& me) remove_vertex(v, r, [](auto&) { return false; });
{
this->_brec[me] -= this->_rec[e];
this->_bdrec[me] -= this->_drec[e];
});
break;
case weight_type::DELTA_T: // waiting times
if (_ignore_degrees[v] > 0)
{
double dt = out_degreeS()(v, _g, _rec);
auto r = _b[v];
_brecsum[r] -= dt;
}
case weight_type::NONE: // no weights
modify_vertex<false>(v, r, bedge, efilt, [](auto&, auto&){});
}
} }
void remove_vertex(size_t v) void remove_vertex(size_t v)
{ {
remove_vertex(v, _emat.get_bedge_map(), size_t r = _b[v];
[](auto&){ return false; }); remove_vertex(v, r);
} }
template <class Vlist, class EOP> template <class Vlist>
void remove_vertices(Vlist& vs, EOP&& eop) void remove_vertices(Vlist& vs)
{ {
typedef typename graph_traits<g_t>::vertex_descriptor vertex_t; typedef typename graph_traits<g_t>::vertex_descriptor vertex_t;
typedef typename graph_traits<g_t>::edge_descriptor edges_t; typedef typename graph_traits<g_t>::edge_descriptor edges_t;
...@@ -374,9 +328,8 @@ public: ...@@ -374,9 +328,8 @@ public:
} }
} }
auto& bedge = _emat.get_bedge_map();
for (auto v : vset) for (auto v : vset)
remove_vertex(v, bedge, remove_vertex(v, _b[v],
[&](auto& e) { return eset.find(e) != eset.end(); }); [&](auto& e) { return eset.find(e) != eset.end(); });
for (auto& e : eset) for (auto& e : eset)
...@@ -386,7 +339,7 @@ public: ...@@ -386,7 +339,7 @@ public:
vertex_t r = _b[v]; vertex_t r = _b[v];
vertex_t s = _b[u]; vertex_t s = _b[u];
auto& me = _emat.get_bedge(e); auto me = _emat.get_me(r, s);
auto ew = _eweight[e]; auto ew = _eweight[e];
_mrs[me] -= ew; _mrs[me] -= ew;
...@@ -396,88 +349,49 @@ public: ...@@ -396,88 +349,49 @@ public:
_mrp[r] -= ew; _mrp[r] -= ew;
_mrm[s] -= ew; _mrm[s] -= ew;
eop(e, me); switch (_rec_type)
{
case weight_type::SIGNED: // signed weights
_bdrec[me] -= _drec[e];
case weight_type::POSITIVE: // positive weights
_brec[me] -= _rec[e];
}
if (_mrs[me] == 0) if (_mrs[me] == 0)
_emat.remove_me(r, s, me, _bg); _emat.remove_me(r, s, me, _bg);
} }
} }
template <class Vec>
void remove_vertices(Vec& vs)
{
switch (_rec_type)
{
case weight_type::POSITIVE: // positive weights
remove_vertices(vs, [&](auto& e, auto& me)
{ this->_brec[me] -= this->_rec[e]; });
break;
case weight_type::SIGNED: // positive and negative weights
remove_vertices(vs, [&](auto& e, auto& me)
{ this->_brec[me] -= this->_rec[e];
this->_bdrec[me] -= this->_drec[e];});
break;
case weight_type::DELTA_T: // waiting times
for (auto v : vs)
{
if (_ignore_degrees[v] > 0)
{
double dt = out_degreeS()(v, _g, _rec);
auto r = _b[v];
_brecsum[r] -= dt;
}
}
case weight_type::NONE: // no weights
remove_vertices(vs, [&](auto&, auto&) {});
}
}
void remove_vertices(python::object ovs) void remove_vertices(python::object ovs)
{ {
multi_array_ref<uint64_t, 1> vs = get_array<uint64_t, 1>(ovs); multi_array_ref<uint64_t, 1> vs = get_array<uint64_t, 1>(ovs);
remove_vertices(vs); remove_vertices(vs);
} }
template <class BEdge, class Efilt> template <class Efilt, class GetB>
void add_vertex(size_t v, size_t r, BEdge&& bedge, Efilt&& efilt) void add_vertex(size_t v, size_t r, Efilt&& efilt, GetB&& get_b)
{ {
switch (_rec_type) modify_vertex<true>(v, r, efilt, get_b);
{ }
case weight_type::POSITIVE: // positive weights
modify_vertex<true>(v, r, bedge, efilt, template <class Efilt>
[&](auto& e, auto& me) void add_vertex(size_t v, size_t r, Efilt&& efilt)
{ {
this->_brec[me] += this->_rec[e]; add_vertex(v, r, efilt,
}); [&](auto u) -> auto& { return this->_b[u]; });
break;
case weight_type::SIGNED: // positive and negative weights
modify_vertex<true>(v, r, bedge, efilt,
[&](auto& e, auto& me)
{
this->_brec[me] += this->_rec[e];
this->_bdrec[me] += this->_drec[e];
});
break;
case weight_type::DELTA_T: // waiting times
if (_ignore_degrees[v] > 0)
{
double dt = out_degreeS()(v, _g, _rec);
_brecsum[r] += dt;
}
case weight_type::NONE: // no weights
modify_vertex<true>(v, r, bedge, efilt, [](auto&, auto&){});
}
} }
void add_vertex(size_t v, size_t r) void add_vertex(size_t v, size_t r)
{ {
add_vertex(v, r, _emat.get_bedge_map(), add_vertex(v, r, [](auto&){ return false; });
[](auto&){ return false; });
} }
template <class Vlist, class Blist, class EOP> template <class Vlist, class Blist>
void add_vertices(Vlist& vs, Blist& rs, EOP&& eop) void add_vertices(Vlist& vs, Blist& rs)
{ {
if (vs.size() != rs.size())
throw ValueException("vertex and group lists do not have the same size");
typedef typename graph_traits<g_t>::vertex_descriptor vertex_t; typedef typename graph_traits<g_t>::vertex_descriptor vertex_t;
gt_hash_map<vertex_t, size_t> vset; gt_hash_map<vertex_t, size_t> vset;
...@@ -498,10 +412,8 @@ public: ...@@ -498,10 +412,8 @@ public:
} }
} }
auto bedge = _emat.get_bedge_map().get_checked();
for (auto vr : vset) for (auto vr : vset)