Commit 32951567 authored by Tiago Peixoto's avatar Tiago Peixoto

inference: isolate entropy_args

parent 96af75c9
...@@ -2442,8 +2442,15 @@ public: ...@@ -2442,8 +2442,15 @@ public:
return _partition_stats[r]; return _partition_stats[r];
} }
void init_mcmc(double c, double dl) template <class MCMCState>
void init_mcmc(MCMCState& state)
{ {
auto c = state._c;
auto& entropy_args = state._entropy_args;
bool dl = (entropy_args.partition_dl ||
entropy_args.degree_dl ||
entropy_args.edges_dl);
if (!std::isinf(c)) if (!std::isinf(c))
{ {
_egroups.clear(); _egroups.clear();
...@@ -2653,6 +2660,7 @@ public: ...@@ -2653,6 +2660,7 @@ public:
std::vector<std::tuple<size_t, size_t, int>> std::vector<std::tuple<size_t, size_t, int>>
_pp_entries; _pp_entries;
typedef entropy_args_t _entropy_args_t;
BlockStateVirtualBase* _coupled_state = nullptr; BlockStateVirtualBase* _coupled_state = nullptr;
entropy_args_t _coupled_entropy_args; entropy_args_t _coupled_entropy_args;
......
...@@ -39,7 +39,7 @@ typedef typename vprop_map_t<int32_t>::type vmap_t; ...@@ -39,7 +39,7 @@ typedef typename vprop_map_t<int32_t>::type vmap_t;
((state, &, State&, 0)) \ ((state, &, State&, 0)) \
((S, , double, 0)) \ ((S, , double, 0)) \
((vlist,&, std::vector<size_t>&, 0)) \ ((vlist,&, std::vector<size_t>&, 0)) \
((entropy_args,, entropy_args_t, 0)) \ ((oentropy_args,, python::object, 0)) \
((b_min,, vmap_t, 0)) \ ((b_min,, vmap_t, 0)) \
((max_iter,, size_t, 0)) ((max_iter,, size_t, 0))
...@@ -64,15 +64,17 @@ struct Exhaustive ...@@ -64,15 +64,17 @@ struct Exhaustive
sizeof...(Ts)>* = nullptr> sizeof...(Ts)>* = nullptr>
ExhaustiveBlockState(ATs&&... as) ExhaustiveBlockState(ATs&&... as)
: ExhaustiveBlockStateBase<Ts...>(as...), : ExhaustiveBlockStateBase<Ts...>(as...),
_g(_state._g), _S_min(_S) _g(_state._g), _S_min(_S),
_entropy_args(python::extract<typename State::_entropy_args_t&>(_oentropy_args))
{ {
_state.init_mcmc(numeric_limits<double>::infinity(), _state.init_mcmc(*this);
(_entropy_args.partition_dl ||
_entropy_args.degree_dl ||
_entropy_args.edges_dl));
} }
typename State::g_t& _g; typename State::g_t& _g;
double _S_min; double _S_min;
typename State::_entropy_args_t& _entropy_args;
double _c = numeric_limits<double>::infinity();
size_t get_B() size_t get_B()
{ {
......
...@@ -38,7 +38,7 @@ using namespace std; ...@@ -38,7 +38,7 @@ using namespace std;
((E,, size_t, 0)) \ ((E,, size_t, 0)) \
((vlist,&, std::vector<size_t>&, 0)) \ ((vlist,&, std::vector<size_t>&, 0)) \
((beta,, double, 0)) \ ((beta,, double, 0)) \
((entropy_args,, entropy_args_t, 0)) \ ((oentropy_args,, python::object, 0)) \
((allow_new_group,, bool, 0)) \ ((allow_new_group,, bool, 0)) \
((sequential,, bool, 0)) \ ((sequential,, bool, 0)) \
((deterministic,, bool, 0)) \ ((deterministic,, bool, 0)) \
...@@ -66,14 +66,15 @@ struct Gibbs ...@@ -66,14 +66,15 @@ struct Gibbs
GibbsBlockState(ATs&&... as) GibbsBlockState(ATs&&... as)
: GibbsBlockStateBase<Ts...>(as...), : GibbsBlockStateBase<Ts...>(as...),
_m_entries(num_vertices(_state._bg)) _m_entries(num_vertices(_state._bg))
{ ,
_state.init_mcmc(numeric_limits<double>::infinity(), _entropy_args(python::extract<typename State::_entropy_args_t&>(_oentropy_args)) {
(_entropy_args.partition_dl || _state.init_mcmc(*this);
_entropy_args.degree_dl ||
_entropy_args.edges_dl));
} }
typename state_t::m_entries_t _m_entries; typename state_t::m_entries_t _m_entries;
typename State::_entropy_args_t& _entropy_args;
double _c = numeric_limits<double>::infinity();
std::vector<size_t> _candidate_blocks; std::vector<size_t> _candidate_blocks;
......
...@@ -40,7 +40,7 @@ using namespace std; ...@@ -40,7 +40,7 @@ using namespace std;
((beta,, double, 0)) \ ((beta,, double, 0)) \
((c,, double, 0)) \ ((c,, double, 0)) \
((d,, double, 0)) \ ((d,, double, 0)) \
((entropy_args,, entropy_args_t, 0)) \ ((oentropy_args,, python::object, 0)) \
((allow_vacate,, bool, 0)) \ ((allow_vacate,, bool, 0)) \
((sequential,, bool, 0)) \ ((sequential,, bool, 0)) \
((deterministic,, bool, 0)) \ ((deterministic,, bool, 0)) \
...@@ -68,17 +68,16 @@ struct MCMC ...@@ -68,17 +68,16 @@ struct MCMC
MCMCBlockState(ATs&&... as) MCMCBlockState(ATs&&... as)
: MCMCBlockStateBase<Ts...>(as...), : MCMCBlockStateBase<Ts...>(as...),
_g(_state._g), _g(_state._g),
_m_entries(num_vertices(_state._bg)) _m_entries(num_vertices(_state._bg)),
_entropy_args(python::extract<typename State::_entropy_args_t&>(_oentropy_args))
{ {
_state.init_mcmc(_c, _state.init_mcmc(*this);
(_entropy_args.partition_dl ||
_entropy_args.degree_dl ||
_entropy_args.edges_dl));
} }
typename state_t::g_t& _g; typename state_t::g_t& _g;
typename state_t::m_entries_t _m_entries; typename state_t::m_entries_t _m_entries;
constexpr static size_t _null_move = null_group; constexpr static size_t _null_move = null_group;
typename State::_entropy_args_t& _entropy_args;
size_t node_state(size_t v) size_t node_state(size_t v)
{ {
......
...@@ -47,7 +47,7 @@ using namespace std; ...@@ -47,7 +47,7 @@ using namespace std;
((nproposal, &, vector<size_t>&, 0)) \ ((nproposal, &, vector<size_t>&, 0)) \
((nacceptance, &, vector<size_t>&, 0)) \ ((nacceptance, &, vector<size_t>&, 0)) \
((gibbs_sweeps,, size_t, 0)) \ ((gibbs_sweeps,, size_t, 0)) \
((entropy_args,, entropy_args_t, 0)) \ ((oentropy_args,, python::object, 0)) \
((verbose,, int, 0)) \ ((verbose,, int, 0)) \
((force_move,, bool, 0)) \ ((force_move,, bool, 0)) \
((niter,, size_t, 0)) ((niter,, size_t, 0))
...@@ -82,12 +82,10 @@ struct MCMC ...@@ -82,12 +82,10 @@ struct MCMC
_bnext(get(vertex_index_t(), _state._g), _bnext(get(vertex_index_t(), _state._g),
num_vertices(_state._g)), num_vertices(_state._g)),
_btemp(get(vertex_index_t(), _state._g), _btemp(get(vertex_index_t(), _state._g),
num_vertices(_state._g)) num_vertices(_state._g)),
_entropy_args(python::extract<typename State::_entropy_args_t&>(_oentropy_args))
{ {
_state.init_mcmc(_c, _state.init_mcmc(*this);
(_entropy_args.partition_dl ||
_entropy_args.degree_dl ||
_entropy_args.edges_dl));
for (auto v : vertices_range(_state._g)) for (auto v : vertices_range(_state._g))
{ {
if (_state.node_weight(v) == 0) if (_state.node_weight(v) == 0)
...@@ -165,6 +163,7 @@ struct MCMC ...@@ -165,6 +163,7 @@ struct MCMC
typename vprop_map_t<int>::type::unchecked_t _bnext; typename vprop_map_t<int>::type::unchecked_t _bnext;
typename vprop_map_t<int>::type::unchecked_t _btemp; typename vprop_map_t<int>::type::unchecked_t _btemp;
typename State::_entropy_args_t& _entropy_args;
constexpr static size_t _null_move = 1; constexpr static size_t _null_move = 1;
......
...@@ -69,7 +69,7 @@ public: ...@@ -69,7 +69,7 @@ public:
template <class Graph, class Vprop, class VWprop, class Eprop, class Degs, template <class Graph, class Vprop, class VWprop, class Eprop, class Degs,
class Vlist> class Vlist>
partition_stats(Graph& g, Vprop& b, Vlist& vlist, size_t E, size_t B, partition_stats(Graph& g, Vprop& b, Vlist&& vlist, size_t E, size_t B,
VWprop& vweight, Eprop& eweight, Degs& degs, VWprop& vweight, Eprop& eweight, Degs& degs,
std::vector<size_t>& bmap) std::vector<size_t>& bmap)
: _bmap(bmap), _N(0), _E(E), _total_B(B) : _bmap(bmap), _N(0), _E(E), _total_B(B)
......
...@@ -241,6 +241,7 @@ struct Layers ...@@ -241,6 +241,7 @@ struct Layers
size_t _actual_B = 0; size_t _actual_B = 0;
size_t _N = 0; size_t _N = 0;
bool _is_partition_stats_enabled = false; bool _is_partition_stats_enabled = false;
typedef entropy_args_t _entropy_args_t;
LayeredBlockStateVirtualBase* _lcoupled_state = nullptr; LayeredBlockStateVirtualBase* _lcoupled_state = nullptr;
typename vc_t::checked_t _vc_c; typename vc_t::checked_t _vc_c;
typename vmap_t::checked_t _vmap_c; typename vmap_t::checked_t _vmap_c;
...@@ -821,11 +822,15 @@ struct Layers ...@@ -821,11 +822,15 @@ struct Layers
_is_partition_stats_enabled = false; _is_partition_stats_enabled = false;
} }
void init_mcmc(double c, double dl) template <class MCMCState>
void init_mcmc(MCMCState& state)
{ {
BaseState::init_mcmc(c, dl); BaseState::init_mcmc(state);
for (auto& state : _layers) double c = state._c;
state.init_mcmc(numeric_limits<double>::infinity(), dl); state._c = numeric_limits<double>::infinity();
for (auto& lstate : _layers)
lstate.init_mcmc(state);
state._c = c;
} }
LayerState& get_layer(size_t l) LayerState& get_layer(size_t l)
......
...@@ -1194,8 +1194,14 @@ public: ...@@ -1194,8 +1194,14 @@ public:
return _pclabel; return _pclabel;
} }
void init_mcmc(double c, double dl) template <class MCMCState>
{ void init_mcmc(MCMCState& state)
{
auto c = state._c;
auto& entropy_args = state._entropy_args;
bool dl = (entropy_args.partition_dl ||
entropy_args.degree_dl ||
entropy_args.edges_dl);
if (!std::isinf(c)) if (!std::isinf(c))
{ {
if (_egroups.empty()) if (_egroups.empty())
...@@ -1316,6 +1322,7 @@ public: ...@@ -1316,6 +1322,7 @@ public:
UnityPropertyMap<int,GraphInterface::edge_t> _eweight; UnityPropertyMap<int,GraphInterface::edge_t> _eweight;
UnityPropertyMap<int,GraphInterface::vertex_t> _vweight; UnityPropertyMap<int,GraphInterface::vertex_t> _vweight;
typedef entropy_args_t _entropy_args_t;
BlockStateVirtualBase* _coupled_state; BlockStateVirtualBase* _coupled_state;
entropy_args_t _coupled_entropy_args; entropy_args_t _coupled_entropy_args;
......
...@@ -40,7 +40,7 @@ using namespace std; ...@@ -40,7 +40,7 @@ using namespace std;
((beta,, double, 0)) \ ((beta,, double, 0)) \
((c,, double, 0)) \ ((c,, double, 0)) \
((d,, double, 0)) \ ((d,, double, 0)) \
((entropy_args,, entropy_args_t, 0)) \ ((oentropy_args,, python::object, 0)) \
((allow_vacate,, bool, 0)) \ ((allow_vacate,, bool, 0)) \
((sequential,, bool, 0)) \ ((sequential,, bool, 0)) \
((deterministic,, bool, 0)) \ ((deterministic,, bool, 0)) \
...@@ -69,12 +69,10 @@ struct MCMC ...@@ -69,12 +69,10 @@ struct MCMC
BundledMCMCOverlapBlockState(ATs&&... as) BundledMCMCOverlapBlockState(ATs&&... as)
: BundledMCMCOverlapBlockStateBase<Ts...>(as...), : BundledMCMCOverlapBlockStateBase<Ts...>(as...),
_g(_state._g), _g(_state._g),
_parallel(false) _parallel(false),
_entropy_args(python::extract<typename State::_entropy_args_t&>(_oentropy_args))
{ {
_state.init_mcmc(_c, _state.init_mcmc(*this);
(_entropy_args.partition_dl ||
_entropy_args.degree_dl ||
_entropy_args.edges_dl));
for (auto v : _vlist) for (auto v : _vlist)
{ {
...@@ -105,6 +103,7 @@ struct MCMC ...@@ -105,6 +103,7 @@ struct MCMC
std::vector<std::vector<size_t>> _half_edges; std::vector<std::vector<size_t>> _half_edges;
std::vector<std::vector<size_t>> _bundles; std::vector<std::vector<size_t>> _bundles;
bool _parallel; bool _parallel;
typename State::_entropy_args_t& _entropy_args;
size_t _null_move = null_group; size_t _null_move = null_group;
size_t node_state(size_t i) size_t node_state(size_t i)
......
...@@ -110,6 +110,8 @@ public: ...@@ -110,6 +110,8 @@ public:
std::vector<size_t> _bclabel; std::vector<size_t> _bclabel;
std::vector<size_t> _pclabel; std::vector<size_t> _pclabel;
typedef char _entropy_args_t;
constexpr static BlockStateVirtualBase* _coupled_state = nullptr; constexpr static BlockStateVirtualBase* _coupled_state = nullptr;
typedef int m_entries_t; typedef int m_entries_t;
...@@ -269,7 +271,8 @@ public: ...@@ -269,7 +271,8 @@ public:
return S; return S;
} }
void init_mcmc(double, double) template <class MCMCState>
void init_mcmc(MCMCState&)
{ {
} }
......
...@@ -160,6 +160,8 @@ public: ...@@ -160,6 +160,8 @@ public:
std::vector<size_t> _bclabel; std::vector<size_t> _bclabel;
std::vector<size_t> _pclabel; std::vector<size_t> _pclabel;
typedef char _entropy_args_t;
constexpr static BlockStateVirtualBase* _coupled_state = nullptr; constexpr static BlockStateVirtualBase* _coupled_state = nullptr;
typedef int m_entries_t; typedef int m_entries_t;
...@@ -312,7 +314,8 @@ public: ...@@ -312,7 +314,8 @@ public:
return -S; return -S;
} }
void init_mcmc(double, double) template <class MCMCState>
void init_mcmc(MCMCState&)
{ {
} }
......
...@@ -1292,6 +1292,7 @@ public: ...@@ -1292,6 +1292,7 @@ public:
std::vector<size_t> _free_pos; std::vector<size_t> _free_pos;
size_t _max_pos = 0; size_t _max_pos = 0;
typedef char _entropy_args_t;
std::shared_ptr<PartitionModeState> _coupled_state; std::shared_ptr<PartitionModeState> _coupled_state;
idx_map<size_t, size_t> _coupled_pos; idx_map<size_t, size_t> _coupled_pos;
......
...@@ -149,6 +149,8 @@ public: ...@@ -149,6 +149,8 @@ public:
bool _egroups_update = true; bool _egroups_update = true;
typedef char _entropy_args_t;
PartitionModeState& get_mode(size_t r) PartitionModeState& get_mode(size_t r)
{ {
return _modes[r]; return _modes[r];
...@@ -547,7 +549,8 @@ public: ...@@ -547,7 +549,8 @@ public:
} }
} }
void init_mcmc(double, double) template <class MCMCState>
void init_mcmc(MCMCState&)
{ {
} }
......
...@@ -1440,7 +1440,7 @@ class BlockState(object): ...@@ -1440,7 +1440,7 @@ class BlockState(object):
hasattr(self, "degs") and hasattr(self, "degs") and
not isinstance(self.degs, libinference.simple_degs_t)): not isinstance(self.degs, libinference.simple_degs_t)):
entropy_args["multigraph"] = False entropy_args["multigraph"] = False
mcmc_state.entropy_args = get_entropy_args(entropy_args) mcmc_state.oentropy_args = get_entropy_args(entropy_args)
mcmc_state.vlist = Vector_size_t() mcmc_state.vlist = Vector_size_t()
if vertices is None: if vertices is None:
vertices = self.g.vertex_index.copy().fa vertices = self.g.vertex_index.copy().fa
...@@ -1560,7 +1560,7 @@ class BlockState(object): ...@@ -1560,7 +1560,7 @@ class BlockState(object):
hasattr(self, "degs") and hasattr(self, "degs") and
not isinstance(self.degs, libinference.simple_degs_t)): not isinstance(self.degs, libinference.simple_degs_t)):
entropy_args["multigraph"] = False entropy_args["multigraph"] = False
mcmc_state.entropy_args = get_entropy_args(entropy_args) mcmc_state.oentropy_args = get_entropy_args(entropy_args)
mcmc_state.state = self._state mcmc_state.state = self._state
dispatch = kwargs.pop("dispatch", True) dispatch = kwargs.pop("dispatch", True)
...@@ -1659,7 +1659,7 @@ class BlockState(object): ...@@ -1659,7 +1659,7 @@ class BlockState(object):
gibbs_state = DictState(locals()) gibbs_state = DictState(locals())
entropy_args = dict(self._entropy_args, **entropy_args) entropy_args = dict(self._entropy_args, **entropy_args)
gibbs_state.entropy_args = get_entropy_args(entropy_args) gibbs_state.oentropy_args = get_entropy_args(entropy_args)
gibbs_state.vlist = Vector_size_t() gibbs_state.vlist = Vector_size_t()
if vertices is None: if vertices is None:
vertices = self.g.get_vertices() vertices = self.g.get_vertices()
...@@ -1933,7 +1933,7 @@ class BlockState(object): ...@@ -1933,7 +1933,7 @@ class BlockState(object):
exhaustive_state = DictState(dict(max_iter=max_iter if max_iter is not None else 0)) exhaustive_state = DictState(dict(max_iter=max_iter if max_iter is not None else 0))
entropy_args = dict(self._entropy_args, **entropy_args) entropy_args = dict(self._entropy_args, **entropy_args)
exhaustive_state.entropy_args = get_entropy_args(entropy_args) exhaustive_state.oentropy_args = get_entropy_args(entropy_args)
exhaustive_state.vlist = Vector_size_t() exhaustive_state.vlist = Vector_size_t()
if vertices is None: if vertices is None:
vertices = self.g.vertex_index.copy().fa vertices = self.g.vertex_index.copy().fa
...@@ -1975,8 +1975,8 @@ class BlockState(object): ...@@ -1975,8 +1975,8 @@ class BlockState(object):
if not self.is_weighted: if not self.is_weighted:
raise ValueError("state must be weighted to perform merges") raise ValueError("state must be weighted to perform merges")
if (merge_state.entropy_args.multigraph and if (merge_state.oentropy_args.multigraph and
not merge_state.entropy_args.dense): not merge_state.oentropy_args.dense):
raise ValueError("can only merge multigraphs if dense == True") raise ValueError("can only merge multigraphs if dense == True")
return libinference.merge_sweep(merge_state, self._state, return libinference.merge_sweep(merge_state, self._state,
...@@ -2031,6 +2031,7 @@ class BlockState(object): ...@@ -2031,6 +2031,7 @@ class BlockState(object):
merge_state.state = self._state merge_state.state = self._state
entropy_args = dict(self._entropy_args, **entropy_args) entropy_args = dict(self._entropy_args, **entropy_args)
merge_state.entropy_args = get_entropy_args(entropy_args) merge_state.entropy_args = get_entropy_args(entropy_args)
merge_state.oentropy_args = merge_state.entropy_args
if _bm_test(): if _bm_test():
assert self._check_clabel(), "invalid clabel before sweep" assert self._check_clabel(), "invalid clabel before sweep"
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from .. import Graph, _get_rng, Vector_size_t from .. import Graph, _get_rng, Vector_size_t
from . blockmodel import DictState, get_entropy_args, _bm_test from . blockmodel import DictState, _bm_test
from . partition_modes import contingency_graph from . partition_modes import contingency_graph
from .. dl_import import dl_import from .. dl_import import dl_import
...@@ -62,13 +62,6 @@ class PartitionCentroidState(object): ...@@ -62,13 +62,6 @@ class PartitionCentroidState(object):
else: else:
self._state = libinference.make_vi_center_state(self) self._state = libinference.make_vi_center_state(self)
self._entropy_args = dict(adjacency=True, deg_entropy=True, dl=True,
partition_dl=True, degree_dl=True,
degree_dl_kind="distributed", edges_dl=True,
dense=False, multigraph=True, exact=True,
recs=True, recs_dl=True, beta_dl=1.,
Bfield=True)
def __copy__(self): def __copy__(self):
return self.copy() return self.copy()
...@@ -109,15 +102,14 @@ class PartitionCentroidState(object): ...@@ -109,15 +102,14 @@ class PartitionCentroidState(object):
def entropy(self): def entropy(self):
return self._state.entropy() return self._state.entropy()
def mcmc_sweep(self, beta=1.,d=.01, niter=1, entropy_args={}, def mcmc_sweep(self, beta=1.,d=.01, niter=1, allow_vacate=True,
allow_vacate=True, sequential=True, deterministic=False, sequential=True, deterministic=False, verbose=False,
verbose=False, **kwargs): **kwargs):
r"""Perform sweeps of a Metropolis-Hastings rejection sampling MCMC to sample r"""Perform sweeps of a Metropolis-Hastings rejection sampling MCMC to sample
network partitions. See network partitions. See
:meth:`graph_tool.inference.blockmodel.BlockState.mcmc_sweep` for the :meth:`graph_tool.inference.blockmodel.BlockState.mcmc_sweep` for the
parameter documentation. """ parameter documentation. """
mcmc_state = DictState(locals()) mcmc_state = DictState(locals())
mcmc_state.entropy_args = get_entropy_args(self._entropy_args)
mcmc_state.vlist = Vector_size_t() mcmc_state.vlist = Vector_size_t()
mcmc_state.vlist.resize(len(self.b)) mcmc_state.vlist.resize(len(self.b))
mcmc_state.vlist.a = np.arange(len(self.b)) mcmc_state.vlist.a = np.arange(len(self.b))
...@@ -139,10 +131,9 @@ class PartitionCentroidState(object): ...@@ -139,10 +131,9 @@ class PartitionCentroidState(object):
_get_rng()) _get_rng())
if _bm_test() and test: if _bm_test() and test:
Sf = self.entropy(**entropy_args) Sf = self.entropy()
assert math.isclose(dS, (Sf - Si), abs_tol=1e-8), \ assert math.isclose(dS, (Sf - Si), abs_tol=1e-8), \
"inconsistent entropy delta %g (%g): %s" % (dS, Sf - Si, "inconsistent entropy delta %g (%g): %s" % (dS, Sf - Si)
str(entropy_args))
if len(kwargs) > 0: if len(kwargs) > 0:
raise ValueError("unrecognized keyword arguments: " +