Commit 32951567 authored by Tiago Peixoto's avatar Tiago Peixoto

inference: isolate entropy_args

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